Feed a ndarray image to the src attribute of a Img component

Hello, I’m pretty new to Dash.

I try to display a ndarray through the src attribute of a Img component. I can display a png file from the server just fine with the data:image/png;base64.{}.format method, but then I also have image that I get from the server code in the format of a numpy array (ndarray). I could save the ndarray as a png on the server then doing something similar to what I do in the get_placeholder_thumbnail_html_value method, but it doesn’t seem to be a correct approach to this.

def get_placeholder_thumbnail_html_value():
    encoded_image = base64.b64encode(open("../assets/placeholder_thumbnail.png", 'rb').read())
    return 'data:image/png;base64,{}'.format(str(encoded_image.decode()))

def get_thumbnail_html_value_from_ndarray(ndarray):
    return 'data:image/png;base64,{}'.format(<what here ?>)

@app.callback(
    output=dash.dependencies.Output("thumbnail-channel1-img", "src"),
    inputs=[dash.dependencies.Input("refresh-button", "n_clicks")]
)
def load_image_channel1(n_clicks):
    ndarray = ra.get_ndarray_by_index(0)
    if image is None:
        res = get_placeholder_thumbnail_html_value()
    else:
        res = get_thumbnail_html_value_from_ndarray(ndarray)
    return res

What do I have to do to convert my ndarray into a string of bytes that fit into a data:image/png;base64.{}.format ?

Thanks

Hi @Clockzarb, we have a function for this in dash-canvas.

from dash_canvas.utils import array_to_data_url
import numpy as np
img = np.random.randint(255, size=(10, 10), dtype=np.uint8)
image_string = array_to_data_url(img)

If you don’t want to add a dependency just for one feature, here is also (courtesy of @xhlu) a function using PIL and base64 to build the image string.


import base64
from io import BytesIO
from PIL import Image

def pil_to_b64(im, ext="jpeg"):
   if ext == "jpg":
       ext = "jpeg"

   if ext == "jpeg" and im.mode in ("RGBA", "LA"):
       background = Image.new(im.mode[:-1], im.size, (255, 255, 255))
       background.paste(im, im.split()[-1])
       im = background

   buffer = BytesIO()
   im.save(buffer, format=ext)
   encoded = base64.b64encode(buffer.getvalue()).decode("utf-8")

   return f"data:image/{ext};base64, " + encoded