Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

Como servir gif animado no browser com Flask

Bom dia, estava fazendo alguns testes de como servir imagens em geral no browser com o Flask, sem precisar salvar qualquer coisa no disco. Segue abaixo um exemplo:

https://f.i.uol.com.br/fotografia/2019/03/15/15526795065c8c025270c53_1552679506_4x3_sm.jpg

Consegui fazer isso com imagens de extensão PNG. Segue uma parte do código (utilizei o pillow):

@app.route("png-image")
def returns_png_image()
    pillow_image = ImageGenerator.generate_png_image()
    b = BytesIO()
    pillow_image.save(b, format='PNG', quality=95)
    pillow_image = b.getvalue()
    response = flask.make_response(pillow_image)
    response.content_type = "image/png"
    length = len(pillow_image)
    response.content_length = length
    return response

A classe ImageGenerator gera imagens com diversos formatos, sem ler dados do disco.

O exemplo acima funciona bem com imagens PNG, agora quando tento fazer com imagens de extensão GIF, até aparece a imagem no browser, porém ela não fica animada. Alguém poderia me ajudar a entender como deixar o gif animado, sem ter que ler ele do disco?

5 respostas

Olá Sergio!

Não sou especialista em Python mas estou disponível para te ajudar.

Essa classe ImageGenerator foi você que criou? Dei uma procurada na documentação do Pillow e não encontrei ela.

Pelo que estou entendendo você está convertendo um imagem em base64 para poder servi-la, seria isso?

Algo como esse site:

https://www.base64-image.de/

Onde você insere uma imagem e ele converte para base64.

Tenta fazer o teste enviando um Gif para o site.

Veja que ele retorna algo como isso (String bem grande, tive que colocar em outra resposta):

data:image/gif;base64,R0lGODlhyACCAPf/ANrcaDZpldXk6Ive8w3O/iaUysjdc7XkhjdyowXN///aS//INv/QQIPd9FLY+djHVLvS5TZsmjd0qAHM/zd2qv/pW6vh7jh8tUnSzBC050nX+jdwoDTL1v/GNALJ/LTag7/IZZnJhv/kVv/PPnvJnjLU/CnS/Td4rv/hUkrMxufHSDCEuoqy08zic7bReHrNogjN/xGm2TZvnrri7P/eTy16q7jNc2Ha+FjLuv/mWFnZ+YvipAy57EyIuv/cTZXf8v/EMmja9//iVFXY+ZHf8iHR/Xnc9f/NPMTj6iyNxP/DK/rMRnbc9jd6sjbU/P/KOf///xDP/qHg8CTS/f/dThqm20HW+xjM7czj6S3T/f/12jd3rP/MOh3R/rXi7ZrWkWrLrGzb9jd0pqnHdznV/IjHkZnf8SLN5jZunC3L3BnQ/hSo3HrRpwnN+RuMw0TW+2Ta93Db9hudzsvGXTCBtRSj1jd8tP/89i5zrD3V+yKb0bHh7X7d9PLEOxaVzJvf8P/VXf/eTvnrYhWs4f/ehhPM8Sx2sSyFtgq98V3Z+PTWTi6GuzdyomOWwTd7s+/cVqbh7zB+sP/OPf/LOhTP/iuKvQbH+Aqx5id1qU3X+jd6sPzDM6bF3uLbX8zmeDh+uDd5sA7M9SdzpjJ5tP/HMRfQ/jd/uTZrmAPI+//RV3DJpTR4sReRxzN1rDdxov/VRf/URP/XR//SQjdzpf/WRv/TQzd4rf/bTP/ZSv/XSP/YSP/QP//ZSf/SQf/YSf/JOP/gUTdvn3Pc9v/hU//WRzDT/P/TQjZtmzzV/AbM+jhyov/MNlDY+tzTXq/Hbj7T1f/UQzJ4sgbD9zOAtcTX6P/77/v9/iCg18HHX8nVb4jQmzd1qfvJOxCn2xui1h7Q7NzHUP/PVfnENzCHv6Hjli7S4j7Mz0DP0SJ5rt7faTR5sm/Vr2HUu//JO/n7/XLdtfHYVDl6rzJ5qzN6rf/WReTVWevRUP/URf/QS//RTf/XRiCIwDFpl//afADM/////yH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFNUEzQjRBQzQ5NTYxMUUzODc0NUE3NjdBMTQ5M0FFOCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFNUEzQjRBRDQ5NTYxMUUzODc0NUE3NjdBMTQ5M0FFOCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkU1QTNCNEFBNDk1NjExRTM4NzQ1QTc2N0ExNDkzQUU4IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkU1QTNCNEFCNDk1NjExRTM4NzQ1QTc2N0ExNDkzQUU4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1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
solução!

Você pode pegar esse código gigante e colocar na barra do seu navegador que ele irá gerar um gif.

Então pra você servir um gif de forma binária sem passar pelo disco você pode tentar fazer dessa maneira, passando pela url.

O Python tem uma bilbioteca de base64 mas você também pode usar o Pillow:

import cStringIO
import PIL.Image

# assumindo que "data" contem aquele código gigante.
file_like = cStringIO.StringIO(data)

img = PIL.Image.open(file_like)
img.show()

Espero que tenha te ajudado!

Qualquer coisa pode me chamar por aqui!

Oi, Guilherme. Cara muito obrigado, você deu uma solução bastante interessante.

Sim a classe ImageGenerator eu criei. Na verdade eu só quis abstrair o resto do código, onde eu pego imagens pela internet, ou gero do zero e não deixo elas passarem pelo disco. Eu não tinha pensado em transformar nada em base64, inclusive as imagens PNG estão funcionando só com esse código que eu expus aqui.

Eu gostaria de fazer a mesma coisa com gifs. Ou seja, baixar um gif da internet ou gerar um, e exibir ele no browser, tudo sem I/O de disco. Vou testar essa solução e já volto aqui para marcar a solução.

Obrigado

A tua sugestão funcionou bem, Guilherme. Agora só restou a dúvida de como converter um arquivo GIF em base64. Vou procurar aqui no fórum se já existe resposta pra isso, qualquer coisa abro outro tópico. Obrigado :)