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. */
|
/** A best-effort "generic" CMYK color space. Either read from disk or built-in. */
|
||||||
public static final int CS_GENERIC_CMYK = 5001;
|
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
|
// 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> adobeRGB1998 = new WeakReference<ICC_Profile>(null);
|
||||||
private static WeakReference<ICC_Profile> genericCMYK = 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);
|
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) {
|
private static ICC_ColorSpace getInternalCS(final int profileCSType, final byte[] profileHeader) {
|
||||||
if (profileCSType == ColorSpace.TYPE_RGB && Arrays.equals(profileHeader, sRGB.header)) {
|
if (profileCSType == ColorSpace.TYPE_RGB && Arrays.equals(profileHeader, sRGB.header)) {
|
||||||
return (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
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.ColorSpace;
|
||||||
import java.awt.color.ICC_ColorSpace;
|
import java.awt.color.ICC_ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
@ -184,4 +185,15 @@ public class ColorSpacesTest {
|
|||||||
public void testIsCS_sRGBNull() {
|
public void testIsCS_sRGBNull() {
|
||||||
ColorSpaces.isCS_sRGB(null);
|
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
|
byte[] profileData = profile.getData(); // Need to clone entire profile, due to a JDK 7 bug
|
||||||
|
|
||||||
if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) {
|
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
|
intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first
|
||||||
|
|
||||||
return ICC_Profile.getInstance(profileData);
|
return ICC_Profile.getInstance(profileData);
|
||||||
@ -1374,10 +1376,10 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
// 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_SMOOTH);
|
||||||
}
|
}
|
||||||
else {
|
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");
|
// 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());
|
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
|
@Test
|
||||||
public void testHasThumbnailNoIFD1() throws IOException {
|
public void testHasThumbnailNoIFD1() throws IOException {
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
Loading…
x
Reference in New Issue
Block a user