1

Try to do some image processing, load an image to show on Graph, but nothing shown. Win10 / Python 3.7.6 / PySimpleGUI 4.16.0 / Numpy 1.18.1

I Load an image by PIL.Image, convert it to numpy array, then to base64, DrawImage in Graph, but show nothing. I had been work on it for serveral times and all OK. checked it for couple hours, but nothing help. Can someone help me to figure out where I missed or wrong ?

Something I found,

  1. im open, im.show() OK
  2. im.shape is correct, for example (200, 150, 3) for an 150 (width) x 200 (height) x RGB image.
  3. im_np shown different data, it seems OK.
  4. im_64 shown the byte string
  5. draw is None, it should be a id.
  6. with filename option set for DrawingImage, it is OK

I need to using numpy for some image process here, so conversion is required.

import base64
import numpy as np
import PySimpleGUI as sg
from PIL import Image

filename = 'D:/Disk.png'
im = Image.open(filename)
width, height = im.size
im_np = np.array(im)    # It is necesary for future process
im_64 = base64.b64encode(im_np)

def Graph(key):
    return sg.Graph(im.size, graph_bottom_left=(0, 0),
                    graph_top_right=(width, height), key=key)

layout = [[Graph('GRAPH')]]
window = sg.Window('Graph', layout=layout, finalize=True)

draw = window.FindElement('GRAPH').DrawImage(
    data=im_64, location=(width/2, height/2))           # It failed
    # filename=filename, location=(width/2, height/2))  # It working well

while True:

    event, values = window.read()

    if event == None:
        break

window.close()
Jason Yang
  • 11,284
  • 2
  • 9
  • 23
  • Presumably you need to save the image after manipulating it, before passing it into `DrawImage`. I would suggest saving it to a `io.BytesIO` buffer. A quick look at the documentation shows `DrawImage` accepts `bytes` as the `data` argument. So use the `BytesIO.getvalue()` method. No need for base64 encoding. – GordonAitchJay Mar 13 '20 at 08:10
  • `im_np = np.asarray(im); buffer = BytesIO(); np.save(buffer, im_np)` and set `data=buffer` in `DrawImage`, still not working. I had been tried it before post. – Jason Yang Mar 13 '20 at 09:44
  • When you do `np.save(buffer, im_np)`, it isn't saving it in the `.png` image format. You need to use `PIL` to save it properly. – GordonAitchJay Mar 13 '20 at 09:46
  • `im.save(buffer, format='PNG')` still not working – Jason Yang Mar 13 '20 at 10:58

1 Answers1

2

You need to pass the PNG "as binary" encoded base64, not numpy array encoded as base64.

It's not so clear from PySimpleGUI documentation, but when passing data as base64, the data is not the raw data as base64, but the image file content as base64.

  • Read PNG file as binary file:

    with open(filename, 'rb') as binary_file:
        #Read image file as binary data
        data = binary_file.read()
    
  • Encode the binary representation as base64:

    im_64 = base64.b64encode(data)
    
  • Pass im_64 as data:

    draw = window.FindElement('GRAPH').DrawImage(
        data=im_64, location=(width/2, height/2))          # Works
    

Here is a code sample:

import base64
import numpy as np
import PySimpleGUI as sg
from PIL import Image

#filename = 'D:/Disk.png'
filename = 'chelsea.png'

with open(filename, 'rb') as binary_file:
    #Read image file as binary data
    data = binary_file.read()

im = Image.open(filename)
width, height = im.size
im_np = np.array(im)    # It is necesary for future process
#im_64 = base64.b64encode(im_np)

# Encode the PNG binary representation 
im_64 = base64.b64encode(data)

def Graph(key):
    return sg.Graph(im.size, graph_bottom_left=(0, 0),
                    graph_top_right=(width, height), key=key)

layout = [[Graph('GRAPH')]]
window = sg.Window('Graph', layout=layout, finalize=True)

draw = window.FindElement('GRAPH').DrawImage(
    data=im_64, location=(width/2, height/2))          # Works
    #filename=filename, location=(width/2, height/2))  # It working well

while True:

    event, values = window.read()

    if event == None:
        break

window.close()

In case you want to display im_np, you may use the solution from the following post.

  • Write im_np as PNG image to string:

    im_pil = Image.fromarray(im_np)
    
    with io.BytesIO() as output:
        im_pil.save(output, format="PNG")
        data = output.getvalue()
    
    im_64 = base64.b64encode(data)
    

Result:
enter image description here

Rotem
  • 30,366
  • 4
  • 32
  • 65
  • The main reason to convert image array to base64 is to show the image after numpy processing. First solution is not necessary because I can use filename option directly in DrawImage. Second solution is what I need, but it may take some time for the conversion in animation. Anyway it's working, thank you for your reply. – Jason Yang Mar 13 '20 at 11:06
  • You don't actually need to convert the data to base64, the following code also works: `draw = window.FindElement('GRAPH').DrawImage(data=data, location=(width/2, height/2))` – Rotem Mar 13 '20 at 11:56