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

发布于 2024-11-26 12:32:54 字数 1017 浏览 2 评论 0原文

首先我想解释一下导致这个问题的情况/要求:

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

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

当向阅读器查询图像类型时,我没有得到任何 CMYK 信息,因此我可能会假设没有图像类型 = 不支持的图像

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

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

这促使我尝试 JAI ImageIO,其 CLibJPEGImageReader 做得非常出色,并正确读取了我的所有测试图像。

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

这就是这个问题的解释,又来了: 是否有 JAI ImageIO 的纯 Java 替代品可以可靠地检测并可能转换 CMYK 图像?

提前致谢,

Thomas

first I'd like to explain the situation/requirements that lead to the question:

In our web application we can't support CMYK images (JPEG) since IE 8 and below can't display them.
Thus we need to detect when someone wants to upload such an image and deny it.

Unfortunately, Java's ImageIO won't read those images or would not enable me to get the detected color space. From debugging it seems like JPEGImageReader internally gets the color space code 11 (which would mean JCS_YCCK) but I can't safely access that information.

When querying the reader for the image types I get nothing for CMYK, so I might assume no image types = unsupported image.

I converted the source CMYK image to RGB using an imaging tool in order to test whether it would then be readable (I tried to simulate the admin's steps when getting the message "No CMYK supported"). However, JPEGImageReader would not read that image, since it assumes (comment in the source!)3-component RGB color space but the image header reports 4 components (maybe RGBA or ARGB) and thus an IllegalArgumentException is thrown.

Thus, ImageIO is not an option since I can't reliably get the color space of an image and I can't tell the admin why an otherwise fine image (it can be displayed by the browser) would not be accepted due to some internal error.

This led me to try JAI ImageIO whose CLibJPEGImageReader does an excellent job and correctly reads all my test images.

However, since we're deploying our application in a JBoss that might host other applications as well, we'd like to keep them as isolated as possible. AFAIK, I'd need to install JAI ImageIO to the JRE or otherwise make the native libs available in order to use them, and thus other applications might get access to them as well, which might cause side effects (at least we'd have to test a lot to ensure that's not the case).

That's the explanation for the question, and here it comes again:
Is there any pure Java alternative to JAI ImageIO which reliably detects and possibly converts CMYK images?

Thanks in advance,

Thomas

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鹊巢 2024-12-03 12:32:54

我找到了一个可以满足我们需求的解决方案: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 图像的效果非常好,不会太亮或太暗。但是,我不确定为什么乘以 k 会阻止增亮。 JPEG 实际上是用本机代码解码的,我得到的 CMYK->RGB 转换表明了不同的情况,我只是尝试乘以查看视觉结果。

如果有人能阐明这一点,我将不胜感激。

I found a solution that is ok for our needs: Apache Commons Sanselan. This library reads JPEG headers quite fast and accurate (at least all my test images) as well as a number of other image formats.

The downside is that it won't read JPEG image data, but I can do that with the basic JRE tools.

Reading JPEG images for conversion is quite easy (the ones that ImageIO refuses to read, too):

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

Then if Sanselan tells me the image is actually CMYK, I get the source image's raster and convert myself:

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;
}

This give quite good results in the RGB images not being too bright or dark. However, I'm not sure why multiplying with k prevents the brightening. The JPEG is actually decoded in native code and the CMYK->RGB conversion I got states something different, I just tried the multiply to see the visual result.

If anybody could shed some light on this, I'd be grateful.

回忆追雨的时光 2024-12-03 12:32:54

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

它基于以下事实:

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

I've posted a pure Java solution for reading all sorts of JPEG images and converting them to RGB.

It's built on the following facts:

  • While ImageIO cannot read JPEG images with CMYK as a buffered image, it can read the raw pixel data (raster).
  • Sanselan (or Apache Commons Imaging as it's called now) can be used to read the details of CMYK images.
  • There are images with inverted CMYK values (an old Photoshop bug).
  • There are images with YCCK instead of CMYK (can easily be converted).
不念旧人 2024-12-03 12:32:54

请注意另一篇文章,因为 Java 7 不允许在没有特殊参数的情况下直接使用 Sun 的实现,如 导入 com.sun.image.codec.jpeg.*

Beware of another post as the Java 7 does not allow to use directly Sun's implementation without special parameters as indicated in import com.sun.image.codec.jpeg.*.

请远离我 2024-12-03 12:32:54

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

我不同意您的“因此我们需要检测何时有人想要上传此类图像并拒绝它”。一个更加用户友好的策略是将其转换为 CMYK 之外的其他内容。

您的帖子的其余部分有点令人困惑,因为您要求检测和转换,这是两个不同的事情。我再次认为转换图像更加用户友好。

不需要用粗体写顺便说一句:

是否有任何纯Java替代JAI ImageIO,它可靠
检测并可能转换 CMYK 图像?

纯 Java 我不知道,但 ImageMagick 可以很好地将 CMYK 图像转换为 RGB 图像。从 Java 在服务器端调用 ImageMagick 实际上并不复杂。我过去常常通过调用外部进程来手动完成此操作,但现在有像 JMagickim4java 这样的包装器。

In our web application we can't support CMYK images (JPEG) since
IE 8 and below can't display them. Thus we need to detect when someone
wants to upload such an image and deny it.

I don't agree with your "Thus we need to detect when someone wants to upload such an image and deny it". A much more user-friendly policy would be to convert it to something else than CMYK.

The rest of your post is a bit confusing in that regards seen that you ask both for detection and conversion, which are two different things. Once again, I think converting the image is much more user-friendly.

No need to write in bold btw:

Is there any pure Java alternative to JAI ImageIO which reliably
detects and possibly converts CMYK images?

Pure Java I don't know, but ImageMagick works fine to convert CMYK image to RGB ones. Calling ImageMagick on the server-side from Java really isn't complicated. I used to do it manually by calling an external process but nowadays there are wrappers like JMagick and im4java.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文