Base64 als Konstante einlesen

Programmierung für GNOME und GTK+, GUI-Erstellung mit Glade.
Antworten
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi pygtk Freunde

Beim näher kennenlernen von GTK+ habe ich folgende Frage. Ist es auch mit pygtk möglich ein Base64-Bild aus einer Konstante 'PYTHON_AT_WORK_48' auf eine Schaltfläche zu projizieren. Als Versuchsskript verwende ich:

Code: Alles auswählen

#!/usr/bin/env python


import pygtk
pygtk.require('2.0')
import gtk

PYTHON_AT_WORK_48 =\
'''
R0lGODlhMAAwAPcAADladTldfE9PT19fX0NjfFVsfmRkZG5ubXRwbWNtdnNz
c3t4dXR3eXx8fP+7G/+9I//DJP/EK//KLf/FMv/LNP/FPv/OOv/SNf/TPYWB
fv/FQf/MRf/NS//VQ//ZRf/STP/cS//IUf/WVf/aVP/TWP/eWv/iTP/jVP/q
Vv/lWv/qW//VZ//eYf/Va//eaf/Wdv/dc//Wff/iY//tYP/pbP/jdf/tc//l
ff/pe//xdv/xeCpbgjdfgDZhhTplhjNljTlnjD1pizRnkDRqlTxtlDRtmzpv
mj9wlzdwnT5ynDFvoS1zqzJxpTx1pDJ0qTt3qDt5qy53sjl8szB8ukJmg0No
hkJqi09uiE9xjVp2jUBuk0hzlUF0n1l3kVx4klF6nVl9nGV8j2h9jnl9gUN2
oUV5o0l7okR+rER/sDiBvGeGn3yKlXKJnlWBpV6EolSEq1mGqleIr0iIvFaJ
s3OPpnSTrm6Zu3OXs3KZuXicuD2IxTiIyEeLwU6MwFuh2Gygyn6kxX2nymqj
0oODg42Kh4WGiIyMjJOTk5mWlJubm6GdmpGeqZ+goKSkpKurq7Owraqxt6Kx
v7Ozs7y8vP/dhP/ci//ekf/fmP/zif/hl//inP/snsLAv//nqv/rq//yo//2
rP/4r//us/bquv/xsf/9tf/wuf//uYemwJewxJ61x5uyzY6z0JK10Ju10Z+8
1py+2aW1xKa4xqKzyaG5y6i5y6O806C/2J/B3qnB1aLC3arE2a7I3bfH07fI
17/P17bK2bzO267O6b/S4MTExMDJyszMzNDLx9TU1NnV0dzc3ODb2P/swvby
xv/xzP/4zP/z1MXV6Mrb6tHd7szh8eTk5ODm6uXp7Ozs7PDv7v/35f/45vHw
7//87OTm8ent8+Xs+uju+uvw9Ozz+/Pz8//98/P2+fT9//39/QAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAACH5BAEAAOkALAAAAAAwADAAAAj+ANMJHEiwoMGD
CBMqXMiwIUJk5tBJNBcxYrmJEsmRw1YNmUdjDhVWM6cMmbJyG7lpxIaNGzpz
LKspM0ZTWbKQCKuRG8jtmzKW16ot08lRpsdJk65dQ4bTYLVyA8mhpDiRJceS
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
Ow==
'''

class Base64Image:

    def __init__(self, app_win, callback):

        button_frame = gtk.VBox()
        button_frame.show()
        app_win.add(button_frame)
        
        image = gtk.Image()
        image.set_from_file("python_at_work_48.gif") # Als Base64-Konstante ??
        image.show()

        button = gtk.Button()
        button.add(image)
        button.show()
        button_frame.pack_start(button)
        button.connect("clicked", callback, "Button activated")

def main():
    gtk.main()
    return 0

def exit_app(widget, event, data=None):
    gtk.main_quit()
    return False
    
if __name__ == "__main__":
    
    app_win = gtk.Window(gtk.WINDOW_TOPLEVEL)
    app_win.connect("delete_event", exit_app)
    app_win.set_border_width(10)
    app_win.show()

    Base64Image(app_win, exit_app)
    
    main()
Danke für eure Hilfe.

Gruß wuf :wink:
Take it easy Mates!
lunar

@wuf: Nun, im Zweifelsfall kannst Du das Bild mithilfe des "tmpfile"-Moduls über eine temporäre Datei laden.

Gibt es einen besonderen Grund, warum Du das Bild unbedingt aus einem base64-kodierten String laden möchtest? Ich würde Dir eher dazu raten, das Bild als separate Datei im Paket abzulegen, und dann über "pkgutil" oder das Drittmodul "pkg_resources" zu laden. Das ist die übliche Vorgehensweise für Resourcen in Python.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi lunar

Danke für deine Antwort. Der Grund ist weil ich bis anhin bei meinen Tkinter-Anwendungen die Bilder in einem Skript mit der Bezeichnung 'anwendung_image_lib.py' als Base64 codierte Stringkonstanten speicherte. Somit wurden alle Bilder in eine einzige Datei gepackt.

In meinem Skript 'anwendung_view.py' importierte ich dann die 'anwendung_image_lib' und wandelte bei Bedarf die benötigten Base64 Bild-Stringkonstante(n) mit:

Code: Alles auswählen

tk_image = tk.PhotoImage(data=Base64-Stringkonstante)
in Tkinter Bildobjekte um.

Gruß wuf :wink:
Take it easy Mates!
lunar

@wuf: Wenn Du die Bilder ohnehin schon in einem eigene Modul deklarierst, kannst Du die Bilder eigentlich auch in eigenen Dateien speichern, und diese Datei über "__file__" laden. Wie gesagt, das ist die übliche Vorgehensweise in Python.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Ok lunar

Für GTK+ Anwendungen werde ich Bild-Dateien in einem dafür vorgesehenen Verzeichnis unterbringen und von dort einlesen. Wollte mein hier platzierten Skript doch noch mit Base64 Stringkonstante zum laufen bringen und machte folgende Änderungen bzw. Ergänzungen:

Code: Alles auswählen

import os
import base64

Code: Alles auswählen

image.set_from_file(self.base64_to_image(PYTHON_AT_WORK_48))

Code: Alles auswählen

def base64_to_image(self, base64_data):
    TEMP_FILE = 'temp_image'
    with open(os.path.join(os.getcwd(), TEMP_FILE), 'w') as f:
        f.write(base64.decodestring(base64_data))
    return TEMP_FILE
Gruß wuf :wink:
Take it easy Mates!
lunar

@wuf: Verwende das "tempfile"-Modul, um temporäre Dateien anzulegen. Ich glaube, das hatte ich schon gesagt… Dein Ansatz funktioniert nicht, wenn die Anwendung in einem Verzeichnis gestartet wird, in das der Benutzer nicht schreiben darf, und wenn mehrere Exemplare der Anwendung gleichzeitig laufen.

Mein Vorschlag mit der temporären Datei war übrigens nur eine Art Notanker, falls es gar keine andere Möglichkeit geben sollte. Laut Dokumentation kann man ein "gtk.Image" auch aus einem "GdkPixbuf" laden, und ein "GdkPixbuf" wiederum aus einem "GInputStream", wovon "GMemoryInputStream" ableitet. Du kannst die base64-Daten also auch mit "base64" dekodieren, daraus einen "GMemoryInputStream" erzeugen, aus diesem Stream ein "GdkPixbuf"-Objekt laden und dieses dann ein "gtk.Image" übergeben. Das wäre wohl der richtige(TM) Weg. Ein Beispiel dafür habe ich nicht, ich habe keine Ahnung von Gtk und nur ein bisschen in der Dokumentation geblättert, etwas was Du auch selbst hättest tun können…
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@ lunar
lunar hat geschrieben:@wuf: Verwende das "tempfile"-Modul, um temporäre Dateien anzulegen. Ich glaube, das hatte ich schon gesagt…
Habe ich nicht vergessen. Wollte mich noch einlesen & einarbeiten.
lunar hat geschrieben:Dein Ansatz funktioniert nicht, wenn die Anwendung in einem Verzeichnis gestartet wird, in das der Benutzer nicht schreiben darf, und wenn mehrere Exemplare der Anwendung gleichzeitig laufen.
Habe ich nicht daran gedacht. Danke für den Hinweis.
lunar hat geschrieben:Laut Dokumentation kann man ein "gtk.Image" auch aus einem "GdkPixbuf" laden, und ein "GdkPixbuf" wiederum aus einem "GInputStream", wovon "GMemoryInputStream" ableitet.
Das ist genau wonach ich suchte. Da GTK+ für mich neue Materie ist muss ich noch einiges durchlesen, reinziehen und ausprobieren. Danke für den Super Tipp.

Gruß wuf :wink:
Take it easy Mates!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Theoretisch würde das so gehen, in der Praxis scheitert das, weil irgendwie das Zusammenspiel von MemoryInputStream und Gdk Pixbuf nicht so gut passt. Ich hab geschaut wie Gdk Pixbuf new_from_file das macht, aber intern nutzt es GIO gar nicht, von dem her schwer zu sagen woran es genau hängt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Leonidas

Danke für dein interessantes Code-Snippet. Genau so etwas in diese Richtung versuchte ich gestern noch auszutesten. Aber spät abends musste ich nach dem herumspielen mit den mir von lunar vorgestellten neuen Begriffen konfrontiert mit unzähligen Exceptions mein Experimentierplatz leicht berauscht verlassen. :D. Da war heute morgen dein Snippet ein neuer Lichtblick. Wollte dein Snippet sofort ausprobieren. Habe aber Probleme mit dem Import der Module:

Code: Alles auswählen

from gi.repository import Gtk as gtk
from gi.repository import GdkPixbuf as gdk_pixbuf
from gi.repository import Gio as gio
Traceback (most recent call last):
File "gtk_base64_03.py", line 1, in <module>
from gi.repository import Gtk as gtk
ImportError: No module named gi.repository
Muss ich da noch etwas nachinstallieren oder ist es möglich diese Module noch auf eine andere Art zu importieren?
Leonidas hat geschrieben:Theoretisch würde das so gehen, in der Praxis scheitert das, weil irgendwie das Zusammenspiel von MemoryInputStream und Gdk Pixbuf nicht so gut passt. Ich hab geschaut wie Gdk Pixbuf new_from_file das macht, aber intern nutzt es GIO gar nicht, von dem her schwer zu sagen woran es genau hängt.
Vielleicht kann uns hier lunar noch etwas dazu erzählen.

Gruß wuf :wink:
Take it easy Mates!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

wuf hat geschrieben:Muss ich da noch etwas nachinstallieren oder ist es möglich diese Module noch auf eine andere Art zu importieren?
Naja, das ist halt PyGObject. Ich dachte mir, ich nehm gleich PyGObject, nachdem ja PyGTK nicht mehr weiterentwickelt wird und die Bindings auf GObject-Introspection und somit auf PyGObject umgestellt wurden. Dann kann man auch GTK+ 3.x nutzen, statt auf GTK+ 2.24 festzusitzen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

lunar hat geschrieben:@wuf: Verwende das "tempfile"-Modul, um temporäre Dateien anzulegen. Ich glaube, das hatte ich schon gesagt…
Habe das Problem jetzt mit tempfile gelöst:

Code: Alles auswählen

image = gtk.Image()
self.base64_convert(image, PYTHON_AT_WORK_48)
image.show()

Code: Alles auswählen

    def base64_convert(self, image, base64_data):
        with tempfile.NamedTemporaryFile(
            mode='w+t', delete=False) as temp_file_obj:
            temp_file_obj.write(base64.decodestring(base64_data))
            image_file_name = temp_file_obj.name
        try:
            image.set_from_file(image_file_name)
        finally:
            os.remove(image_file_name)
Leonidas hat geschrieben:Naja, das ist halt PyGObject. Ich dachte mir, ich nehm gleich PyGObject, nachdem ja PyGTK nicht mehr weiterentwickelt wird und die Bindings auf GObject-Introspection und somit auf PyGObject umgestellt wurden. Dann kann man auch GTK+ 3.x nutzen, statt auf GTK+ 2.24 festzusitzen.
Wusste ich noch nicht. In diesem Fall werde ich mich auf PyGObject konzentrieren und PyGTK möglichst schnell vergessen. Danke noch für den Hinweis.

Gruß wuf :wink:
Take it easy Mates!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Sonderlich gut ist die Lösung ja nicht, aber das sagte lunar schon. Ich schließe mich ihm an: vergiss doch diesen base64-Ressourcen-Kram den man vielleicht in Tkinter so gemacht hat und liefer einfach die Grafiken mit. Das ist einfacher für dich, weil du bei Änderungen nicht die Grafik extrahieren musst, editieren und nochmal einfügen musst, einfacher für User falls sie andere Iconsets verwenden wollen etc. Dafür haben wir ja das Dateisystem.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten