Upload Image via FileInput and display in a panel

Hey, I’m trying to create a panel where to user is able to select an image and have it displayed above the respective data plots.

In general the desired panel has two sections:

  1. A settings section
  2. A plot section

My idea was to use an FileInput Widget in the Settings section and after all the other desired settings are selected the user can press a “Plot” button widget, which will create the panel with the image and the desired plots.

My problem is that the “value” attribute of the FileInput widget is a bytestring and I have not found an easy way to turn that bytestring into an image (or any way at all, rather new to the python world, so excuse me if this is a trivial question).

Desired functionality would be to just to do
pn.panel(FileInput.value)
and have an image ready.

Does anybody have an idea how to do this? Thanks in advance!

Hi @martinii26

I have an example in the gallery at awesome-panel.org.

You can find the code here https://github.com/MarcSkovMadsen/awesome-panel/blob/master/application/pages/image_classifier/image_classifier.py.

The part processing the image is

@param.depends("image_file")
def image_view(self,):
    """A view of the image_file"""
    if self.image_file:
        bytes_io = io.BytesIO(self.image_file)
        return pn.pane.HTML(
            (
                '<img application="data:image/jpg;base64,{0}" '
                'style="height:400px;min-width:600px;"/>'
            ).format(b64encode(bytes_io.getvalue()).decode("utf-8"))
        )
    return pnx.InfoAlert("Upload an image in .jpg format", height=400, min_width=600,)

It used to work. But when I test it now. It no longer seems to work.

But I think its a starting point.

Try to create a minimum reproducible code example and upload it if you need specific help. It’s a much easier starting point for somebody like me trying to help.

Thanks.

Hi, you can use the PIL library :

import param
import panel as pn
pn.extension()
from io import BytesIO
from PIL import Image

class TestApp(param.Parameterized):
         fi = pn.widgets.FileInput()
         
         @pn.depends('fi.value')
         def pict(self):
               if isinstance(self.fi.value,type(None)):
                   return pn.Row()
               b = BytesIO()
               self.fi.save(b)
               return pn.Pane(Image.open(b))

t1=TestApp()
pn.Row(t1.fi,t1.pict)
1 Like

Thank you very much for the very quick answers. I got it working with @Marc’s code.

The relevant line looks a bit different though

pn.pane.HTML('<img src ="data:image/png;base64{0}"height="600">'.format(b64encode(bytes_io.getvalue()).decode("utf-8"))

Also now another question popped up:
Is there an easy way to reset the file input selector, so it does not hold any values? Or do I have to reset every attribute by hand?

1 Like

You Will have to redet it i believe.

This works for me

fi = pn.widgets.FileInput()
def update_fi_widget(event):
    image_widget.object = event.new
fi.param.watch(update_fi_widget, "value");
image_widget = pn.pane.PNG()
1 Like

pn.bind(pn.pane.PNG, fi) is the best solution.

1 Like