Hi there, I am completely new to Pythonista UI and all I need to do is show an image generated within PIL, I have found https://forum.omz-software.com/topic/1935/how-can-i-convert-a-pil-image-to-a-ui-image However I can only get it to work on a button, as I have no idea how to get it to work.
The reason I need it to displayed outside of a button is that I need to be able to tap anywhere on the image and get the x and y coordinates of the tap, which I don’t think you can do with the button.
Any help; would be great thanks!!!
Forum Archive
I need help displaying a python PIL image within Pythonista UI
@PeterDaGrape try this little script (tap anywhere) and tell me if I had correctly understood your request
import ui
from PIL import Image
import io
def pil2ui(imgIn):
with io.BytesIO() as bIO:
imgIn.save(bIO, 'PNG')
imgOut = ui.Image.from_data(bIO.getvalue())
return imgOut
class MyView(ui.View):
def __init__(self, pil, *args, **kwargs):
super().__init__(self, *args, **kwargs)
iv = ui.ImageView()
iv.touch_enabled = True
iv.frame = self.frame
self.add_subview(iv)
iv.image = pil2ui(pil)
def touch_began(self, touch):
x,y = touch.location
self.name = f'x={x} y={y}'
pil = Image.open('test:Lenna')
wi,hi = pil.size
w = 400
h = w * hi/wi
mv = MyView(pil,frame=(0,0,w,h))
mv.present('sheet')
@cvp
You my friend are a genius, I had sort of figured out how to display the image within a window but only as a button, and I couldn’t find anywhere how you would just show a simple image within a window, and it works just as I needed, thanks as well for including the tap location part, that will also be extremely useful thank you!!!
@cvp this code is working perfectly, I have been playing around, and I can’t figure out how to refresh the image, so it will use the same image, and will refresh the view to show an updated version of the image, is this possible?
@PeterDaGrape It will depend how/when you want to change the image. Here a quick and dirty script to show how to change the image by tapping a button. It does not foresee the case where your images do not have the same proportion
import ui
from PIL import Image
import io
def pil2ui(imgIn):
with io.BytesIO() as bIO:
imgIn.save(bIO, 'PNG')
imgOut = ui.Image.from_data(bIO.getvalue())
return imgOut
class MyView(ui.View):
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self.images = ['test:Lenna', 'test:Mandrill', 'test:Peppers', 'test:Sailboat']
self.idx = 0
pil = Image.open(self.images[self.idx])
wi,hi = pil.size
self.width = 400
self.height = self.width * hi/wi
iv = ui.ImageView()
iv.touch_enabled = True
iv.frame = self.frame
self.add_subview(iv)
iv.image = pil2ui(pil)
iv.name = 'iv'
b = ui.ButtonItem()
b.title = 'new image'
b.action = self.b_action
self.right_button_items = (b,)
def touch_began(self, touch):
x,y = touch.location
self.name = f'x={x} y={y}'
def b_action(self,sender):
self.idx += 1
if self.idx == len(self.images):
self.idx = 0
pil = Image.open(self.images[self.idx])
self['iv'].image = pil2ui(pil)
mv = MyView()
mv.present('sheet')
@PeterDaGrape another example with a gif (which contains a set of images) where the updating of images is automatically done by the standard update method of your ui.View. Try it
from PIL import Image
import ui
import io
class Gif(ui.View):
def __init__(self,gif_file,duration):
self.frame = (0,0,400,400)
self.duration = duration
self.ImageView = ui.ImageView()
self.ImageView.frame = self.frame
self.add_subview(self.ImageView)
self.pil = Image.open(gif_file)
self.update_interval = self.duration / self.pil.n_frames
self.frame_id = 0
def pil2ui(self,imgIn):
with io.BytesIO() as bIO:
imgIn.save(bIO, 'PNG')
imgOut = ui.Image.from_data(bIO.getvalue())
del bIO
return imgOut
def update(self):
# Display individual frames from the loaded animated GIF file
self.pil.seek(self.frame_id)
self.ImageView.image = self.pil2ui(self.pil)
self.frame_id = self.frame_id + 1
if self.frame_id >= self.pil.n_frames:
self.frame_id = 0
def touch_ended(self,touch):
if self.update_interval == 0:
self.update_interval = self.duration / self.pil.n_frames
else:
self.update_interval = 0
if __name__ == '__main__':
v = Gif('../Examples/Misc/animation.gif',1)
v.present('sheet')#,hide_title_bar=True)
Ah, thank you very much, Ill have a play around with this, currently it would be creating a new window for every image generated which isn’t ideal, ill let you know if it does as needed!!