Topic: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx  (Letto 4389 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline TerabyteST

  • python neanderthalensis
  • ****
  • Post: 433
  • Punti reputazione: 0
  • Quindicenne
    • Mostra profilo
.-|TUTORIAL: COMPILARE LE IMMAGINI|-.
Siete stanchi di dover sempre includere immagini esterne nelle vostre distribuzioni wx e quindi di rischiare che senza immagine il programma non parta?
In questo tutorial vi spiegherò come fare per impedire che questo accada: creeremo un eseguibile che contiene al suo interno le immagini.

Per fare questo abbiamo bisogno di:

     -wxPython 2.8 o superiore

     -pyInstaller, che potete scaricare sul sito
      (quando l'avete scaricato semplicemente scompattate il contenuto dell'archivio in una cartella a piacere)

     -Lo script usato per questo tutorial (download)
      da scompattare in una cartella a piacere, che non abbia spazi nel nome (meglio se facilmente raggiungibile da console/prompt dei comandi)

Ciò che ci serve fare è rendere l'immagine "memorizzabile" all'interno dell'eseguibile. Come si fa, direte voi? E' semplice! Rendiamola un file python!

Infatti, ogni modulo che viene importato dalla nostra applicazione viene automaticamente compilato dentro l'eseguibile della nostra applicazione da pyinstaller. Quindi, in teoria, se noi possiamo importare la nostra immagine come fosse un modulo anch'essa sarebbe inclusa nell'eseguibile.

Per Pythonizzare un'immagine, wx fornisce un utile script, img2py.py, che permette di creare un immagine compatibile con wx sotto forma di script (in cui sono memorizzate le informazioni di colore e dimensione).

Per trovare lo script rechiamoci, tramite il terminale, o prompt dei comandi, nella nostra cartella di installazione di python (la mia è C:\Python25) dove è installato wx.

Quindi entriamo nella cartella Lib, dove sono inclusi tutti i moduli di python (o gran parte), dopodichè entramo nella sottocartella site-packages e troviamo la cartella di wx 2.8 (per questo tutorial). La mia si chiama wx-2.8-msw-unicode. Entramo, sempre col terminale, nella cartella e poi semplicemente andiamo ancora 'giù' dentro a wx/tools/. Finalmente abbiamo trovato il nostro script img2py.py. Se lo eseguiamo senza nessun parametro possiamo vedere i modi d'uso. Ciò che interessa a noi è:

img2py.py [options] image_file python_file

Quindi vediamo che richiede le opzioni, il nome dell'immagine e il nome dello script d'output. Dato che non ci serve alcuna opzione speciale, gli daremo solo il nome della nostra immagine, in questo caso immagine.jpg (scrivete il percorso più il nome dell'immagine), e il nome dello script (sempre percorso più nome, e come nome mettiamo immagine.py per non confonderci).

Premiamo INVIO e lasciamolo lavorare per un po'. Quando ha finito nella cartella dovremmo vedere il file 'immagine.py'. Quindi possiamo procedere ad applicarlo nel nostro script.

Prima di tutto, come per ogni modulo che si rispetti, lo dovremmo importare. Semplicemente scrivamo

import immagine

Ora che il nostro modulo è importato, procediamo col sostituire l'immagine. Cancelliamo la parte che sta dopo l'uguale alla riga 11, dove dice self.fileimmagine e sostituiamola con questo:

immagine.getimmagineBitmap()

Come forse già qualcuno avrà notato, abbiamo estratto un'immagine Bitmap dal nostro modulo, che si può usare nello stesso modo dell'oggetto wx.Bitmap. Quindi dato che abbiamo sostituito questo e il resto riferisce già all'oggetto nello stesso modo, il tutto dovrebbe funzionare. Proviamo a farlo partire e vedremo che l'immagine appare. E ciò succederà anche se portiamo gli script main.py e immagine.py in un altra cartella.

Come avrete notato la funzione per estrarre l'immagine dal modulo è getimmagineBitmap(), quindi il nome corrisponde a quello che avete dato allo script python.

Quindi ora che abbiamo tutto pronto possiamo procedere alla creazione dell'eseguibile con l'immagine inserita all'interno.

Per fare questo, sempre tramire console/prompt dei comandi, rechiamoci nella cartella dove abbiamo scompattato pyinstaller, ed eseguiamo makespec.py. Per farlo funzionare avremo bisogno di alcune istruzioni. Ecco cosa dovremo scrivere:

makespec.py -F -w <percorso+nome.py>

-F fa in modo che pyinstaller crei un solo file (l'eseguibile) per tutta l'applicazione, -w farà in modo che la console non sia mostrata.

Ora lo script ci dirà che ha creato uno spec file (main.spec) nella sottocartella main. Per compilare lo script nell'eseguibile vero e proprio ora avremo da far partire lo script build.py e dargli come parametro il percorso del file .spec. Quindi:

build.py .\main\main.spec

Premiamo INVIO ed attendiamo. Quando avrà finito, nella cartella main ci sarà il nostro agognato eseguibile  :D. Come prova del suo funzionamento possiamo metterlo su un altro computer che non ha python installato, nè ha l'immagine in qualsiasi luogo e vedere se funziona... SORPRESA!!! Il programma parte perfettamente! Non c'è più alcun bisogno di immagini e sottocartelle che se assenti o diverse possono rovinare il nostro programma!

Spero che questo tutorial vi sia servito. Sono aperto a rispondere a qualsiasi domanda-dubbio che possa capitarvi.
« Ultima modifica: Giugno 10, 2009, 22:34 da TerabyteST »

Offline Charles_Stain

  • python sapiens sapiens
  • *
  • moderatore
  • Post: 1.220
  • Punti reputazione: 0
    • Mostra profilo
    • My personal website
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #1 il: Giugno 10, 2009, 18:29 »
Ho fatto bene a mancarlo importante, alla fine l'hai finito, bravo  :ok:

Offline Markon

  • python sapiens sapiens
  • *
  • moderatore
  • Post: 4.104
  • Punti reputazione: 5
    • Mostra profilo
    • Neolithic
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #2 il: Giugno 10, 2009, 19:02 »
ma ci vuole veramente tutto sto bordello per fare delle immagini?
in qt il discorso è assai più fico, con i qt resource :P

Offline TerabyteST

  • python neanderthalensis
  • ****
  • Post: 433
  • Punti reputazione: 0
  • Quindicenne
    • Mostra profilo
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #3 il: Giugno 10, 2009, 22:31 »
eh be, purtroppo con wxpython si può solo fare così

Offline pythonista

  • python erectus
  • ***
  • Post: 110
  • Punti reputazione: 0
    • Mostra profilo
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #4 il: Febbraio 23, 2010, 09:31 »
ottimo tutorial :)

mi chiedevo però, questo rallenta le prestazioni del programma?

Offline JKwest

  • python habilis
  • **
  • Post: 87
  • Punti reputazione: 0
    • Mostra profilo
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #5 il: Giugno 19, 2011, 13:03 »
Tutorial GRANDIOSO. Di solito non sono uno che si lascia prendere dall'entusiasmo....ma questo tutorial mi ha aperto un mondo! Python ha davvero delle grandi potenzialità.

Ottimo tutorial, bravo TerabyteST.  :ok:

Volevo fare un ultima precisazione. L'ultima versione di pyinstaller, la 1.5, ha cambiato alcuni nomi dei moduli scrivendoli con la lettera maiuscola, es: makespec.py ==> Makespec.py, build.py ==> Build.py, ecc..

Grazie ancora!

Offline bluprofondo79

  • python unicellularis
  • *
  • Post: 30
  • Punti reputazione: 0
    • Mostra profilo
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #6 il: Novembre 22, 2011, 10:50 »
Ciao a tutti,
ho iniziato a seguire la procedura, ma già al primo passo non succede nulla, nel senso che:

quando lancio :

c:\Python27\Lib\site-packages\wx-2.8-msw-unicode\wx\tools>img2py.py c:\new.png c:\new.py

Non mi crea alcun file py, dipende per caso dall'estensione della mia immagine png, oppure sbaglio qualcosa ?

Grazie

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.972
  • Punti reputazione: 9
    • Mostra profilo
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #7 il: Novembre 22, 2011, 14:32 »
Citazione
Markon: ma ci vuole veramente tutto sto bordello per fare delle immagini? in qt il discorso è assai più fico, con i qt resource
TerabyteST: eh be, purtroppo con wxpython si può solo fare così
Manno, è questo tutorial che fa sembrare le cose più complicate di quello che sono... Non l'avevo mai visto prima d'ora, e non mi convince proprio tantissimo (fermo restando l'impegno di chi l'ha fatto, e la soddisfazione di chi l'ha usato con successo, beninteso).

Prima di tutto chiariamo, se ce ne fosse bisogno, che in wxPython si possono ovviamente importare e trattare immagini "al naturale" in un miliardo di modi. Quindi questo non è il solo modo in cui si possono usare le immagini, anzi (non vorrei che qualche nuovo arrivato si confondesse). Qui si sta parlando solo del caso particolare in cui si voglia serializzare un'immagine, e usarla.

Per serializzare un'immagine wxPython fornisce uno strumento apposito, img2py, che si può usare standalone da riga di comando (con le solite precauzioni di avere python nella PATH del sistema, etc... per rispondere a bluprofondo79).

Ma si può anche usare importandolo in uno script python o dalla shell di python, molto comodamente!
[codice]
>>> from wx.tools import img2py
>>> img2py.img2py('c:/bla/bla/uno.gif', 'c:/bla/bla/serializzata.py', imgName='img_uno')
Embedded uno.gif using "img_uno" into serializzata.py
>>>
[/codice]
Ecco fatto! Questo serializza l'immagine 'uno.gif' dentro il file 'serializzata.py', attribuendole il nome 'img_uno'.
Ovviamente si possono anche immagazzinare più immagini dentro un solo file python, con il parametro "append=True":
[codice]
>>> from wx.tools import img2py
>>> # conviene fare la prima a parte...
>>> img2py.img2py('uno.gif', 'serializzate.py', imgName='img_uno')
Embedded uno.gif using "img_uno" into serializzate.py
>>> # e poi aggiungere le altre:
>>> for img, name in (('due.gif', 'img_due'),
                ('tre.gif', 'img_tre'),
                ('quattro.gif', 'img_quattro')):
       img2py.img2py(img, 'serializzate.py', imgName=name, append=True)

Embedded due.gif using "img_due" into serializzate.py
Embedded tre.gif using "img_tre" into serializzate.py
Embedded quattro.gif using "img_quattro" into serializzate.py
>>>
[/codice]
Unica piccola astuzia: mettete la prima separatamente, e poi aggiungete le altre; altrimenti nel file creato non viene inserita la necessaria intestazione "from wx.lib.embeddedimage import PyEmbeddedImage" (e allora, gran fatica, dovete aggiungerla a mano).

Ok, fine del tutorial su img2py.
Per Markon (se ancora legge questo thread dopo tanto tempo): le QtResource sono comode, ma in fondo hanno solo in più un indice xml e un meccanismo di sincronizzazione... Niente che volendo non si possa mimare in una funzione di dieci righe, senza contare che uno script python è sempre più leggibile ai miei occhi di un file xml...


Ultima questione, come si usano queste immagini serializzate? Facile, basta importare i loro nomi dentro il nostro codice:
[codice]
import wx
from serializzate import img_uno

class Prova(wx.Frame):
    def __init__(self, *a, **k):
        wx.Frame.__init__(self, *a, **k)
        bmp = wx.StaticBitmap(self, -1, img_uno.GetBitmap())  # ta-da!!

app = wx.App(False)
Prova(None, -1, 'Prova').Show()
app.MainLoop()
[/codice]
Oppure, naturalmente, se la stringa non è proprio chilometrica, potete direttamente copincollare dentro il vostro codice: in questo caso, attenti solo a importare anche PyEmbeddedImage in testa al tutto:
[codice]
import wx
from wx.lib.embeddedimage import PyEmbeddedImage

img_uno = PyEmbeddedImage(
    "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAA3NCSVQICAjb4U/gAAABmElE"
    "QVQokXVSoW4bQRB9Xk+rAatqgMHAU1VgaFAQUHDQoCAwsPCgQUFAPsAg4GBgYUCBYaBBgEHA"
    "wUKDggEHFqysUbRqC6652LU6aPX2vdV7s29CgfAyFfFSeE6sxACs+A/3TU5WRgomo6ARqaNs"
    "c9q5mzsISnzBPIB3KZ0I1qoAWjPDv6PAShXAtRmAaZiERkSIWrNGpGbu3B0AIMC1yEfm277/"
    "FOMHoid3qojrKKuf+0akiQLggvnKjAnfZrogBuBA21ur1UN2Wkbe5mSAv3hYEN+rDocBYcAK"
    "tjktI4c5884dwF1KXfFRM7K74uuUAHTuc+agxFYcQAIuzUbNyL4yG6B9cSUOx9d8tqLzCVa8"
    "Ih7Y96qjk+M8MuyX2IpP3795q0RP7jcinzmOTuxX0UAANFAJeHS/jLEvJWxyqqPoaz/++j7O"
    "w4ACdZRNTtPD7zALWL6T276ngMdnX/V9BgrwPWcEdM/epvRVtTvk7cFPqrE2S2cplbCavVbj"
    "rHyedtlTgcMr4sX/yjc+9iWK8km9H7Lvjz7nD4Hk0Ocmff/7AAAAAElFTkSuQmCC")

class Prova(wx.Frame):
    # tutto come sopra...
[/codice]

Offline bluprofondo79

  • python unicellularis
  • *
  • Post: 30
  • Punti reputazione: 0
    • Mostra profilo
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #8 il: Novembre 22, 2011, 16:30 »
Ciao Ric,
ora sono riuscito a creare il file serializzate.py con le mie immagini.

dopo di che nel mio script dove avevo:

[codice]self.SetIcon(wx.Icon(config.IconLogoapp,wx.BITMAP_TYPE_ANY))[/codice]

Sono andato a fare la sostituzione:

[codice]import ImgSerializzate[/codice]

Dopo ho provato a scrivere diverse righe ma va sempe in errore
Es.:

self.SetIcon(wx.Icon(ImgSerializzate.getIconLogoappImage(),wx.BITMAP_TYPE_ANY))
self.SetIcon(ImgSerializzate.getIconLogoappBitmap())
self.SetIcon(ImgSerializzate.IconLogoapp.GetBitmap())

Ma va sempre in errore

Dove sbaglio???

Offline bluprofondo79

  • python unicellularis
  • *
  • Post: 30
  • Punti reputazione: 0
    • Mostra profilo
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #9 il: Novembre 22, 2011, 16:43 »
[codice]self.SetIcon(wx.Icon(config.IconLogoapp,wx.BITMAP_TYPE_ANY))[/codice]

Mi auto cito...

Ho trovato la soluzione:

[codice]self.SetIcon(ImgSerializzate.IconLogoapp.GetIcon())[/codice]

Grazie

Offline Markon

  • python sapiens sapiens
  • *
  • moderatore
  • Post: 4.104
  • Punti reputazione: 5
    • Mostra profilo
    • Neolithic
Re: [TUTORIAL][FINITO] Compilare le immagini dentro un applicazione wx
« Risposta #10 il: Novembre 23, 2011, 21:50 »
Citazione
Markon: ma ci vuole veramente tutto sto bordello per fare delle immagini? in qt il discorso è assai più fico, con i qt resource
TerabyteST: eh be, purtroppo con wxpython si può solo fare così
Manno, è questo tutorial che fa sembrare le cose più complicate di quello che sono... Non l'avevo mai visto prima d'ora, e non mi convince proprio tantissimo (fermo restando l'impegno di chi l'ha fatto, e la soddisfazione di chi l'ha usato con successo, beninteso).



In effetti rileggendo ora mi pare strano... però non so, stiamo parlando di due anni fa, magari all'epoca ... non lo so! :D