我需要在Java中检测图像文件是否损坏。我只使用PNG、JPG格式的图片。使用Sanselan可以实现吗?或者可以使用ImageIO来完成吗?我尝试过使用ImageIO.read似乎可以工作。但我不确定它能够检测所有种类的图像错误。我想知道最佳实践是什么。
我需要在Java中检测图像文件是否损坏。我只使用PNG、JPG格式的图片。使用Sanselan可以实现吗?或者可以使用ImageIO来完成吗?我尝试过使用ImageIO.read似乎可以工作。但我不确定它能够检测所有种类的图像错误。我想知道最佳实践是什么。
以下是我的解决方案,可以检查损坏的 GIF、JPG 和 PNG。它使用 JPEG EOF 标记检查截断的 JPEG,使用索引越界异常检查 GIF,并使用 EOFException 检查 PNG。
public static ImageAnalysisResult analyzeImage(final Path file)
throws NoSuchAlgorithmException, IOException {
final ImageAnalysisResult result = new ImageAnalysisResult();
final InputStream digestInputStream = Files.newInputStream(file);
try {
final ImageInputStream imageInputStream = ImageIO
.createImageInputStream(digestInputStream);
final Iterator<ImageReader> imageReaders = ImageIO
.getImageReaders(imageInputStream);
if (!imageReaders.hasNext()) {
result.setImage(false);
return result;
}
final ImageReader imageReader = imageReaders.next();
imageReader.setInput(imageInputStream);
final BufferedImage image = imageReader.read(0);
if (image == null) {
return result;
}
image.flush();
if (imageReader.getFormatName().equals("JPEG")) {
imageInputStream.seek(imageInputStream.getStreamPosition() - 2);
final byte[] lastTwoBytes = new byte[2];
imageInputStream.read(lastTwoBytes);
if (lastTwoBytes[0] != (byte)0xff || lastTwoBytes[1] != (byte)0xd9) {
result.setTruncated(true);
} else {
result.setTruncated(false);
}
}
result.setImage(true);
} catch (final IndexOutOfBoundsException e) {
result.setTruncated(true);
} catch (final IIOException e) {
if (e.getCause() instanceof EOFException) {
result.setTruncated(true);
}
} finally {
digestInputStream.close();
}
return result;
}
public class ImageAnalysisResult {
boolean image;
boolean truncated;
public void setImage(boolean image) {
this.image = image;
}
public void setTruncated(boolean truncated) {
this.truncated = truncated;
}
}
}
如果是JPEG格式的图片,请使用以下方法:
JPEGImageDecoder decoder = new JPEGImageDecoder(new FileImageSource(f) ,new FileInputStream(f));
decoder.produceImage();
如果出现异常,就意味着图像已经损坏。
对于其他情况,只需使用new ImageIcon(file)
来检查有效性。
PNGImageDecoder
处理 PNG
格式,使用 GifImageDecoder
处理 gif
格式。 - Mir-Ismailiimport sun.awt.image.JPEGImageDecoder
会导致以下错误:Package 'sun.awt.image' is declared in module 'java.desktop', which does not export it to module 'MODULE_NAME'
! - Mir-Ismailipublic boolean isValidImage(File f) {
boolean isValid = true;
try {
ImageIO.read(f).flush();
} catch (Exception e) {
isValid = false;
}
return isValid;
}
如果图像无法解析,则文件已损坏,否则文件应该是有效的,但包含错误的像素,正如Andrzej所指出的那样。如果您无法定义如何找到“错误”的像素,则可能很难检测到它们。
如果您拥有有关基本图像的信息,例如直方图或甚至原始像素,则可以尝试将其与读取的图像进行比较。但请注意,由于压缩可能会出现一些错误,因此您需要添加一些容差值。
另外需要注意的是:Sanselan无法读取JPEG图像,因此您必须在此处使用ImageIO。