温泽海
温泽海

Reputation: 354

PySimpleGUI Graph Displaying an image directly

I am trying to use Pysimplegui and its "graph" component to make an app such that the user can draw polygons on an image using the app. Here is a part of my code:

layout = [[sg.Graph(
    canvas_size=(length, width),
    graph_bottom_left=(0, 0),
    graph_top_right=(length, width),
    key="-GRAPH-",
    change_submits=True,  # mouse click events
    background_color='lightblue',
    drag_submits=True), ],]
window = sg.Window("draw rect on image", layout, finalize=True)
graph = window["-GRAPH-"]

Here length and width refers to the size of image I have. The only way which I know how to display the image is via graph.draw_image(path, location=(0,width)), where the path is the location of an png file.

My question is: Is there a way to display an image in graph that uses directly the image and not a path. (i.e. If I have an nd numpy array that represents an image, is it possible for me to directly make it show up in the canvas rather than first save as png then load the location?). Is it possible to avoid any kind of saving at all?

Intuitively, the method graph.draw_image reads the path and opens the image and then displays. There should be a method to avoid any saving and make graph directly display an image.

Upvotes: 0

Views: 4895

Answers (1)

Jason Yang
Jason Yang

Reputation: 13061

You can use option data here, but you need to convert image from array to data first.

def draw_image(self, filename=None, data=None, location=(None, None)):

Places an image onto your canvas.  It's a really important method for this element as it enables so much

:param filename: if image is in a file, path and filename for the image. (GIF and PNG only!)
:type filename:  (str)
:param data:     if image is in Base64 format or raw? format then use instead of filename
:type data:      str | bytes
:param location: the (x,y) location to place image's top left corner
:type location:  (int, int) | Tuple[float, float]
:return:         id returned from tkinter that you'll need if you want to manipulate the image
:rtype:          int | None

The data in array maybe just value for RGBA, no image format, like PNG. So I convert it from array to PIL.Image, then save it to data use io.BytesIO

Example code

from io import BytesIO
from PIL import Image
import numpy as np
import PySimpleGUI as sg

def array_to_data(array):
    im = Image.fromarray(array)
    with BytesIO() as output:
        im.save(output, format="PNG")
        data = output.getvalue()
    return data

font = ("Courier New", 11)
sg.theme("DarkBlue3")
sg.set_options(font=font)

im = Image.open("D:/Fandom.png")
array = np.array(im, dtype=np.uint8)
data = array_to_data(array)

width, height = 640, 480

layout = [[sg.Graph(
    canvas_size=(width, height),
    graph_bottom_left=(0, 0),
    graph_top_right=(width, height),
    key="-GRAPH-",
    change_submits=True,  # mouse click events
    background_color='lightblue',
    drag_submits=True), ],]
window = sg.Window("draw rect on image", layout, finalize=True)
graph = window["-GRAPH-"]
graph.draw_image(data=data, location=(0, height))

while True:

    event, values = window.read()
    if event in (sg.WINDOW_CLOSED, 'Exit'):
        break
    print(event, values)

window.close()

enter image description here

Upvotes: 2

Related Questions