TMI-JPEG-10: Fixed an issue with JPEGs without JFIF segment being treated as RGB, even when YCbCr.

This commit is contained in:
Harald Kuhr 2013-09-19 09:25:59 +02:00
parent 602e5ec34b
commit 086357694a
3 changed files with 41 additions and 13 deletions

View File

@ -66,6 +66,7 @@ import java.util.List;
* <p/>
* Main features:
* <ul>
* <li>Support for YCbCr JPEGs without JFIF segment (converted to RGB, using the embedded ICC profile if applicable)</li>
* <li>Support for CMYK JPEGs (converted to RGB by default or as CMYK, using the embedded ICC profile if applicable)</li>
* <li>Support for Adobe YCCK JPEGs (converted to RGB by default or as CMYK, using the embedded ICC profile if applicable)</li>
* <li>Support for JPEGs containing ICC profiles with interpretation other than 'Perceptual' (profile is assumed to be 'Perceptual' and used)</li>
@ -298,26 +299,25 @@ public class JPEGImageReader extends ImageReaderBase {
// }
// }
// 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.
boolean unsupported = !delegate.getImageTypes(imageIndex).hasNext();
ICC_Profile profile = getEmbeddedICCProfile(false);
AdobeDCTSegment adobeDCT = getAdobeDCT();
SOFSegment sof = getSOF();
JPEGColorSpace sourceCSType = getSourceCSType(adobeDCT, sof);
// 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.
if (delegate.canReadRaster() && (
unsupported ||
sourceCSType == JPEGColorSpace.CMYK ||
sourceCSType == JPEGColorSpace.YCCK ||
adobeDCT != null && adobeDCT.getTransform() == AdobeDCTSegment.YCCK ||
profile != null && !ColorSpaces.isCS_sRGB(profile))) {
// profile != null && (ColorSpaces.isOffendingColorProfile(profile) || profile.getColorSpaceType() == ColorSpace.TYPE_CMYK))) {
profile != null && !ColorSpaces.isCS_sRGB(profile)) ||
sourceCSType == JPEGColorSpace.YCbCr && getRawImageType(imageIndex) != null) { // TODO: Issue warning?
if (DEBUG) {
System.out.println("Reading using raster and extra conversion");
System.out.println("ICC color profile: " + profile);
}
return readImageAsRasterAndReplaceColorProfile(imageIndex, param, ensureDisplayProfile(profile));
return readImageAsRasterAndReplaceColorProfile(imageIndex, param, sof, sourceCSType, adobeDCT, ensureDisplayProfile(profile));
}
if (DEBUG) {
@ -327,14 +327,10 @@ public class JPEGImageReader extends ImageReaderBase {
return delegate.read(imageIndex, param);
}
private BufferedImage readImageAsRasterAndReplaceColorProfile(int imageIndex, ImageReadParam param, ICC_Profile profile) throws IOException {
private BufferedImage readImageAsRasterAndReplaceColorProfile(int imageIndex, ImageReadParam param, SOFSegment startOfFrame, JPEGColorSpace csType, AdobeDCTSegment adobeDCT, ICC_Profile profile) throws IOException {
int origWidth = getWidth(imageIndex);
int origHeight = getHeight(imageIndex);
AdobeDCTSegment adobeDCT = getAdobeDCT();
SOFSegment startOfFrame = getSOF();
JPEGColorSpace csType = getSourceCSType(adobeDCT, startOfFrame);
Iterator<ImageTypeSpecifier> imageTypes = getImageTypes(imageIndex);
BufferedImage image = getDestination(param, imageTypes, origWidth, origHeight);
WritableRaster destination = image.getRaster();

View File

@ -600,6 +600,38 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTestCase<JPEGImageRe
reader.dispose();
}
@Test
public void testReadNoJFIFYCbCr() throws IOException {
// Basically the same issue as http://stackoverflow.com/questions/9340569/jpeg-image-with-wrong-colors
JPEGImageReader reader = createReader();
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/no-jfif-ycbcr.jpg")));
assertEquals(310, reader.getWidth(0));
assertEquals(206, reader.getHeight(0));
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(new Rectangle(0, 0, 310, 8));
BufferedImage image = reader.read(0, param);
assertNotNull(image);
assertEquals(310, image.getWidth());
assertEquals(8, image.getHeight());
int[] expectedRGB = new int[] {
0xff3c1b14, 0xff35140b, 0xff4b2920, 0xff3b160e, 0xff49231a, 0xff874e3d, 0xff563d27, 0xff926c61,
0xff350005, 0xff84432d, 0xff754f46, 0xff2c2223, 0xff422016, 0xff220f0b, 0xff251812, 0xff1c1209,
0xff483429, 0xff1b140c, 0xff231c16, 0xff2f261f, 0xff2e2923, 0xff170c08, 0xff383025, 0xff443b34,
0xff574a39, 0xff3b322b, 0xffeee1d0, 0xffebdecd, 0xffe9dccb, 0xffe8dbca, 0xffe7dcca,
};
// Validate strip colors
for (int i = 0; i < image.getWidth() / 10; i++) {
int actualRGB = image.getRGB(i * 10, 7);
assertEquals((actualRGB >> 16) & 0xff, (expectedRGB[i] >> 16) & 0xff, 5);
assertEquals((actualRGB >> 8) & 0xff, (expectedRGB[i] >> 8) & 0xff, 5);
assertEquals((actualRGB) & 0xff, (expectedRGB[i]) & 0xff, 5);
}
}
// TODO: Test RGBA/YCbCrA handling
@Test

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB