diff --git a/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/ColorSpaces.java b/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/ColorSpaces.java index b5968606..ba622ab4 100644 --- a/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/ColorSpaces.java +++ b/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/ColorSpaces.java @@ -86,6 +86,9 @@ public final class ColorSpaces { /** A best-effort "generic" CMYK color space. Either read from disk or built-in. */ public static final int CS_GENERIC_CMYK = 5001; + /** Value used instead of 'XYZ ' in problematic Corbis RGB Profiles */ + private static final byte[] CORBIS_RGB_ALTERNATE_XYZ = new byte[] {0x17, (byte) 0xA5, 0x05, (byte) 0xB8}; + // Weak references to hold the color spaces while cached private static WeakReference adobeRGB1998 = new WeakReference(null); private static WeakReference genericCMYK = new WeakReference(null); @@ -135,9 +138,42 @@ public final class ColorSpaces { } } + // Special handling to detect problematic Corbis RGB ICC Profile. + // This makes sure tags that are expected to be of type 'XYZ ' really have this expected type. + // Should leave other ICC profiles unchanged. + if (fixProfileXYZTag(profile, ICC_Profile.icSigMediaWhitePointTag)) { + fixProfileXYZTag(profile, ICC_Profile.icSigRedColorantTag); + fixProfileXYZTag(profile, ICC_Profile.icSigGreenColorantTag); + fixProfileXYZTag(profile, ICC_Profile.icSigBlueColorantTag); + } + return getCachedOrCreateCS(profile, profileHeader); } + /** + * Fixes problematic 'XYZ ' tags in Corbis RGB profile. + * + * @return {@code true} if found and fixed, otherwise {@code false} for short-circuiting + * to avoid unnecessary array copying. + */ + private static boolean fixProfileXYZTag(ICC_Profile profile, final int tagSignature) { + byte[] data = profile.getData(tagSignature); + + // The CMM expects 0x64 65 73 63 ('XYZ ') but is 0x17 A5 05 B8..? + if (data != null && Arrays.equals(Arrays.copyOfRange(data, 0, 4), CORBIS_RGB_ALTERNATE_XYZ)) { + data[0] = 'X'; + data[1] = 'Y'; + data[2] = 'Z'; + data[3] = ' '; + + profile.setData(tagSignature, data); + + return true; + } + + return false; + } + private static ICC_ColorSpace getInternalCS(final int profileCSType, final byte[] profileHeader) { if (profileCSType == ColorSpace.TYPE_RGB && Arrays.equals(profileHeader, sRGB.header)) { return (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); diff --git a/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/color/ColorSpacesTest.java b/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/color/ColorSpacesTest.java index ac154765..6f7cd126 100644 --- a/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/color/ColorSpacesTest.java +++ b/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/color/ColorSpacesTest.java @@ -33,6 +33,7 @@ import org.junit.Test; import java.awt.color.ColorSpace; import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_Profile; +import java.io.IOException; import static org.junit.Assert.*; @@ -184,4 +185,15 @@ public class ColorSpacesTest { public void testIsCS_sRGBNull() { ColorSpaces.isCS_sRGB(null); } + + @Test + public void testCorbisRGBSpecialHandling() throws IOException { + ICC_Profile corbisRGB = ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/Corbis RGB.icc")); + ICC_Profile corbisRGBFixed = ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/Corbis RGB_fixed.icc")); + + ICC_ColorSpace colorSpace = ColorSpaces.createColorSpace(corbisRGB); + + assertNotNull(colorSpace); + assertArrayEquals(colorSpace.getProfile().getData(), corbisRGBFixed.getData()); + } } diff --git a/imageio/imageio-core/src/test/resources/profiles/Corbis RGB.icc b/imageio/imageio-core/src/test/resources/profiles/Corbis RGB.icc new file mode 100644 index 00000000..487f03b1 Binary files /dev/null and b/imageio/imageio-core/src/test/resources/profiles/Corbis RGB.icc differ diff --git a/imageio/imageio-core/src/test/resources/profiles/Corbis RGB_fixed.icc b/imageio/imageio-core/src/test/resources/profiles/Corbis RGB_fixed.icc new file mode 100755 index 00000000..f6293449 Binary files /dev/null and b/imageio/imageio-core/src/test/resources/profiles/Corbis RGB_fixed.icc differ diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReader.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReader.java index 77a095df..e8be131d 100644 --- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReader.java +++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReader.java @@ -632,6 +632,8 @@ public class JPEGImageReader extends ImageReaderBase { byte[] profileData = profile.getData(); // Need to clone entire profile, due to a JDK 7 bug if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) { + processWarningOccurred("ICC profile is Perceptual but Display class, treating as Display class"); + intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first return ICC_Profile.getInstance(profileData); @@ -1374,10 +1376,10 @@ public class JPEGImageReader extends ImageReaderBase { // start = System.currentTimeMillis(); float aspect = reader.getAspectRatio(0); 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_SMOOTH); } else { - image = ImageUtil.createResampled(image, Math.round(maxH * aspect), maxH, Image.SCALE_DEFAULT); + image = ImageUtil.createResampled(image, Math.round(maxH * aspect), maxH, Image.SCALE_SMOOTH); } // System.err.println("Scale time: " + (System.currentTimeMillis() - start) + " ms"); } diff --git a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java index 661f6243..aa5042ee 100644 --- a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java +++ b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java @@ -329,6 +329,25 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTestCase