【问题标题】:Get Binary Representation of PIL Image Without Saving在不保存的情况下获取 PIL 图像的二进制表示
【发布时间】:2015-02-23 11:17:05
【问题描述】:

我正在编写一个大量使用图像的应用程序。它由两部分组成。客户端部分是用 Python 编写的。它对图像进行一些预处理,并通过 TCP 将它们发送到 Node.js 服务器。 预处理后的 Image 对象如下所示:

window = img.crop((x,y,width+x,height+y))
window = window.resize((48,48),Image.ANTIALIAS)

要通过套接字发送它,我必须以二进制格式发送它。我现在做的是:

window.save("window.jpg")
infile = open("window.jpg","rb")
encodedWindow = base64.b64encode(infile.read())
#Then send encodedWindow 

不过,这是一个巨大的开销,因为我先将图像保存到硬盘,然后再次加载它以获得二进制格式。这导致我的应用程序非常缓慢。 我阅读了 PIL Image 的文档,但没有发现任何有用的东西。

【问题讨论】:

标签: python node.js sockets python-imaging-library


【解决方案1】:

根据文档,(在 effbot.org):

"您可以使用文件对象而不是文件名。在这种情况下,您必须始终指定格式。文件对象必须实现 seek、tell 和 write 方法,并以二进制模式打开。"

这意味着您可以传递一个 StringIO 对象。写入它并获取大小而无需访问磁盘。

像这样:

s = StringIO.StringIO()
window.save(s, "jpg")
encodedWindow = base64.b64encode(s.getvalue())

【讨论】:

  • 这给出了以下异常:文件“/usr/local/lib/python2.7/dist-packages/PIL/Image.py”,第 1670 行,在保存中引发 KeyError(ext) # unknown扩展
  • @Wahbivic 使用window.save(s, "jpg")。使用 PIL/Pillow,如果无法通过文件名检测格式(或者如果没有文件名,如这里),则需要指定所需的格式。
  • @MattDMo 谢谢一百万。由于某些奇怪的原因, window.save(s, "jpg") 也引发了异常。不过,window.save(s,"jpeg") 工作得很好。
  • @Wahbivic 没有问题。您使用的是什么版本的 PIL/Pillow?我让 Pillow 保持最新状态,"jpg" 对我来说从来都不是问题。你还在用古老的 1.1.7 版本的 PIL 吗?
  • @swstephe 也感谢一百万。我编辑了你对实际工作的答案。
【解决方案2】:

这是关于内存中类文件对象和 BufferedReader 对象之间的区别。

这里是 Jupyter(Python 3.8.10)中的my experiment

from PIL import Image as PILImage, ImageOps as PILImageOps
from IPython.display import display, Image
from io import BytesIO
import base64

url = "https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/april/images/mt846470.0418_mccaffreytrun_figure2_hires(en-us,msdn.10).png"
print("get computer-readable bytes from the url")
img_bytes = requests.get(url).content
print(type(img_bytes))
display(Image(img_bytes))
print("convert to in-memory file-like object")
in_memory_file_like_object = BytesIO(img_bytes)
print(type(in_memory_file_like_object))

print("convert to an PIL Image object for manipulating") 
pil_img = PILImage.open(in_memory_file_like_object)
print("let's rotate it, and it remains a PIL Image object") 
pil_img.show()
rotated_img = pil_img.rotate(45)
print(type(rotated_img))
print("let's create an in-memory file-like object and save the PIL Image object into it")  
in_memory_file_like_object = BytesIO()
rotated_img.save(in_memory_file_like_object, 'png')
print(type(in_memory_file_like_object))

print("get computer-readable bytes") 
img_bytes = in_memory_file_like_object.getvalue()
print(type(img_bytes))
display(Image(img_bytes))
print('convert to base64 to be transmitted over channels that do not preserve all 8-bits of data, such as email')
# https://stackoverflow.com/a/8909233/3552975
base_64 = base64.b64encode(img_bytes)
print(type(base_64))
# https://stackoverflow.com/a/45928164/3552975
assert base64.b64encode(base64.b64decode(base_64)) == base_64

总之你可以通过rotated_img.save(in_memory_file_like_object, 'png')将PIL Image对象保存到内存中的类文件对象中,然后将内存中的类文件对象转换为base64。

【讨论】:

    【解决方案3】:
    from io import BytesIO
    
    b = BytesIO()
    img.save(b, format="png")
    b.seek(0)
    data = b.read()
    del b
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-17
      • 2015-09-17
      • 2020-05-09
      • 2014-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多