Kodowanie pliku obrazu przy użyciu base64


161

Chcę zakodować obraz w ciągu za pomocą modułu base64. Jednak napotkałem problem. Jak określić obraz, który chcę zakodować? Próbowałem użyć katalogu do obrazu, ale to po prostu prowadzi do zakodowania katalogu. Chcę, aby rzeczywisty plik obrazu był zakodowany.

EDYTOWAĆ

Wypróbowałem ten fragment:

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

ale pojawia się następujący błąd:

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

Co ja robię źle?

Odpowiedzi:


299

Nie jestem pewien, czy rozumiem twoje pytanie. Zakładam, że robisz coś w stylu:

import base64

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

Musisz oczywiście najpierw otworzyć plik i przeczytać jego zawartość - nie możesz po prostu podać ścieżki do funkcji kodowania.

Edycja: OK, oto aktualizacja po edycji oryginalnego pytania.

Przede wszystkim pamiętaj, aby używać nieprzetworzonych ciągów (poprzedzić je znakiem „r”) podczas używania ograniczników ścieżek w systemie Windows, aby zapobiec przypadkowemu naciśnięciu znaku ucieczki. Po drugie, Image.open w PIL'u akceptuje nazwę pliku lub plik podobny (to znaczy obiekt musi zapewniać metody odczytu, wyszukiwania i informowania).

Mając to na uwadze, możesz użyć cStringIO do stworzenia takiego obiektu z bufora pamięci:

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
Dzięki, jeszcze jeden problem, kiedy drukuję zdekodowany obraz, pojawia się ciąg „ÿØÿà”. Jednak gdy uruchamiam to samodzielnie jako substytut danych, pojawia się błąd. Zakodowany ciąg jest znacznie dłuższy dla porównania. Więc myślę, że prawdopodobnie przechowuje dane obrazu. czy zdekodowany ciąg po prostu odnosi się do zakodowanego ciągu czy coś? Wydaje się, że jest zbyt krótki do przechowywania danych.
prostokąt

Wydruk niekoniecznie odpowiada rzeczywistej zawartości - zależy to od tego, jak i gdzie je drukujesz.
Jim Brissom,

8
W moim przypadku muszę zdekodować: base64.b64encode(fh.read()).decode()aby uzyskać ciąg znaków do wykorzystania w plikach html.
okazania

1
base64.b64encode (fh.read ()). decode () jest subtelny, ale potrzebowałem tego również @qed, dzięki. Różnica polega na tym, że jeden zwraca bajty, a drugi ciąg ... a mój serwer SOAP po prostu nie połknąłby tego bez dekodowania!
zzart

57

W Pythonie 2.x możesz w trywialny sposób kodować używając .encode:

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

12

Pierwsza odpowiedź wypisze łańcuch z prefiksem b '. Oznacza to, że Twój ciąg będzie wyglądał następująco: b'your_string 'Aby rozwiązać ten problem, dodaj następujący wiersz kodu.

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

2
Wygląda na to, że to dobra odpowiedź, ale nie publikuj, jeśli celem jest promocja Twojej witryny. Możesz jednak dodawać linki do swojego profilu.
halfer

1
(Nawiasem mówiąc, nie można tu polegać na kolejności odpowiedzi, dlatego warto unikać komentarzy typu „pierwsza odpowiedź”. Ta, która pojawi się jako pierwsza, może się zmienić z czasem. :-))
halfer

W oryginalnej wersji tej odpowiedzi wygląda na to, że utworzyłeś link do własnej witryny lub witryny, z którą jesteś powiązany. Jeśli umieścisz link do takiej witryny, musisz ujawnić, że jest to Twoja witryna . Jeśli nie ujawnisz przynależności, zostanie to uznane za spam. Zobacz: Co oznacza „dobrą” autopromocję? oraz centrum pomocy dotyczące autopromocji . Ujawnienie musi być jawne, ale nie musi być formalne. Jeśli jest to Twoja osobista treść, może to być po prostu coś w rodzaju „na mojej stronie…”, „na moim blogu…” itp.
Makyen

Dzięki za sugestię @Makyen ujawnię, że to moja witryna. Czy będzie teraz legalna edycja odpowiedzi w celu ujawnienia, że ​​to moja witryna? Albo nie powinienem go edytować.
CodeSpeedy

9

Jak powiedziałem w poprzednim pytaniu, nie ma potrzeby kodowania łańcucha przy użyciu base64, spowoduje to jedynie spowolnienie programu. Po prostu użyj 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))
...

Teraz obraz jest przechowywany jako zmienna wywołana image_dataw pliku o nazwie image.py Start a fresh interpreter i zaimportuj image_data

>>> from image import image_data
>>>

Naprawdę nie rozumiem, jak repr () może się tutaj przydać.
Ivo van der Wijk

6
@Ivo, Anteater chce mieć możliwość przechowywania obrazów w plikach Pythona. Zwracam uwagę, że używanie base64 jest nieproduktywne, ponieważ dane muszą być dekodowane za każdym razem, gdy moduł jest ładowany. Użycie repr zamiast tego oznacza, że ​​dosłowny ciąg jest przechowywany jako gotowy do natychmiastowego użycia w pliku .pyc bez przetwarzania furthur
John La Rooy

7

Pożyczanie od tego, co van der Wijk Ivo i gnibbler opracowali wcześniej, jest to rozwiązanie dynamiczne

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

Następnie możesz zdecydować o skompilowaniu wyjściowego pliku obrazu za pomocą Cythona, aby był fajny. Dzięki tej metodzie możesz połączyć całą swoją grafikę w jeden moduł.


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
ta odpowiedź naprawdę powinna być na szczycie ... najlepsza - dzięki!
Luther
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.