有没有一种完全使用Java编写的替代ImageIO读取JPEG文件的解决方案?

20
我们正在使用Java2D来调整上传到我们网站的照片大小,但是我们遇到了一个问题(似乎是一个旧问题,参见:http://forums.sun.com/thread.jspa?threadID=5425569)- 当我们尝试ImageIO.read()读取包含它们二进制数据的InputStream时,一些特定的JPEG会引发CMMException
java.awt.color.CMMException: Invalid image format
 at sun.awt.color.CMM.checkStatus(CMM.java:131)
 at sun.awt.color.ICC_Transform.<init>(ICC_Transform.java:89)
 at java.awt.image.ColorConvertOp.filter(ColorConvertOp.java:516)
 at com.sun.imageio.plugins.jpeg.JPEGImageReader.acceptPixels(JPEGImageReader.java:1114)
 at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImage(Native Method)
 at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1082)
 at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:897)
 at javax.imageio.ImageIO.read(ImageIO.java:1422)
 at javax.imageio.ImageIO.read(ImageIO.java:1326)
    ...

我们已经缩小了范围,发现只有特定相机拍摄的照片会导致这个错误: http://img214.imageshack.us/img214/5121/estacaosp.jpg。 我们注意到只有 Sun 的 JVM(在 Linux 和 Mac 上,刚测试了 1.6.0_20)会出现这种情况 - 使用 OpenJDK 的测试机器可以毫无问题地读取相同的照片,可能是由于 JPEG 阅读器的不同实现所导致。

不幸的是,我们无法在生产环境中切换 JVM,也不能使用依赖本机的解决方案,如 ImageMagick (http://www.imagemagick.org/)。

考虑到这一点,我的问题是:是否存在可以处理像链接中那样的照片的 ImageIO 的 JPEG 阅读器替代品? 如果没有,是否有其他 100% 纯 Java 的照片调整大小解决方案可供我们使用?

谢谢!


顺便说一下,我知道ImageIO不处理CMYK图像(详见https://dev59.com/znE95IYBdhLWcg3wN7Kv)。但是示例是RGB格式的(就Mac预览而言,如果有人可以确认一下就好了)。 - chesterbr
我在Oracle/Sun的错误数据库上开了一个bug,链接在这里: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7064516 如果你仍然对修复感兴趣,请投票支持它! - Ilias Bartolini
1
请注意,该错误在2012年被标记为“已在Java 8b56中修复”。因此,另一种解决方案是升级到最新的Java 8(或更高版本)。 - Stephen C
3个回答

12

对你可能有用的一个库是Java高级图像处理库(JAI

使用这个库可能比使用ImageIO要复杂得多,但在我刚刚运行的快速测试中,它确实打开并显示了你提供的问题图像文件。

public static void main(String[] args) {
        RenderedImage image = JAI.create("fileload", "estacaosp.jpg");

        float scale=(float) 0.5;

        ParameterBlock pb = new ParameterBlock();
        pb.addSource(image);

        pb.add(scale);
        pb.add(scale);
        pb.add(1.0F);
        pb.add(1.0F);

        pb.add(new InterpolationNearest() );// ;InterpolationBilinear());
        image = JAI.create("scale", pb);

        // Create an instance of DisplayJAI.
        DisplayJAI srcdj = new DisplayJAI(image);

        JScrollPane srcScrollPaneImage = new JScrollPane(srcdj);

// Use a label to display the image
        JFrame frame = new JFrame();

        frame.getContentPane().add(srcScrollPaneImage, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
运行这段代码后,图像似乎可以正常加载。然后使用ParamaterBlock将其缩小50%。 最后,如果您想保存文件,只需调用:
String filename2 = new String ("tofile.jpg");
  String format = new String ("JPEG");
  RenderedOp op = JAI.create ("filestore", image, filename2, format);

希望这能帮到你,祝你好运。


当然可以!必须检查一下它在“无头”设置中的工作效果,但我相信我们能够解决。谢谢! - chesterbr
1
只是想让您知道,我们的开发人员实施了这个解决方案,而且它非常成功。再次感谢! - chesterbr
2
链接失效,请更新为http://www.oracle.com/technetwork/java/current-142188.html或者最新的链接。 - user1133275

10

虽然是旧帖,但为了以后的参考:

在此问题和这里找到的链接的启发下,我已经为ImageIO编写了一个JPEGImageReader插件,支持这种具有“不良”ICC颜色配置文件的JPEG图像(“问题”是ICC配置文件中的渲染意图与Java的ColorConvertOp不兼容)。它是纯Java代码,不需要JAI。

源代码和相关二进制文件可从GitHub上的TwelveMonkeys项目免费获取。


7
我遇到了同样的问题。我不想使用过时的JAI,但看起来这是最简单的解决方案。
此代码将InputStream转换为BufferedImage,使用sun的ImageIO(快速),或在出现此问题的少数情况下,使用JAI:
public static BufferedImage read(InputStream is) throws IOException {
    try {
        // We try it with ImageIO
        return ImageIO.read(ImageIO.createImageInputStream(is));
    } catch (CMMException ex) {
        // If we failed...
        // We reset the inputStream (start from the beginning)
        is.reset();
        // And use JAI
        return JAI.create("stream", SeekableStream.wrapInputStream(is, true)).getAsBufferedImage();
    }
}

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