2016-09-05 5 views
1

Ich möchte herausfinden, wie binäre Inhalte in ein Python-Skript eingebettet werden. Zum Beispiel möchte ich keine externen Dateien (Bilder, Sound, ...) haben, ich möchte, dass all diese Inhalte in meinen Python-Skripten leben.Einbetten von Ressourcen in Python-Skripts

kleines Beispiel zu klären, lassen Sie uns sagen, dass ich dieses kleine Schnipsel bekam:

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() 

Wie Sie sehen können, ist das Beispiel die externe Datei 'Lenna.png' Lesen

enter image description here

Frage

So gehen Sie vor, um "Lenna.png" als Ressource (Variable) einzubetten in mein Python-Skript. Was ist der schnellste Weg, um diese einfache Aufgabe mit Python zu erreichen?

+0

Das einzige, was ich mir vorstellen kann, ist das Bild in "rohe" Daten zu konvertieren und das in einer Variablen zu speichern. Nicht sicher, ob das sehr pythonisch ist, obwohl – UnholySheep

Antwort

1

Vielleicht finden Sie die folgende Klasse eher nützlich für die Einbettung Ressourcen in Ihrem Programm. Um sie zu verwenden, rufen Sie die Methode package mit Pfaden zu den Dateien auf, die Sie einbetten möchten. Die Klasse gibt ein DATA Attribut aus, das verwendet werden sollte, um das in der Klasse bereits vorhandene zu ersetzen. Wenn Sie Dateien zu Ihren vorgefertigten Daten hinzufügen möchten, verwenden Sie stattdessen die Methode add. Um die Klasse in Ihrem Programm zu verwenden, rufen Sie die Methode load unter Verwendung der Kontextmanagersyntax auf. Der zurückgegebene Wert ist ein Path-Objekt, das als Dateinamensargument für andere Funktionen oder zum direkten Laden der wiederhergestellten Datei verwendet werden kann. Sehen Sie diese SMTP Client zum Beispiel Verwendung.

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') 
+0

Danke! Ich habe die angenommene Antwort geändert. Ich mag das nicht wirklich, sobald ich die andere Antwort akzeptiert habe, aber deine wird wirklich nützlich sein für meine Zwecke. – BPL

+0

Danke für das Vertrauensvotum! Hoffentlich wird das Referenzprogramm ein ausreichendes Beispiel für die Verwendung der Klasse liefern. Wenn Sie möchten, dass die Ressourcendateien nach dem Laden verweilen, können Sie 'delete = True' in' load' in 'delete = False' ändern, oder Sie können die Methode aufrufen und' False' als ihre zweite übergeben Streit. Eine erfinderische Verwendung der Klasse besteht darin, andere Module, die Sie in Ihrem Programm geschrieben haben, zu integrieren, die als Abhängigkeiten benötigt werden. Der SMTP-Client tut dies, so dass er einen Thread-sicheren Wrapper um die Klassen in "tkinter" laden kann. Insgesamt hat es ziemlich gut funktioniert. –

3

Der beste Weg, um dies zu tun ist die Umwandlung Ihres Bildes in eine Python-Zeichenfolge, und haben es in einer separaten Datei namens so etwas wie resources.py, dann Sie einfach analysieren.

Wenn Sie das ganze Ding in eine einzelne Binärdatei einbetten möchten, dann betrachten Sie etwas wie py2exe. Here ist ein Beispiel externe Dateien einbetten

Im ersten Szenario wird sogar base64 zu (de) Code das Bild, so etwas wie diese verwenden:

import base64 
file = open('yourImage.png'); 
encoded = base64.b64encode(file.read()) 
data = base64.b64decode(encoded) # Don't forget to file.close() ! 
+1

Av4t4r Ich würde die [base64] (http://kb.worldviz.com/articles/878) Lösung jetzt posten :). Ja, genau das habe ich gesucht, danke. – BPL