-
-
引入配置文件
相关代码如下:
import org.apache.commons.cli.*;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.image.ICCProfile;
import org.dcm4che3.imageio.plugins.dcm.DicomImageReadParam;
import org.dcm4che3.io.DicomInputStream;
import org.dcm4che3.tool.common.CLIUtils;
import org.dcm4che3.util.SafeClose;
import javax.imageio.*;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.MessageFormat;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.StreamSupport;
public class Dcm2JpgUtils {
private static ResourceBundle rb = ResourceBundle.getBundle("jpg-messages", Locale.getDefault());
public interface ReadImage {
BufferedImage apply(File src) throws IOException;
}
private static ReadImage readImage;
private String suffix;
private int frame = 1;
private int windowIndex;
private int voiLUTIndex;
private boolean preferWindow = true;
private float windowCenter;
private float windowWidth;
private boolean autoWindowing = true;
private boolean ignorePresentationLUTShape;
private Attributes prState;
private final ImageReader imageReader =
ImageIO.getImageReadersByFormatName("DICOM").next();
private static ImageWriter imageWriter;
private static ImageWriteParam imageWriteParam;
private int overlayActivationMask = 0xffff;
private int overlayGrayscaleValue = 0xffff;
private int overlayRGBValue = 0xffffff;
private static ICCProfile.Option iccProfile = ICCProfile.Option.none;
public void initImageWriter(String formatName, String suffix,
String clazz, String compressionType, Number quality) {
this.suffix = suffix != null ? suffix : formatName.toLowerCase();
Iterator<ImageWriter> imageWriters =
ImageIO.getImageWritersByFormatName(formatName);
if (!imageWriters.hasNext())
throw new IllegalArgumentException(
MessageFormat.format(rb.getString("formatNotSupported"),
formatName));
Iterable<ImageWriter> iterable = () -> imageWriters;
imageWriter = StreamSupport.stream(iterable.spliterator(), false)
.filter(matchClassName(clazz))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(
MessageFormat.format(rb.getString("noSuchImageWriter"),
clazz, formatName)));
imageWriteParam = imageWriter.getDefaultWriteParam();
if (compressionType != null || quality != null) {
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
if (compressionType != null)
imageWriteParam.setCompressionType(compressionType);
if (quality != null)
imageWriteParam.setCompressionQuality(quality.floatValue());
}
}
private static Predicate<Object> matchClassName(String clazz) {
Predicate<String> predicate = clazz.endsWith("*")
? startsWith(clazz.substring(0, clazz.length() - 1))
: clazz::equals;
return w -> predicate.test(w.getClass().getName());
}
private static Predicate<String> startsWith(String prefix) {
return s -> s.startsWith(prefix);
}
public final void setFrame(int frame) {
this.frame = frame;
}
public final void setWindowCenter(float windowCenter) {
this.windowCenter = windowCenter;
}
public final void setWindowWidth(float windowWidth) {
this.windowWidth = windowWidth;
}
public final void setWindowIndex(int windowIndex) {
this.windowIndex = windowIndex;
}
public final void setVOILUTIndex(int voiLUTIndex) {
this.voiLUTIndex = voiLUTIndex;
}
public final void setPreferWindow(boolean preferWindow) {
this.preferWindow = preferWindow;
}
public final void setAutoWindowing(boolean autoWindowing) {
this.autoWindowing = autoWindowing;
}
public boolean isIgnorePresentationLUTShape() {
return ignorePresentationLUTShape;
}
public void setIgnorePresentationLUTShape(boolean ignorePresentationLUTShape) {
this.ignorePresentationLUTShape = ignorePresentationLUTShape;
}
public final void setPresentationState(Attributes prState) {
this.prState = prState;
}
public void setOverlayActivationMask(int overlayActivationMask) {
this.overlayActivationMask = overlayActivationMask;
}
public void setOverlayGrayscaleValue(int overlayGrayscaleValue) {
this.overlayGrayscaleValue = overlayGrayscaleValue;
}
public void setOverlayRGBValue(int overlayRGBValue) {
this.overlayRGBValue = overlayRGBValue;
}
public final void setICCProfile(ICCProfile.Option iccProfile) {
this.iccProfile = Objects.requireNonNull(iccProfile);
}
public final void setReadImage(ReadImage readImage) {
this.readImage = readImage;
}
private static CommandLine parseComandLine(String[] args)
throws ParseException {
Options opts = new Options();
CLIUtils.addCommonOptions(opts);
opts.addOption(Option.builder("F")
.hasArg()
.argName("format")
.desc(rb.getString("format"))
.build());
opts.addOption(Option.builder("E")
.hasArg()
.argName("class")
.desc(rb.getString("encoder"))
.build());
opts.addOption(Option.builder("C")
.hasArg()
.argName("type")
.desc(rb.getString("compression"))
.build());
opts.addOption(Option.builder("q")
.hasArg()
.argName("quality")
.type(PatternOptionBuilder.NUMBER_VALUE)
.desc(rb.getString("quality"))
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("suffix")
.desc(rb.getString("suffix"))
.longOpt("suffix")
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("number")
.type(PatternOptionBuilder.NUMBER_VALUE)
.desc(rb.getString("frame"))
.longOpt("frame")
.build());
opts.addOption(Option.builder("c")
.hasArg()
.argName("center")
.type(PatternOptionBuilder.NUMBER_VALUE)
.desc(rb.getString("windowCenter"))
.longOpt("windowCenter")
.build());
opts.addOption(Option.builder("w")
.hasArg()
.argName("width")
.type(PatternOptionBuilder.NUMBER_VALUE)
.desc(rb.getString("windowWidth"))
.longOpt("windowWidth")
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("number")
.type(PatternOptionBuilder.NUMBER_VALUE)
.desc(rb.getString("window"))
.longOpt("window")
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("number")
.type(PatternOptionBuilder.NUMBER_VALUE)
.desc(rb.getString("voilut"))
.longOpt("voilut")
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("profile")
.desc(rb.getString("iccprofile"))
.longOpt("iccprofile")
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("file")
.type(PatternOptionBuilder.EXISTING_FILE_VALUE)
.desc(rb.getString("ps"))
.longOpt("ps")
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("mask")
.desc(rb.getString("overlays"))
.longOpt("overlays")
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("value")
.desc(rb.getString("ovlygray"))
.longOpt("ovlygray")
.build());
opts.addOption(Option.builder()
.hasArg()
.argName("value")
.desc(rb.getString("ovlyrgb"))
.longOpt("ovlyrgb")
.build());
opts.addOption(null, "uselut", false, rb.getString("uselut"));
opts.addOption(null, "noauto", false, rb.getString("noauto"));
opts.addOption(null, "noshape", false, rb.getString("noshape"));
opts.addOption(null, "lsE", false, rb.getString("lsencoders"));
opts.addOption(null, "lsF", false, rb.getString("lsformats"));
OptionGroup useGroup = new OptionGroup();
useGroup.addOption(Option.builder()
.longOpt("usedis")
.desc(rb.getString("usedis"))
.build());
useGroup.addOption(Option.builder()
.longOpt("useiis")
.desc(rb.getString("useiis"))
.build());
opts.addOptionGroup(useGroup);
CommandLine cl = CLIUtils.parseComandLine(args, opts, rb, Dcm2JpgUtils.class);
if (cl.hasOption("lsF")) {
listSupportedFormats();
System.exit(0);
}
if (cl.hasOption("lsE")) {
listSupportedImageWriters(cl.getOptionValue("F", "JPEG"));
System.exit(0);
}
return cl;
}
private void mconvert(File src, File dest) {
if (src.isDirectory()) {
dest.mkdir();
for (File file : src.listFiles())
mconvert(file, new File(dest,
file.isFile() ? suffix(file) : file.getName()));
return;
}
if (dest.isDirectory())
dest = new File(dest, suffix(src));
try {
convert(src, dest);
System.out.println(
MessageFormat.format(rb.getString("converted"),
src, dest));
} catch (Exception e) {
System.out.println(
MessageFormat.format(rb.getString("failed"),
src, e.getMessage()));
e.printStackTrace(System.out);
}
}
public static void convert(File src, File dest) throws IOException {
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
writeImage(dest, iccProfile.adjust(readImage.apply(src)));
}
public BufferedImage readImageFromImageInputStream(File file) throws IOException {
try (ImageInputStream iis = new FileImageInputStream(file)) {
imageReader.setInput(iis);
return imageReader.read(frame - 1, readParam());
}
}
public BufferedImage readImageFromDicomInputStream(File file) throws IOException {
try (DicomInputStream dis = new DicomInputStream(file)) {
imageReader.setInput(dis);
return imageReader.read(frame - 1, readParam());
}
}
private ImageReadParam readParam() {
DicomImageReadParam param =
(DicomImageReadParam) imageReader.getDefaultReadParam();
param.setWindowCenter(windowCenter);
param.setWindowWidth(windowWidth);
param.setAutoWindowing(autoWindowing);
param.setIgnorePresentationLUTShape(ignorePresentationLUTShape);
param.setWindowIndex(windowIndex);
param.setVOILUTIndex(voiLUTIndex);
param.setPreferWindow(preferWindow);
param.setPresentationState(prState);
param.setOverlayActivationMask(overlayActivationMask);
param.setOverlayGrayscaleValue(overlayGrayscaleValue);
param.setOverlayRGBValue(overlayRGBValue);
return param;
}
private static void writeImage(File dest, BufferedImage bi) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(dest, "rw")) {
raf.setLength(0);
imageWriter.setOutput(new FileImageOutputStream(raf));
imageWriter.write(null, new IIOImage(bi, null, null), imageWriteParam);
}
}
private String suffix(File src) {
String suf = src.getName().endsWith(".dcm") ? src.getName().substring(0, src.getName().length() - 4) : src.getName();
return suf + '.' + suffix;
}
private static Attributes loadDicomObject(File f) throws IOException {
if (f == null)
return null;
DicomInputStream dis = new DicomInputStream(f);
try {
return dis.readDataset();
} finally {
SafeClose.close(dis);
}
}
public static void listSupportedImageWriters(String format) {
System.out.println(MessageFormat.format(rb.getString("writers"), format));
Iterator<ImageWriter> it = ImageIO.getImageWritersByFormatName(format);
while (it.hasNext()) {
ImageWriter writer = it.next();
ImageWriteParam param = writer.getDefaultWriteParam();
System.out.println(MessageFormat.format(rb.getString("writer"),
writer.getClass().getName(),
param.canWriteCompressed(),
param.canWriteProgressive(),
param.canWriteTiles(),
param.canOffsetTiles(),
param.canWriteCompressed()
? Arrays.toString(param.getCompressionTypes())
: null));
}
}
public static void listSupportedFormats() {
System.out.println(
MessageFormat.format(rb.getString("formats"),
Arrays.toString(ImageIO.getWriterFormatNames())));
}
}
配置文件resources/ jpg-messages.properties
usage=dcm2jpg [<options>] <dicom-file> <jpeg-file>\n\
or dcm2jpg [Options] <dicom-file>... <outdir>\n\
or dcm2jpg [Options] <indir>... <outdir>
try=Try `dcm2jpg --help' for more information.
description=\nConvert DICOM image(s) to JPEG(s) or other image formats.\
\n-\
\nOptions\:
example=-\nExample: dcm2jpg img.dcm img.jpg\n\
=> Convert DICOM image 'img.dcm' to JPEG image 'img.jpg'
frame=frame to convert, 1 (= first frame) by default
format=output image format, JPEG by default
lsformats=list supported output image formats
suffix=file extension used with destination directory argument,\
lower case format name by default
quality=compression quality (0.0-1.0) of output image
encoder=ImageWriter class to be used for encoding,\n\
com.sun.imageio.plugins.* (= JDK ImageIO plugins) by default
lsencoders=list available Image Writers for specified output image format
compression=Compression Type of Image Writer to be used
ps=file path of presentation state to apply
windowCenter=Window Center of linear VOI LUT function to apply
windowWidth=Window Width of linear VOI LUT function to apply
window=use <number>. Window Center/Width value, if the image provides \
several Window Center/Width values; use 1. by default.
voilut=use <number>. explicit VOI LUT, if the image provides \
several explicit VOI LUT; use 1. by default.
uselut=use explicit VOI LUT in image, even if the image also specifies \
Window Center/Width; prefer applying Window Center/Width over explicit VOI LUT \
by default
noauto=disable auto-windowing for images w/o VOI attributes
noshape=ignore present (2050,0020) Presentation LUT Shape; prioritize value of \
(0028,0004) Photometric Interpretation to determine if minimum sample value is \
intended to be displayed as white (=MONCHROME1) or as black (=MONCHROME2)
overlays=render overlays specified by bits 1-16 of <mask> in hex; FFFF by default.
ovlygray=grayscale value of rendered overlays in hex; FFFF (= white) by default.
ovlyrgb=color of rendered overlays as RGB color code; #ffffff (= white) by default.
iccprofile=specifies the color characteristics of, and inclusion of an ICC Profile in the rendered image:\n\
- no: include no ICC profile\n\
- yes: include the ICC Profile specified in the DICOM image, otherwise the sRGB ICC profile\n\
- srgb: include sRGB ICC profile and transform original pixels to sRGB color space if an ICC Profile is specified in the DICOM image\n\
- adobergb: include Adobe RGB ICC profile and transform original pixels to Adobe RGB color space\n\
- rommrgb: include ROMM RGB ICC profile and transform original pixels to ROMM RGB color space\n\
By default, include no ICC profile, but transform original pixels to sRGB color space if an ICC Profile is specified in the DICOM image.
writers=Supported Image Writers for format: {0}
writer=\n{0}\:\
\n canWriteCompressed\: {1}\
\n canWriteProgressive\: {2}\
\n canWriteTiles\: {3}\
\n canOffsetTiles\: {4}\
\n Compression Types\: {5}
formats=Supported output image formats: {0}
missing=missing file operand
nodestdir=target {0} is not a directory
formatNotSupported=output image format: {0} not supported
noSuchImageWriter=no Image Writer: {0} for format {1} found
converted={0} -> {1}
failed=Failed to convert {0}: {1}
usedis=use DicomInputStream for reading the DICOM image. Supports deflated transfer syntaxes (default, without option --frame <number>)
useiis=use ImageInputStream for reading the DICOM image (default, with option --frame <number>)
调用
public static void main(String[] args) {
try {
File src = new File("C:\\Users\\hp\\Desktop\\dicm");
File dest = new File("C:\\Users\\hp\\Desktop\\jpg");
Dcm2JpgUtils dcm2jpg = new Dcm2JpgUtils();
dcm2jpg.initImageWriter("jpg", null, "com.sun.imageio.plugins.*", null, 1l);
dcm2jpg.setReadImage(dcm2jpg::readImageFromDicomInputStream);
dcm2jpg.mconvert(src, dest);
} catch (Exception e) {
e.printStackTrace();
}
}