001/* ***** BEGIN LICENSE BLOCK ***** 002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 003 * 004 * The contents of this file are subject to the Mozilla Public License Version 005 * 1.1 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * http://www.mozilla.org/MPL/ 008 * 009 * Software distributed under the License is distributed on an "AS IS" basis, 010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 011 * for the specific language governing rights and limitations under the 012 * License. 013 * 014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in 015 * Java(TM), hosted at https://github.com/gunterze/dcm4che. 016 * 017 * The Initial Developer of the Original Code is 018 * Agfa Healthcare. 019 * Portions created by the Initial Developer are Copyright (C) 2011 020 * the Initial Developer. All Rights Reserved. 021 * 022 * Contributor(s): 023 * See @authors listed below 024 * 025 * Alternatively, the contents of this file may be used under the terms of 026 * either the GNU General Public License Version 2 or later (the "GPL"), or 027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 028 * in which case the provisions of the GPL or the LGPL are applicable instead 029 * of those above. If you wish to allow use of your version of this file only 030 * under the terms of either the GPL or the LGPL, and not to allow others to 031 * use your version of this file under the terms of the MPL, indicate your 032 * decision by deleting the provisions above and replace them with the notice 033 * and other provisions required by the GPL or the LGPL. If you do not delete 034 * the provisions above, a recipient may use your version of this file under 035 * the terms of any one of the MPL, the GPL or the LGPL. 036 * 037 * ***** END LICENSE BLOCK ***** */ 038 039package org.dcm4che3.tool.dcm2json; 040 041import java.io.BufferedOutputStream; 042import java.io.File; 043import java.io.FileInputStream; 044import java.io.FileOutputStream; 045import java.io.IOException; 046import java.io.InputStream; 047import java.io.InputStreamReader; 048import java.io.OutputStream; 049import java.util.HashMap; 050import java.util.List; 051import java.util.Map; 052import java.util.ResourceBundle; 053 054import javax.json.Json; 055import javax.json.stream.JsonGenerator; 056import javax.xml.transform.TransformerConfigurationException; 057 058import org.apache.commons.cli.CommandLine; 059import org.apache.commons.cli.OptionBuilder; 060import org.apache.commons.cli.OptionGroup; 061import org.apache.commons.cli.Options; 062import org.apache.commons.cli.ParseException; 063import org.dcm4che3.data.Attributes; 064import org.dcm4che3.io.BulkDataDescriptor; 065import org.dcm4che3.io.DicomInputStream; 066import org.dcm4che3.io.DicomInputStream.IncludeBulkData; 067import org.dcm4che3.json.JSONReader; 068import org.dcm4che3.json.JSONWriter; 069import org.dcm4che3.tool.common.CLIUtils; 070import org.dcm4che3.util.SafeClose; 071 072/** 073 * Tool to convert DICOM to JSON representation. 074 * 075 * @author Gunter Zeilinger <gunterze@gmail.com> 076 */ 077public class Dcm2Json { 078 079 private static ResourceBundle rb = 080 ResourceBundle.getBundle("org.dcm4che3.tool.dcm2json.messages"); 081 082 private boolean indent = false; 083 private IncludeBulkData includeBulkData = IncludeBulkData.URI; 084 private boolean catBlkFiles = false; 085 private String blkFilePrefix = "blk"; 086 private String blkFileSuffix; 087 private File blkDirectory; 088 private Attributes blkAttrs; 089 090 public final void setIndent(boolean indent) { 091 this.indent = indent; 092 } 093 094 public final void setIncludeBulkData(IncludeBulkData includeBulkData) { 095 this.includeBulkData = includeBulkData; 096 } 097 098 public final void setConcatenateBulkDataFiles(boolean catBlkFiles) { 099 this.catBlkFiles = catBlkFiles; 100 } 101 102 public final void setBulkDataFilePrefix(String blkFilePrefix) { 103 this.blkFilePrefix = blkFilePrefix; 104 } 105 106 public final void setBulkDataFileSuffix(String blkFileSuffix) { 107 this.blkFileSuffix = blkFileSuffix; 108 } 109 110 public final void setBulkDataDirectory(File blkDirectory) { 111 this.blkDirectory = blkDirectory; 112 } 113 114 public final void setBulkDataAttributes(Attributes blkAttrs) { 115 this.blkAttrs = blkAttrs; 116 } 117 118 private static CommandLine parseComandLine(String[] args) 119 throws ParseException { 120 Options opts = new Options(); 121 CLIUtils.addCommonOptions(opts); 122 opts.addOption("I", "indent", false, rb.getString("indent")); 123 addBulkdataOptions(opts); 124 125 return CLIUtils.parseComandLine(args, opts, rb, Dcm2Json.class); 126 } 127 128 @SuppressWarnings("static-access") 129 private static void addBulkdataOptions(Options opts) { 130 OptionGroup group = new OptionGroup(); 131 group.addOption(OptionBuilder 132 .withLongOpt("no-bulkdata") 133 .withDescription(rb.getString("no-bulkdata")) 134 .create("B")); 135 group.addOption(OptionBuilder 136 .withLongOpt("with-bulkdata") 137 .withDescription(rb.getString("with-bulkdata")) 138 .create("b")); 139 opts.addOptionGroup(group); 140 opts.addOption(OptionBuilder 141 .withLongOpt("blk-file-dir") 142 .hasArg() 143 .withArgName("directory") 144 .withDescription(rb.getString("blk-file-dir")) 145 .create("d")); 146 opts.addOption(OptionBuilder 147 .withLongOpt("blk-file-prefix") 148 .hasArg() 149 .withArgName("prefix") 150 .withDescription(rb.getString("blk-file-prefix")) 151 .create()); 152 opts.addOption(OptionBuilder 153 .withLongOpt("blk-file-suffix") 154 .hasArg() 155 .withArgName("suffix") 156 .withDescription(rb.getString("blk-file-dir")) 157 .create()); 158 opts.addOption("c", "cat-blk-files", false, 159 rb.getString("cat-blk-files")); 160 opts.addOption(OptionBuilder 161 .withLongOpt("blk-spec") 162 .hasArg() 163 .withArgName("json-file") 164 .withDescription(rb.getString("blk-spec")) 165 .create("J")); 166 } 167 168 @SuppressWarnings("unchecked") 169 public static void main(String[] args) { 170 try { 171 CommandLine cl = parseComandLine(args); 172 Dcm2Json main = new Dcm2Json(); 173 main.setIndent(cl.hasOption("I")); 174 configureBulkdata(main, cl); 175 String fname = fname(cl.getArgList()); 176 if (fname.equals("-")) { 177 main.convert(new DicomInputStream(System.in), System.out); 178 } else { 179 main.convert(new File(fname), System.out); 180 } 181 } catch (ParseException e) { 182 System.err.println("dcm2xml: " + e.getMessage()); 183 System.err.println(rb.getString("try")); 184 System.exit(2); 185 } catch (Exception e) { 186 System.err.println("dcm2xml: " + e.getMessage()); 187 e.printStackTrace(); 188 System.exit(2); 189 } 190 } 191 192 private static void configureBulkdata(Dcm2Json dcm2json, CommandLine cl) 193 throws Exception { 194 if (cl.hasOption("b")) { 195 dcm2json.setIncludeBulkData(IncludeBulkData.YES); 196 } 197 if (cl.hasOption("B")) { 198 dcm2json.setIncludeBulkData(IncludeBulkData.NO); 199 } 200 if (cl.hasOption("blk-file-prefix")) { 201 dcm2json.setBulkDataFilePrefix( 202 cl.getOptionValue("blk-file-prefix")); 203 } 204 if (cl.hasOption("blk-file-suffix")) { 205 dcm2json.setBulkDataFileSuffix( 206 cl.getOptionValue("blk-file-suffix")); 207 } 208 if (cl.hasOption("d")) { 209 File tempDir = new File(cl.getOptionValue("d")); 210 dcm2json.setBulkDataDirectory(tempDir); 211 } 212 dcm2json.setConcatenateBulkDataFiles(cl.hasOption("c")); 213 if (cl.hasOption("J")) { 214 dcm2json.setBulkDataAttributes( 215 parseJSON(cl.getOptionValue("J"))); 216 } 217 } 218 219 private static Attributes parseJSON(String fname) throws Exception { 220 InputStream in = new FileInputStream(fname); 221 try { 222 JSONReader reader = new JSONReader( 223 Json.createParser(new InputStreamReader(in, "UTF-8"))); 224 return reader.readDataset(null); 225 } finally { 226 SafeClose.close(in); 227 } 228 } 229 230 231 private static String fname(List<String> argList) throws ParseException { 232 int numArgs = argList.size(); 233 if (numArgs == 0) 234 throw new ParseException(rb.getString("missing")); 235 if (numArgs > 1) 236 throw new ParseException(rb.getString("too-many")); 237 return argList.get(0); 238 } 239 240 public void convert(DicomInputStream dis, OutputStream out) throws IOException { 241 dis.setIncludeBulkData(includeBulkData); 242 if (blkAttrs != null) 243 dis.setBulkDataDescriptor(BulkDataDescriptor.valueOf(blkAttrs)); 244 dis.setBulkDataDirectory(blkDirectory); 245 dis.setBulkDataFilePrefix(blkFilePrefix); 246 dis.setBulkDataFileSuffix(blkFileSuffix); 247 dis.setConcatenateBulkDataFiles(catBlkFiles); 248 JsonGenerator jsonGen = createGenerator(out); 249 JSONWriter jsonWriter = new JSONWriter(jsonGen); 250 dis.setDicomInputHandler(jsonWriter); 251 dis.readDataset(-1, -1); 252 jsonGen.flush(); 253 } 254 255 public void convert(File dicomFile, OutputStream out) throws IOException, 256 TransformerConfigurationException { 257 DicomInputStream dis = new DicomInputStream(dicomFile); 258 try { 259 convert(dis, out); 260 } finally { 261 dis.close(); 262 } 263 } 264 265 public void convert(File dicomFile, File jsonFile) throws IOException, 266 TransformerConfigurationException { 267 OutputStream out = new BufferedOutputStream(new FileOutputStream(jsonFile)); 268 try { 269 convert(dicomFile, out); 270 } finally { 271 out.close(); 272 } 273 } 274 275 private JsonGenerator createGenerator(OutputStream out) { 276 Map<String, ?> conf = new HashMap<String, Object>(2); 277 if (indent) 278 conf.put(JsonGenerator.PRETTY_PRINTING, null); 279 return Json.createGeneratorFactory(conf).createGenerator(out); 280 } 281 282}