【问题标题】:Convert RGB PNG to CMYK JPEG (using ICC Color Profiles)将 RGB PNG 转换为 CMYK JPEG(使用 ICC 颜色配置文件)
【发布时间】:2014-04-13 10:44:41
【问题描述】:

我需要将 PNG 文件转换为 CMYK JPEG。

在我的研究过程中,我发现了多篇关于 SO 描述该问题的文章。我已经使用BufferedImageColorConvertOp 复制了this answer

我想出了这个小例子:

public static void main(final String[] args) throws IOException
{
    final String imageFile = "/tmp/page0.png";

    final BufferedImage pngImage = ImageIO.read(new File(imageFile));

    // convert PNG to JPEG
    // http://www.mkyong.com/java/convert-png-to-jpeg-image-file-in-java/
    final BufferedImage rgbImage = new BufferedImage(pngImage.getWidth(), pngImage.getHeight(), BufferedImage.TYPE_INT_RGB);
    rgbImage.createGraphics().drawImage(pngImage, 0, 0, Color.WHITE, null);

    // RGB to CMYK using ColorConvertOp
    // https://stackoverflow.com/questions/380678/how-to-set-icc-color-profile-in-java-and-change-colorspace/2804370#2804370
    final ICC_Profile ip = ICC_Profile.getInstance("icc/ISOcoated_v2_300_eci.icc");
    // final ICC_Profile ip = ICC_Profile.getInstance("icc/CoatedFOGRA27.icc");
    // final ICC_Profile ip = ICC_Profile.getInstance("icc/USWebUncoated.icc");

    final ColorConvertOp cco = new ColorConvertOp(new ICC_ColorSpace(ip), null);
    final BufferedImage cmykImage = cco.filter(rgbImage, null);

    // Write the result into an bytearray
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(cmykImage, "jpg", baos);
    baos.flush();

    final byte[] imageInByte = baos.toByteArray();
}

问题是,它让我陷入了这个异常:

Exception in thread "main" javax.imageio.IIOException: Invalid argument to native writeImage
    at com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeImage(Native Method)
    at com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeOnThread(JPEGImageWriter.java:1058)
    at com.sun.imageio.plugins.jpeg.JPEGImageWriter.write(JPEGImageWriter.java:360)
    at javax.imageio.ImageWriter.write(ImageWriter.java:615)
    at javax.imageio.ImageIO.doWrite(ImageIO.java:1612)
    at javax.imageio.ImageIO.write(ImageIO.java:1578)
    at ... .pdf.ReportGeneratorPublicContentTest.main(ReportGeneratorPublicContentTest.java:69)

异常的消息对我没有帮助。在 this thread 他们说 sun jdk 或 JAI 将解决问题。

我尝试了 apt-get install libjai-core-java 和 oracle JDK jdk1.7.0_51。错误仍然存​​在。

【问题讨论】:

    标签: java jai color-profile jmagick color-management


    【解决方案1】:

    @克里斯蒂安·施耐德: 在我下载带有 CMYK JPEG 链接的图像文件后,我打开文件的属性。我看到图像的色彩空间仍然是 RGB。此图片未转换为 CMYK 颜色。 请看以下链接:

    how can I convert an RGB image to CMYK and vice versa in Java?

    lovelywib 的回答解决了这个问题。

    【讨论】:

      【解决方案2】:

      问题已通过使用TYPE_3BYTE_BGR 而不是TYPE_INT_RGB 解决。

      public static void main(String[] args) throws Exception
      {
          final String imageFile = "/tmp/page0.png";
      
          final BufferedImage pngImage = ImageIO.read(new File(imageFile));
      
          // convert PNG to JPEG
          // http://www.mkyong.com/java/convert-png-to-jpeg-image-file-in-java/
          final BufferedImage rgbImage = new BufferedImage(pngImage.getWidth(), pngImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
          rgbImage.createGraphics().drawImage(pngImage, 0, 0, Color.WHITE, null);
      
          // RGB to CMYK using ColorConvertOp
          // http://stackoverflow.com/questions/380678/how-to-set-icc-color-profile-in-java-and-change-colorspace/2804370#2804370
          final ICC_Profile ip = ICC_Profile.getInstance("icc/USWebUncoated.icc");
      
          final ColorConvertOp cco = new ColorConvertOp(rgbImage.getColorModel().getColorSpace(), new ICC_ColorSpace(ip), null);
      
          final BufferedImage cmykImage = new BufferedImage(pngImage.getWidth(), pngImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
      
          cco.filter(rgbImage, cmykImage);
      
          // Write the result into an bytearray
          final ByteArrayOutputStream baos = new ByteArrayOutputStream();
          ImageIO.write(cmykImage, "JPEG", baos);
          baos.flush();
      }
      

      【讨论】:

      • 图片看起来好吗?我不明白TYPE_3BYTE_BGR 图像如何保存生成的图像数据,因为没有足够的通道(RGB == 3 通道 cs CMYK == 4 通道)。不幸的是,使用普通的JPEGImageWriter 编写 CMYK JPEG 是一种魔法,但编写 Raster 应该是可能的。
      • @haraldK 有点暗。
      • @haraldK 我在 github 添加了转换后的屏幕截图和一个正在运行的 maven 项目的链接
      • 感谢分享这些链接!正如我想的那样,您的 JPEG 不是 CMYK JPEG,它是普通的 YCbCr 4:2:2 二次采样 JFIF(没有嵌入的 ICC 配置文件)。但这可能正是您需要/期望的,所以如果您高兴,我会很高兴。 :-)
      • 我明白了。我认为您 question 中的代码在逻辑上是合理的(不幸的是,JPEGImageWriter 现在不支持 CMYK BufferedImages,因此您会遇到异常)。你答案中的那个不是。正如我所说,3 通道 RGB 图像 cmykImage 甚至没有足够的通道来保存 CMYK 数据……而且您无法在创建后更改 BufferedImage 的颜色模型/通道数。也许 iText 会为您将 JPEG 转换为 CMYK,或者 CMYK 不是真的强制性的?我正在做一个项目来简化这一切,但与此同时,我想我只能把它留给你。 :-/