--- test/java/org/apache/xmlgraphics/java2d/color/profile/ColorProfileUtilTestCase.java (revision 0) +++ test/java/org/apache/xmlgraphics/java2d/color/profile/ColorProfileUtilTestCase.java (revision 0) @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: ColorProfileUtil.java 1345683 2012-06-03 14:50:33Z gadams $ */ + +package org.apache.xmlgraphics.java2d.color.profile; + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class ColorProfileUtilTestCase { + + @Test + public void testIsDefaultsRGB() throws IOException { + ICC_Profile profile = ICC_Profile.getInstance(ColorSpace.CS_sRGB); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + profile.write(baos); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ICC_Profile profileFromFile = ICC_Profile.getInstance(bais); + assertTrue(ColorProfileUtil.isDefaultsRGB(profileFromFile)); + } + +} --- src/java/org/apache/xmlgraphics/java2d/color/profile/ColorProfileUtil.java (revision 1366216) +++ src/java/org/apache/xmlgraphics/java2d/color/profile/ColorProfileUtil.java (working copy) @@ -22,9 +22,11 @@ import java.awt.color.ColorSpace; import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_Profile; +import java.awt.color.ICC_ProfileRGB; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.util.Arrays; // CSOFF: MethodName @@ -64,12 +66,24 @@ * @return true if it is the default sRGB profile */ public static boolean isDefaultsRGB(ICC_Profile profile) { - ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); - ICC_Profile sRGBProfile = null; - if (sRGB instanceof ICC_ColorSpace) { - sRGBProfile = ((ICC_ColorSpace)sRGB).getProfile(); + if (!(profile instanceof ICC_ProfileRGB)) { + return false; + } + // not sure what the best way to compare two profiles is, but comparing instances is not the right way + ICC_Profile sRGBProfile = ICC_Profile.getInstance(ColorSpace.CS_sRGB); + if (profile.getProfileClass() != sRGBProfile.getProfileClass()) { + return false; + } + if (profile.getMajorVersion() != sRGBProfile.getMajorVersion()) { + return false; + } + if (profile.getMinorVersion() != sRGBProfile.getMinorVersion()) { + return false; } - return profile == sRGBProfile; + if (!Arrays.equals(profile.getData(), sRGBProfile.getData())) { + return false; + } + return true; } /** --- src/java/org/apache/xmlgraphics/image/loader/impl/ImageRawPNG.java (revision 1366216) +++ src/java/org/apache/xmlgraphics/image/loader/impl/ImageRawPNG.java (working copy) @@ -40,6 +40,7 @@ private int redTransparentAlpha; private int greenTransparentAlpha; private int blueTransparentAlpha; + private int renderingIntent = -1; /** * Main constructor. @@ -141,4 +142,20 @@ return color; } + /** + * Used to set the rendering intent when the color space is sRGB. + * @param intent the rendering intent of the sRGB color space + */ + public void setRenderingIntent(int intent) { + renderingIntent = intent; + } + + /** + * Returns the rendering intent of the sRGB color space. + * @return the rendering intent + */ + public int getRenderingIntent() { + return this.renderingIntent; + } + } --- src/java/org/apache/xmlgraphics/image/loader/impl/PNGFile.java (revision 1366216) +++ src/java/org/apache/xmlgraphics/image/loader/impl/PNGFile.java (working copy) @@ -20,6 +20,7 @@ package org.apache.xmlgraphics.image.loader.impl; import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_Profile; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; @@ -34,6 +35,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; import org.apache.xmlgraphics.image.codec.png.PNGChunk; import org.apache.xmlgraphics.image.codec.util.PropertyUtil; @@ -49,6 +52,7 @@ private ColorModel colorModel; private ICC_Profile iccProfile; + private int sRGBRenderingIntent = -1; private int bitDepth; private int colorType; private boolean isTransparent; @@ -96,6 +100,12 @@ } else if (chunkType.equals(PNGChunk.ChunkType.tRNS.name())) { chunk = PNGChunk.readChunk(distream); parse_tRNS_chunk(chunk); + } else if (chunkType.equals(PNGChunk.ChunkType.iCCP.name())) { + chunk = PNGChunk.readChunk(distream); + parse_iCCP_chunk(chunk); + } else if (chunkType.equals(PNGChunk.ChunkType.sRGB.name())) { + chunk = PNGChunk.readChunk(distream); + parse_sRGB_chunk(chunk); } else { // chunk = PNGChunk.readChunk(distream); PNGChunk.skipChunk(distream); @@ -110,6 +120,7 @@ public ImageRawPNG getImageRawPNG(ImageInfo info) throws ImageException { InputStream seqStream = new SequenceInputStream(Collections.enumeration(streamVec)); + ColorSpace rgbCS = null; switch (colorType) { case PNG_COLOR_GRAY: if (hasPalette) { @@ -119,9 +130,14 @@ ColorModel.OPAQUE, DataBuffer.TYPE_BYTE); break; case PNG_COLOR_RGB: - // actually a check of the sRGB chunk would be necessary to confirm if it's really sRGB - colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false, - ColorModel.OPAQUE, DataBuffer.TYPE_BYTE); + if (iccProfile != null) { + rgbCS = new ICC_ColorSpace(iccProfile); + } else if (sRGBRenderingIntent != -1) { + rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); + } else { + rgbCS = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); + } + colorModel = new ComponentColorModel(rgbCS, false, false, ColorModel.OPAQUE, DataBuffer.TYPE_BYTE); break; case PNG_COLOR_PALETTE: if (hasAlphaPalette) { @@ -140,9 +156,15 @@ ColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE); break; case PNG_COLOR_RGB_ALPHA: - // actually a check of the sRGB chunk would be necessary to confirm if it's really sRGB - colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, - ColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE); + if (iccProfile != null) { + rgbCS = new ICC_ColorSpace(iccProfile); + } else if (sRGBRenderingIntent != -1) { + rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); + } else { + rgbCS = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); + } + colorModel = new ComponentColorModel(rgbCS, true, false, ColorModel.TRANSLUCENT, + DataBuffer.TYPE_BYTE); break; default: throw new ImageException("Unsupported color type: " + colorType); @@ -161,6 +183,9 @@ // } } + if (sRGBRenderingIntent != -1) { + rawImage.setRenderingIntent(sRGBRenderingIntent); + } return rawImage; } @@ -235,4 +260,28 @@ isTransparent = true; } + private void parse_iCCP_chunk(PNGChunk chunk) { + int length = chunk.getLength(); + String name = ""; // todo simplify this + byte b; + int textIndex = 0; + while ((b = chunk.getByte(textIndex++)) != 0) { + name += (char) b; + } + byte compression = chunk.getByte(textIndex++); + byte[] profile = new byte[length - textIndex]; + System.arraycopy(chunk.getData(), textIndex, profile, 0, length - textIndex); + ByteArrayInputStream bais = new ByteArrayInputStream(profile); + InflaterInputStream iis = new InflaterInputStream(bais, new Inflater()); + try { + iccProfile = ICC_Profile.getInstance(iis); + } catch (IOException ioe) { + // this is OK; the profile will be null + } + } + + private void parse_sRGB_chunk(PNGChunk chunk) { + sRGBRenderingIntent = chunk.getByte(0); + } + }