【问题标题】:Store a sha224 Hash of a JPEG image using Exif metatadata使用 Exif 元数据存储 JPEG 图像的 sha224 哈希
【发布时间】:2021-09-04 16:12:59
【问题描述】:

我必须存储大量由机器人显微镜生成的科学图像。 在存储过程中,我想在 Exif 元数据中存储图像数据的哈希值,以便使每个图像都可识别并确定它是否在之后被修改。 图像数据以 16 位 uint 的二维数组形式出现。 我尝试使用的代码是:

import math,png,io,hashlib, numpy as np
import piexif
import piexif.helper
from PIL import Image

  def MOEDAL_IMGWR_JPG_h(img,fname,q,js='{}',exif_ifd ={}):
        y=np.asarray(img);
        z = (65535*((y - y.min())/y.ptp())).astype(np.uint16)
        a=(np.array(z)//256).astype("uint8");
        im = Image.fromarray(a)
        im.save(fname, format='JPEG', quality=q) # save the image
        im=Image.open(fname)  # reload it
        img_byte_arr = io.BytesIO()
        im.save(img_byte_arr,format='PNG') # write the image content in memory
        jdc=json.loads(js)
        jdc['sha244']=hashlib.sha224(img_byte_arr.getvalue()).hexdigest()
        a=json.dumps(jdc)
        exif_dict = {"Exif":exif_ifd}
        exif_dict["Exif"][piexif.ExifIFD.UserComment] = piexif.helper.UserComment.dump(a)
        exif_bytes = piexif.dump(exif_dict)
        piexif.insert(exif_bytes,fname)  # This method is supposed to work (but does not)
#            im.save(fname, exif=exif_bytes) #

如您所见,我尝试在使用所需压缩保存图像后重新加载图像数据,计算哈希并将其(作为 JSON 键)存储在 exif 元数据的 UserComment 字段中。 在第二次保存中,我尝试使用压缩
但是当我尝试从 Python CLI 重新加载图像并再次计算哈希时,我得到了不同的值。

>>> im=Image.open('Test.jpg')
>>> img_byte_arr = io.BytesIO()
>>> im.save(img_byte_arr,format='PNG')
>>> exif_dict=piexif.load('TEST.jpg')
>>> print(exif_dict)
{'0th': {34665: 26}, 'Exif': {37510: b'ASCII\x00\x00\x00{"sha244": "94ae6bcfbb94c75c8adf65536993a03a107aa076cb94e20ef6bdff12"}'}, 'GPS': {}, 'Interop': {}, '1st': {}, 'thumbnail': None}
>>> hashlib.sha224(img_byte_arr.getvalue()).hexdigest()
'ef5966d665aaefc0d5b48c293957f66007c8dcaab7afc39f85a3964e'

也许我上次的 im.save 有误,但我也尝试指定 format='JPEG' 和 quality=100 以便我不会再次重复压缩。 有什么建议 ? 谢谢,G.L.

【问题讨论】:

  • 我也尝试过这里描述的方法:stackoverflow.com/questions/53543549/… 但似乎不起作用
  • 这行不通。 JPEG 读取器和写入器可以进行权衡以节省空间(磁盘上的图像大小以字节为单位)或加快处理速度。每个库和每个库的每个新版本都可能会做出不同的权衡,这将导致您的哈希不正确。你可以使用无损PNG吗?
  • 我猜你可以在创建后散列整个 JPEG 并将散列保存为 xattr 或在文件名或数据库中或以某种方式在外部 - Mac 资源叉或 Windows NTFS 备用数据流。

标签: python metadata jpeg exif sha


【解决方案1】:

最后我在我的函数中发现了错误并发布了正确的版本,因为我认为它对其他人也有用。 错误是两个一个是原始保存

#            im.save(fname, exif=exif_bytes) #

正确替换为

piexif.insert(exif_bytes,fname)

但第二个也是更微妙的是关于如何提取图像字节以计算散列。正确的方法(或至少一种有效的方法)是将图像(读取为灰度)内容转换为 Numpy 数组,然后将数组转换为字节。 最后的程序行是:

jdc['sha244']=hashlib.sha224(np.float32(im).tobytes()).hexdigest()

所以完整的功能是:

def MOEDAL_IMGWR_JPG_h(img,fname,q,js='{}',exif_ifd ={}):
        y=np.asarray(img);
        z = (65535*((y - y.min())/y.ptp())).astype(np.uint16)
        a=(np.array(z)//256).astype("uint8");
        im = Image.fromarray(a)
        im.save(fname, format='JPEG', quality=q) # save the image
        im=Image.open(fname)  # load the saved image
        jdc=json.loads(js)    # prepare the JSON record from a
        jdc['sha244']=hashlib.sha224(np.float32(im).tobytes()).hexdigest() # compute the hash from the np array converted to bytes
        a=json.dumps(jdc)
        exif_dict = {"Exif":exif_ifd}
        exif_dict["Exif"][piexif.ExifIFD.UserComment] = piexif.helper.UserComment.dump(a)
        exif_bytes = piexif.dump(exif_dict)
        piexif.insert(exif_bytes,fname) # insert the Exif data

【讨论】:

    【解决方案2】:

    这是行不通的,不是这样。您计算图像的散列,然后将其保存为 JPEG 流,JPEG 是有损。所以你的形象会立即改变。

    您需要做的是将图像保存为JPEG格式,重新加载它并计算重新加载的图像的哈希值,然后更新EXIF元数据不进一步修改图像(通常 EXIF 工具不会修改图像流,但我不熟悉 Python 库;您应该检查一下)。

    【讨论】:

    • 当您阅读代码时,这正是我想要做的。我存储图像然后重新加载它并尝试存储 exif 元数据。您知道如何存储元数据而无需再次存储图像吗?
    • 似乎部分答案在这里:stackoverflow.com/questions/53543549/…
    • 抱歉,我被这两个存档弄糊涂了。导致问题的很可能是带有修改后的 Exif 的最终 im.save()。但是从我在网上找到的内容来看,这个库应该可以工作。 pypi.org/project/exif
    • 其实我也试过 piexif.insert(exif_bytes,fname) 插入exif数据....但是图像数据似乎仍然被修改了。
    猜你喜欢
    • 2021-09-08
    • 1970-01-01
    • 2012-10-15
    • 1970-01-01
    • 2017-07-12
    • 1970-01-01
    • 2016-08-20
    • 2013-07-11
    • 2017-09-11
    相关资源
    最近更新 更多