我需要一种快速的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;
}
但是它只能检测出我测试过的文件中几个已损坏的文件,并且速度非常慢(在我的电脑上大约每1张图像一次)。
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倍(在我的电脑上大约10张图像/秒)
答案 0 :(得分:3)
我查看了JPEG format,根据我的理解,最后EOI
(图像结束)两个字节(FF D9
)的段应该是最后一个。
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] == -23; // DD D9
}
}
答案 1 :(得分:2)
可能不是最好的答案,但是......
你提到的jpeginfo程序是在C语言中。这让我回想起当时我想在我正在开发的Java应用程序中使用由海军编写的代码(在C ++中)。
我有两个选择:
选项1对我来说很难,因为我需要将一个对象传递给库并从库中取回对象(S),这迫使我做选项2(另外,由于截止日期调度)。
所以在你的情况下,因为我不知道Java中任何其他符合你要求的库,我会建议这两个选项,或者可能构建你自己的解析器。
答案 2 :(得分:1)
判断JPEG图像是否已损坏的唯一方法是解压缩它。
你问是否有快捷方式。你可以肯定地将速度换成准确性。最简单的方法是检查流是否在前面有一个SOI标记,在末尾有一个EOI标记。
接下来,您可以尝试解析标记以确保它们具有有效值。
答案 3 :(得分:0)
这不是本机Java方法,但您总是可以使用jpeginfo或imagemagick's identify等程序 - shell的开销可能比Java库花费的时间少。
我必须做类似的事情,我发现我可以使用Runtime.exec从一个字节数组中调用identify -regard-warnings -verbose -
stdin,在2013 macbook pro上大约200ms(我正在检查mp3艺术品,因此图像大小约为300x300px)。不是很好,但速度超过每秒1张图像!
(注意我的图片我必须为imagemagick指定-verbose
以获取一些错误)