JAI ImageIO 的纯 Java 替代方案,用于检测 CMYK 图像

2022-09-03 13:22:41

首先,我想解释导致问题的情况/要求:

在我们的Web应用程序中,我们无法支持CMYK图像(JPEG),因为IE 8及以下版本无法显示它们。因此,我们需要检测何时有人想要上传这样的图像并拒绝它。

不幸的是,Java的ImageIO不会读取这些图像,或者无法让我获得检测到的色彩空间。从调试来看,似乎内部获得了色彩空间代码11(这意味着),但我无法安全地访问该信息。JPEGImageReaderJCS_YCCK

在向读者查询图像类型时,我没有得到CMYK的任何东西,所以我可能会假设.no image types = unsupported image

我使用映像工具将源CMYK图像转换为RGB,以测试它是否可读(我尝试在收到消息“不支持CMYK”时模拟管理员的步骤)。但是,不会阅读该图像,因为它假设(在源代码中注释!3 分量 RGB 色彩空间,但图像标头报告 4 个分量(可能是 RGBA 或 ARGB),因此抛出一个分量。JPEGImageReaderIllegalArgumentException

因此,ImageIO不是一个选项,因为我无法可靠地获取图像的色彩空间,并且我无法告诉管理员为什么由于某些内部错误而无法接受其他精美的图像(它可以由浏览器显示)。

这导致我尝试了JAI ImageIO,它做得很好,可以正确读取我的所有测试图像。CLibJPEGImageReader

但是,由于我们将应用程序部署在可能同时托管其他应用程序的 JBoss 中,因此我们希望使它们尽可能保持隔离。AFAIK,我需要将JAI ImageIO安装到JRE中,或者以其他方式使本机库可用才能使用它们,因此其他应用程序也可能可以访问它们,这可能会导致副作用(至少我们必须进行大量测试以确保情况并非如此)。

这就是这个问题的解释,在这里它再次出现:除了JAI ImageIO之外,是否有任何纯Java替代品可以可靠地检测并可能转换CMYK图像?

提前致谢,

托马斯


答案 1

我找到了一个可以满足我们需求的解决方案:Apache Commons Sanselan。该库可以非常快速准确地读取JPEG标头(至少是我的所有测试图像)以及许多其他图像格式。

缺点是它不会读取JPEG图像数据,但我可以使用基本的JRE工具做到这一点。

阅读JPEG图像进行转换非常容易(那些拒绝阅读的图像也很容易):ImageIO

JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new FileInputStream( new File(pFilename) ) );
BufferedImage sourceImg = decoder.decodeAsBufferedImage();

然后,如果Sanselan告诉我图像实际上是CMYK,我会获得源图像的光栅并转换自己:

for( /*each pixel in the raster, which is represented as int[4]*/ )
{  
   double k = pixel[3] / 255.0;

   double r = (255.0 - pixel[0])*k;
   double g = (255.0 - pixel[1])*k;
   double b = (255.0 - pixel[2])*k;
}

这在RGB图像不太亮或太暗的情况下给出了非常好的结果。但是,我不确定为什么乘以会阻止变亮。JPEG实际上是用本机代码解码的,而CMYK->RGB转换我得到了一些不同的东西,我只是尝试乘法以查看视觉结果。k

如果有人能对此有所了解,我将不胜感激。


答案 2

我已经发布了一个纯Java解决方案,用于读取各种JPEG图像并将其转换为RGB。

它建立在以下事实之上:

  • 虽然 ImageIO 无法读取具有 CMYK 作为缓冲图像的 JPEG 图像,但它可以读取原始像素数据(栅格)。
  • Sanselan(或现在称为Apache Commons Imaging)可用于读取CMYK图像的详细信息。
  • 有些图像具有倒置的CMYK值(旧的Photoshop错误)。
  • 有些图像带有YCCK而不是CMYK(可以轻松转换)。

推荐