001/*
002 * ** BEGIN LICENSE BLOCK *****
003 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
004 *
005 * The contents of this file are subject to the Mozilla Public License Version
006 * 1.1 (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 * http://www.mozilla.org/MPL/
009 *
010 * Software distributed under the License is distributed on an "AS IS" basis,
011 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012 * for the specific language governing rights and limitations under the
013 * License.
014 *
015 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in
016 * Java(TM), hosted at https://github.com/gunterze/dcm4che.
017 *
018 * The Initial Developer of the Original Code is
019 * J4Care.
020 * Portions created by the Initial Developer are Copyright (C) 2016
021 * the Initial Developer. All Rights Reserved.
022 *
023 * Contributor(s):
024 * See @authors listed below
025 *
026 * Alternatively, the contents of this file may be used under the terms of
027 * either the GNU General Public License Version 2 or later (the "GPL"), or
028 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
029 * in which case the provisions of the GPL or the LGPL are applicable instead
030 * of those above. If you wish to allow use of your version of this file only
031 * under the terms of either the GPL or the LGPL, and not to allow others to
032 * use your version of this file under the terms of the MPL, indicate your
033 * decision by deleting the provisions above and replace them with the notice
034 * and other provisions required by the GPL or the LGPL. If you do not delete
035 * the provisions above, a recipient may use your version of this file under
036 * the terms of any one of the MPL, the GPL or the LGPL.
037 *
038 * ** END LICENSE BLOCK *****
039 */
040
041package org.dcm4che3.tool.swappxdata;
042
043import org.dcm4che3.data.Attributes;
044import org.dcm4che3.data.BulkData;
045import org.dcm4che3.data.Tag;
046import org.dcm4che3.data.VR;
047import org.dcm4che3.io.DicomInputStream;
048import org.dcm4che3.util.ByteUtils;
049import org.dcm4che3.util.SafeClose;
050
051import java.io.File;
052import java.io.IOException;
053import java.io.RandomAccessFile;
054import java.util.ArrayList;
055
056/**
057 * @author Gunter Zeilinger <gunterze@gmail.com>
058 * @since Oct 2016
059 */
060public class SwapPxData {
061
062    private int updated;
063    private int skipped;
064    private int failed;
065
066    public static void main(String[] args) throws Exception {
067        if (args.length == 0) {
068            System.out.println("Usage: swappxdata <dicom-file>|<directory>...");
069            System.exit(-1);
070        }
071        long start = System.currentTimeMillis();
072        SwapPxData inst = new SwapPxData();
073        for (String path : args) {
074            inst.processFileOrDirectory(new File(path));
075        }
076        long stop = System.currentTimeMillis();
077        System.out.println();
078        log(inst.updated, " files updated");
079        log(inst.skipped, " files skipped");
080        log(inst.failed, " files failed to update");
081        System.out.println("in " + (stop - start) + " ms");
082    }
083
084    private static void log(int n, String suffix) {
085        if (n > 0)
086            System.out.println(n + suffix);
087    }
088
089    private void processFileOrDirectory(File fileOrDir) {
090        if (fileOrDir.isDirectory()) {
091            for (File fileOrSubDir : fileOrDir.listFiles()) {
092                processFileOrDirectory(fileOrSubDir);
093            }
094        } else
095            System.out.print(processFile(fileOrDir));
096    }
097
098    private char processFile(File file) {
099        try {
100            Attributes dataset;
101            DicomInputStream is = null;
102            try {
103                is = new DicomInputStream(file);
104                is.setIncludeBulkData(DicomInputStream.IncludeBulkData.URI);
105                dataset = is.readDataset(-1, -1);
106            } finally {
107                SafeClose.close(is);
108            }
109            VR.Holder vr = new VR.Holder();
110            Object value = dataset.getValue(Tag.PixelData, vr);
111            if ((value instanceof BulkData) && vr.vr == VR.OW) {
112                RandomAccessFile raf = null;
113                try {
114                    raf = new RandomAccessFile(file, "rw");
115                    toggleEndian(raf, (BulkData) value);
116                } finally {
117                    SafeClose.close(raf);
118                }
119                updated++;
120                return '.';
121            }
122            skipped++;
123            return value == null ? 'p' : (value instanceof BulkData) ? 'b' : 'c';
124        } catch (IOException e) {
125            System.err.println("Failed to update " + file + ':');
126            e.printStackTrace(System.err);
127            failed++;
128        }
129        return 'E';
130    }
131
132    private void toggleEndian(RandomAccessFile raf, BulkData bulkData) throws IOException {
133        byte[] b = new byte[bulkData.length()];
134        raf.seek(bulkData.offset());
135        raf.readFully(b);
136        raf.seek(bulkData.offset());
137        raf.write(ByteUtils.swapShorts(b, 0, b.length));
138    }
139
140}