Reputation: 354
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
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()
Upvotes: 2