我想弄清楚如何在python脚本中嵌入二进制内容。例如,我不想要任何外部文件(图像,声音......),我希望所有这些内容都存在于我的python脚本中。
澄清一点的例子,让我们说我得到了这个小片段:
from StringIO import StringIO
from PIL import Image, ImageFilter
embedded_resource = StringIO(open("Lenna.png", "rb").read())
im = Image.open(embedded_resource)
im.show()
im_sharp = im.filter(ImageFilter.SHARPEN)
im_sharp.show()
如您所见,示例是阅读外部文件' Lenna.png'
问题
如何进行嵌入" Lenna.png"作为我的python脚本的资源(变量)。使用python实现这个简单任务的最快方法是什么?
答案 0 :(得分:4)
解决此问题的最佳方法是将您的图片转换为python字符串,并将其放在一个名为resources.py
的单独文件中,然后您只需解析它。
如果您希望将整个内容嵌入到单个二进制文件中,那么您需要查看py2exe之类的内容。 Here是嵌入外部文件的示例
在第一个场景中,您甚至可以使用base64
来(de)对图片进行编码,如下所示:
import base64
file = open('yourImage.png');
encoded = base64.b64encode(file.read())
data = base64.b64decode(encoded) # Don't forget to file.close() !
答案 1 :(得分:1)
您可能会发现以下类对于在程序中嵌入资源非常有用。要使用它,请使用指向要嵌入的文件的路径调用package
方法。该类将打印出DATA
属性,该属性应该用于替换已在类中找到的属性。如果要将文件添加到预建数据,请改用add
方法。要在程序中使用该类,请使用上下文管理器语法调用load
方法。返回的值是Path
对象,可以用作其他函数的文件名参数,也可以用于直接加载重构文件。有关示例用法,请参阅此SMTP Client。
import base64
import contextlib
import pathlib
import pickle
import pickletools
import sys
import zlib
class Resource:
"""Manager for resources that would normally be held externally."""
WIDTH = 76
__CACHE = None
DATA = b''
@classmethod
def package(cls, *paths):
"""Creates a resource string to be copied into the class."""
cls.__generate_data(paths, {})
@classmethod
def add(cls, *paths):
"""Include paths in the pre-generated DATA block up above."""
cls.__preload()
cls.__generate_data(paths, cls.__CACHE.copy())
@classmethod
def __generate_data(cls, paths, buffer):
"""Load paths into buffer and output DATA code for the class."""
for path in map(pathlib.Path, paths):
if not path.is_file():
raise ValueError('{!r} is not a file'.format(path))
key = path.name
if key in buffer:
raise KeyError('{!r} has already been included'.format(key))
with path.open('rb') as file:
buffer[key] = file.read()
pickled = pickle.dumps(buffer, pickle.HIGHEST_PROTOCOL)
optimized = pickletools.optimize(pickled)
compressed = zlib.compress(optimized, zlib.Z_BEST_COMPRESSION)
encoded = base64.b85encode(compressed)
cls.__print(" DATA = b'''")
for offset in range(0, len(encoded), cls.WIDTH):
cls.__print("\\\n" + encoded[
slice(offset, offset + cls.WIDTH)].decode('ascii'))
cls.__print("'''")
@staticmethod
def __print(line):
"""Provides alternative printing interface for simplicity."""
sys.stdout.write(line)
sys.stdout.flush()
@classmethod
@contextlib.contextmanager
def load(cls, name, delete=True):
"""Dynamically loads resources and makes them usable while needed."""
cls.__preload()
if name not in cls.__CACHE:
raise KeyError('{!r} cannot be found'.format(name))
path = pathlib.Path(name)
with path.open('wb') as file:
file.write(cls.__CACHE[name])
yield path
if delete:
path.unlink()
@classmethod
def __preload(cls):
"""Warm up the cache if it does not exist in a ready state yet."""
if cls.__CACHE is None:
decoded = base64.b85decode(cls.DATA)
decompressed = zlib.decompress(decoded)
cls.__CACHE = pickle.loads(decompressed)
def __init__(self):
"""Creates an error explaining class was used improperly."""
raise NotImplementedError('class was not designed for instantiation')