Codifica di un file di immagine con base64


161

Voglio codificare un'immagine in una stringa usando il modulo base64. Tuttavia ho riscontrato un problema. Come si specifica l'immagine che si desidera codificare? Ho provato a utilizzare la directory per l'immagine, ma questo porta semplicemente alla codifica della directory. Voglio che il file di immagine reale sia codificato.

MODIFICARE

Ho provato questo frammento:

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

ma ottengo il seguente errore:

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

Che cosa sto facendo di sbagliato?

Risposte:


299

Non sono sicuro di aver capito la tua domanda. Presumo che tu stia facendo qualcosa sulla falsariga di:

import base64

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

Devi prima aprire il file e leggerne il contenuto - non puoi semplicemente passare il percorso alla funzione di codifica.

Modifica: Ok, ecco un aggiornamento dopo aver modificato la domanda originale.

Prima di tutto, ricorda di utilizzare le stringhe non elaborate (prefissa la stringa con 'r') quando usi i delimitatori di percorso su Windows, per evitare di colpire accidentalmente un carattere di escape. In secondo luogo, Image.open di PIL accetta un nome di file o un file simile (ovvero, l'oggetto deve fornire metodi di lettura, ricerca e spiegazione).

Detto questo, puoi usare cStringIO per creare un tale oggetto da un buffer di memoria:

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
Grazie, un altro problema quando stampo l'immagine decodificata ottengo la stringa 'ÿØÿà'. Tuttavia, quando eseguo questo da solo come sostituto dei dati, viene visualizzato un errore. La stringa codificata è molto più lunga per il confronto. Quindi penso che probabilmente memorizzi i dati dell'immagine. la stringa decodificata fa semplicemente riferimento alla stringa codificata o qualcosa del genere? Sembra troppo breve per l'archiviazione dei dati.
rettangolo

L'output stampato non è necessariamente uguale al contenuto effettivo, dipende da come e dove lo si stampa.
Jim Brissom,

8
Nel mio caso, ho bisogno di decodificare: base64.b64encode(fh.read()).decode()per ottenere una stringa da utilizzare nei file html.
Qed

1
base64.b64encode (fh.read ()). decode () è sottile ma ne avevo bisogno anche @qed, grazie. La differenza è che uno restituisce byte e altra stringa ... e il mio server SOAP non lo inghiottirebbe senza decodificare!
zzart,

57

Con Python 2.x, puoi codificare banalmente usando .encode:

with open("path/to/file.png", "rb") as f:
    data = f.read()
    print data.encode("base64")

12

La prima risposta stamperà una stringa con prefisso b '. Ciò significa che la tua stringa sarà così b'your_string 'Per risolvere questo problema, aggiungi la seguente riga di codice.

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

2
Questa sembra una buona risposta, ma ti preghiamo di astenersi dal pubblicare se lo scopo è quello di promuovere il tuo sito web. Puoi comunque aggiungere link al tuo profilo.
halfer

1
(Per inciso, qui non si può fare affidamento sull'ordine di risposta, quindi vale la pena evitare commenti come "la prima risposta". Quello che appare per primo può cambiare nel tempo. :-))
Halfer

Nella tua versione originale di questa risposta, sembra che tu sia collegato al tuo sito o a un sito a cui sei affiliato. Se si collega a tale sito, è necessario rivelare che è il tuo sito . Se non divulga l'affiliazione, viene considerato spam. Vedi: Cosa significa autopromozione "buona"? e il centro assistenza sull'autopromozione . La divulgazione deve essere esplicita, ma non deve essere formale. Quando è il tuo contenuto personale , può essere solo qualcosa come "sul mio sito ...", "sul mio blog ...", ecc.
Makyen

Grazie per il suggerimento @Makyen ho intenzione di rivelare che è il mio sito. Sarà legale modificare la risposta ora per rivelare che è il mio sito? O non dovrei modificarlo.
CodeSpeedy

9

Come ho detto nella domanda precedente, non è necessario codificare base64 la stringa, renderà il programma solo più lento. Basta usare il 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))
...

Ora l'immagine è memorizzata come una variabile chiamata image_datain un file chiamato image.py Avvia un nuovo interprete e importa image_data

>>> from image import image_data
>>>

Non vedo davvero come repr () possa essere di qualche utilità qui.
Ivo van der Wijk,

6
@Ivo, Anteater vuole essere in grado di archiviare immagini in file Python. Sto sottolineando che l'utilizzo di base64 è controproducente perché i dati devono essere decodificati ogni volta che il modulo viene caricato. L'uso di repr significa invece che la stringa letterale è memorizzata pronta per l'uso immediato nel file .pyc senza elaborazione furthur
John La Rooy,

7

Prendendo in prestito da ciò che Ivo van der Wijk e gnibbler hanno sviluppato in precedenza, questa è una soluzione dinamica

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

È quindi possibile decidere di compilare il file di immagine di output con Cython per renderlo interessante. Con questo metodo, puoi raggruppare tutta la tua grafica in un modulo.


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

1
questa risposta dovrebbe davvero essere al top ... la migliore - grazie!
Luther, il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.