2012-04-09 24 views
15

Estoy escribiendo un script para calcular la suma MD5 de una imagen sin incluir la etiqueta EXIF.Calcular el hash de solo los datos de imagen del núcleo (excluyendo los metadatos) para una imagen

Para hacer esto con precisión, necesito saber dónde está ubicada la etiqueta EXIF ​​en el archivo (principio, medio, final) para poder excluirla.

¿Cómo puedo determinar en qué parte del archivo se encuentra la etiqueta?

Las imágenes que estoy escaneando están en el formato TIFF, JPG, PNG, BMP, DNG, CR2, NEF y algunos videos MOV, AVI y MPG.

+1

¿Qué estás tratando de lograr? –

+0

Intentando crear eficientemente un hash de una imagen que no cambia cuando se editan los datos EXIF. (ImageMagick tiene una función de suma visual, pero esto es muy lento.) – ensnare

+0

Consulte la especificación http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf –

Respuesta

7

Una forma sencilla de hacerlo es recortar los datos de la imagen del núcleo. Para PNG, puede hacer esto contando solo los "fragmentos críticos" (es decir, los que comienzan con letras mayúsculas). JPEG tiene una estructura de archivos similar pero más simple.

El hash visual en ImageMagick descomprime la imagen a medida que la arrastra. En su caso, podría comprimir los datos de la imagen comprimida de inmediato, por lo que (si se implementan correctamente) a debería ser tan rápido como mezclar el archivo sin formato.

Este es un pequeño script de Python que ilustra la idea. Puede o no puede trabajar para usted, pero debería al menos dar una indicación de lo que quiero decir :)

import struct 
import os 
import hashlib 

def png(fh): 
    hash = hashlib.md5() 
    assert fh.read(8)[1:4] == "PNG" 
    while True: 
     try: 
      length, = struct.unpack(">i",fh.read(4)) 
     except struct.error: 
      break 
     if fh.read(4) == "IDAT": 
      hash.update(fh.read(length)) 
      fh.read(4) # CRC 
     else: 
      fh.seek(length+4,os.SEEK_CUR) 
    print "Hash: %r" % hash.digest() 

def jpeg(fh): 
    hash = hashlib.md5() 
    assert fh.read(2) == "\xff\xd8" 
    while True: 
     marker,length = struct.unpack(">2H", fh.read(4)) 
     assert marker & 0xff00 == 0xff00 
     if marker == 0xFFDA: # Start of stream 
      hash.update(fh.read()) 
      break 
     else: 
      fh.seek(length-2, os.SEEK_CUR) 
    print "Hash: %r" % hash.digest() 


if __name__ == '__main__': 
    png(file("sample.png")) 
    jpeg(file("sample.jpg")) 
+0

Gracias - ¿cómo cuento los pedazos críticos? Cualquier código de muestra es muy apreciado. – ensnare

+0

Por favor, eche un vistazo a la respuesta actualizada. – Krumelur

+0

Volviendo a la respuesta. ¿Cómo puedo extender esto para trabajar con archivos TIFF, CR2, DNG, MOV y AVI? ¿O de manera más general, alguna sugerencia sobre cómo encontrar patrones dentro del archivo para ver dónde comienzan los fragmentos críticos? – ensnare

13

Es mucho más fácil de utilizar la biblioteca de imágenes de Python para extraer los datos de la imagen (ejemplo en la iPython):

In [1]: import Image 

In [2]: import hashlib 

In [3]: im = Image.open('foo.jpg') 

In [4]: hashlib.md5(im.tostring()).hexdigest() 
Out[4]: '171e2774b2549bbe0e18ed6dcafd04d5' 

Esto funciona en cualquier tipo de imagen que PIL pueda manejar. El método tostring devuelve una cadena que contiene los datos de píxeles.

Por cierto, el hash MD5 ahora se considera bastante débil. Mejor utilizar SHA512:

In [6]: hashlib.sha512(im.tostring()).hexdigest() 
Out[6]: '6361f4a2722f221b277f81af508c9c1d0385d293a12958e2c56a57edf03da16f4e5b715582feef3db31200db67146a4b52ec3a8c445decfc2759975a98969c34' 

En mi máquina, el cálculo de la suma de control MD5 para un JPEG 2500x1600 toma alrededor de 0,07 segundos. Usando SHA512, toma 0,10 segundos.

Para películas, puede extraer marcos de ellas con p. Ej. ffmpeg, y luego procesarlos como se muestra arriba.

+3

Tenga en cuenta que MD5 es débil con respecto a las colisiones hash. Para comprobar rápidamente si un archivo ha cambiado (después de lo cual puede hacer una verificación de byte por byte), sigue siendo un algoritmo excelente y muy rápido. – parasietje

+1

En mi máquina, la creación de la suma de comprobación MD5 de un archivo JPEG de 2560x1600 como se muestra arriba toma alrededor de 0.07 segundos. Usar SHA512 toma alrededor de 0.10 segundos. No es una gran diferencia. La suma de comprobación SHA256 es la más larga, alrededor de 0,14 segundos. Desde una perspectiva humana, todos son rápidos. Respaldaré mi recomendación de usar SHA512. –

+0

Me has convencido. Gracias por hacer la investigación. – parasietje

1

me gustaría utilizar un extractor de metadatos para preprocesar el hash:

De paquete ImageMagick tiene ...

mogrify -strip blah.jpg 

y si lo hace

identify -list format 

aparentemente funciona con todas las los formatos citados.

+0

Esta solución funciona para todo el formato de video e imágenes que era un requisito para la recompensa no? – gbin

0

Puede utilizar stream que es parte de la suite ImageMagick:

$ stream -map rgb -storage-type short image.tif - | sha256sum 
d39463df1060efd4b5a755b09231dcbc3060e9b10c5ba5760c7dbcd441ddcd64 - 

o

$ sha256sum <(stream -map rgb -storage-type short image.tif -) 
d39463df1060efd4b5a755b09231dcbc3060e9b10c5ba5760c7dbcd441ddcd64 /dev/fd/63 

Este ejemplo es para un archivo TIFF que es RGB con 16 bits por muestra (es decir, 48 bits por pixel).Entonces uso map a rgb y shortstorage-type (aquí puede usar char si los valores RGB son de 8 bits).

Este método informa el mismo signature hash que los detallados informes Imagemagick identify comando:

$ identify -verbose image.tif | grep signature 
signature: d39463df1060efd4b5a755b09231dcbc3060e9b10c5ba5760c7dbcd441ddcd64 
Cuestiones relacionadas