#841: Filter out incompatible ICC profiles

This commit is contained in:
Harald Kuhr
2023-10-19 11:10:47 +02:00
parent 2c7c47b158
commit 2e0e575183
3 changed files with 20 additions and 4 deletions

View File

@@ -77,6 +77,11 @@ final class WebPImageReader extends ImageReaderBase {
// Either VP8_, VP8L or VP8X chunk // Either VP8_, VP8L or VP8X chunk
private long fileSize; private long fileSize;
private VP8xChunk header; private VP8xChunk header;
// The ICC Profile contained in the stream, only suitable for metadata.
private ICC_Profile containedICCP;
// A safe, verified RGB ICC Profile used for color conversion.
private ICC_Profile iccProfile; private ICC_Profile iccProfile;
private final List<AnimationFrame> frames = new ArrayList<>(); private final List<AnimationFrame> frames = new ArrayList<>();
@@ -88,6 +93,7 @@ final class WebPImageReader extends ImageReaderBase {
protected void resetMembers() { protected void resetMembers() {
fileSize = -1; fileSize = -1;
header = null; header = null;
containedICCP = null;
iccProfile = null; iccProfile = null;
lsbBitReader = null; lsbBitReader = null;
frames.clear(); frames.clear();
@@ -299,13 +305,20 @@ final class WebPImageReader extends ImageReaderBase {
if (header.containsICCP) { if (header.containsICCP) {
// ICCP chunk must be first chunk, if present // ICCP chunk must be first chunk, if present
while (iccProfile == null && imageInput.getStreamPosition() < fileSize) { while (containedICCP == null && imageInput.getStreamPosition() < fileSize) {
int nextChunk = imageInput.readInt(); int nextChunk = imageInput.readInt();
long chunkLength = imageInput.readUnsignedInt(); long chunkLength = imageInput.readUnsignedInt();
long chunkStart = imageInput.getStreamPosition(); long chunkStart = imageInput.getStreamPosition();
if (nextChunk == WebP.CHUNK_ICCP) { if (nextChunk == WebP.CHUNK_ICCP) {
iccProfile = ColorProfiles.readProfile(IIOUtil.createStreamAdapter(imageInput, chunkLength)); containedICCP = ColorProfiles.readProfile(IIOUtil.createStreamAdapter(imageInput, chunkLength));
if (containedICCP.getColorSpaceType() == ColorSpace.TYPE_RGB) {
iccProfile = containedICCP;
}
else {
processWarningOccurred("Encountered non-RGB ICC Profile, ignoring color profile, colors may appear incorrect");
}
} }
else { else {
processWarningOccurred(String.format("Expected 'ICCP' chunk, '%s' chunk encountered", fourCC(nextChunk))); processWarningOccurred(String.format("Expected 'ICCP' chunk, '%s' chunk encountered", fourCC(nextChunk)));
@@ -386,9 +399,10 @@ final class WebPImageReader extends ImageReaderBase {
if (iccProfile != null && !ColorProfiles.isCS_sRGB(iccProfile)) { if (iccProfile != null && !ColorProfiles.isCS_sRGB(iccProfile)) {
ICC_ColorSpace colorSpace = ColorSpaces.createColorSpace(iccProfile); ICC_ColorSpace colorSpace = ColorSpaces.createColorSpace(iccProfile);
int[] bandOffsets = header.containsALPH ? new int[] {0, 1, 2, 3} : new int[] {0, 1, 2}; int[] bandOffsets = header.containsALPH ? new int[]{0, 1, 2, 3} : new int[]{0, 1, 2};
return ImageTypeSpecifiers.createInterleaved(colorSpace, bandOffsets, DataBuffer.TYPE_BYTE, header.containsALPH, false); return ImageTypeSpecifiers.createInterleaved(colorSpace, bandOffsets, DataBuffer.TYPE_BYTE, header.containsALPH, false);
} }
// Non-RGB profile is simply ignored
return ImageTypeSpecifiers.createFromBufferedImageType(header.containsALPH ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR); return ImageTypeSpecifiers.createFromBufferedImageType(header.containsALPH ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR);
} }

View File

@@ -60,7 +60,9 @@ public class WebPImageReaderTest extends ImageReaderAbstractTest<WebPImageReader
new Dimension(394, 383), new Dimension(394, 394), new Dimension(372, 394), new Dimension(394, 383), new Dimension(394, 394), new Dimension(372, 394),
new Dimension(400, 400), new Dimension(320, 382)), new Dimension(400, 400), new Dimension(320, 382)),
// Alpha transparency and Alpha filtering // Alpha transparency and Alpha filtering
new TestData(getClassLoaderResource("/webp/alpha_filter.webp"), new Dimension(1600, 1600)) new TestData(getClassLoaderResource("/webp/alpha_filter.webp"), new Dimension(1600, 1600)),
// Lossy with grayscale ICC profile
new TestData(getClassLoaderResource("/webp/incompatible-icc-gray.webp"), new Dimension(766, 1100))
); );
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB