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.json2dcm; 040 041import java.io.BufferedOutputStream; 042import java.io.File; 043import java.io.FileDescriptor; 044import java.io.FileInputStream; 045import java.io.FileOutputStream; 046import java.io.IOException; 047import java.io.InputStream; 048import java.io.InputStreamReader; 049import java.io.OutputStream; 050import java.util.List; 051import java.util.ResourceBundle; 052 053import javax.json.Json; 054 055import org.apache.commons.cli.CommandLine; 056import org.apache.commons.cli.OptionBuilder; 057import org.apache.commons.cli.OptionGroup; 058import org.apache.commons.cli.Options; 059import org.apache.commons.cli.ParseException; 060import org.dcm4che3.data.Attributes; 061import org.dcm4che3.data.Tag; 062import org.dcm4che3.data.UID; 063import org.dcm4che3.io.BulkDataDescriptor; 064import org.dcm4che3.io.DicomEncodingOptions; 065import org.dcm4che3.io.DicomInputStream; 066import org.dcm4che3.io.DicomInputStream.IncludeBulkData; 067import org.dcm4che3.io.DicomOutputStream; 068import org.dcm4che3.json.JSONReader; 069import org.dcm4che3.tool.common.CLIUtils; 070import org.dcm4che3.util.SafeClose; 071 072/** 073 * Tool to convert JSON to XML. 074 * 075 * @author Gunter Zeilinger <gunterze@gmail.com> 076 */ 077public class Json2Dcm { 078 079 private static ResourceBundle rb = 080 ResourceBundle.getBundle("org.dcm4che3.tool.json2dcm.messages"); 081 082 private IncludeBulkData includeBulkData = IncludeBulkData.URI; 083 private boolean catBlkFiles = false; 084 private String blkFilePrefix = "blk"; 085 private String blkFileSuffix; 086 private File blkDirectory; 087 private Attributes blkAttrs; 088 private String tsuid; 089 private boolean withfmi; 090 private boolean nofmi; 091 private DicomEncodingOptions encOpts = DicomEncodingOptions.DEFAULT; 092 private List<File> bulkDataFiles; 093 private Attributes fmi; 094 private Attributes dataset; 095 096 public final void setIncludeBulkData(IncludeBulkData includeBulkData) { 097 this.includeBulkData = includeBulkData; 098 } 099 100 public final void setConcatenateBulkDataFiles(boolean catBlkFiles) { 101 this.catBlkFiles = catBlkFiles; 102 } 103 104 public final void setBulkDataFilePrefix(String blkFilePrefix) { 105 this.blkFilePrefix = blkFilePrefix; 106 } 107 108 public final void setBulkDataFileSuffix(String blkFileSuffix) { 109 this.blkFileSuffix = blkFileSuffix; 110 } 111 112 public final void setBulkDataDirectory(File blkDirectory) { 113 this.blkDirectory = blkDirectory; 114 } 115 116 public final void setBulkDataAttributes(Attributes blkAttrs) { 117 this.blkAttrs = blkAttrs; 118 } 119 120 public final void setTransferSyntax(String uid) { 121 this.tsuid = uid; 122 } 123 124 public final void setWithFileMetaInformation(boolean withfmi) { 125 this.withfmi = withfmi; 126 } 127 128 public final void setNoFileMetaInformation(boolean nofmi) { 129 this.nofmi = nofmi; 130 } 131 132 public final void setEncodingOptions(DicomEncodingOptions encOpts) { 133 this.encOpts = encOpts; 134 } 135 136 private static CommandLine parseComandLine(String[] args) 137 throws ParseException{ 138 Options opts = new Options(); 139 CLIUtils.addCommonOptions(opts); 140 addIOFileNameOptions(opts); 141 addBulkdataOptions(opts); 142 addFileEncodingOptions(opts); 143 CommandLine cl = CLIUtils.parseComandLine(args, opts, rb, Json2Dcm.class); 144 if (!(cl.hasOption("j") || cl.hasOption("i"))) 145 throw new ParseException(rb.getString("missing-i-j")); 146 return cl; 147 } 148 149 @SuppressWarnings("static-access") 150 private static void addIOFileNameOptions(Options opts) { 151 opts.addOption(OptionBuilder 152 .hasArg() 153 .withArgName("json-file") 154 .withDescription(rb.getString("j-file")) 155 .create("j")); 156 opts.addOption(OptionBuilder 157 .hasArg() 158 .withArgName("dicom-file") 159 .withDescription(rb.getString("i-file")) 160 .create("i")); 161 opts.addOption(OptionBuilder 162 .hasArg() 163 .withArgName("dicom-file") 164 .withDescription(rb.getString("o-file")) 165 .create("o")); 166 } 167 168 169 @SuppressWarnings("static-access") 170 private static void addBulkdataOptions(Options opts) { 171 OptionGroup blkGroup = new OptionGroup(); 172 blkGroup.addOption(OptionBuilder 173 .withLongOpt("no-bulkdata") 174 .withDescription(rb.getString("no-bulkdata")) 175 .create("B")); 176 blkGroup.addOption(OptionBuilder 177 .withLongOpt("alloc-bulkdata") 178 .withDescription(rb.getString("alloc-bulkdata")) 179 .create("b")); 180 opts.addOptionGroup(blkGroup); 181 opts.addOption(OptionBuilder 182 .withLongOpt("blk-file-dir") 183 .hasArg() 184 .withArgName("directory") 185 .withDescription(rb.getString("blk-file-dir")) 186 .create("d")); 187 opts.addOption(OptionBuilder 188 .withLongOpt("blk-file-prefix") 189 .hasArg() 190 .withArgName("prefix") 191 .withDescription(rb.getString("blk-file-prefix")) 192 .create()); 193 opts.addOption(OptionBuilder 194 .withLongOpt("blk-file-suffix") 195 .hasArg() 196 .withArgName("suffix") 197 .withDescription(rb.getString("blk-file-suffix")) 198 .create()); 199 opts.addOption("c", "cat-blk-files", false, 200 rb.getString("cat-blk-files")); 201 opts.addOption(null, "keep-blk-files", false, 202 rb.getString("keep-blk-files")); 203 opts.addOption(OptionBuilder 204 .withLongOpt("blk-spec") 205 .hasArg() 206 .withArgName("json-file") 207 .withDescription(rb.getString("blk-spec")) 208 .create("J")); 209 } 210 211 @SuppressWarnings("static-access") 212 private static void addFileEncodingOptions(Options opts) { 213 opts.addOption(OptionBuilder 214 .withLongOpt("transfer-syntax") 215 .hasArg() 216 .withArgName("uid") 217 .withDescription(rb.getString("transfer-syntax")) 218 .create("t")); 219 OptionGroup fmiGroup = new OptionGroup(); 220 fmiGroup.addOption(OptionBuilder 221 .withLongOpt("no-fmi") 222 .withDescription(rb.getString("no-fmi")) 223 .create("F")); 224 fmiGroup.addOption(OptionBuilder 225 .withLongOpt("fmi") 226 .withDescription(rb.getString("fmi")) 227 .create("f")); 228 opts.addOptionGroup(fmiGroup); 229 CLIUtils.addEncodingOptions(opts); 230 } 231 232 public static void main(String[] args) { 233 try { 234 CommandLine cl = parseComandLine(args); 235 Json2Dcm main = new Json2Dcm(); 236 configureBulkdata(main, cl); 237 if (cl.hasOption("t")) { 238 main.setTransferSyntax(cl.getOptionValue("t")); 239 } 240 main.setWithFileMetaInformation(cl.hasOption("f")); 241 main.setNoFileMetaInformation(cl.hasOption("F")); 242 main.setEncodingOptions(CLIUtils.encodingOptionsOf(cl)); 243 try { 244 if (cl.hasOption("i")) { 245 String fname = cl.getOptionValue("i"); 246 if (fname.equals("-")) { 247 main.parse(new DicomInputStream(System.in)); 248 } else { 249 DicomInputStream dis = 250 new DicomInputStream(new File(fname)); 251 try { 252 main.parse(dis); 253 } finally { 254 dis.close(); 255 } 256 } 257 } 258 259 if (cl.hasOption("j")) 260 main.mergeJSON(cl.getOptionValue("j")); 261 262 OutputStream out = cl.hasOption("o") 263 ? new FileOutputStream(cl.getOptionValue("o")) 264 : new FileOutputStream(FileDescriptor.out); 265 try { 266 main.writeTo(out); 267 } finally { 268 out.close(); 269 } 270 } finally { 271 if (!cl.hasOption("keep-blk-files")) 272 main.delBulkDataFiles(); 273 } 274 } catch (ParseException e) { 275 System.err.println("json2dcm: " + e.getMessage()); 276 System.err.println(rb.getString("try")); 277 System.exit(2); 278 } catch (Exception e) { 279 System.err.println("json2dcm: " + e.getMessage()); 280 e.printStackTrace(); 281 System.exit(2); 282 } 283 } 284 285 private static void configureBulkdata(Json2Dcm json2dcm, CommandLine cl) 286 throws Exception { 287 if (cl.hasOption("b")) { 288 json2dcm.setIncludeBulkData(IncludeBulkData.YES); 289 } 290 if (cl.hasOption("B")) { 291 json2dcm.setIncludeBulkData(IncludeBulkData.NO); 292 } 293 if (cl.hasOption("blk-file-prefix")) { 294 json2dcm.setBulkDataFilePrefix( 295 cl.getOptionValue("blk-file-prefix")); 296 } 297 if (cl.hasOption("blk-file-suffix")) { 298 json2dcm.setBulkDataFileSuffix( 299 cl.getOptionValue("blk-file-suffix")); 300 } 301 if (cl.hasOption("d")) { 302 File tempDir = new File(cl.getOptionValue("d")); 303 json2dcm.setBulkDataDirectory(tempDir); 304 } 305 json2dcm.setConcatenateBulkDataFiles(cl.hasOption("c")); 306 if (cl.hasOption("J")) { 307 json2dcm.setBulkDataAttributes( 308 parseJSON(cl.getOptionValue("J"))); 309 } 310 } 311 312 public void writeTo(OutputStream out) throws IOException { 313 if (nofmi) 314 fmi = null; 315 else if (fmi == null 316 ? withfmi 317 : tsuid != null && !tsuid.equals( 318 fmi.getString(Tag.TransferSyntaxUID, null))) { 319 fmi = dataset.createFileMetaInformation(tsuid); 320 } 321 @SuppressWarnings("resource") 322 DicomOutputStream dos = new DicomOutputStream( 323 new BufferedOutputStream(out), 324 fmi != null 325 ? UID.ExplicitVRLittleEndian 326 : tsuid != null 327 ? tsuid 328 : UID.ImplicitVRLittleEndian); 329 dos.setEncodingOptions(encOpts); 330 dos.writeDataset(fmi, dataset); 331 dos.finish(); 332 dos.flush(); 333 } 334 335 public void delBulkDataFiles() { 336 if (bulkDataFiles != null) 337 for (File f : bulkDataFiles) 338 f.delete(); 339 } 340 341 public void parse(DicomInputStream dis) throws IOException { 342 dis.setIncludeBulkData(includeBulkData); 343 if (blkAttrs != null) 344 dis.setBulkDataDescriptor(BulkDataDescriptor.valueOf(blkAttrs)); 345 dis.setBulkDataDirectory(blkDirectory); 346 dis.setBulkDataFilePrefix(blkFilePrefix); 347 dis.setBulkDataFileSuffix(blkFileSuffix); 348 dis.setConcatenateBulkDataFiles(catBlkFiles); 349 dataset = dis.readDataset(-1, -1); 350 fmi = dis.getFileMetaInformation(); 351 bulkDataFiles = dis.getBulkDataFiles(); 352 } 353 354 public void mergeJSON(String fname) throws Exception { 355 if (dataset == null) 356 dataset = new Attributes(); 357 JSONReader reader = parseJSON(fname, dataset); 358 Attributes fmi2 = reader.getFileMetaInformation(); 359 if (fmi2 != null) 360 fmi = fmi2; 361 } 362 363 public static Attributes parseJSON(String fname) throws Exception { 364 Attributes attrs = new Attributes(); 365 parseJSON(fname, attrs); 366 return attrs; 367 } 368 369 private static JSONReader parseJSON(String fname, Attributes attrs) 370 throws IOException { 371 @SuppressWarnings("resource") 372 InputStream in = fname.equals("-") ? System.in : new FileInputStream(fname); 373 try { 374 JSONReader reader = new JSONReader( 375 Json.createParser(new InputStreamReader(in, "UTF-8"))); 376 reader.readDataset(attrs); 377 return reader; 378 } finally { 379 if (in != System.in) 380 SafeClose.close(in); 381 } 382 } 383 384}