【问题标题】:Image Manipulation - Java图像处理 - Java
【发布时间】:2016-05-03 18:22:55
【问题描述】:

我最近开发了一个在 Tomcat7 上运行的 Java Servlet,它应该接受来自不同格式(PNG、JPG、BMP)的图片的 POST。并执行以下任务:

  • 如果大于 2000 像素,则按比例缩小
  • 缓存其他维度(如果允许)
  • 运行散列算法来识别相似图像
  • 将它们全部存储和缓存为 JPG

作为最快的解决方案,我依赖 ImageIO,它在我遇到更多“新”格式之前产生了不错的结果。有两个主要问题我找不到有效的解决方案:

  • 渐进式 JPEG
  • 包含 EXIF 元数据的 JPEG

我评估了不同的解决方案,但似乎都没有解决这两个解决方案(我将列出最好的两个):

  • Apache Imaging(读取 EXIF,无法读取/写入 JPEG速度很慢
  • JMagick(接受 JPEG 和渐进式 JPEG,不关心 EXIF

你们中是否有人能够实施适用于这两种格式的解决方案?

【问题讨论】:

  • Exif 元数据和渐进式 JPEG 会导致什么问题?普通的ImageIO 应该可以正常阅读其中的大部分内容。我的TwelveMonkeys ImageIO JPEG 插件增加了对更多特殊情况和 CMYK JPEG 的支持。您需要保留 Exif 元数据吗?你想根据方向标签旋转图像吗?您所说的“同时使用两种格式”不是很清楚......
  • 从我所见(我让它工作了,但我花了一周时间)没有 TwelveMonkeys ImageIO,没有任何渐进式 JPEG 的默认支持,我尝试了很多。 Exif 元数据未被识别,因此图像被读取但方向错误。
  • 是的,Exif 方向是一个常见问题。我想过在我的插件中修复它,但需求从来没有大到无法实现它。只需获取元数据并在插件外部进行方向更改就很容易了。随意建议它作为一个新功能!但是我还没有遇到我的插件无法读取的许多渐进式 JPEG。如果您能向我提供一些无法读取的文件,我将非常高兴。

标签: java image javax.imageio jmagick


【解决方案1】:

您可以尝试im4java,它也像JMagick 一样在后台使用ImageMagick。但它不是作为原生库的包装器,而是使用命令行与 ImageMagick 进行通信。

ImageMagick 具有操作-auto-orient 自动将图像转换为“正确”方向。有关详细信息,请查看documentation

优势

  • 非常快,特别是如果 ImageMagick 是用优化的库编译的,例如 libjpeg-turbo(标准,例如在 Debian 发行版中)
  • 支持比 Debian 等发行版中包含的 JMagick 版本更多的 ImageMagick 操作(截至撰写时)。

缺点

  • 使用命令行界面与 ImageMagick 进行通信,由于安全限制,这可能是不允许的。

Maven 依赖

    <dependency>
        <groupId>org.im4java</groupId>
        <artifactId>im4java</artifactId>
        <version>1.4.0</version>
    </dependency>

示例 1(带文件)

        // prepare operations
        final int width = 2000;
        final double quality = 85.0;
        final IMOperation op = new IMOperation();
        op.addImage("/path/to/input/image.jpg"); // input
        op.autoOrient();
        op.resize(width);
        op.quality(quality);
        op.addImage("/path/to/output/image.jpg"); // output (rotated image @ 85% quality)

        // create and execute command
        final ConvertCmd convertCmd = new ConvertCmd();
        convertCmd.run(op);

示例 2(带有输入/输出流)

        // prepare operations
        final String outputFormat = "jpeg";
        final int width = 2000;
        final double quality = 85.0;
        final IMOperation op = new IMOperation();
        op.addImage("-"); // input: stdin
        op.autoOrient();
        op.resize(width);
        op.quality(quality);
        op.addImage(outputFormat + ":-"); // output: stdout

        // create and execute command
        final ConvertCmd convertCmd = new ConvertCmd();
        final Pipe inPipe = new Pipe(inputStreamWithOriginalImage,
                null); // no output stream, using stdin
        convertCmd.setInputProvider(inPipe);
        final Pipe outPipe = new Pipe(null, // no input stream, using stdout
                outputStreamForConvertedImage);
        convertCmd.setOutputConsumer(outPipe);
        convertCmd.run(op);

示例3(图片信息)

        final boolean baseInfoOnly = true;
        final Info info = new Info("/path/to/input/image.jpg",
                baseInfoOnly);
        System.out.println("Geometry: " + info.getImageGeometry());

性能

您还可以查看this question 以获得性能优化(但请注意,有一个-colorspace rgb 和一个不必要的,因为不支持JPEG 图像,-coalesce 操作都增加了处理时间)。

文档

Here你可以找到开发者指南以及更多示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 2015-05-10
    • 2013-01-13
    • 2011-01-14
    • 1970-01-01
    相关资源
    最近更新 更多