javacolor-profiletwelvemonkeys

Add Tiff Image Color Profile (sRGB or Adobe 1998) with Java


I searched the web high and low and I can't find a solution for how to add a sRGB or Abobe (1998) color profile to a Tiff Image with Java. There's some examples out there for jpgs and pngs, but they don't apply to tiffs. I have been trying to do it with Commons Imaging and java.awt but not having any luck. Is it possible?

Thanks

Update:

I've made some progress using the TwelveMonkeys imageio-tiff library and the following code:

File file = new File("/Users/user/Desktop/demo/sandal.tif");
BufferedImage image = ImageIO.read(file);

ICC_Profile ip = ICC_Profile.getInstance("/Users/user/Documents/icc/AdobeRGB1998.icc");
ICC_ColorSpace ics = new ICC_ColorSpace( ip );
ColorConvertOp cco = new ColorConvertOp( ics, null );
BufferedImage result = cco.filter(image, null);

ImageIO.write(result, "TIFF", new File("/Users/user/Desktop/demo/sandal2.tif"));

The color profile is applied, but the tiff is flattened and the alpha removed. How can the alpha channel be preserved?


Solution

  • As mentioned in the comments, the code you have should have worked, unless there's something special about your AdobeRGB1998 ICC profile...

    The below code works for me, converting the image from sRGB to the AdobeRGB1998 profile. The resulting TIFF file has the correct ICC profile and contains the alpha channel intact (258/BitsPerSample: [8, 8, 8, 8], 277/SamplesPerPixels: 4, 34675/ICCProfile: [...]). The only minor issues I can see, is that the compression is changed from LZW to no compression, and DPI is changed from 300 to 72 (+ XMP metadata is lost).

    BufferedImage image = ImageIO.read(new File("C:\\Downloads\\sandal.tif"));
    
    ICC_ColorSpace ics = (ICC_ColorSpace) ColorSpaces.getColorSpace(ColorSpaces.CS_ADOBE_RGB_1998);
    ColorConvertOp cco = new ColorConvertOp(ics, null);
    BufferedImage result = cco.filter(image, null);
    
    File tempFile = File.createTempFile("test-", ".tif");
    System.out.println("tempFile: " + tempFile); // Just to know where to look
    ImageIO.write(result, "TIFF", tempFile);
    

    As you can see, the only real difference here is how the ICC profile/color space is obtained.

    If you want to preserve the meta data and/or control compression, that is possible too. The below code does basically the same (but preserves the LZW compression and 300dpi), unfortunately it's a bit more verbose:

    try (ImageInputStream input = ImageIO.createImageInputStream(new File("C:\\Downloads\\sandal.tif"))) {
        ImageReader reader = ImageIO.getImageReaders(input).next();
        reader.setInput(input);
        IIOImage imageAndMeta = reader.readAll(0, reader.getDefaultReadParam());
        reader.dispose();
    
        ICC_ColorSpace ics = (ICC_ColorSpace) ColorSpaces.getColorSpace(ColorSpaces.CS_ADOBE_RGB_1998);
        ColorConvertOp cco = new ColorConvertOp(ics, null);
        BufferedImage result = cco.filter((BufferedImage) imageAndMeta.getRenderedImage(), null);
    
        imageAndMeta.setRenderedImage(result);
    
        File tempFile = File.createTempFile("test-", ".tif");
        System.err.println("tempFile: " + tempFile);
    
        ImageWriter tiffWriter = ImageIO.getImageWritersByFormatName("TIFF").next();
        try (ImageOutputStream stream = ImageIO.createImageOutputStream(tempFile)) {
            tiffWriter.setOutput(stream);
    
            ImageWriteParam writeParam = tiffWriter.getDefaultWriteParam();
    
            // If you want a specific compression, uncommment these lines
            // The default setting is to copy from metadata
    //        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            // Allowed compression type values are: 
            // "None", "CCITT RLE", "CCITT T.4", "CCITT T.6","LZW", "JPEG", "ZLib", "PackBits" and "Deflate"
    //        writeParam.setCompressionType("PackBits");
    
            tiffWriter.write(null, imageAndMeta, writeParam);
        }
    
        tiffWriter.dispose();
    }
    

    (for some reason the XMP metadata is still stripped from the output, I believe that is a bug).

    Tiling is currently not supported by the writer, but it may be controlled by the writeParam in the future (using the standard API to do so). Your original image isn't tiled, so I guess that is less of a concern.