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) 2013 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.emf2sf; 040 041import java.io.File; 042import java.io.IOException; 043import java.text.DecimalFormat; 044import java.text.MessageFormat; 045import java.util.List; 046import java.util.ResourceBundle; 047 048import org.apache.commons.cli.CommandLine; 049import org.apache.commons.cli.OptionBuilder; 050import org.apache.commons.cli.Options; 051import org.apache.commons.cli.ParseException; 052import org.dcm4che3.data.Tag; 053import org.dcm4che3.data.Attributes; 054import org.dcm4che3.emf.MultiframeExtractor; 055import org.dcm4che3.io.DicomInputStream; 056import org.dcm4che3.io.DicomOutputStream; 057import org.dcm4che3.io.DicomInputStream.IncludeBulkData; 058import org.dcm4che3.tool.common.CLIUtils; 059import org.dcm4che3.util.SafeClose; 060 061/** 062 * @author Gunter Zeilinger <gunterze@gmail.com> 063 * 064 */ 065public class Emf2sf { 066 067 private static ResourceBundle rb = 068 ResourceBundle.getBundle("org.dcm4che3.tool.emf2sf.messages"); 069 070 private MultiframeExtractor extractor = new MultiframeExtractor(); 071 private int[] frames; 072 private DecimalFormat outFileFormat; 073 private File outDir; 074 075 public final void setOutputDirectory(File outDir) { 076 outDir.mkdirs(); 077 this.outDir = outDir; 078 } 079 080 public final void setOutputFileFormat(String outFileFormat) { 081 this.outFileFormat = new DecimalFormat(outFileFormat); 082 } 083 084 public final void setFrames(int[] frames) { 085 this.frames = frames; 086 } 087 088 public void setPreserveSeriesInstanceUID(boolean PreserveSeriesInstanceUID) { 089 extractor.setPreserveSeriesInstanceUID(PreserveSeriesInstanceUID); 090 } 091 092 public void setInstanceNumberFormat(String instanceNumberFormat) { 093 extractor.setInstanceNumberFormat(instanceNumberFormat); 094 } 095 096 097 @SuppressWarnings("unchecked") 098 public static void main(String[] args) { 099 try { 100 CommandLine cl = parseComandLine(args); 101 Emf2sf main = new Emf2sf(); 102 if (cl.hasOption("frame")) 103 main.setFrames(toFrames(cl.getOptionValues("frame"))); 104 main.setPreserveSeriesInstanceUID(cl.hasOption("not-chseries")); 105 main.setOutputDirectory(new File(cl.getOptionValue("out-dir", "."))); 106 if (cl.hasOption("out-file")) 107 main.setOutputFileFormat(cl.getOptionValue("out-file")); 108 long start = System.currentTimeMillis(); 109 int n = main.extract(new File(fname(cl.getArgList()))); 110 long end = System.currentTimeMillis(); 111 System.out.println(); 112 System.out.println( 113 MessageFormat.format(rb.getString("extracted"), n, 114 (end - start) / 1000f)); 115 } catch (ParseException e) { 116 System.err.println("emf2sf: " + e.getMessage()); 117 System.err.println(rb.getString("try")); 118 System.exit(2); 119 } catch (Exception e) { 120 System.err.println("emf2sf: " + e.getMessage()); 121 e.printStackTrace(); 122 System.exit(2); 123 } 124 } 125 126 private static int[] toFrames(String[] ss) throws ParseException { 127 if (ss == null) 128 return null; 129 130 int[] is = new int[ss.length]; 131 for (int i = 0; i < is.length; i++) 132 try { 133 is[i] = Integer.parseInt(ss[i]) - 1; 134 } catch (NumberFormatException e) { 135 throw new ParseException( 136 "Invalid argument of option --frame: " + ss[i]); 137 } 138 139 return is; 140 } 141 142 private String fname(File srcFile, int frame) { 143 if (outFileFormat != null) 144 synchronized (outFileFormat) { 145 return outFileFormat.format(frame); 146 } 147 return String.format(srcFile.getName() + "-%04d", frame); 148 } 149 150 public int extract(File file) throws IOException { 151 Attributes src; 152 DicomInputStream dis = new DicomInputStream(file); 153 try { 154 dis.setIncludeBulkData(IncludeBulkData.URI); 155 src = dis.readDataset(-1, -1); 156 } finally { 157 SafeClose.close(dis); 158 } 159 Attributes fmi = dis.getFileMetaInformation(); 160 if (frames == null) { 161 int n = src.getInt(Tag.NumberOfFrames, 1); 162 for (int frame = 0; frame < n; ++frame) 163 extract(file, fmi, src, frame); 164 return n; 165 } else { 166 for (int frame : frames) 167 extract(file, fmi, src, frame); 168 return frames.length; 169 } 170 } 171 172 private void extract(File file, Attributes fmi, Attributes src, int frame) 173 throws IOException { 174 Attributes sf = extractor.extract(src, frame); 175 DicomOutputStream out = new DicomOutputStream( 176 new File(outDir, fname(file, frame+1))); 177 try { 178 out.writeDataset(fmi != null 179 ? sf.createFileMetaInformation( 180 fmi.getString(Tag.TransferSyntaxUID)) 181 : null, sf); 182 System.out.print('.'); 183 } finally { 184 SafeClose.close(out); 185 } 186 } 187 188 @SuppressWarnings("static-access") 189 private static CommandLine parseComandLine(String[] args) 190 throws ParseException { 191 Options opts = new Options(); 192 CLIUtils.addCommonOptions(opts); 193 opts.addOption(OptionBuilder 194 .withLongOpt("frame") 195 .hasArgs() 196 .withArgName("no[,..]") 197 .withValueSeparator(',') 198 .withDescription(rb.getString("frame")) 199 .create("f")); 200 opts.addOption(null, "not-chseries", false, rb.getString("not-chseries")); 201 opts.addOption(OptionBuilder 202 .withLongOpt("inst-no") 203 .hasArg() 204 .withArgName("format") 205 .withDescription(rb.getString("inst-no")) 206 .create()); 207 opts.addOption(OptionBuilder 208 .withLongOpt("out-dir") 209 .hasArg() 210 .withArgName("directory") 211 .withDescription(rb.getString("out-dir")) 212 .create()); 213 opts.addOption(OptionBuilder 214 .withLongOpt("out-file") 215 .hasArg() 216 .withArgName("name") 217 .withDescription(rb.getString("out-file")) 218 .create()); 219 return CLIUtils.parseComandLine(args, opts, rb, Emf2sf.class); 220 } 221 222 private static String fname(List<String> argList) throws ParseException { 223 int numArgs = argList.size(); 224 if (numArgs == 0) 225 throw new ParseException(rb.getString("missing")); 226 if (numArgs > 1) 227 throw new ParseException(rb.getString("too-many")); 228 return argList.get(0); 229 } 230}