使用ICC色彩配置文件将RGB PNG转换为CMYK JPEG

4

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

在我的研究中,我找到了多篇关于此问题的文章。我复制了这个回答,使用了BufferedImageColorConvertOp

我得出了这个小例子:

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://dev59.com/IUbRa4cB1Zd3GeqPwgzx/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)

异常的消息对我没有帮助。在这个帖子中,他们说 sun jdk 或 JAI 可以解决这个问题。

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

2个回答

0

-1
问题通过使用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
    // https://dev59.com/IUbRa4cB1Zd3GeqPwgzx#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个通道,CMYK == 4个通道)。不幸的是,使用普通的 JPEGImageWriter 编写 CMYK JPEG 是一种黑魔法,但可以通过编写 Raster 实现。 - Harald K
@haraldK 这有点更暗了。 - d0x
1
@haraldK 我添加了转换后的截图和一个指向 GitHub 上正在运行的 Maven 项目的链接。 - d0x
谢谢分享这些链接!正如我所想,你的JPEG不是CMYK JPEG,而是普通的YCbCr 4:2:2子采样JFIF(没有嵌入ICC配置文件)。但这可能正是你需要/期望的,所以如果你满意,我也很高兴。 :-) - Harald K
@haraldK其实如果图片不那么暗,我会很高兴。我对所有这些ICC配置文件一无所知。对我来说,必须使用CMYK JPEG文件将其添加到使用iText的PDF/X-3文件中。这就是为什么我这样做的原因:)。请随意改进答案或提出自己的答案。 - d0x
1
我明白了。我认为你问题中的代码在逻辑上是正确的(不幸的是,JPEGImageWriter目前不支持CMYK BufferedImage,所以你会得到一个异常)。而你回答中的代码则不然。正如我所说,三通道RGB图像cmykImage甚至没有足够的通道来容纳CMYK数据...而且你不能在创建后更改BufferedImage的颜色模型/通道数。也许iText会为你转换JPEG为CMYK,或者CMYK并不是真正必需的?我正在开发一个项目来简化所有这些,但在此期间,我想我只能把它留给你自己解决了。 :-/ - Harald K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接