Reputation: 324
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
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
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
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
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