Byambatsogt
Byambatsogt

Reputation: 324

How to detect corrupted images (PNG, JPG) in Java

I need to detect if the image file is corrupted in Java. I'm working only with PNG, JPG images. Is this possible to do with Sanselan? Or can it be done with ImageIO? I've tried using ImageIO.read seems like it works. But I'm not sure if it can detect every kind of errors in images. I'd like to know what's the best practice.

Upvotes: 15

Views: 21526

Answers (4)

Harsha Reddy
Harsha Reddy

Reputation: 21

below code validates .jpeg, .png, .jpg, .tiff images in java

public boolean isValidImage(File f) {
  boolean isValid = true;
  try {
    ImageIO.read(f).flush();
  } catch (Exception e) {
    isValid = false;
  }
  return isValid;
}

Upvotes: 2

Archimedes Trajano
Archimedes Trajano

Reputation: 41682

Here is my solution that would handle checking for broken GIF, JPG and PNG. It checks for truncated JPEG using the JPEG EOF marker, GIF using an index out of bounds exception check and PNG using an EOFException

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

Upvotes: 16

Bassel Kh
Bassel Kh

Reputation: 1977

If the image in JPEG, use this:

JPEGImageDecoder decoder = new JPEGImageDecoder(new FileImageSource(f) ,new FileInputStream(f));
decoder.produceImage();

if it throws an exception; this means the image is corrupted.

for the other cases; just use new ImageIcon(file) to check the validity.

Upvotes: 6

Thomas
Thomas

Reputation: 88757

If the image can't be parsed the file is corrupt, otherwise the file should be valid but contains the wrong pixels as Andrzej pointed out. Detecting that might be quite hard if you can't define how you would find "wrong" pixels.

If you have information on the base image, e.g. a histogram or even the original pixels, you might try and compare those with the read image. Note, however, that due to compression there might be some errors, so you'd need to add some tolerance value.

An additional side note: Sanselan won't read JPEG images so you'd have to use ImageIO here.

Upvotes: 1

Related Questions