Jak napisać obraz PNG do łańcucha za pomocą PIL?

100

Wygenerowałem obraz za pomocą PIL . Jak mogę zapisać go do ciągu w pamięci? Image.save()Metoda wymaga pliku.

Chciałbym mieć kilka takich obrazków zapisanych w słowniku.

maxp
źródło

Odpowiedzi:

194

Możesz użyć BytesIOklasy, aby uzyskać opakowanie wokół łańcuchów, które zachowuje się jak plik. BytesIOObiekt zapewnia ten sam interfejs jako plik, ale zapisuje zawartość tylko w pamięci:

import io

with io.BytesIO() as output:
    image.save(output, format="GIF")
    contents = output.getvalue()

Musisz wyraźnie określić format wyjściowy za pomocą formatparametru, w przeciwnym razie PIL zgłosi błąd podczas próby automatycznego wykrycia go.

Jeśli wczytałeś obraz z pliku, ma on formatparametr zawierający oryginalny format pliku, więc w tym przypadku możesz użyć format=image.format.

W starszych wersjach Pythona 2 przed wprowadzeniem modułu zamiast iotego używałbyś StringIOmodułu.

sth
źródło
1
Tak! To jest dokładnie to, czego szukałem. Wyszukałem w Google każdą kombinację Pythona, stringów, czytnika, pisarza, bufora i niczego nie wymyśliłem. Dzięki!
rik.the.vik
2
Nie działa dla mnie :( Otrzymałem ten KeyError w Imaging / PIL / Image.pyc line 1423 -> podnieś KeyError (ext) # nieznane rozszerzenie
Radian
6
@Radian, Dokumentacja PIL dotycząca metody save () mówi: You can use a file object instead of a filename. In this case, you must always specify the format.Więc jeśli pierwszym argumentem jest obiekt plikowy, musisz przekazać drugi argument, którym jest format (np 'PNG'.).
Su Zhang
1
W obecnej wersji Pythona StringIO jest w pakiecie io, musisz napisać:from io import StringIO
Spoutnik16
4
możesz lepiej wykorzystaćimage.save(output, format=image.format)
reetesh11
29

W przypadku Python3 wymagane jest użycie BytesIO:

from io import BytesIO
from PIL import Image, ImageDraw

image = Image.new("RGB", (300, 50))
draw = ImageDraw.Draw(image)
draw.text((0, 0), "This text is drawn on image")

byte_io = BytesIO()

image.save(byte_io, 'PNG')

Czytaj więcej: http://fadeit.dk/blog/post/python3-flask-pil-in-memory-image

ozooner
źródło
24

rozwiązanie czegoś nie zadziałało,
ponieważ w ...

Imaging / PIL / Image.pyc line 1423 -> podnieś KeyError (ext) # nieznane rozszerzenie

Próbował wykryć format z rozszerzenia w nazwie pliku, które nie istnieje w przypadku StringIO

Możesz ominąć wykrywanie formatu, ustawiając format samodzielnie w parametrze

import StringIO
output = StringIO.StringIO()
format = 'PNG' # or 'JPEG' or whatever you want
image.save(output, format)
contents = output.getvalue()
output.close()
Radian
źródło
14

save()może wziąć obiekt podobny do pliku, jak również ścieżkę, więc możesz użyć bufora w pamięci, takiego jak StringIO:

buf = StringIO.StringIO()
im.save(buf, format='JPEG')
jpeg = buf.getvalue()
bobince
źródło
Dziękuję Ci. StringIO - tego potrzebuję.
maxp
Interfejs save () jest znacznie bardziej przejrzysty niż interfejs tostring (), jeśli chodzi o pobieranie formatu PNG, JPEG lub faktycznego formatu pliku.
Kekoa
13

Z nowoczesnym (od połowy 2017 Python 3.5 i Pillow 4.0):

Wygląda na to, że StringIO nie działa już tak, jak kiedyś. Klasa BytesIO jest właściwym sposobem radzenia sobie z tym. Funkcja save Pillow oczekuje łańcucha jako pierwszego argumentu i, co zaskakujące, nie widzi StringIO jako takiego. Poniższe jest podobne do starszych rozwiązań StringIO, ale z BytesIO na swoim miejscu.

from io import BytesIO
from PIL import Image

image = Image.open("a_file.png")
faux_file = BytesIO()
image.save(faux_file, 'png')
mightypile
źródło
2
jaki jest cel, image_data = faux_file.getvalue ()?
Ryan
@Ryan Dobry chwyt, bez celu. Został po testach i ostatecznie usunięty.
mightypile
9

Kiedy mówisz „Chciałbym mieć pewną liczbę takich obrazów przechowywanych w słowniku”, nie jest jasne, czy jest to struktura w pamięci, czy nie.

Nie musisz tego robić, aby potulny obraz w pamięci. Po prostu zachowaj imageobiekt w swoim słowniku.

Jeśli masz zamiar zapisywać słownik do pliku, możesz przyjrzeć się im.tostring()metodzie i Image.fromstring()funkcji

http://effbot.org/imagingbook/image.htm

im.tostring () => string

Zwraca ciąg zawierający dane pikseli przy użyciu standardowego kodera „surowego”.

Image.fromstring (tryb, rozmiar, dane) => obraz

Tworzy pamięć obrazu z danych pikseli w ciągu przy użyciu standardowego dekodera „surowego”.

„Format” (.jpeg, .png itp.) Ma znaczenie tylko na dysku podczas wymiany plików. Jeśli nie wymieniasz plików, format nie ma znaczenia.

S.Lott
źródło
2
Wygląda na to, że chce zachować format PNG, a nie zredukować go do surowych danych pikseli.
Ben Blank,