如何在Java中检测损坏的图像(PNG,JPG)

Bya*_*ogt 12 java image javax.imageio

我需要检测图像文件是否在Java中被破坏.我只使用PNG,JPG图像.这可能与Sanselan有关吗?或者可以用ImageIO完成吗?我尝试过使用ImageIO.read似乎很有效.但我不确定它是否可以检测到图像中的各种错误.我想知道什么是最好的做法.

Arc*_*ano 12

这是我的解决方案,可以处理损坏的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;
    }
 }
}
Run Code Online (Sandbox Code Playgroud)

  • JPEG条件检查的两个子句不应该与逻辑OR而不是AND连接吗? (2认同)

Bas*_* Kh 6

如果是JPEG图像,请使用:

JPEGImageDecoder decoder = new JPEGImageDecoder(new FileImageSource(f) ,new FileInputStream(f));
decoder.produceImage();
Run Code Online (Sandbox Code Playgroud)

如果它抛出异常; 这意味着图像已损坏.

对于其他情况; 只是new ImageIcon(file)用来检查有效性.


Tho*_*mas 1

如果无法解析图像,则文件已损坏,否则文件应该有效,但包含错误的像素,正如 Andrzej 指出的那样。如果您无法定义如何找到“错误”像素,那么检测到这一点可能会非常困难。

如果您有基本图像的信息,例如直方图甚至原始像素,您可以尝试将它们与读取的图像进行比较。但请注意,由于压缩,可能会出现一些错误,因此您需要添加一些容差值。

附加说明:Sanselan 不会读取 JPEG 图像,因此您必须在此处使用 ImageIO。