TMI-JPEG: Refactorings for better separation.

This commit is contained in:
Harald Kuhr 2013-04-22 21:01:30 +02:00
parent 28d8796e54
commit 1d5cc6d266
4 changed files with 142 additions and 86 deletions

View File

@ -29,13 +29,13 @@
package com.twelvemonkeys.imageio.plugins.jpeg; package com.twelvemonkeys.imageio.plugins.jpeg;
/** /**
* AdobeDCT * AdobeDCTSegment
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$ * @author last modified by $Author: haraldk$
* @version $Id: AdobeDCT.java,v 1.0 23.04.12 16:55 haraldk Exp$ * @version $Id: AdobeDCTSegment.java,v 1.0 23.04.12 16:55 haraldk Exp$
*/ */
class AdobeDCT { class AdobeDCTSegment {
public static final int Unknown = 0; public static final int Unknown = 0;
public static final int YCC = 1; public static final int YCC = 1;
public static final int YCCK = 2; public static final int YCCK = 2;
@ -45,7 +45,7 @@ class AdobeDCT {
final int flags1; final int flags1;
final int transform; final int transform;
public AdobeDCT(int version, int flags0, int flags1, int transform) { AdobeDCTSegment(int version, int flags0, int flags1, int transform) {
this.version = version; // 100 or 101 this.version = version; // 100 or 101
this.flags0 = flags0; this.flags0 = flags0;
this.flags1 = flags1; this.flags1 = flags1;

View File

@ -58,7 +58,7 @@ import java.util.List;
/** /**
* A JPEG {@code ImageReader} implementation based on the JRE {@code JPEGImageReader}, * A JPEG {@code ImageReader} implementation based on the JRE {@code JPEGImageReader},
* with support for CMYK/YCCK JPEGs, non-standard color spaces,broken ICC profiles * with support for CMYK/YCCK JPEGs, non-standard color spaces, broken ICC profiles
* and more. * and more.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
@ -268,14 +268,14 @@ public class JPEGImageReader extends ImageReaderBase {
boolean unsupported = !delegate.getImageTypes(imageIndex).hasNext(); boolean unsupported = !delegate.getImageTypes(imageIndex).hasNext();
ICC_Profile profile = getEmbeddedICCProfile(); ICC_Profile profile = getEmbeddedICCProfile();
AdobeDCT adobeDCT = getAdobeDCT(); AdobeDCTSegment adobeDCT = getAdobeDCT();
// TODO: Probably something bogus here, as ICC profile isn't applied if reading through the delegate any more... // TODO: Probably something bogus here, as ICC profile isn't applied if reading through the delegate any more...
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is) // We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
// - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream. // - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream.
if (delegate.canReadRaster() && ( if (delegate.canReadRaster() && (
unsupported || unsupported ||
adobeDCT != null && adobeDCT.getTransform() == AdobeDCT.YCCK || adobeDCT != null && adobeDCT.getTransform() == AdobeDCTSegment.YCCK ||
profile != null && (ColorSpaces.isOffendingColorProfile(profile) || profile.getColorSpaceType() == ColorSpace.TYPE_CMYK))) { 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");
@ -296,8 +296,8 @@ public class JPEGImageReader extends ImageReaderBase {
int origWidth = getWidth(imageIndex); int origWidth = getWidth(imageIndex);
int origHeight = getHeight(imageIndex); int origHeight = getHeight(imageIndex);
AdobeDCT adobeDCT = getAdobeDCT(); AdobeDCTSegment adobeDCT = getAdobeDCT();
SOF startOfFrame = getSOF(); SOFSegment startOfFrame = getSOF();
JPEGColorSpace csType = getSourceCSType(adobeDCT, startOfFrame); JPEGColorSpace csType = getSourceCSType(adobeDCT, startOfFrame);
Iterator<ImageTypeSpecifier> imageTypes = getImageTypes(imageIndex); Iterator<ImageTypeSpecifier> imageTypes = getImageTypes(imageIndex);
@ -436,7 +436,7 @@ public class JPEGImageReader extends ImageReaderBase {
return image; return image;
} }
static JPEGColorSpace getSourceCSType(AdobeDCT adobeDCT, final SOF startOfFrame) throws IIOException { static JPEGColorSpace getSourceCSType(AdobeDCTSegment adobeDCT, final SOFSegment startOfFrame) throws IIOException {
/* /*
ADAPTED from http://download.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html: ADAPTED from http://download.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html:
@ -478,11 +478,11 @@ public class JPEGImageReader extends ImageReaderBase {
if (adobeDCT != null) { if (adobeDCT != null) {
switch (adobeDCT.getTransform()) { switch (adobeDCT.getTransform()) {
case AdobeDCT.YCC: case AdobeDCTSegment.YCC:
return JPEGColorSpace.YCbCr; return JPEGColorSpace.YCbCr;
case AdobeDCT.YCCK: case AdobeDCTSegment.YCCK:
return JPEGColorSpace.YCCK; return JPEGColorSpace.YCCK;
case AdobeDCT.Unknown: case AdobeDCTSegment.Unknown:
if (startOfFrame.components.length == 1) { if (startOfFrame.components.length == 1) {
return JPEGColorSpace.Gray; return JPEGColorSpace.Gray;
} }
@ -639,7 +639,7 @@ public class JPEGImageReader extends ImageReaderBase {
return appSegments; return appSegments;
} }
private SOF getSOF() throws IOException { private SOFSegment getSOF() throws IOException {
for (JPEGSegment 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 ||
@ -664,7 +664,7 @@ public class JPEGImageReader extends ImageReaderBase {
components[i] = new SOFComponent(id, ((sub & 0xF0) >> 4), (sub & 0xF), qtSel); components[i] = new SOFComponent(id, ((sub & 0xF0) >> 4), (sub & 0xF), qtSel);
} }
return new SOF(segment.marker(), samplePrecision, lines, samplesPerLine, componentsInFrame, components); return new SOFSegment(segment.marker(), samplePrecision, lines, samplesPerLine, componentsInFrame, components);
} }
finally { finally {
data.close(); data.close();
@ -675,7 +675,7 @@ public class JPEGImageReader extends ImageReaderBase {
return null; return null;
} }
private AdobeDCT getAdobeDCT() throws IOException { private AdobeDCTSegment getAdobeDCT() throws IOException {
// TODO: Investigate http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6355567: 33/35 byte Adobe APP14 markers // TODO: Investigate http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6355567: 33/35 byte Adobe APP14 markers
List<JPEGSegment> adobe = getAppSegments(JPEG.APP14, "Adobe"); List<JPEGSegment> adobe = getAppSegments(JPEG.APP14, "Adobe");
@ -683,7 +683,7 @@ public class JPEGImageReader extends ImageReaderBase {
// 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)
DataInputStream stream = new DataInputStream(adobe.get(0).data()); DataInputStream stream = new DataInputStream(adobe.get(0).data());
return new AdobeDCT( return new AdobeDCTSegment(
stream.readUnsignedByte(), stream.readUnsignedByte(),
stream.readUnsignedShort(), stream.readUnsignedShort(),
stream.readUnsignedShort(), stream.readUnsignedShort(),
@ -1145,73 +1145,6 @@ public class JPEGImageReader extends ImageReaderBase {
} }
} }
private static class SOF {
private final int marker;
private final int samplePrecision;
private final int lines; // height
private final int samplesPerLine; // width
private final int componentsInFrame;
final SOFComponent[] components;
public SOF(int marker, int samplePrecision, int lines, int samplesPerLine, int componentsInFrame, SOFComponent[] components) {
this.marker = marker;
this.samplePrecision = samplePrecision;
this.lines = lines;
this.samplesPerLine = samplesPerLine;
this.componentsInFrame = componentsInFrame;
this.components = components;
}
public int getMarker() {
return marker;
}
public int getSamplePrecision() {
return samplePrecision;
}
public int getLines() {
return lines;
}
public int getSamplesPerLine() {
return samplesPerLine;
}
public int getComponentsInFrame() {
return componentsInFrame;
}
@Override
public String toString() {
return String.format(
"SOF%d[%04x, precision: %d, lines: %d, samples/line: %d, components: %s]",
marker & 0xf, marker, samplePrecision, lines, samplesPerLine, Arrays.toString(components)
);
}
}
private static class SOFComponent {
final int id;
final int hSub;
final int vSub;
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);
}
}
protected static void showIt(final BufferedImage pImage, final String pTitle) { protected static void showIt(final BufferedImage pImage, final String pTitle) {
ImageReaderBase.showIt(pImage, pTitle); ImageReaderBase.showIt(pImage, pTitle);
} }
@ -1282,7 +1215,7 @@ public class JPEGImageReader extends ImageReaderBase {
// param.setSourceSubsampling(sub, sub, 0, 0); // param.setSourceSubsampling(sub, sub, 0, 0);
// } // }
long start = System.currentTimeMillis(); // long start = System.currentTimeMillis();
BufferedImage image = reader.read(0, param); BufferedImage image = reader.read(0, param);
// System.err.println("Read time: " + (System.currentTimeMillis() - start) + " ms"); // System.err.println("Read time: " + (System.currentTimeMillis() - start) + " ms");
// System.err.println("image: " + image); // System.err.println("image: " + image);
@ -1295,7 +1228,7 @@ public class JPEGImageReader extends ImageReaderBase {
int maxW = 400; int maxW = 400;
int maxH = 400; int maxH = 400;
if (image.getWidth() > maxW || image.getHeight() > maxH) { if (image.getWidth() > maxW || image.getHeight() > maxH) {
start = System.currentTimeMillis(); // start = System.currentTimeMillis();
float aspect = reader.getAspectRatio(0); float aspect = reader.getAspectRatio(0);
if (aspect >= 1f) { if (aspect >= 1f) {
image = ImageUtil.createResampled(image, maxW, Math.round(maxW / aspect), Image.SCALE_DEFAULT); image = ImageUtil.createResampled(image, maxW, Math.round(maxW / aspect), Image.SCALE_DEFAULT);

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2013, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.jpeg;
import java.io.Serializable;
/**
* SOFComponent
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: SOFComponent.java,v 1.0 22.04.13 16:40 haraldk Exp$
*/
final class SOFComponent {
final int id;
final int hSub;
final int vSub;
final int qtSel;
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);
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2013, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.jpeg;
import java.util.Arrays;
/**
* SOFSegment
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: SOFSegment.java,v 1.0 22.04.13 16:40 haraldk Exp$
*/
final class SOFSegment {
final int marker;
final int samplePrecision;
final int lines; // height
final int samplesPerLine; // width
final int componentsInFrame;
final SOFComponent[] components;
SOFSegment(int marker, int samplePrecision, int lines, int samplesPerLine, int componentsInFrame, SOFComponent[] components) {
this.marker = marker;
this.samplePrecision = samplePrecision;
this.lines = lines;
this.samplesPerLine = samplesPerLine;
this.componentsInFrame = componentsInFrame;
this.components = components;
}
@Override
public String toString() {
return String.format(
"SOF%d[%04x, precision: %d, lines: %d, samples/line: %d, components: %s]",
marker & 0xf, marker, samplePrecision, lines, samplesPerLine, Arrays.toString(components)
);
}
}