Search on blog:

Flask: How to display image without saving in file using BytesIO and base64 string in url

To display image in web browser without saving image on disk you can use BytesIO to create file-like object in memory RAM which can be used like normal file to work with it without saving on disk.

This example uses matplotlib to create PNG in memory

import io
import matplotlib.pyplot as plt
import random

def generate_image():

    # genereate matplotlib image
    y = [random.randint(-10, 10) for _ in range(10)]
    x = list(range(10))
    plt.plot(x, y)

    # create PNG image in memory
    img = io.BytesIO()              # create file-like object in memory to save image without using disk
    plt.savefig(img, format='png')  # save image in file-like object
    img.seek(0)                     # move to beginning of file-like object to read it later

    return img

And later you can use img.read() or img.getvalue() to get data already converted to PNG and use them to different way: save in file, send to web browser (as normal file or base64 string or POST in HTTP) send by socket, or even send to database.

As first example you can save it on disk - you have to use standard open(), write(), close() because image is already converted to PNG data. You have to write it in bytes mode which means "wb".

# ... code ... #

img = generate_image()

#data = img.read()
data = img.getvalue()

fh = open('output.png', 'wb')
fh.write(data)
fh.close()

As second example you can use base64.b64encode() to convert PNG data to base64 string which you can use directly in HTML: on web page, in email or in any program which can display HTML.

import base64

# ... code ... #

img = generate_image()

data = img.getvalue()         # get data from file (BytesIO)

data = base64.b64encode(data) # convert to base64 as bytes
data = data.decode()          # convert bytes to string

print('<img src="data:image/png;base64,{}">'.format(data))

You can also send this data using POST in HTTP

import requests

# ... code ... #

img = generate_image()

data = img.getvalue()         # get data from file (BytesIO)

r = resuqests.post(url, files={'name': data})

Or using socket

import socket

# ... code ... #

img = generate_image()

data = img.getvalue()         # get data from file (BytesIO)

soc.send(data)

Here example with Flask which generates image in memory and sends to client using different methods.

It shows how to get image: - from url, - from local file, - from form on page, - generate new image and edit it with pillow and send to client - as image file (so you can use standard <img src="url">) - as normal file (so browser will ask where to save it) - as string Base64 (directly in HTML or use in JavaScript with object Canvas)

In similar way you can work with other files: music, PDF, excel, csv, etc. or with stream from webcam.

from flask import Flask, send_file, request #render_template,
import io
import random
import base64
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import urllib.request


app = Flask(__name__)


@app.route('/')
def index():
    return """Examples<br>""" +
    """- <a href="/send_image">send image</a><br>""" +
    """- <a href="/send_file">send image to download</a><br>""" +
    """- <a href="/base64">img base64</a><br>""" +
    """- <a href="/form1">form1 (image without changes)</a><br>""" +
    """- <a href="/form2">form2 (image with changes)</a><br>"""


def generate_image():
    """Generate plot. Save in BytesIO"""

    # create random plot
    plt.cla()   # to clear it because it may keep it between sessions
    y = [random.randint(-10, 10) for _ in range(10)]
    x = list(range(10))
    plt.plot(x, y)

    # convert to file-like object
    obj = io.BytesIO()              # file in memory to save image without using disk
    plt.savefig(obj, format='png')  # save in file (BytesIO)
    obj.seek(0)                     # move to beginning of file (BytesIO) to read it

    return obj


def generate_image():
    """Load file to Pillow OR generate empty file in Pillow. Draw. Save in BytesIO"""

    # read image from file
    #image = Image.open('lenna.png')

    # OR: create empty image
    image = Image.new('RGB', (300, 300), (0,0,0))  # RGB, 300x300, black

    # draw something
    draw = ImageDraw.Draw(image)                                      # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html
    #draw.rectangle([(10,10), (90,90)], fill=(255,0,0))
    draw.rectangle([(20,20), (280,280)], outline=(255,0,0), width=3)  # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.rectangle
    draw.text((5,5), "Hello World!", anchor="ms")                     # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.text

    # convert to file-like object
    obj = io.BytesIO()             # file in memory to save image without using disk  #
    image.save(obj, format='png')  # save in file (BytesIO)                           # https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.save
    obj.seek(0)                    # move to beginning of file (BytesIO) to read it   #

    return obj


def generate_image():
    """Get image from url. Doesn't have .getvalue() but still has .read()"""

    # get from url
    response = urllib.request.urlopen('https://picsum.photos/300/300')

    return response


def generate_image():
    """Get image from url. Read to Pillow. Draw. Save in BytesIO"""

    # get from url
    response = urllib.request.urlopen('https://picsum.photos/300/300')

    # read to pillow
    image = Image.open(response)  #

    # draw something
    draw = ImageDraw.Draw(image)                                      # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html
    draw.rectangle([(20,20), (280,280)], outline=(255,0,0), width=3)  # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.rectangle
    draw.text((15,5), "Hello World!")                                 # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.text

    # convert to file-like data
    obj = io.BytesIO()             # file in memory to save image without using disk  #
    image.save(obj, format='png')  # save in file (BytesIO)                           # https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.save
    obj.seek(0)                    # move to beginning of file (BytesIO) to read it   #

    return obj


def generate_image():
    """Get image from POST data"""

    request
    # get from url
    response = urllib.request.urlopen('https://picsum.photos/300/300')

    return response


@app.route('/base64')
def example1():
    """Convert iamge to BASE64 url"""

    # get images
    img1 = generate_image()
    img2 = generate_image()

    # convert to bases64
    data1 = img1.read()              # get data from file (BytesIO)
    data1 = base64.b64encode(data1)  # convert to base64 as bytes
    data1 = data1.decode()           # convert bytes to string

    data2 = img2.read()              # get data from file (BytesIO)
    data2 = base64.b64encode(data2)  # convert to base64 as bytes
    data2 = data2.decode()           # convert bytes to string

    # convert to <img> with embed image
    img1 = '<img src="data:image/png;base64,{}">'.format(data1)
    img2 = '<img src="data:image/png;base64,{}">'.format(data2)

    # use in HTML
    html = img1 + img2

    return html


@app.route('/send_image')
def example2():
    """Send to client as image which browser will display"""

    # get image
    img = generate_image()

    # send to client as image
    # it needs object which has method `read()
    return send_file(img, 'file.png') # name `file.png` assigned to `mimetype`


@app.route('/send_file')
def example3():
    """Send to client as file which browser will try to download"""

    # get image
    img = generate_image()

    # send to client as download file (with mimetype='application/octet-stream')
    # it needs object which has method `read()
    return send_file(img, as_attachment=True, attachment_filename='file.png')  # mimetype='application/octet-stream')  # without name as second argument because it was mimetype


@app.route('/form1', methods=['GET', 'POST'])
def example4():
    """Get from POST (form)"""

    img = '- empty -'

    if request.method == 'POST':
        if "image" in request.files:
            print(request.files)

            # get image
            img = request.files["image"]   # it has methodn .read() so it doesn't need to

            # convert to bases64
            data = img.read()              # get data from file (BytesIO)
            data = base64.b64encode(data)  # convert to base64 as bytes
            data = data.decode()           # convert bytes to string

            # convert to <img> with embed image
            img = '<img src="data:image/png;base64,{}">'.format(data)

    return '<form method="POST" enctype="multipart/form-data"><input type="file" name="image"><button type="submit">Send</button></form><br>' + img


@app.route('/form2', methods=['GET', 'POST'])
def example5():
    """Get from POST (form)"""

    img = '- empty -'

    if request.method == 'POST':
        if "image" in request.files:
            print(request.files)

            # get image
            img = request.files["image"]   # it has methodn .read() so it doesn't need to

            # read to pillow
            image = Image.open(img)  #

            # draw something
            draw = ImageDraw.Draw(image)                                      # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html
            draw.rectangle([(20,20), (280,280)], outline=(255,0,0), width=3)  # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.rectangle
            draw.text((15,5), "Hello World!")                                 # https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.text

            # convert to file-like data
            obj = io.BytesIO()             # file in memory to save image without using disk  #
            image.save(obj, format='png')  # save in file (BytesIO)                           # https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.save
            obj.seek(0)

            # convert to bases64
            data = obj.read()              # get data from file (BytesIO)
            data = base64.b64encode(data)  # convert to base64 as bytes
            data = data.decode()           # convert bytes to string

            # convert to <img> with embed image
            img = '<img src="data:image/png;base64,{}">'.format(data)

    return '<form method="POST" enctype="multipart/form-data"><input type="file" name="image"><button type="submit">Send</button></form><br>' + img


if __name__ == '__main__':
    app.run(debug=True)  # matplotlib need to work in main thread so flask can't use debug

Flask: Jak wyświetlić obraz bez zapisywania go w pliku korzystając z BytesIO oraz obrazu w postaci stringu BASE64 w url

Można użyć BytesIO do stworzenia obiektu podobnego do pliku (file-like object) ale trzymanego w pamięci RAM, który może być użyty do działań na pliku obrazka bez zapisywania na dysku.

Ten przykład używa matplotlib do stworzenia PNG w pamięci

import io
import matplotlib.pyplot as plt
import random

def generate_image():

    # genereate …

« Page: 1 / 1 »