I have some PIL images coming from some library and am trying to understand what is going on with them. To do that, I compute some values, call the library, and look for the picture. The computed values are of interest to me. I use a Jupyter notebook with some sliders to interact with the library.
Here is a very brief example of my code:
from PIL import Image, ImageDraw
import ipywidgets
def explore_call(width, height, foo, bar):
# some very important computation
essential_value_one = width - foo
essential_value_two = height - bar
# output interim results
print(f"{essential_value_one=}, {essential_value_two=}")
# mimic PIL image return from a library
image = Image.new(mode="RGB", size=(width, height), color="black")
draw = ImageDraw.Draw(image)
draw.rectangle(xy=(foo, bar, essential_value_one, essential_value_two))
return image
ipywidgets.interact(explore_call,
width=ipywidgets.IntSlider(min=10, max=200, step=1, value=100),
height=ipywidgets.IntSlider(min=10, max=200, step=1, value=100),
foo=ipywidgets.IntSlider(min=0, max=20, step=1, value=10),
bar=ipywidgets.IntSlider(min=0, max=20, step=1, value=10),
)
That is semi-okay. Jupyter Notebook displays the returned image, but I wish to put it inside an ipywidgets container widget, replace the prints with some other widget, and do some basic layout. I found an ipywidgets.Image
but couldn't instantiate it properly (I tried to save the PIL image into an io.StringIO
buffer and then pass the value of it into ipywidgets.Image
, but without success). So, how do I wrap a PIL image in a widget?
Well you have asked too much in single question, but according to my understanding your main problem is to display the image as a jupyter widget and not simple image to make it compaitible with other jupyter widgets. So according to your following statement
(I tried to save the PIL image into a io.StringIO buffer and then pass the value of it into ipywidgets.Image, but without success)
Its not going to work as the correct way is to convert the PIL image into bytearray/bytes and then pass the bytes to the ipywidgets.Image. e.g. check modified version of your function below
from PIL import Image, ImageDraw
from io import BytesIO
import ipywidgets
def explore_call(width, height, foo, bar):
# some very important computation
essential_value_one = width - foo
essential_value_two = height - bar
# output interim results
print(f"{essential_value_one=}, {essential_value_two=}")
# mimic PIL image return from a library
image = Image.new(mode="RGB", size=(width, height), color="black")
draw = ImageDraw.Draw(image)
draw.rectangle(xy=(foo, bar, essential_value_one, essential_value_two))
imgBytes = BytesIO()
image.save(imgBytes, format="PNG")
return ipywidgets.Image(value=imgBytes.getvalue())