Java中检查损坏的JPEG文件

5

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

我尝试过几种方法:

  • using the javax.ImageIO library

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

    but it can detect only few corrupted files of the ones I have tested and it's very slow (on my PC around 1 image / second).

  • Apache Commons Imaging library

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

    This code can detect all the corrupted images I've tested, but the performances are very poor (on my PC less than 1 image / second).

我正在寻找一个 Java 替代 UNIX 程序jpeginfo,其速度大约快了10倍(在我的电脑上大约每秒可处理10张图片)。


你是否使用特定属性来确定JPEG文件是否损坏?我猜测BufferedImage或JpegImageParser正在查看整个文件,这就解释了为什么速度比你想要的慢? - Shar1er80
“损坏”指的是一些数据丢失,比如截断文件。我需要检查的图像集来自于在格式化的硬盘上运行的恢复程序(我忘记备份中的一个文件夹...),许多恢复的文件都是损坏的,部分数据丢失,因此这些图像相当无用。我正在寻找的是一种可以在不将其转换为光栅图像的情况下查找JPEG文件结构问题的方法(这是一项昂贵的操作)。 - Lorenzo Cameroni
4个回答

5
我看了一下JPEG格式,据我理解,最后应该是一个包含两个字节(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 吗?因为有符号的 D9 的 8 位补码是 -39。 - coverboy
1
@coverboy 当然,7年之后!!已经更正了。 - Joop Eggen

2
也许不是最好的答案,但是...
你提到的jpeginfo程序是用C语言编写的。这让我想起了当我想在我开发的Java应用程序中使用海军编写的代码(那是用C++编写的)时的回忆。
我有两个选择:
1. 使用JNI(Java Native Interface)将我的Java代码与C++(在你的情况下是C)库链接起来。 2. 将C++库转换为Java代码。
对我来说,选项1证明是困难的,因为我需要将一个对象传递到库中,并从库中获取对象,这迫使我选择选项2(也因为截止日期安排)。
所以,在你的情况下,因为我不知道是否有其他Java库能够满足你的要求,我建议这两个选项,或者可能构建自己的解析器。

看到一个JPEG文件的大致格式 - 由类型代码标记的一系列段 - 移植jpeginfo可能确实是可行的。 - Joop Eggen
第二个选项并不容易,因为jpeginfo是基于libjpeg的,所以移植jpeginfo意味着移植libjpeg。第一个选项是可行的,但我更喜欢以可移植的方式完成它。 - Lorenzo Cameroni

1

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

您问是否有快速的方法。您可以在速度和准确性之间进行权衡。最简单的方法是检查流的开头是否有SOI标记,结尾是否有EOI标记。

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


0

这不是Java的本地方法,但您可以始终调用像jpeginfo或{{link1:imagemagick's identify}}这样的程序 - shell的开销可能小于Java库所花费的时间。

我曾经做过类似的事情,并发现我可以使用Runtime.exec调用identify -regard-warnings -verbose -并从字节数组的stdin中读取,在2013年的MacBook Pro上大约需要200毫秒(我正在检查mp3艺术品,因此图像大小约为300x300px)。 不是很好,但比每秒1张图片要快!

(请注意,对于我的图像,我必须指定-verbose以便imagemagick捕获一些错误)


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