mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 03:25:28 -04:00
Changed default indent from double space to tab. Minor clean-up.
This commit is contained in:
parent
7546a9d2ab
commit
18abfcdbc2
@ -59,12 +59,6 @@ public class XMLSerializer {
|
|||||||
// TODO: Consider using IOException to communicate trouble, rather than RTE,
|
// TODO: Consider using IOException to communicate trouble, rather than RTE,
|
||||||
// to be more compatible...
|
// to be more compatible...
|
||||||
|
|
||||||
// TODO: Idea: Create a SerializationContext that stores attributes on
|
|
||||||
// serialization, to keep the serialization thread-safe
|
|
||||||
// Store preserveSpace attribute in this context, to avoid costly traversals
|
|
||||||
// Store user options here too
|
|
||||||
// TODO: Push/pop?
|
|
||||||
|
|
||||||
private final OutputStream output;
|
private final OutputStream output;
|
||||||
private final Charset encoding;
|
private final Charset encoding;
|
||||||
private final SerializationContext context;
|
private final SerializationContext context;
|
||||||
@ -76,7 +70,7 @@ public class XMLSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final void setIndentation(String pIndent) {
|
public final void setIndentation(String pIndent) {
|
||||||
context.indent = pIndent != null ? pIndent : " ";
|
context.indent = pIndent != null ? pIndent : "\t";
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setStripComments(boolean pStrip) {
|
public final void setStripComments(boolean pStrip) {
|
||||||
@ -279,11 +273,7 @@ public class XMLSerializer {
|
|||||||
pos = appendAndEscape(pValue, pos, i, builder, ">");
|
pos = appendAndEscape(pValue, pos, i, builder, ">");
|
||||||
break;
|
break;
|
||||||
//case '\'':
|
//case '\'':
|
||||||
// pos = appendAndEscape(pString, pos, i, builder, "'");
|
|
||||||
// break;
|
|
||||||
//case '"':
|
//case '"':
|
||||||
// pos = appendAndEscape(pString, pos, i, builder, """);
|
|
||||||
// break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -347,17 +337,6 @@ public class XMLSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//StringBuilder builder = new StringBuilder(pValue.length() + 30);
|
|
||||||
//
|
|
||||||
//int start = 0;
|
|
||||||
//while (end >= 0) {
|
|
||||||
// builder.append(pValue.substring(start, end));
|
|
||||||
// builder.append(""");
|
|
||||||
// start = end + 1;
|
|
||||||
// end = pValue.indexOf('"', start);
|
|
||||||
//}
|
|
||||||
//builder.append(pValue.substring(start));
|
|
||||||
|
|
||||||
builder.append(pValue.substring(pos));
|
builder.append(pValue.substring(pos));
|
||||||
|
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
@ -389,14 +368,14 @@ public class XMLSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String validateCDataValue(final String pValue) {
|
private static String validateCDataValue(final String pValue) {
|
||||||
if (pValue.indexOf("]]>") >= 0) {
|
if (pValue.contains("]]>")) {
|
||||||
throw new IllegalArgumentException("Malformed input document: CDATA block may not contain the string ']]>'");
|
throw new IllegalArgumentException("Malformed input document: CDATA block may not contain the string ']]>'");
|
||||||
}
|
}
|
||||||
return pValue;
|
return pValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String validateCommentValue(final String pValue) {
|
private static String validateCommentValue(final String pValue) {
|
||||||
if (pValue.indexOf("--") >= 0) {
|
if (pValue.contains("--")) {
|
||||||
throw new IllegalArgumentException("Malformed input document: Comment may not contain the string '--'");
|
throw new IllegalArgumentException("Malformed input document: Comment may not contain the string '--'");
|
||||||
}
|
}
|
||||||
return pValue;
|
return pValue;
|
||||||
@ -420,8 +399,6 @@ public class XMLSerializer {
|
|||||||
// even if the document was created using attributes instead of namespaces...
|
// even if the document was created using attributes instead of namespaces...
|
||||||
// In that case, prefix will be null...
|
// In that case, prefix will be null...
|
||||||
|
|
||||||
// TODO: Don't insert duplicate/unnecessary namesspace declarations
|
|
||||||
|
|
||||||
// Handle namespace
|
// Handle namespace
|
||||||
String namespace = pNode.getNamespaceURI();
|
String namespace = pNode.getNamespaceURI();
|
||||||
if (namespace != null && !namespace.equals(pContext.defaultNamespace)) {
|
if (namespace != null && !namespace.equals(pContext.defaultNamespace)) {
|
||||||
@ -570,6 +547,11 @@ public class XMLSerializer {
|
|||||||
pre.appendChild(document.createTextNode(" \t \n\r some text & white ' ' \n "));
|
pre.appendChild(document.createTextNode(" \t \n\r some text & white ' ' \n "));
|
||||||
test.appendChild(pre);
|
test.appendChild(pre);
|
||||||
|
|
||||||
|
Element pre2 = document.createElementNS("http://www.twelvemonkeys.com/xml/test", "tight");
|
||||||
|
pre2.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve");
|
||||||
|
pre2.appendChild(document.createTextNode("no-space-around-me"));
|
||||||
|
test.appendChild(pre2);
|
||||||
|
|
||||||
// Create serializer and output document
|
// Create serializer and output document
|
||||||
//XMLSerializer serializer = new XMLSerializer(pOutput, new OutputFormat(document, UTF_8_ENCODING, true));
|
//XMLSerializer serializer = new XMLSerializer(pOutput, new OutputFormat(document, UTF_8_ENCODING, true));
|
||||||
System.out.println("XMLSerializer:");
|
System.out.println("XMLSerializer:");
|
||||||
@ -612,7 +594,7 @@ public class XMLSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class SerializationContext implements Cloneable {
|
static class SerializationContext implements Cloneable {
|
||||||
String indent = " ";
|
String indent = "\t";
|
||||||
int level = 0;
|
int level = 0;
|
||||||
boolean preserveSpace = false;
|
boolean preserveSpace = false;
|
||||||
boolean stripComments = false;
|
boolean stripComments = false;
|
||||||
|
@ -32,6 +32,7 @@ import com.twelvemonkeys.image.ImageUtil;
|
|||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
@ -47,12 +48,13 @@ import java.awt.color.ICC_ColorSpace;
|
|||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPEGImageReader
|
* A JPEG {@code ImageReader} implementation based on the JDK {@code JPEGImageReader},
|
||||||
|
* with support for CMYK JPEGs and other non-standard color spaces,
|
||||||
|
* like embedded ICC color spaces with rendering intent other than 'perceptual'.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author LUT-based YCbCR conversion by Werner Randelshofer
|
* @author LUT-based YCbCR conversion by Werner Randelshofer
|
||||||
@ -63,14 +65,14 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
private final static boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.jpeg.debug"));
|
private final static boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.jpeg.debug"));
|
||||||
|
|
||||||
/** Segment identifiers for the JPEG app segments we care about reading. */
|
/** Segment identifiers for the JPEG segments we care about reading. */
|
||||||
private static final Map<Integer, List<String>> SEGMENT_IDENTIFIERS = createSegmentIds();
|
private static final Map<Integer, List<String>> SEGMENT_IDENTIFIERS = createSegmentIds();
|
||||||
|
|
||||||
private static Map<Integer, List<String>> createSegmentIds() {
|
private static Map<Integer, List<String>> createSegmentIds() {
|
||||||
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
|
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
|
||||||
|
|
||||||
// JFIF APP0 markers
|
// JFIF APP0 markers
|
||||||
map.put(JPEG.APP0, Arrays.asList("JFIF", "JFXX"));
|
map.put(JPEG.APP0, JPEGSegmentUtil.ALL_IDS);
|
||||||
|
|
||||||
// ICC Color Profile
|
// ICC Color Profile
|
||||||
map.put(JPEG.APP2, Collections.singletonList("ICC_PROFILE"));
|
map.put(JPEG.APP2, Collections.singletonList("ICC_PROFILE"));
|
||||||
@ -99,47 +101,49 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
/** Our JPEG reading delegate */
|
/** Our JPEG reading delegate */
|
||||||
private final ImageReader delegate;
|
private final ImageReader delegate;
|
||||||
|
|
||||||
private final ICCSpaceInterceptor iccSpaceInterceptor;
|
// private final ICCSpaceInterceptor iccSpaceInterceptor;
|
||||||
private final ProgressDelegator progressDelegator;
|
private final ProgressDelegator progressDelegator;
|
||||||
|
|
||||||
/** Cached JFIF app segments */
|
/** Cached JPEG app segments */
|
||||||
private List<JPEGSegmentUtil.Segment> segments;
|
private List<JPEGSegment> segments;
|
||||||
|
|
||||||
private static Field getFieldSafely(final Class<?> cl, final String fieldName) {
|
// private static Field getFieldSafely(final Class<?> cl, final String fieldName) {
|
||||||
try {
|
// try {
|
||||||
Field field = cl.getDeclaredField(fieldName);
|
// Field field = cl.getDeclaredField(fieldName);
|
||||||
field.setAccessible(true);
|
// field.setAccessible(true);
|
||||||
return field;
|
// return field;
|
||||||
}
|
// }
|
||||||
catch (NoSuchFieldException ignore) {
|
// catch (NoSuchFieldException ignore) {
|
||||||
}
|
// }
|
||||||
catch (SecurityException ignore) {
|
// catch (SecurityException ignore) {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
||||||
super(provider);
|
super(provider);
|
||||||
this.delegate = Validate.notNull(delegate);
|
this.delegate = Validate.notNull(delegate);
|
||||||
|
|
||||||
Field iccCS = getFieldSafely(delegate.getClass(), "iccCS");
|
// Field iccCS = getFieldSafely(delegate.getClass(), "iccCS");
|
||||||
iccSpaceInterceptor = iccCS != null ? new ICCSpaceInterceptor(iccCS) : null;
|
// iccSpaceInterceptor = iccCS != null ? new ICCSpaceInterceptor(iccCS) : null;
|
||||||
|
|
||||||
progressDelegator = new ProgressDelegator();
|
progressDelegator = new ProgressDelegator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
File file = new File(args[0]);
|
File file = new File(args[0]);
|
||||||
|
|
||||||
ImageInputStream input = ImageIO.createImageInputStream(file);
|
ImageInputStream input = ImageIO.createImageInputStream(file);
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||||
|
|
||||||
if (!readers.hasNext()) {
|
if (!readers.hasNext()) {
|
||||||
System.err.println("No reader for: " + file);
|
System.err.println("No reader for: " + file);
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageReader myReader = readers.next();
|
ImageReader myReader = readers.next();
|
||||||
System.err.println("Reading using: " + myReader);
|
System.err.println("Reading using: " + myReader);
|
||||||
|
|
||||||
myReader.addIIOReadWarningListener(new IIOReadWarningListener() {
|
myReader.addIIOReadWarningListener(new IIOReadWarningListener() {
|
||||||
public void warningOccurred(ImageReader source, String warning) {
|
public void warningOccurred(ImageReader source, String warning) {
|
||||||
System.err.println("warning: " + warning);
|
System.err.println("warning: " + warning);
|
||||||
@ -185,23 +189,37 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
BufferedImage image = myReader.read(0, param);
|
BufferedImage image = myReader.read(0, param);
|
||||||
System.err.println("Time: " + (System.currentTimeMillis() - start) + " ms");
|
System.err.println("Read time: " + (System.currentTimeMillis() - start) + " ms");
|
||||||
System.err.println("image: " + image);
|
System.err.println("image: " + image);
|
||||||
|
|
||||||
// image = new ResampleOp(myReader.getWidth(0) / 4, myReader.getHeight(0) / 4, ResampleOp.FILTER_BLACKMAN_SINC).filter(image, null);
|
// image = new ResampleOp(myReader.getWidth(0) / 4, myReader.getHeight(0) / 4, ResampleOp.FILTER_LANCZOS).filter(image, null);
|
||||||
|
|
||||||
if (image.getWidth() > 1600 || image.getHeight() > 1000) {
|
int maxW = 1280;
|
||||||
|
int maxH = 800;
|
||||||
|
if (image.getWidth() > maxW || image.getHeight() > maxH) {
|
||||||
|
start = System.currentTimeMillis();
|
||||||
float aspect = myReader.getAspectRatio(0);
|
float aspect = myReader.getAspectRatio(0);
|
||||||
int height = Math.round(1600 / aspect);
|
if (aspect >= 1f) {
|
||||||
if (height <= 1000) {
|
image = ImageUtil.createResampled(image, maxW, Math.round(maxW / aspect), Image.SCALE_DEFAULT);
|
||||||
image = ImageUtil.createResampled(image, 1600, height, Image.SCALE_DEFAULT);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
image = ImageUtil.createResampled(image, Math.round(1000 * aspect), 1000, Image.SCALE_DEFAULT);
|
image = ImageUtil.createResampled(image, Math.round(maxH * aspect), maxH, Image.SCALE_DEFAULT);
|
||||||
}
|
}
|
||||||
|
System.err.println("Scale time: " + (System.currentTimeMillis() - start) + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
showIt(image, String.format("Image: %s [%d x %d]", file.getName(), myReader.getWidth(0), myReader.getHeight(0)));
|
showIt(image, String.format("Image: %s [%d x %d]", file.getName(), myReader.getWidth(0), myReader.getHeight(0)));
|
||||||
|
|
||||||
|
try {
|
||||||
|
int numThumbnails = myReader.getNumThumbnails(0);
|
||||||
|
for (int i = 0; i < numThumbnails; i++) {
|
||||||
|
BufferedImage thumbnail = myReader.readThumbnail(0, i);
|
||||||
|
showIt(thumbnail, String.format("Image: %s [%d x %d]", file.getName(), thumbnail.getWidth(), thumbnail.getHeight()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IIOException e) {
|
||||||
|
System.err.println("Could not read thumbnails: " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
input.close();
|
input.close();
|
||||||
@ -209,9 +227,9 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void installListeners() {
|
private void installListeners() {
|
||||||
if (iccSpaceInterceptor != null) {
|
// if (iccSpaceInterceptor != null) {
|
||||||
delegate.addIIOReadProgressListener(iccSpaceInterceptor);
|
// delegate.addIIOReadProgressListener(iccSpaceInterceptor);
|
||||||
}
|
// }
|
||||||
|
|
||||||
delegate.addIIOReadProgressListener(progressDelegator);
|
delegate.addIIOReadProgressListener(progressDelegator);
|
||||||
delegate.addIIOReadUpdateListener(progressDelegator);
|
delegate.addIIOReadUpdateListener(progressDelegator);
|
||||||
@ -260,9 +278,27 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
// TODO: Read header, and make sure we return valid types for the images we can now read
|
// TODO: Read header, and make sure we return valid types for the images we can now read
|
||||||
|
|
||||||
Iterator<ImageTypeSpecifier> types = delegate.getImageTypes(imageIndex);
|
Iterator<ImageTypeSpecifier> types = delegate.getImageTypes(imageIndex);
|
||||||
if (iccSpaceInterceptor != null) {
|
|
||||||
iccSpaceInterceptor.replaceCS(delegate);
|
ICC_Profile profile = getEmbeddedICCProfile();
|
||||||
|
AdobeDCT adobeDCT = getAdobeDCT();
|
||||||
|
|
||||||
|
// TODO: FixMe
|
||||||
|
if (types == null || !types.hasNext() || adobeDCT != null && adobeDCT.getTransform() == AdobeDCT.YCCK || profile != null && profile.getColorSpaceType() == ColorSpace.TYPE_CMYK) {
|
||||||
|
return Arrays.asList(
|
||||||
|
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR),
|
||||||
|
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB),
|
||||||
|
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR)
|
||||||
|
|
||||||
|
// TODO: We can/should also read and return it as CMYK if it is..
|
||||||
|
// + original color profile should be an option
|
||||||
|
|
||||||
|
).iterator();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (iccSpaceInterceptor != null) {
|
||||||
|
// iccSpaceInterceptor.replaceCS(delegate);
|
||||||
|
// }
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,12 +325,22 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
assertInput();
|
assertInput();
|
||||||
checkBounds(imageIndex);
|
checkBounds(imageIndex);
|
||||||
|
|
||||||
|
// TODO: This test is not good enough for JDK7, which seems to have fixed some of the issues.
|
||||||
// NOTE: We rely on the fact that unsupported images has no valid types. This is kind of hacky.
|
// NOTE: We rely on the fact that unsupported images has no valid types. This is kind of hacky.
|
||||||
// Might want to look into the metadata, to see if there's a better way to identify these.
|
// Might want to look into the metadata, to see if there's a better way to identify these.
|
||||||
boolean unsupported = !delegate.getImageTypes(imageIndex).hasNext();
|
boolean unsupported = !delegate.getImageTypes(imageIndex).hasNext();
|
||||||
|
|
||||||
ICC_Profile profile = getEmbeddedICCProfile();
|
ICC_Profile profile = getEmbeddedICCProfile();
|
||||||
if (delegate.canReadRaster() && (unsupported || profile != null && ColorSpaces.isOffendingColorProfile(profile))) {
|
AdobeDCT adobeDCT = getAdobeDCT();
|
||||||
|
|
||||||
|
if (
|
||||||
|
delegate.canReadRaster() &&
|
||||||
|
(
|
||||||
|
unsupported ||
|
||||||
|
adobeDCT != null && adobeDCT.getTransform() == AdobeDCT.YCCK ||
|
||||||
|
profile != null && (ColorSpaces.isOffendingColorProfile(profile) || profile.getColorSpaceType() == ColorSpace.TYPE_CMYK)
|
||||||
|
)
|
||||||
|
) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println("Reading using raster and extra conversion");
|
System.out.println("Reading using raster and extra conversion");
|
||||||
System.out.println("ICC color profile = " + profile);
|
System.out.println("ICC color profile = " + profile);
|
||||||
@ -304,8 +350,10 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println("Reading using " + (iccSpaceInterceptor != null ? "intercepted " : "") + "delegate");
|
// System.out.println("Reading using " + (iccSpaceInterceptor != null ? "intercepted " : "") + "delegate");
|
||||||
|
System.out.println("Reading using delegate");
|
||||||
}
|
}
|
||||||
|
|
||||||
return delegate.read(imageIndex, param);
|
return delegate.read(imageIndex, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +363,6 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
int origHeight = getHeight(imageIndex);
|
int origHeight = getHeight(imageIndex);
|
||||||
|
|
||||||
ColorSpace srcCs = null;
|
ColorSpace srcCs = null;
|
||||||
int xform = AdobeDCT.Unknown;
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -356,41 +403,57 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------------------------------------*/
|
--------------------------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
// TODO: Fix this algorithm to behave like above, except for the presence of JFIF APP0 dictating YCbCr or gray,
|
// TODO: Fix this algorithm to behave like above, except the presence of JFIF APP0 might mean YCbCr, gray or CMYK.
|
||||||
// as it might just as well be CMYK...
|
|
||||||
// AdobeApp14 with transform either 1 or 2 can be trusted to be YCC/YCCK respectively, transform 0 means 1 component gray, 3 comp rgb, 4 comp cmyk
|
// AdobeApp14 with transform either 1 or 2 can be trusted to be YCC/YCCK respectively, transform 0 means 1 component gray, 3 comp rgb, 4 comp cmyk
|
||||||
//
|
//
|
||||||
|
|
||||||
// 9788245605525.jpg: JFIF App0 + Adobe App14 transform 0, channel Id's C, M, Y, K
|
// 9788245605525.jpg: JFIF App0 + Adobe App14 transform 0, channel Id's C, M, Y, K, no ICC
|
||||||
// lund-logo-cmyk.jpg: Adobe App14 transform 0 (+ flag?), channel Id's 1-4
|
// lund-logo-cmyk.jpg: No App0, Adobe App14 transform 0 (+ flag?), channel Id's 1-4, no ICC
|
||||||
// teastar_300dpi_cmyk.jpg: Adobe App14 transform 2 (+ flag), channel Id's 1-4
|
// teastar_300dpi_cmyk.jpg: No App0, Adobe App14 transform 2 (+ flag), channel Id's 1-4, ICC
|
||||||
|
|
||||||
|
|
||||||
// System.err.println("----> isAPP0Present(): " + isJFIFAPP0Present());
|
// System.err.println("----> isAPP0Present(): " + isJFIFAPP0Present());
|
||||||
|
// System.err.println("getAppSegments(JPEG.APP0, null): " + getAppSegments(JPEG.APP0, null));
|
||||||
|
// System.err.println("segments: " + segments);
|
||||||
SOF startOfFrame = getSOF();
|
SOF startOfFrame = getSOF();
|
||||||
|
|
||||||
// System.err.println("startOfFrame: " + startOfFrame);
|
// System.err.println("startOfFrame: " + startOfFrame);
|
||||||
|
|
||||||
Iterator<ImageTypeSpecifier> imageTypes = delegate.getImageTypes(imageIndex);
|
|
||||||
|
|
||||||
// CMYK Support, assuming the delegate reader can't decode, and any 4 component image is CMYK
|
|
||||||
if (!imageTypes.hasNext() && startOfFrame.componentsInFrame == 4) {
|
|
||||||
// NOTE: Reading the metadata here chokes on some images. Instead, parse the Adobe App14 segment and read transform directly
|
|
||||||
AdobeDCT adobeDCT = getAdobeDCT();
|
AdobeDCT adobeDCT = getAdobeDCT();
|
||||||
// System.err.println("adobeDCT: " + adobeDCT);
|
// System.err.println("adobeDCT: " + adobeDCT);
|
||||||
xform = adobeDCT != null ? adobeDCT.getTransform() : AdobeDCT.Unknown;
|
|
||||||
|
|
||||||
|
Iterator<ImageTypeSpecifier> imageTypes = delegate.getImageTypes(imageIndex);
|
||||||
|
int transform = adobeDCT != null ? adobeDCT.getTransform() : AdobeDCT.Unknown;
|
||||||
|
|
||||||
|
// TODO: The !types.hasNext test is broken for JDK7, as it does return types...
|
||||||
|
// CMYK Support, assuming the delegate reader can't decode, and any 4 component image is CMYK
|
||||||
|
if ((!imageTypes.hasNext() || transform == AdobeDCT.YCCK || profile != null && profile.getColorSpaceType() == ColorSpace.TYPE_CMYK) && startOfFrame.componentsInFrame == 4) {
|
||||||
|
// NOTE: Reading the metadata here chokes on some images. Instead, parse the Adobe App14 segment and read transform directly
|
||||||
|
|
||||||
|
// TODO: If cmyk and no ICC profile, just use FastCMYKToRGB, without attempting loading Generic CMYK profile first!
|
||||||
|
// TODO: Also, don't get generic CMYK if we already have a profile...
|
||||||
srcCs = ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
|
srcCs = ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
|
||||||
imageTypes = Arrays.asList(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR)).iterator();
|
imageTypes = Arrays.asList(
|
||||||
|
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR),
|
||||||
|
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB),
|
||||||
|
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR)
|
||||||
|
// TODO: Only alpha if source has alpha... (ColorConvertOp chokes otherwise)
|
||||||
|
// ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB),
|
||||||
|
// ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE),
|
||||||
|
// ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR),
|
||||||
|
// ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE)
|
||||||
|
// TODO: Move to getImageTypes + add native color space if profile != null
|
||||||
|
).iterator();
|
||||||
}
|
}
|
||||||
|
// ...else blow up as there's no possible types to decode into...
|
||||||
|
|
||||||
BufferedImage image = getDestination(param, imageTypes, origWidth, origHeight);
|
BufferedImage image = getDestination(param, imageTypes, origWidth, origHeight);
|
||||||
|
|
||||||
|
// System.err.println("JPEGImageReader.readImageAsRasterAndReplaceColorProfile: " + image);
|
||||||
|
|
||||||
WritableRaster destination = image.getRaster();
|
WritableRaster destination = image.getRaster();
|
||||||
|
|
||||||
// TODO: checkReadParamBandSettings(param, );
|
// TODO: checkReadParamBandSettings(param, );
|
||||||
|
|
||||||
ColorConvertOp convert = null;
|
RasterOp convert = null;
|
||||||
ICC_ColorSpace replacement = profile != null ? ColorSpaces.createColorSpace(profile) : null;
|
ICC_ColorSpace replacement = profile != null ? ColorSpaces.createColorSpace(profile) : null;
|
||||||
|
|
||||||
if (profile != null && profile.getColorSpaceType() == ColorSpace.TYPE_GRAY && image.getColorModel().getColorSpace().getType() == ColorSpace.CS_GRAY) {
|
if (profile != null && profile.getColorSpaceType() == ColorSpace.TYPE_GRAY && image.getColorModel().getColorSpace().getType() == ColorSpace.CS_GRAY) {
|
||||||
@ -398,13 +461,20 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
// probably because IJG native part does it already...? If applied, color looks wrong (too dark)...
|
// probably because IJG native part does it already...? If applied, color looks wrong (too dark)...
|
||||||
}
|
}
|
||||||
else if (replacement != null) {
|
else if (replacement != null) {
|
||||||
// NOTE: CCO is not really necessary if replacement == image.getCM().getCS(),
|
// NOTE: Avoid using CCOp if same color space, as it's more compatible that way
|
||||||
// but in practice it's as fast/faster than raster.setRect() (see below)
|
if (replacement != image.getColorModel().getColorSpace()) {
|
||||||
convert = new ColorConvertOp(replacement, image.getColorModel().getColorSpace(), null);
|
convert = new ColorConvertOp(replacement, image.getColorModel().getColorSpace(), null);
|
||||||
}
|
}
|
||||||
|
// Else, pass through with no conversion
|
||||||
|
}
|
||||||
else if (srcCs != null) {
|
else if (srcCs != null) {
|
||||||
|
if (!(srcCs instanceof ICC_ColorSpace) && image.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_RGB && srcCs.getType() == ColorSpace.TYPE_CMYK) {
|
||||||
|
convert = new FastCMYKToRGB();
|
||||||
|
}
|
||||||
|
else {
|
||||||
convert = new ColorConvertOp(srcCs, image.getColorModel().getColorSpace(), null);
|
convert = new ColorConvertOp(srcCs, image.getColorModel().getColorSpace(), null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// else if (!image.getColorModel().getColorSpace().isCS_sRGB()) {
|
// else if (!image.getColorModel().getColorSpace().isCS_sRGB()) {
|
||||||
// TODO: Need to handle case where src and dest differ still
|
// TODO: Need to handle case where src and dest differ still
|
||||||
// convert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), image.getColorModel().getColorSpace(), null);
|
// convert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), image.getColorModel().getColorSpace(), null);
|
||||||
@ -414,47 +484,53 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We'll need a read param
|
// We'll need a read param
|
||||||
|
Rectangle origSourceRegion;
|
||||||
if (param == null) {
|
if (param == null) {
|
||||||
param = delegate.getDefaultReadParam();
|
param = delegate.getDefaultReadParam();
|
||||||
|
origSourceRegion = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
origSourceRegion = param.getSourceRegion();
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle srcRegion = new Rectangle();
|
Rectangle srcRegion = new Rectangle();
|
||||||
Rectangle dstRegion = new Rectangle();
|
Rectangle dstRegion = new Rectangle();
|
||||||
|
|
||||||
computeRegions(param, origWidth, origHeight, image, srcRegion, dstRegion);
|
computeRegions(param, origWidth, origHeight, image, srcRegion, dstRegion);
|
||||||
|
|
||||||
// We're ready to go
|
// We're ready to go
|
||||||
processImageStarted(imageIndex);
|
processImageStarted(imageIndex);
|
||||||
|
|
||||||
// Unfortunately looping is slower than reading all at once, but
|
// Unfortunately looping is slower than reading all at once, but
|
||||||
// that requires 2 x memory, so a few steps is an ok compromise I guess
|
// that requires 2 x + memory, so a few steps is an ok compromise I guess
|
||||||
try {
|
try {
|
||||||
int csType = srcCs != null ? srcCs.getType() : image.getColorModel().getColorSpace().getType();
|
int srcCsType = srcCs != null ? srcCs.getType() : image.getColorModel().getColorSpace().getType();
|
||||||
int step = Math.max(1024, srcRegion.height / 10);
|
int step = Math.max(1024, srcRegion.height / 10); // * param.getSourceYSubsampling(); // TODO: Using a multiple of 8 is probably a good idea for JPEG
|
||||||
|
|
||||||
|
int destY = dstRegion.y;
|
||||||
for (int y = srcRegion.y; y < srcRegion.height; y += step) {
|
for (int y = srcRegion.y; y < srcRegion.height; y += step) {
|
||||||
int scan = Math.min(step, srcRegion.height - y);
|
int scan = Math.min(step, srcRegion.height - y);
|
||||||
// Let the progress delegator handle progress, using corrected range
|
// Let the progress delegator handle progress, using corrected range
|
||||||
progressDelegator.updateProgressRange(100f * (y + scan) / srcRegion.height);
|
progressDelegator.updateProgressRange(100f * (y + scan) / srcRegion.height);
|
||||||
// try {
|
|
||||||
param.setSourceRegion(new Rectangle(srcRegion.x, y, srcRegion.width, scan));
|
Rectangle subRegion = new Rectangle(srcRegion.x, y, srcRegion.width, scan);
|
||||||
|
param.setSourceRegion(subRegion);
|
||||||
Raster raster = delegate.readRaster(imageIndex, param); // non-converted
|
Raster raster = delegate.readRaster(imageIndex, param); // non-converted
|
||||||
|
|
||||||
// Apply source color conversion form implicit color space
|
// Apply source color conversion form implicit color space
|
||||||
if ((xform == AdobeDCT.YCC || xform == AdobeDCT.Unknown) && csType == ColorSpace.TYPE_RGB) {
|
if ((transform == AdobeDCT.YCC || transform == AdobeDCT.Unknown) && srcCsType == ColorSpace.TYPE_RGB) {
|
||||||
YCbCrConverter.convertYCbCr2RGB(raster);
|
YCbCrConverter.convertYCbCr2RGB(raster);
|
||||||
}
|
}
|
||||||
else if (xform == AdobeDCT.YCCK && csType == ColorSpace.TYPE_CMYK) {
|
else if (transform == AdobeDCT.YCCK && srcCsType == ColorSpace.TYPE_CMYK) {
|
||||||
YCbCrConverter.convertYCCK2CMYK(raster);
|
YCbCrConverter.convertYCCK2CMYK(raster);
|
||||||
}
|
}
|
||||||
else if (xform == AdobeDCT.Unknown && csType == ColorSpace.TYPE_CMYK) {
|
else if (transform == AdobeDCT.Unknown && srcCsType == ColorSpace.TYPE_CMYK) {
|
||||||
invertCMYK(raster);
|
invertCMYK(raster);
|
||||||
}
|
}
|
||||||
|
// ...else assume the raster is already converted
|
||||||
|
|
||||||
// TODO: Subsampling
|
int destHeight = Math.min(raster.getHeight(), dstRegion.height - destY); // Avoid off-by-one
|
||||||
|
Raster src = raster.createChild(0, 0, raster.getWidth(), destHeight, 0, 0, param.getSourceBands());
|
||||||
Raster src = raster.createChild(0, 0, raster.getWidth(), raster.getHeight(), 0, 0, param.getSourceBands());
|
WritableRaster dest = destination.createWritableChild(dstRegion.x, destY, raster.getWidth(), destHeight, 0, 0, param.getDestinationBands());
|
||||||
WritableRaster dest = destination.createWritableChild(dstRegion.x, dstRegion.y + y - srcRegion.y, dstRegion.width, raster.getHeight(), 0, 0, param.getDestinationBands());
|
|
||||||
|
|
||||||
// Apply further color conversion for explicit color space, or just copy the pixels into place
|
// Apply further color conversion for explicit color space, or just copy the pixels into place
|
||||||
if (convert != null) {
|
if (convert != null) {
|
||||||
@ -464,25 +540,17 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
dest.setRect(0, 0, src);
|
dest.setRect(0, 0, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destY += raster.getHeight();
|
||||||
|
|
||||||
if (abortRequested()) {
|
if (abortRequested()) {
|
||||||
processReadAborted();
|
processReadAborted();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
// catch (RasterFormatException e) {
|
|
||||||
// System.err.println("y: " + y);
|
|
||||||
// System.err.println("step: " + step);
|
|
||||||
// System.err.println("scan: " + scan);
|
|
||||||
// System.err.println("srcRegion: " + srcRegion);
|
|
||||||
// System.err.println("dstRegion: " + dstRegion);
|
|
||||||
//
|
|
||||||
// throw e;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// NOTE: Would be cleaner to clone the param, unfortunately it can't be done easily...
|
// NOTE: Would be cleaner to clone the param, unfortunately it can't be done easily...
|
||||||
param.setSourceRegion(srcRegion);
|
param.setSourceRegion(origSourceRegion);
|
||||||
|
|
||||||
// Restore normal read progress processing
|
// Restore normal read progress processing
|
||||||
progressDelegator.resetProgressRange();
|
progressDelegator.resetProgressRange();
|
||||||
@ -509,7 +577,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
long pos = imageInput.getStreamPosition();
|
long pos = imageInput.getStreamPosition();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
imageInput.seek(0); // TODO: Seek to wanted image
|
imageInput.seek(0); // TODO: Seek to wanted image, skip images on the way
|
||||||
|
|
||||||
segments = JPEGSegmentUtil.readSegments(imageInput, SEGMENT_IDENTIFIERS);
|
segments = JPEGSegmentUtil.readSegments(imageInput, SEGMENT_IDENTIFIERS);
|
||||||
}
|
}
|
||||||
@ -523,15 +591,15 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<JPEGSegmentUtil.Segment> getAppSegments(final int marker, final String identifier) throws IOException {
|
private List<JPEGSegment> getAppSegments(final int marker, final String identifier) throws IOException {
|
||||||
initHeader();
|
initHeader();
|
||||||
|
|
||||||
List<JPEGSegmentUtil.Segment> appSegments = Collections.emptyList();
|
List<JPEGSegment> appSegments = Collections.emptyList();
|
||||||
|
|
||||||
for (JPEGSegmentUtil.Segment segment : segments) {
|
for (JPEGSegment segment : segments) {
|
||||||
if (segment.marker() == marker && identifier.equals(segment.identifier())) {
|
if (segment.marker() == marker && (identifier == null || identifier.equals(segment.identifier()))) {
|
||||||
if (appSegments == Collections.EMPTY_LIST) {
|
if (appSegments == Collections.EMPTY_LIST) {
|
||||||
appSegments = new ArrayList<JPEGSegmentUtil.Segment>(segments.size());
|
appSegments = new ArrayList<JPEGSegment>(segments.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
appSegments.add(segment);
|
appSegments.add(segment);
|
||||||
@ -546,7 +614,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SOF getSOF() throws IOException {
|
private SOF getSOF() throws IOException {
|
||||||
for (JPEGSegmentUtil.Segment segment : segments) {
|
for (JPEGSegment segment : segments) {
|
||||||
if (JPEG.SOF0 <= segment.marker() && segment.marker() <= JPEG.SOF3 ||
|
if (JPEG.SOF0 <= segment.marker() && segment.marker() <= JPEG.SOF3 ||
|
||||||
JPEG.SOF5 <= segment.marker() && segment.marker() <= JPEG.SOF7 ||
|
JPEG.SOF5 <= segment.marker() && segment.marker() <= JPEG.SOF7 ||
|
||||||
JPEG.SOF9 <= segment.marker() && segment.marker() <= JPEG.SOF11 ||
|
JPEG.SOF9 <= segment.marker() && segment.marker() <= JPEG.SOF11 ||
|
||||||
@ -559,20 +627,16 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
int samplesPerLine = data.readUnsignedShort();
|
int samplesPerLine = data.readUnsignedShort();
|
||||||
int componentsInFrame = data.readUnsignedByte();
|
int componentsInFrame = data.readUnsignedByte();
|
||||||
|
|
||||||
/**
|
SOFComponent[] components = new SOFComponent[componentsInFrame];
|
||||||
// Might not need this
|
|
||||||
for (int i = 0; i < componentsInFrame; i++) {
|
for (int i = 0; i < componentsInFrame; i++) {
|
||||||
int comp = i + 1;
|
|
||||||
int id = data.readUnsignedByte();
|
int id = data.readUnsignedByte();
|
||||||
System.err.println(comp + " id: " + id + " '" + (char) id + "'"); // typically 1-4, but may be 'C'/'M'/'Y'/'K' or similar...
|
|
||||||
int hv = data.readUnsignedByte();
|
int hv = data.readUnsignedByte();
|
||||||
System.err.println(comp + " horiz sub: " + ((hv & 0xF0) >> 4));
|
int qtsel = data.readUnsignedByte();
|
||||||
System.err.println(comp + " vertical sub: " + ((hv & 0xF)));
|
|
||||||
System.err.println(comp + " qt sel: " + data.readUnsignedByte());
|
|
||||||
}
|
|
||||||
//*/
|
|
||||||
|
|
||||||
return new SOF(segment.marker(), samplePrecision, lines, samplesPerLine, componentsInFrame);
|
components[i] = new SOFComponent(id, ((hv & 0xF0) >> 4), (hv & 0xF), qtsel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SOF(segment.marker(), samplePrecision, lines, samplesPerLine, componentsInFrame, components);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
data.close();
|
data.close();
|
||||||
@ -584,7 +648,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AdobeDCT getAdobeDCT() throws IOException {
|
private AdobeDCT getAdobeDCT() throws IOException {
|
||||||
List<JPEGSegmentUtil.Segment> adobe = getAppSegments(JPEG.APP14, "Adobe");
|
List<JPEGSegment> adobe = getAppSegments(JPEG.APP14, "Adobe");
|
||||||
|
|
||||||
if (!adobe.isEmpty()) {
|
if (!adobe.isEmpty()) {
|
||||||
// version (byte), flags (4bytes), color transform (byte: 0=unknown, 1=YCC, 2=YCCK)
|
// version (byte), flags (4bytes), color transform (byte: 0=unknown, 1=YCC, 2=YCCK)
|
||||||
@ -605,11 +669,11 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
// ICC v 1.42 (2006) annex B:
|
// ICC v 1.42 (2006) annex B:
|
||||||
// APP2 marker (0xFFE2) + 2 byte length + ASCII 'ICC_PROFILE' + 0 (termination)
|
// APP2 marker (0xFFE2) + 2 byte length + ASCII 'ICC_PROFILE' + 0 (termination)
|
||||||
// + 1 byte chunk number + 1 byte chunk count (allows ICC profiles chunked in multiple APP2 segments)
|
// + 1 byte chunk number + 1 byte chunk count (allows ICC profiles chunked in multiple APP2 segments)
|
||||||
List<JPEGSegmentUtil.Segment> segments = getAppSegments(JPEG.APP2, "ICC_PROFILE");
|
List<JPEGSegment> segments = getAppSegments(JPEG.APP2, "ICC_PROFILE");
|
||||||
|
|
||||||
if (segments.size() == 1) {
|
if (segments.size() == 1) {
|
||||||
// Faster code for the common case
|
// Faster code for the common case
|
||||||
JPEGSegmentUtil.Segment segment = segments.get(0);
|
JPEGSegment segment = segments.get(0);
|
||||||
DataInputStream stream = new DataInputStream(segment.data());
|
DataInputStream stream = new DataInputStream(segment.data());
|
||||||
int chunkNumber = stream.readUnsignedByte();
|
int chunkNumber = stream.readUnsignedByte();
|
||||||
int chunkCount = stream.readUnsignedByte();
|
int chunkCount = stream.readUnsignedByte();
|
||||||
@ -913,6 +977,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
private static class ICCSpaceInterceptor extends ProgressListenerBase {
|
private static class ICCSpaceInterceptor extends ProgressListenerBase {
|
||||||
final Field iccCS;
|
final Field iccCS;
|
||||||
|
|
||||||
@ -957,6 +1022,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
private static class SOF {
|
private static class SOF {
|
||||||
private final int marker;
|
private final int marker;
|
||||||
@ -964,13 +1030,15 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
private final int lines; // height
|
private final int lines; // height
|
||||||
private final int samplesPerLine; // width
|
private final int samplesPerLine; // width
|
||||||
private final int componentsInFrame;
|
private final int componentsInFrame;
|
||||||
|
private final SOFComponent[] components;
|
||||||
|
|
||||||
public SOF(int marker, int samplePrecision, int lines, int samplesPerLine, int componentsInFrame) {
|
public SOF(int marker, int samplePrecision, int lines, int samplesPerLine, int componentsInFrame, SOFComponent[] components) {
|
||||||
this.marker = marker;
|
this.marker = marker;
|
||||||
this.samplePrecision = samplePrecision;
|
this.samplePrecision = samplePrecision;
|
||||||
this.lines = lines;
|
this.lines = lines;
|
||||||
this.samplesPerLine = samplesPerLine;
|
this.samplesPerLine = samplesPerLine;
|
||||||
this.componentsInFrame = componentsInFrame;
|
this.componentsInFrame = componentsInFrame;
|
||||||
|
this.components = components;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMarker() {
|
public int getMarker() {
|
||||||
@ -996,12 +1064,33 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"SOF[marker: %04x, preciscion: %d, lines: %d, samples/line: %d, components: %d]",
|
"SOF[marker: %04x, preciscion: %d, lines: %d, samples/line: %d, components: %s]",
|
||||||
marker, samplePrecision, lines, samplesPerLine, componentsInFrame
|
marker, samplePrecision, lines, samplesPerLine, Arrays.toString(components)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class SOFComponent {
|
||||||
|
private final int id;
|
||||||
|
private final int hSub;
|
||||||
|
private final int vSub;
|
||||||
|
private final int qtSel;
|
||||||
|
|
||||||
|
public SOFComponent(int id, int hSub, int vSub, int qtSel) {
|
||||||
|
this.id = id;
|
||||||
|
this.hSub = hSub;
|
||||||
|
this.vSub = vSub;
|
||||||
|
this.qtSel = qtSel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
// Use id either as component number or component name, based on value
|
||||||
|
Serializable idStr = (id >= 'a' && id <= 'z' || id >= 'A' && id <= 'Z') ? "'" + (char) id + "'" : id;
|
||||||
|
return String.format("id: %s, sub: %d/%d, sel: %d", idStr, hSub, vSub, qtSel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class AdobeDCT {
|
private static class AdobeDCT {
|
||||||
public static final int Unknown = 0;
|
public static final int Unknown = 0;
|
||||||
public static final int YCC = 1;
|
public static final int YCC = 1;
|
||||||
@ -1038,8 +1127,8 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"AdobeDCT[ver: %d, flags: %s %s, transform: %d]",
|
"AdobeDCT[ver: %d.%02d, flags: %s %s, transform: %d]",
|
||||||
getVersion(), Integer.toBinaryString(getFlags0()), Integer.toBinaryString(getFlags1()), getTransform()
|
getVersion() / 100, getVersion() % 100, Integer.toBinaryString(getFlags0()), Integer.toBinaryString(getFlags1()), getTransform()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user