Como escrever uma imagem PNG em string com o PIL?


100

Eu gerei uma imagem usando PIL . Como posso salvá-lo em uma string na memória? O Image.save()método requer um arquivo.

Eu gostaria de ter várias dessas imagens armazenadas no dicionário.

Respostas:


194

Você pode usar a BytesIOclasse para obter um invólucro em torno de strings que se comportam como um arquivo. O BytesIOobjeto fornece a mesma interface de um arquivo, mas salva o conteúdo apenas na memória:

import io

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

Você deve especificar explicitamente o formato de saída com o formatparâmetro, caso contrário, o PIL gerará um erro ao tentar detectá-lo automaticamente.

Se você carregou a imagem de um arquivo, ela possui um formatparâmetro que contém o formato do arquivo original, portanto, neste caso, você pode usar format=image.format.

Nas versões antigas do Python 2, antes da introdução do iomódulo, você usaria o StringIOmódulo.


1
Sim! Isso é exatamente o que eu estava procurando. Eu pesquisei todas as combinações de python, string, reader, writer, buffer e não encontrei nada. Obrigado!
rik.the.vik

2
Não funciona para mim :( Recebi este KeyError em Imaging / PIL / Image.pyc linha 1423 -> raise KeyError (ext) # extensão desconhecida
Radian

6
@Radian, A documentação PIL sobre o método save () diz: You can use a file object instead of a filename. In this case, you must always specify the format.Portanto, se o primeiro argumento é um objeto de arquivo, você deve passar o segundo argumento, que é o formato (por exemplo 'PNG').
Su Zhang

1
Na versão atual do Python, StringIO está no pacote io, você deve escrever:from io import StringIO
Spoutnik16

4
você pode usar melhorimage.save(output, format=image.format)
reetesh11


24

A solução do sth não funcionou para mim
porque em ...

Imaging / PIL / Image.pyc linha 1423 -> aumentar KeyError (ext) # extensão desconhecida

Ele estava tentando detectar o formato da extensão no nome do arquivo, que não existe no caso StringIO

Você pode ignorar a detecção de formato definindo o formato por conta própria em um parâmetro

import StringIO
output = StringIO.StringIO()
format = 'PNG' # or 'JPEG' or whatever you want
image.save(output, format)
contents = output.getvalue()
output.close()

14

save()pode pegar um objeto semelhante a um arquivo, bem como um caminho, então você pode usar um buffer na memória como StringIO:

buf = StringIO.StringIO()
im.save(buf, format='JPEG')
jpeg = buf.getvalue()

Obrigado. StringIO - isso é o que eu preciso.
máx.

A interface save () é muito mais limpa do que a interface tostring () quando se trata de obter um formato de arquivo PNG, JPEG ou real.
Kekoa de

13

Com o moderno (em meados de 2017 Python 3.5 e Pillow 4.0):

StringIO parece não funcionar mais como antes. A classe BytesIO é a maneira adequada de lidar com isso. A função save de Pillow espera uma string como o primeiro argumento e, surpreendentemente, não vê StringIO como tal. O seguinte é semelhante a soluções StringIO mais antigas, mas com BytesIO em seu lugar.

from io import BytesIO
from PIL import Image

image = Image.open("a_file.png")
faux_file = BytesIO()
image.save(faux_file, 'png')

2
qual é o propósito de image_data = faux_file.getvalue ()?
Ryan

@Ryan Boa captura, sem nenhum propósito. Sobrou do teste e finalmente foi removido.
mightypile de

9

Quando você diz "Eu gostaria de ter algumas dessas imagens armazenadas no dicionário", não fica claro se essa é uma estrutura na memória ou não.

Você não precisa fazer nada disso para suavizar uma imagem na memória. Basta manter o imageobjeto em seu dicionário.

Se você vai escrever seu dicionário em um arquivo, pode querer olhar para o im.tostring()método e a Image.fromstring()função

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

im.tostring () => string

Retorna uma string contendo dados de pixel, usando o codificador "bruto" padrão.

Image.fromstring (modo, tamanho, dados) => imagem

Cria uma memória de imagem a partir de dados de pixel em uma string, usando o decodificador "bruto" padrão.

O "formato" (.jpeg, .png, etc.) só importa no disco quando você está trocando os arquivos. Se você não estiver trocando arquivos, o formato não importa.


2
Parece que ele deseja manter o formato PNG, não reduzi-lo a dados de pixel brutos.
Ben Blank,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.