2011-11-07 56 views
9

Necesito detectar si el archivo de imagen está dañado en Java. Estoy trabajando solo con PNG, imágenes JPG. ¿Es esto posible con Sanselan? ¿O se puede hacer con ImageIO? Intenté usar ImageIO.read parece que funciona. Pero no estoy seguro de si puede detectar todo tipo de errores en las imágenes. Me gustaría saber cuál es la mejor práctica.Cómo detectar imágenes dañadas (PNG, JPG) en Java

+2

Sugeriría que la única manera de detectar * cada * tipo de error en una imagen (donde "error" se define como cualquier discrepancia que causa un comportamiento imperfecto) es seguir adelante y usar la imagen. Es muy posible que una imagen sufra una corrupción que, no obstante, da como resultado un archivo válido, aunque uno con "los píxeles incorrectos". Puede ser útil pensar muy específicamente sobre qué es lo que quiere detectar. –

+2

ImageIO puede detectar PNG truncado con una excepción lanzada, pero para JPG que está truncado, no puedo hacer que arroje una excepción. –

+0

¿Obtuviste alguna solución para esto? –

Respuesta

1

Si la imagen no se puede analizar, el archivo está dañado, de lo contrario, el archivo debería ser válido pero contiene los píxeles incorrectos como señaló Andrzej. Detectar eso podría ser bastante difícil si no puede definir cómo encontraría píxeles "incorrectos".

Si tiene información sobre la imagen base, p. un histograma o incluso los píxeles originales, puede intentar y compararlos con la imagen leída. Tenga en cuenta, sin embargo, que debido a la compresión puede haber algunos errores, por lo que deberá agregar algún valor de tolerancia.

Una nota adicional: Sanselan no leerá imágenes JPEG, por lo que tendrá que utilizar ImageIO aquí.

9

Aquí está mi solución que manejaría la comprobación de GIF roto, JPG y PNG. Comprueba si truncada JPEG usando el marcador JPEG EOF, GIF utilizando un índice de verificación de los límites excepción y PNG utilizando un 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; 
    } 
} 
} 
+2

¿No deberían las dos cláusulas de la comprobación de estado JPEG conectarse con OR lógico en lugar de Y? – mnicky

+0

Puede vincular esta clase ImageAnalysisResult –

+0

¿Podría incluir todas las instrucciones de importación en su respuesta? –

4

Si la imagen en formato JPEG, utilice esto:

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

si arroja una excepción; esto significa que la imagen está corrupta.

para los demás casos; solo use new ImageIcon(file) para verificar la validez.

+0

No funciona para mí (http://i.imgur.com/rE89Bpl.jpg). – mnicky