StringIO对象与保存文件的MD5sum差异?
我有一段Python代码,内容如下:
def make_portrait(self, image_name):
im = Image.open(str(image_name))
output = StringIO.StringIO()
im.save(output, 'JPEG', quality=70)
self.portrait_md5 = hashlib.md5(output.getvalue()).hexdigest()
output.close()
self.portrait_asset = self.portrait_md5 + '.jpg'
self.portrait_xml = '<net.rptools.maptool.model.Asset>\n <id>\n <id>' + self.portrait_md5 + \
'</id>\n </id>\n <name>' + self.name + \
'</name>\n <extension>jpg</extension>\n <image/>\n</net.rptools.maptool.model.Asset>\n'
self.portrait = im
这段代码的功能是读取一个指定的图片文件,把图片转换成JPG格式,质量设置为70%,然后计算转换后数据的MD5校验和。在程序的其他地方,转换后的图片数据会被写入到磁盘上的一个实际文件中,同时还会有一个包含关于这张图片的元数据的文件(比如MD5值)。
代码运行得很好,但校验和不匹配最终输出的结果。假设我给它输入一张图片,它完成转换后,得到了“ce5d1126ba52ba1618c402a13bee1c0c”作为校验和。如果我之后去检查保存到磁盘上的最终文件,md5sum却显示它的校验和是“bb5ae2fdfea6294267b7ffdc226e21fa”。
这造成了问题,因为应该使用这个代码生成的文件的程序会检查实际文件的MD5值,并将其与元数据中报告的MD5值进行比较。如果这两个值不匹配,程序就会出错。
我对Python非常陌生。请问我该如何生成一个与保存到磁盘的图片文件的MD5值匹配的校验和呢?
如果需要,我很乐意提供更多细节。
1 个回答
2
我猜这可能跟PIL写文件有关,因为从StringIO()
和文件得到的md5值是一样的,像这里显示的那样:
>>> import StringIO
>>> import string
>>> import random
>>> import hashlib
>>> import subprocess
>>>
>>> sample = StringIO.StringIO()
>>> data = "".join([random.choice(string.lowercase) for _ in range(10000)])
>>> sample.write(data)
>>> sample.seek(0)
>>> md5 = hashlib.md5()
>>> md5.update(sample.read())
>>> md5.hexdigest()
'1b0d867b8e5aa66de816285076b7d457'
>>> sample.seek(0)
>>> with open("as_file.txt", "w") as f:
... f.write(sample.read())
...
>>> subprocess.call("md5 as_file.txt".split())
MD5 (as_file.txt) = 1b0d867b8e5aa66de816285076b7d457
也许在生成哈希值之前,先把输出的位置移动到开头试试。
im.save(output, "JPEG", quality=70)
output.seek(0)
self.portrait_md5 = hashlib.md5(output.getvalue()).hexdigest()
编辑
这跟我预期的一样,基本上和你的代码是相同的。你是把文件写到哪里去的呢?
from PIL import Image
import StringIO
import hashlib
import subprocess
im = Image.open("foo.png")
data = StringIO.StringIO()
im.save(data, "JPEG", quality=70)
md5 = hashlib.md5(data.getvalue()).hexdigest()
with open("foo.jpg", "w") as f:
im.save(f, "JPEG", quality=70)
print md5
print subprocess.call("md5 foo.jpg".split())
输出
e5954ce7fb4d22dfac63372bfc948903
MD5 (foo.jpg) = e5954ce7fb4d22dfac63372bfc948903