Codificando um arquivo de imagem com base64

161

Eu quero codificar uma imagem em uma string usando o módulo base64. Eu já tive um problema. Como faço para especificar a imagem que quero ser codificada? Tentei usar o diretório para a imagem, mas isso simplesmente leva à codificação do diretório. Quero que o arquivo de imagem real seja codificado.

EDITAR

Eu tentei este trecho:

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

mas eu recebo o seguinte erro:

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

O que estou fazendo de errado?

rectangletangle
fonte

Respostas:

299

Não sei se entendi sua pergunta. Presumo que você esteja fazendo algo como:

import base64

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

É necessário abrir o arquivo primeiro, é claro, e ler seu conteúdo - você não pode simplesmente passar o caminho para a função de codificação.

Editar: Ok, aqui está uma atualização depois de editar sua pergunta original.

Antes de tudo, lembre-se de usar strings brutas (prefixe a string com 'r') ao usar delimitadores de caminho no Windows, para evitar bater acidentalmente em um caractere de escape. Segundo, o Image.open do PIL aceita um nome de arquivo ou semelhante a um arquivo (ou seja, o objeto precisa fornecer métodos de leitura, busca e indicação).

Dito isto, você pode usar o cStringIO para criar esse objeto a partir de um buffer de memória:

import cStringIO
import PIL.Image

# assume data contains your decoded image
file_like = cStringIO.StringIO(data)

img = PIL.Image.open(file_like)
img.show()
Jim Brissom
fonte
1
Obrigado, mais um problema ao imprimir a imagem decodificada, recebo a string 'ÿØÿà'. No entanto, quando executo isso sozinho como substituto dos dados, recebo um erro. A cadeia codificada é muito mais longa para comparação. Então eu acho que provavelmente armazena os dados da imagem. a string decodificada simplesmente faz referência à string codificada ou algo assim? Parece muito curto para o armazenamento de dados.
Retangletangle
A saída impressa não é necessariamente igual ao conteúdo real - depende de como e onde você a imprime.
Jim Brissom
8
No meu caso, eu preciso decodificar: base64.b64encode(fh.read()).decode()para obter uma string para ser usada em arquivos html.
qed
1
base64.b64encode (fh.read ()). decode () é sutil, mas eu precisava disso também @qed, obrigado. A diferença é que um retorna bytes e outra string ... e meu servidor SOAP simplesmente não o engole sem decodificar!
Zzart 06/06
57

Com o python 2.x, você pode codificar trivialmente usando .encode:

with open("path/to/file.png", "rb") as f:
    data = f.read()
    print data.encode("base64")
Ivo van der Wijk
fonte
12

A primeira resposta imprimirá uma string com o prefixo b '. Isso significa que sua string será assim b'your_string 'Para resolver esse problema, adicione a seguinte linha de código.

encoded_string= base64.b64encode(img_file.read())
print(encoded_string.decode('utf-8'))
CodeSpeedy
fonte
2
Parece uma boa resposta, mas evite postar se o objetivo é promover seu site. Entretanto, você pode adicionar links ao seu perfil.
halfer
1
(Aliás, a fim resposta não pode ser invocado aqui, então vale a pena evitar comentários como "a primeira resposta" O que aparece primeiro pode mudar ao longo do tempo.. :-))
halfer
Na sua versão original desta resposta, parece que você vinculou ao seu próprio site ou a um site ao qual está afiliado. Se você criar um link para um site desse tipo, deve divulgar que é o seu site . Se você não divulgar a afiliação, ela será considerada spam. Veja: O que significa "boa" autopromoção? e o centro de ajuda sobre autopromoção . A divulgação deve ser explícita, mas não precisa ser formal. Quando é o seu próprio pessoal de conteúdo, ele pode simplesmente ser algo como "no meu site ...", "no meu blog ...", etc.
Makyen
Obrigado pela sugestão @Makyen, vou divulgar que é o meu site. Será legal editar a resposta agora para divulgar que é o meu site? Ou não devo editá-lo.
precisa saber é o seguinte
9

Como eu disse na sua pergunta anterior, não há necessidade de codificar base64 a string, isso apenas tornará o programa mais lento. Basta usar o 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))
...

Agora a imagem é armazenada como uma variável chamada image_dataem um arquivo chamado image.py Iniciar um novo intérprete e importe os dados da imagem

>>> from image import image_data
>>>
John La Rooy
fonte
Realmente não vejo como repr () pode ser útil aqui.
Ivo van der Wijk
6
@ Ivo, o Anteater quer poder armazenar imagens em arquivos python. Estou apontando que usar o base64 é contraproducente porque os dados precisam ser decodificados toda vez que o módulo é carregado. O uso de repr significa que a string literal é armazenada pronta para uso imediato no arquivo .pyc sem processamento adicional
John La Rooy
7

Tomando emprestado o que Ivo van der Wijk e o gnibbler desenvolveram anteriormente, essa é uma solução dinâmica

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

Você pode então decidir compilar o arquivo de imagem de saída com o Cython para torná-lo legal. Com esse método, você pode agrupar todos os seus gráficos em um módulo.

iChux
fonte
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')
Soluções de software DooDle
fonte
1
esta resposta realmente deve estar no topo ... melhor - obrigado!
Luther