1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
/* Copyright (c) 2015, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
package com.pixelmed.imageio;
// follow the pattern described in "http://docs.oracle.com/javase/1.5.0/docs/guide/imageio/spec/extending.fm3.html"
import com.pixelmed.codec.jpeg.Markers;
import com.pixelmed.codec.jpeg.Utilities;
import java.io.IOException;
import java.util.Locale;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
public class JPEGLosslessImageReaderSpi extends ImageReaderSpi {
private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/imageio/JPEGLosslessImageReaderSpi.java,v 1.5 2016/01/16 15:07:52 dclunie Exp $";
static final String vendorName = "PixelMed Publishing, LLC.";
static final String version = "0.01";
static final String readerClassName = "com.pixelmed.imageio.JPEGLosslessImageReader";
static final String description = "PixelMed JPEG Lossless Image Reader";
public static final Class<?>[] inputTypes = { ImageInputStream.class }; // current JavaDoc says STANDARD_INPUT_TYPE is deprecated
static final String[] names = { "jpeg-lossless" }; // this is what Sun JIIO JAI codecs use to recognize JPEG lossless
static final String[] suffixes = { "ljpeg", "jpl" }; // not "jls", which is JPEG-LS; "ljpeg" was used by USF Mammo
static final String[] MIMETypes = null; // current JavaDoc says null or empty array OK
static final String nativeImageMetadataFormatName = "com.pixelmed.imageio.JPEGLosslessMetadata_0.1";
static final String nativeImageMetadataFormatClassName = "com.pixelmed.imageio.JPEGLosslessMetadata";
public JPEGLosslessImageReaderSpi() {
super(
vendorName,
version,
names,
suffixes,
MIMETypes,
readerClassName,
inputTypes,
null/*writerSpiNames*/,
false/*supportsStandardStreamMetadataFormat*/,
null/*nativeStreamMetadataFormatName*/,
null/*nativeStreamMetadataFormatClassName*/,
null/*extraStreamMetadataFormatNames*/,
null/*extraStreamMetadataFormatClassNames*/,
false/*supportsStandardImageMetadataFormat*/,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
null/*extraImageMetadataFormatNames*/,
null/*extraImageMetadataFormatClassNames*/);
}
public boolean canDecodeInput(Object input) throws IOException {
// Need SOI Start of Image
// May be intervening table/misc segments
// Need SOF3 Huffman Lossless Sequential length variable 0x0b
boolean canDecode = false;
try {
if (input instanceof ImageInputStream) {
ImageInputStream stream = (ImageInputStream)input;
byte[] b = new byte[4];
stream.mark();
stream.readFully(b,0,2);
if (b[0] == (byte)0xff && b[1] == (byte)0xd8) { // have SOI
int markerprefix = stream.read();
while (markerprefix == 0xff) { // keep reading until we have an SOF or until not a marker segment
int marker = stream.read();
marker|=0xff00; // convention is to express them with the leading ff, so that is what we look up
//System.err.println("JPEGLosslessImageReaderSpi.canDecodeInput(): have marker "+Utilities.toPaddedHexString(marker,4)+" "+Markers.getAbbreviation(marker));
// should not have to worry about stuffed bytes in ECS or padding because we never get that far in the stream
if (Markers.isSOF(marker)) {
//System.err.println("JPEGLosslessImageReaderSpi.canDecodeInput(): have some type of SOF marker");
if (marker == Markers.SOF3) {
//System.err.println("JPEGLosslessImageReaderSpi.canDecodeInput(): have SOF3");
canDecode = true;
}
break; // stop reading after any SOF
}
else if (marker == Markers.SOS) {
break; // stop reading at SOS since too late to get SOF3
}
else if (Markers.isVariableLengthJPEGSegment(marker)) {
stream.readFully(b,0,2);
int length=((b[0]&0xff)<<8) + (b[1]&0xff); // big endian
if (length > 2) {
//System.err.println("JPEGLosslessImageReaderSpi.canDecodeInput(): skipping variable length marker segment length="+length);
stream.skipBytes(length-2);
}
else {
//System.err.println("JPEGLosslessImageReaderSpi.canDecodeInput(): variable length marker segment with invalid length="+length);
break;
}
}
else if (Markers.isNoLengthJPEGSegment(marker)) {
}
else {
int length=Markers.isFixedLengthJPEGSegment(marker);
if (length == 0) {
//System.err.println("JPEGLosslessImageReaderSpi.canDecodeInput(): stopping on unrecognized marker segment");
break;
}
else {
//System.err.println("JPEGLosslessImageReaderSpi.canDecodeInput(): skipping fixed length marker segment length="+length);
stream.skipBytes(length-2);
}
}
markerprefix=stream.read();
}
}
// else no SOI so not JPEG
stream.reset();
System.err.println("JPEGLosslessImageReaderSpi.canDecodeInput() = "+canDecode);
}
}
catch (IOException e) {
}
return canDecode;
}
public String getDescription(Locale locale) {
return description;
}
public ImageReader createReaderInstance(Object extension) {
return new JPEGLosslessImageReader(this);
}
}
|