Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
How can I convert a PIL Image to a ui.Image?
-
i just tried
import ui, io from PIL import Image as ImageP def test(ip): with io.BytesIO() as bIO: ip.save(bIO, 'PNG') ui.Button(image = ui.Image.from_data(bIO.getvalue())).present() ip = ImageP.open('Test_Lenna') #ip = ImageP.open('ionicons-ios7-reload-32') test(ip)
but the result is a big blue square, not lenna color image...
Thanks. -
I see... The image is probably alright, it's just that it doesn't work well as a button image. By default, a button only uses the alpha component of an image (which is completely opaque in this case) and tints that with its
tint_color
(which is blue by default). This works well with icons, but not so much with photos. To create a button with a full-color image, you have to convert it to an image with "original" rendering mode:import ui, io from PIL import Image as ImageP def test(ip): with io.BytesIO() as bIO: ip.save(bIO, 'PNG') img = ui.Image.from_data(bIO.getvalue()) img = img.with_rendering_mode(ui.RENDERING_MODE_ORIGINAL) ui.Button(image=img).present() ip = ImageP.open('Test_Lenna') test(ip)
-
@omz Bingo!!!
Thanks a lot! -
here are the various conversions i have set. Tell me if there is some better code. Thanks.
[edit] modified according to @ccc comment below.
[edit] modified to add functions and tests.#coding: utf-8 import ui import io from PIL import ImageOps, ImageDraw from PIL import Image import numpy as np import StringIO import console # numpy <=> pil def np2pil(arrayIn): imgOut = Image.fromarray(arrayIn) return imgOut def pil2np(imgIn,arrayOut=None): if arrayOut == None: arrayOut = np.array(imgIn) return arrayOut else: arrayOut[:] = np.array(imgIn) return None # pil <=> ui def pil2ui(imgIn): with io.BytesIO() as bIO: imgIn.save(bIO, 'PNG') imgOut = ui.Image.from_data(bIO.getvalue()) del bIO return imgOut def ui2pil(imgIn): # create a fake png file in memory memoryFile = StringIO.StringIO( imgIn.to_png() ) # this creates the pil image, but does not read the data imgOut = Image.open(memoryFile) # this force the data to be read imgOut.load() # this releases the memory from the png file memoryFile.close() return imgOut # numpy <=> ui def np2ui(arrayIn): # this is a lazy implementation, maybe could be more efficient? return pil2ui( np2pil(arrayIn) ) def ui2np(imgIn): # this is a lazy implementation, maybe could be more efficient? return pil2np( ui2pil(imgIn) ) if __name__ == "__main__": # testing the functions above img = Image.open('Test_Lenna') s = 256 img = img.resize((s, s), Image.BILINEAR) img = ImageOps.grayscale(img) console.clear() print( 'test: open a pil image:') img.show() print('- ') print( 'test: pil image => return a new np array') print(' ') arr = pil2np(img) print(arr) print('- ') print( 'test: pil image => write into existing np array') print(' ') pil2np(img.rotate(90), arr) print(arr) print('- ') print( 'test: np array => return a new pil image') img1 = np2pil(arr) img1.show() # test: pil2ui verification is done via a popover iv = ui.ImageView(frame=(0,0,256,256)) iv.name = 'pil2ui' iv.image = pil2ui(img) iv.present('popover', popover_location=(600,100)) print('- ') print( 'test: ui image => return a new pil image (rotated by -90° to prove pil type)') img2 = ui2pil(iv.image).rotate(-90) print( type(img2)) img2.show() # test: np2ui verification is done via a popover iv2 = ui.ImageView(frame=(0,0,256,256)) iv2.name = 'np2ui' iv2.image = np2ui(arr) iv2.present('popover', popover_location=(300,100)) print('- ') print( 'test: ui image => return a new np array') arr2 = ui2np(iv2.image) print( arr2)
-
Should
np2pil()
always return imgOut?Should
pil2np()
always return arrayOut?If the
else
clauses are supposed toreturn None
then you should do that explicitly. -
@ccc changes done. Thanks.
-
I have updated my code above:
- corrected for a bug.
- added ui -> pil and np conversions.
- Added tests for all functions.
This is certainly not the best code possible,
but i hope it hepls someone.
Thanks.
-
Helped me! I used your pil2ui(), thanks!
-
Is there a faster way? I have a user take a picture with the camera, then have it displayed in an ImageView, but it takes a while
-
Which function above are you using? Can you try wrapping the call to the conversion function in a
with timer():
block (or similar) and tell us how long the conversion function takes to execute? -
Using the first method with a photos.capture_image(). Strange behavior:
x = Image.open('test.jpg') a = time.time() pil_to_ui(x) b = time.time() print b-a
prints 0.97... but
x = photos.capture_image() a = time.time() pil_to_ui(x) b = time.time() print b-a
prints 6.22...
I don't think this is a resolution difference, they're both about the same size. -
Wait, I had changed the
img.format
to PNG to fix an error, JPG makes it take 0.2 seconds. Related to my PNG crash? -
one thing that helps, not with speed, but with the problem of
capture_image
returning, yet the conversion is not yet complete, is to add an ActivityIndicator which starts animating before starting conversion, and stops animation (and removes the indicator ) afterwards. the ActivityIndicator can be added on top of your imageview, or else it can be added to your root view, and sized to the root view, so that it essentially blocks anything else from happening while the processing happens.on my ipad3, pil2ui takes a second or two for an image captured by the camera... an indicator at least doesn't leave the user wondering if something didn't work right, and prevents you from hitting the capture button again
-
@Webmaster4o: You should start a blog dedicated to problems with PNG images in Pythonista 1.5...except you would have no way to maintain it when 1.6 comes out. Still, it might gain some good traffic until that happens.
@omz: Did you know about these bugs while developing 1.6, or were the fixes just accidents? All this seems quite strange to me.
-
How do I make this support alpha? Using
def pil_to_ui(img): b = BytesIO() img.save(b, "JPEG") data = b.getvalue() b.close() return ui.Image.from_data(data)
Clear turns white...
-
Oops, I feel stupid, JPEG doesn't support transparency XD
-
Why would you use JPEG, you heretic. JPEG has three use cases: photos (the kind you make with your digital camera or smartphone), situations where something else requires you to use JPEG, and memes about lossy image compression.
;)