如何在ImageIO或TwelveMonkeys中旋转CMYK格式TIFF图像?
解决CMYK TIFF图像旋转时的
Unknown image type 0异常问题 问题根源
你遇到的IllegalArgumentException: Unknown image type 0,是因为TwelveMonkeys读取CMYK TIFF后返回的BufferedImage类型是TYPE_CUSTOM(值为0)——标准Java的BufferedImage没有内置CMYK的预定义类型,直接用bi.getType()作为参数创建新BufferedImage会触发这个异常。
两种解决方案
方案1:转换为RGB色彩空间后旋转(简单通用)
如果不需要保留CMYK色彩,转成RGB是最省心的方式,因为RGB是BufferedImage支持的标准类型,旋转不会有类型问题:
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 cmykImage; try { reader.setInput(iis); cmykImage = reader.read(0); } finally { reader.dispose(); } // 将CMYK图像转换为RGB BufferedImage rgbImage = new BufferedImage(cmykImage.getWidth(), cmykImage.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = rgbImage.createGraphics(); g2d.drawImage(cmykImage, 0, 0, null); g2d.dispose(); // 执行旋转 BufferedImage rotatedImage; AffineTransform transform = new AffineTransform(); int rotatedWidth, rotatedHeight; if (angle == 90) { rotatedWidth = rgbImage.getHeight(); rotatedHeight = rgbImage.getWidth(); transform.translate(rotatedWidth / 2, rotatedHeight / 2); transform.rotate(Math.toRadians(90)); transform.translate(-rgbImage.getWidth() / 2, -rgbImage.getHeight() / 2); } else if (angle == 270) { rotatedWidth = rgbImage.getHeight(); rotatedHeight = rgbImage.getWidth(); transform.translate(rotatedWidth / 2, rotatedHeight / 2); transform.rotate(Math.toRadians(270)); transform.translate(-rgbImage.getWidth() / 2, -rgbImage.getHeight() / 2); } else { // 0或180度 rotatedWidth = rgbImage.getWidth(); rotatedHeight = rgbImage.getHeight(); if (angle == 180) { transform.translate(rotatedWidth / 2, rotatedHeight / 2); transform.rotate(Math.toRadians(180)); transform.translate(-rgbImage.getWidth() / 2, -rgbImage.getHeight() / 2); } } rotatedImage = new BufferedImage(rotatedWidth, rotatedHeight, BufferedImage.TYPE_INT_RGB); g2d = rotatedImage.createGraphics(); g2d.setTransform(transform); g2d.drawImage(rgbImage, 0, 0, null); g2d.dispose(); // 这里可以处理rotatedImage,比如保存或输出 } catch (IOException e) { throw new RuntimeException("Image processing failed", e); }
方案2:保留CMYK色彩旋转(适合需要原色彩空间的场景)
如果必须保留CMYK,不能用BufferedImage的类型构造器,要直接基于原图像的ColorModel和SampleModel创建新图,再通过AffineTransformOp完成旋转:
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 cmykImage; try { reader.setInput(iis); cmykImage = reader.read(0); } finally { reader.dispose(); } // 计算旋转后的尺寸和变换矩阵 AffineTransform transform = new AffineTransform(); int rotatedWidth, rotatedHeight; if (angle == 90 || angle == 270) { rotatedWidth = cmykImage.getHeight(); rotatedHeight = cmykImage.getWidth(); transform.translate(rotatedWidth / 2, rotatedHeight / 2); transform.rotate(Math.toRadians(angle)); transform.translate(-cmykImage.getWidth() / 2, -cmykImage.getHeight() / 2); } else { rotatedWidth = cmykImage.getWidth(); rotatedHeight = cmykImage.getHeight(); if (angle == 180) { transform.translate(rotatedWidth / 2, rotatedHeight / 2); transform.rotate(Math.toRadians(180)); transform.translate(-cmykImage.getWidth() / 2, -cmykImage.getHeight() / 2); } } // 使用原CMYK图像的ColorModel和SampleModel创建目标图 ColorModel colorModel = cmykImage.getColorModel(); SampleModel sampleModel = colorModel.createCompatibleSampleModel(rotatedWidth, rotatedHeight); WritableRaster raster = Raster.createWritableRaster(sampleModel, null); BufferedImage rotatedCmykImage = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null); // 执行旋转 AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); op.filter(cmykImage, rotatedCmykImage); // 处理旋转后的CMYK图像 } catch (IOException e) { throw new RuntimeException("Image processing failed", e); }
关键注意点
- 不要直接用
bi.getType()创建新图,CMYK图的类型是TYPE_CUSTOM,不被构造器支持。 - 如果用
Graphics2D绘制CMYK图像,Java会自动做色彩转换,所以方案1里直接draw就能转RGB。 - 方案2中必须用
AffineTransformOp而不是手动绘制,避免色彩空间不兼容的问题。
内容的提问来源于stack exchange,提问作者bepopov
相关产品推荐
相关产品推荐

