使用Base64编码图像文件

247
我想使用base64模块将图像编码为字符串。但我遇到了一个问题。我该如何指定要编码的图像?我尝试使用图像所在的目录,但这只会导致目录被编码。我希望实际的图像文件被编码。

编辑

我尝试了这段代码:

with open("C:\Python26\seriph1.BMP", "rb") as f:
    data12 = f.read()
    UU = data12.encode("base64")
    UUU = base64.b64decode(UU)

    print UUU

    self.image = ImageTk.PhotoImage(Image.open(UUU))

但是我得到了以下错误:

Traceback (most recent call last):
  File "<string>", line 245, in run_nodebug
  File "C:\Python26\GUI1.2.9.py", line 473, in <module>
    app = simpleapp_tk(None)
  File "C:\Python26\GUI1.2.9.py", line 14, in __init__
    self.initialize()
  File "C:\Python26\GUI1.2.9.py", line 431, in initialize
    self.image = ImageTk.PhotoImage(Image.open(UUU))
  File "C:\Python26\lib\site-packages\PIL\Image.py", line 1952, in open
    fp = __builtin__.open(fp, "rb")
TypeError: file() argument 1 must be encoded string without NULL bytes, not str

我做错了什么?

6个回答

442

我不确定我理解你的问题。我假设你正在做类似于以下内容的事情:

import base64

with open("yourfile.ext", "rb") as image_file:
    encoded_string = base64.b64encode(image_file.read())

当然,你需要先打开文件并读取其内容,不能仅仅将路径传递给编码函数。

编辑: 好的,在您编辑原始问题后,这里有一个更新。

首先,请记得在Windows上使用路径分隔符时使用原始字符串(将字符串用'r'作为前缀),以防止意外触发转义字符。其次,PIL的Image.open函数接受文件名或类似文件的对象(即,该对象必须提供读取、查找和告知方法)。

话虽如此,您可以使用cStringIO从内存缓冲区创建这样的对象:

import cStringIO
import PIL.Image

# assume data contains your decoded image
file_like = cStringIO.StringIO(data)

img = PIL.Image.open(file_like)
img.show()

1
谢谢,还有一个问题,当我打印解码后的图像时,我得到字符串'ÿØÿà'。然而,当我将其作为数据替代单独运行时,会出现错误。相比之下,编码的字符串要长得多。因此,我认为它很可能存储了图像数据。解码后的字符串是否仅引用编码的字符串或其他内容?它看起来对于数据存储来说太短了。 - rectangletangle
打印输出并不一定等同于实际内容 - 这取决于您在何处以及如何进行打印。 - Jim Brissom
18
为了在HTML文件中使用,我需要解码base64.b64encode(fh.read()).decode()得到一个字符串。 - qed
1
base64.b64encode(fh.read()).decode() 微妙但我也需要这个,@qed 谢谢。它们的区别在于一个返回字节,另一个返回字符串...我的 SOAP 服务器如果不解码就无法接受! - zzart

65
import base64
from PIL import Image
from io import BytesIO

with open("image.jpg", "rb") as image_file:
    data = base64.b64encode(image_file.read())

im = Image.open(BytesIO(base64.b64decode(data)))
im.save('image1.png', 'PNG')


8
这个答案真的应该排在最顶部... 是最好的一个 -- 谢谢! - Luther

59

只使用base64.b64encode(img_file.read())会返回字节。 这意味着你的结果看起来像b'your_string'。为了解决这个问题,你需要这样解码:

encoded_string = base64.b64encode(img_file.read())
print(encoded_string.decode('utf-8'))

在将图像转换为Base64字符串时,我遇到了这个问题。您可以查看我如何从中删除它。链接在这里 Image to base64 string and fix 'b from prefix


3
这看起来是一个不错的答案,但如果目的是为了推广你的网站,请不要发布。但是,欢迎您在个人资料中添加链接。 - halfer
1
(顺便说一句,在这里不能依赖答案的顺序,所以最好避免像“第一个答案”这样的评论。出现在最前面的可能会随时间而改变。:-)) - halfer
在你最初的回答版本中,看起来像是你链接到了自己的网站或者一个你有关联的网站。如果你确实链接到这样的网站,你必须要披露这是你自己的网站。如果你不披露关联,那么就被认为是垃圾信息。请参考:什么是“好”的自我推广?自我推广的帮助中心。披露必须是明确的,但不需要正式。当它是你自己的个人内容时,可以简单地说“在我的网站上……”、“在我的博客上……”等等。 - Makyen
谢谢您的建议@Makyen。我要披露这是我的网站。现在编辑回答以披露这是我的网站是否合法?还是说我不应该编辑它? - CodeSpeedy

11

如我在你之前的问题中所说,没有必要对字符串进行base64编码,这只会使程序变慢。只需要使用repr函数即可。

>>> with open("images/image.gif", "rb") as fin:
...  image_data=fin.read()
...
>>> with open("image.py","wb") as fout:
...  fout.write("image_data="+repr(image_data))
...

现在图像被存储为一个变量,名为image_data,在一个名为image.py的文件中。 启动一个新的解释器并导入image_data

>>> from image import image_data
>>>

1
我真的不明白在这里如何使用repr()。 - Ivo van der Wijk
6
@Ivo,Anteater想要能够在Python文件中存储图像。我指出使用base64是低效的,因为每次加载模块时都需要解码数据。使用repr代替意味着字面字符串已经准备好存储在.pyc文件中,无需进一步处理即可立即使用。 - John La Rooy
@JohnLaRooy 非常感谢。我在 fout.write("image_data="+repr(image_data)) 这一行遇到了 TypeError: a bytes-like object is required, not 'str' 的错误。我该如何解决? - YasserKhalil

11

借鉴了之前由Ivo van der Wijkgnibbler开发的内容,这是一种动态解决方案。

import cStringIO
import PIL.Image

image_data = None

def imagetopy(image, output_file):
    with open(image, 'rb') as fin:
        image_data = fin.read()

    with open(output_file, 'w') as fout:
        fout.write('image_data = '+ repr(image_data))

def pytoimage(pyfile):
    pymodule = __import__(pyfile)
    img = PIL.Image.open(cStringIO.StringIO(pymodule.image_data))
    img.show()

if __name__ == '__main__':
    imagetopy('spot.png', 'wishes.py')
    pytoimage('wishes')

您可以选择使用Cython编译输出图像文件,使其更加酷炫。使用这种方法,您可以将所有图形捆绑到一个模块中。


7

这对我有用

import base64
import requests

# Getting image in bytes
response = requests.get("image_url") 

# image encoding
encoded_image = base64.b64encode(response.content)

# image decoding and without it's won't work due to some '\xff' error
decoded_image= base64.b64decode(encoded_image)


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