mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 11:35:29 -04:00
TMI-34: Handling of problematic Corbis RGB ICC profiles.
This commit is contained in:
parent
14e12eb2c1
commit
db259bff10
@ -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<ICC_Profile> adobeRGB1998 = new WeakReference<ICC_Profile>(null);
|
||||
private static WeakReference<ICC_Profile> genericCMYK = new WeakReference<ICC_Profile>(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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
BIN
imageio/imageio-core/src/test/resources/profiles/Corbis RGB.icc
Normal file
BIN
imageio/imageio-core/src/test/resources/profiles/Corbis RGB.icc
Normal file
Binary file not shown.
BIN
imageio/imageio-core/src/test/resources/profiles/Corbis RGB_fixed.icc
Executable file
BIN
imageio/imageio-core/src/test/resources/profiles/Corbis RGB_fixed.icc
Executable file
Binary file not shown.
@ -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");
|
||||
}
|
||||
|
@ -329,6 +329,25 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTestCase<JPEGImageRe
|
||||
verify(warningListener).warningOccurred(eq(reader), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorbisRGB() throws IOException {
|
||||
// Special case, throws exception below without special treatment
|
||||
// java.awt.color.CMMException: General CMM error517
|
||||
JPEGImageReader reader = createReader();
|
||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cmm-exception-corbis-rgb.jpg")));
|
||||
|
||||
assertEquals(512, reader.getWidth(0));
|
||||
assertEquals(384, reader.getHeight(0));
|
||||
|
||||
BufferedImage image = reader.read(0);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(512, image.getWidth());
|
||||
assertEquals(384, image.getHeight());
|
||||
|
||||
reader.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasThumbnailNoIFD1() throws IOException {
|
||||
JPEGImageReader reader = createReader();
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
Loading…
x
Reference in New Issue
Block a user