Python PIL 字节转图像

28
import PIL
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import urllib.request

with urllib.request.urlopen('http://pastebin.ca/raw/2311595') as in_file:
    hex_data = in_file.read()
print(hex_data)
img = Image.frombuffer('RGB', (320,240), hex_data) #i have tried fromstring
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("arial.ttf",14)
draw.text((0, 220),"This is a test11",(255,255,0),font=font)
draw = ImageDraw.Draw(img)
img.save("a_test.jpg")

我正在尝试将二进制转换为图像,然后绘制文本。但是我遇到了以下错误:

img = Image.frombuffer('RGB', (320,240), hex_data) 
raise ValueError("not enough image data")
ValueError: not enough image data

我已经将字节字符串上传到这里http://pastebin.ca/raw/2311595
而且图片大小我可以确定是320x240。

额外信息

我可以确定这些图片的字节字符串是从320x240的图片中生成的,只需运行代码即可从字节字符串创建图像。

import urllib.request
import binascii
import struct

# Download the data.
with urllib.request.urlopen('http://pastebin.ca/raw/2311595') as in_file:
     hex_data = in_file.read()
# Unhexlify the data.
bin_data = binascii.unhexlify(hex_data)
print(bin_data)
# Remove the embedded lengths.
jpeg_data = bin_data
# Write out the JPEG.
with open('out.jpg', 'wb') as out_file:
    out_file.write(jpeg_data)

问题已解决,以下是更新后的代码

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import urllib.request
import io
import binascii

data = urllib.request.urlopen('http://pastebin.ca/raw/2311595').read()
r_data = binascii.unhexlify(data)
#r_data = "".unhexlify(chr(int(b_data[i:i+2],16)) for i in range(0, len(b_data),2))

stream = io.BytesIO(r_data)

img = Image.open(stream)
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("arial.ttf",14)
draw.text((0, 220),"This is a test11",(255,255,0),font=font)
draw = ImageDraw.Draw(img)
img.save("a_test.png")

这个字节串长度为118216字节,怎么可能是320x240?RGB(3x8位像素,真彩色)。 - Fredrik Pihl
你可以尝试使用binascii.unhexlify(hex_data)将字节转换为图片。 - user2040602
当我尝试这样做时,我只得到了9108字节,这甚至不足以支持320x240像素、每像素1位的图像。 - Mark Ransom
2个回答

19

那个图像不是由原始字节组成的 - 它是一个经过编码的JPEG文件。此外,您没有将流的ASCII HEX表示解析为正确的字节: 也就是说,在该文件中,“ff”序列被传递给PIL作为两个c字母“f”,而不是一个具有数字255的字节。

因此,首先,您需要解码字符串为正确的字节序列 - 对于这种复杂性我很抱歉 - 可能有更好的方法来实现,但我今天效率较低:

data = urllib.urlopen("http://pastebin.ca/raw/2311595").read()
r_data = "".join(chr(int(data[i:i+2],16)) for i in range(0, len(data),2)) 

啊,C.Y.在评论中发布了这条留言:

>>> import binascii
>>> b_data = binascii.unhexlify(data)

现在,您将其作为JPEG图像导入到PIL中:

>>> from PIL import Image
>>> import cStringIO as StringIO
>>> stream = StringIO.StringIO(b_data)
>>> img = Image.open(stream)
>>> img.size
(320, 240)

引发 IOError("无法识别图像文件") OSError: 无法识别图像文件 #这是我得到的错误 - user2040602
C.Y.:在将其传递给PIL之前,您是否对前两个示例中的十六进制进行了正确的解码? - jsbueno
@MarkRansom 我正在使用Python 3.3,并且我已经更新了我的代码,但它仍然无法工作。 - user2040602
1
@C.Y 回到使用 unhexlify 而不是 join,因为 Python 3 将把所有这些字节解释为 Unicode。 - Mark Ransom
3
请使用BytesIO而不是StringIOBytesIO适用于字节数据处理,而StringIO适用于字符串数据处理。 - Mark Ransom
显示剩余5条评论

19

正如其他人所说,Python 3 更好地使用 io.BytesIO

import io
from PIL import Image

imageFileObj = open(imageFilename, "rb")
imageBinaryBytes = imageFileObj.read()
imageStream = io.BytesIO(imageBinaryBytes)
imageFile = Image.open(imageStream)
print("imageFile.size=%s" % imageFile.size)

1
我正在从zip文件中读取一个png文件,这对我很有效。谢谢! - Pedro P. Camellon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接