在我们的网络应用程序中,我们不能支持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,否则可以使本机库可用,以便使用它们,因此其他应用程序也可能会访问它们,这可能会导致副作用(至少我们会有测试很多,以确保不是这种情况).
这就是这个问题的解释,这里再说一遍:
是否有任何纯Java替代JAI ImageIO可靠地检测和可能转换CMYK图像?
提前致谢,
托马斯
解决方法
缺点是它不会读取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转换我得到了不同的东西,我只是尝试乘法来看到视觉效果.
如果有人在这方面有所作为,我将不胜感激.