javatiffbufferedimagecmyktwelvemonkeys

How can I rotate TIFF CMYK image in ImageIO or TwelveMonkeys?


I need to rotate my TIFF image with color space CMYK. Standard Java ImageIO doesn't support CMYK TIFF images so I used TwelveMonkeys plugin. But it didn't help. When I tried to rotate my image I faced with an exception.

I do the following:

try (InputStream is = new ByteArrayInputStream(bytes);
        ImageInputStream iis = ImageIO.createImageInputStream(is)) {
      Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);

      if (!iter.hasNext()) {
        throw new RuntimeException("Image type is not supported");
      }

      ImageReader reader = iter.next();
      BufferedImage bi;
      try {
        reader.setInput(iis);
        bi = reader.read(0);
      } finally {
        reader.dispose();
      }
      int type = bi.getType();
      BufferedImage newBi;
      if (angle == 90 || angle == 270) {
        newBi= new BufferedImage(height, width, type);
      } else {
        newBi= new BufferedImage(width, height, type);
      }
      //writing the image content to new buffered image
}

But it throws java.lang.IllegalArgumentException: Unknown image type 0. How can I create a BufferedImage for TIFF CMYK image? Or at least how can I rotate TIFF CMYK image?


Solution

  • To rotate a BufferedImage in Java, the normal way would be to use AffineTransformOp. This will allow you to rotate any image without having to create a new image of the same type up front.

    For an example see the TIFFUtilities.applyOrientation method in TwelveMonkeys "contrib" module. You can also just use this method directly, if you like. Just beware the input is one of the TIFF orientation tag constant values, not an angle:

    Ie. to rotate 90 degrees (assuming static imports for readability):

    BufferedImage original;
    
    BufferedImage rotated = applyOrientation(original, ORIENTATION_RIGHTTOP); // 6
    

    For the more general topic "How can I create a BufferedImage for a TIFF CMYK image", the quick answer is use the constructor that takes a WritableRaster and a ColorModel as argument like this:

    BufferedImage original;
    
    ColorModel cm = original.getColorModel();
    WritableRaster raster = cm.createCompatibleWritableRaster(newWidth, newHeight);
    BufferedImage image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
    

    You have to use this constructor, as any CMYK BufferedImage has to be TYPE_CUSTOM (the constant value 0). And the BufferedImage constructor taking a type argument does not allow TYPE_CUSTOM (after all, which of the countless possible custom types would that be?).