【问题标题】:Check for corrupted JPEG files in Java在 Java 中检查损坏的 JPEG 文件
【发布时间】:2022-04-21 21:57:55
【问题描述】:

我需要一种快速的 Java 方法来检查 JPEG 文件是否有效,或者它是否是截断/损坏的图像。

我尝试了几种方法:

  • 使用 javax.ImageIO 库

    public boolean check(File image) throws IOException {
        try {
            BufferedImage bi = ImageIO.read(image);
            bi.flush();
        } catch (IIOException e) {
            return false;
        }
        return true;
    }
    

    但它只能检测到我测试过的文件中的少数损坏文件,而且速度非常慢(在我的 PC 上大约 1 张图像/秒)。

  • Apache Commons Imaging图书馆

    public boolean check(File image) throws IOException {
        JpegImageParser parser = new JpegImageParser();
        ByteSourceFile bs = new ByteSourceFile(image);
        try {
            BufferedImage bi = parser.getBufferedImage(bs, null);
            bi.flush();
    
            return true;
        } catch (ImageReadException e) {
            return false;
        }
    }
    

    这段代码可以检测到我测试过的所有损坏的图像,但是性能很差(在我的电脑上不到 1 张图像/秒)。

我正在寻找 UNIX 程序 jpeginfo 的 Java 替代方案,它的速度大约快 10 倍(在我的 PC 上大约 10 张图像/秒)。

【问题讨论】:

  • 您是否使用特定属性来知道 JPEG 已损坏?我希望 BufferedImage 或 JpegImageParser 正在查看整个文件,这会解释它比您想要的要慢吗?
  • 损坏的意思是丢失了一些数据,例如截断的文件。我需要检查的图像集来自在格式化的硬盘驱动器上运行的恢复程序(我忘记了备份中的文件夹......),许多恢复的文件已损坏,部分数据丢失,所以这些图像毫无用处。我正在寻找的是在 JPEG 文件结构中寻找问题而不将其转换为光栅图像(这是一项昂贵的操作)的东西。谢谢

标签: java jpeg


【解决方案1】:

我查看了 JPEG format,据我了解,两个字节 (FF D9) 的最后一个 EOI(图像结束)段应该是最后一个。

boolean jpegEnded(String path) throws IOException {
    try (RandomAccessFile fh = new RandomAccessFile(path, "r")) {
        long length = fh.length();
        if (length < 10L) { // Or whatever
            return false;
        }
        fh.seek(length - 2);
        byte[] eoi = new byte[2];
        fh.readFully(eoi);
        return eoi[0] == -1 && eoi[1] == -39; // FF D9 (first falsely -23)
    }
}

【讨论】:

  • eoi[1] 应该是 -39 吗? singed D9 的有符号 8 位是 -39。
  • @coverboy 当然是 7 年后!!已更正。
【解决方案2】:

可能不是最好的答案,但是...

您提到的 jpeginfo 程序是用 C 语言编写的。所以这让我想起了我想在我正在开发的 Java 应用程序中使用 Navy 编写的代码(那是用 C++ 编写的代码)时的回忆。

我有两个选择:

  1. 使用 JNI(Java 本机接口)将我的 java 代码链接到 C++(在您的情况下为 C)库。
  2. 将 C++ 库转换为 java 代码。

事实证明,选项 1 对我来说很难,因为我需要将对象传递到库中并从库中取回对象(S),这迫使我执行选项 2(另外,由于截止日期调度)。

所以在你的情况下,因为我不知道任何其他 Java 库可以满足你的要求,我会建议这 2 个选项,或者可能构建你自己的解析器。

【讨论】:

  • 查看 jJPEG 文件的粗略格式 - 一系列标有类型代码的段 - 移植 jpeginfo 可能确实可行。
  • 第二个选项就不是那么容易了,因为jpeginfo是基于libjpeg的,所以jpeginfo的一个端口就是libjpeg的一个端口。第一个选项是可行的,但我更喜欢以便携的方式进行
【解决方案3】:

确定 JPEG 图像是否损坏的唯一方法是对其进行解压缩。

你问是否有快速的方法。您可以肯定地以速度换取准确性。最简单的方法是检查流的前面是否有 SOI 标记,最后是否有 EOI 标记。

接下来,您可以尝试解析标记以确保它们具有有效值。

【讨论】:

    【解决方案4】:

    这不是原生 Java 方法,但您始终可以使用 jpeginfo 或 imagemagick's identify 之类的程序进行外壳处理 - 外壳程序的开销可能少于 Java 库所花费的时间。

    我不得不做类似的事情,我发现我可以使用 Runtime.exec 从字节数组中调用 identify -regard-warnings -verbose - 和 stdin,在 2013 macbook pro 上大约 200 毫秒(我正在检查 mp3 艺术品,所以图像尺寸约为 300x300 像素)。不是很好,但比每秒 1 张图像快!

    (注意我的图片我必须指定 -verbose 以便 imagemagick 发现一些错误)

    【讨论】:

      猜你喜欢
      • 2010-09-16
      • 2021-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-26
      • 1970-01-01
      • 2018-03-29
      相关资源
      最近更新 更多