mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-02 11:05:29 -04:00
TMI-JPEG: Refactorings for better separation.
This commit is contained in:
parent
28d8796e54
commit
1d5cc6d266
@ -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;
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user