omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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?

    Pythonista
    10
    25
    29107
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Sebastian
      Sebastian last edited by

      How can I convert a PIL Image to a ui.Image?

      1 Reply Last reply Reply Quote 0
      • dgelessus
        dgelessus last edited by

        Taken more or less directly from filenav:

        try:
            import cStringIO as StringIO
        except ImportError:
            import StringIO
        import ui
        
        def pil_to_ui(img):
            strio = StringIO.StringIO()
            img.save(strio, img.format)
            data = strio.getvalue()
            strio.close()
            return ui.Image.from_data(data)
        
        1 Reply Last reply Reply Quote 0
        • ?
          A Former User last edited by

          Or...

          import ui, io
          from PIL import Image as ImageP
          
          ip = ImageP.open('ionicons-ios7-reload-32')
          
          with io.BytesIO() as bIO:
          	ip.save(bIO, ip.format)
          	ui.Button(image = ui.Image.from_data(bIO.getvalue())).present()
          

          Python Tutorial 6.2.1
          It is good practice to use the with keyword when dealing with file objects. This has the advantage that the file is properly closed after its suite finishes, even if an exception is raised on the way.

          1 Reply Last reply Reply Quote 0
          • Sebastian
            Sebastian last edited by

            Thanks guys! :D

            1 Reply Last reply Reply Quote 0
            • jmv38
              jmv38 last edited by

              this code works with the above image, but not with 'Test_Lenna' image.
              How can convert a pil image like Lenna into ui.image? Thanks

              1 Reply Last reply Reply Quote 0
              • omz
                omz last edited by

                @jmv38 If you want a ui.Image from a built-in image, the easiest/fastest would be to just not create a PIL image to start with:

                import ui
                
                img = ui.Image.named('Test_Lenna')
                img.show()
                # ...
                
                1 Reply Last reply Reply Quote 0
                • jmv38
                  jmv38 last edited by

                  @omz thanks, but i know this way, it is not what i want to achieve. Ok let me be more detailed:

                  A/ i must have an array from numpy that contains an image. i must have this because of fft functions.
                  B/ i must have a ui image because i want to display my array A and touch it and do actions from the touch. I could use a scene image, but i also want buttons, so i thought i'll have to go through ui anyway, which supports images, and i dont need 60 hz updates, hence my choice not to add another lib on top of it. (maybe wrong choice?).
                  C/ i want to draw a mask on top of my image, and i assume this mask will be a PIL image, because all drawing functions are there. But i'll have to convert this mask to array to multiply it to A. Note It is a gray scale mask, not binary one.

                  A,B and C will be updated all the time, so they are not built in images, but computed images.
                  And i will have 2, maybe 3 such sets of images in the same display.

                  Due to A,B and C, i will have to convert from one type to the other, and rather efficiently. I though i should not save the Array on disk each time i want to update the ui image, because i assume it will be too slow, but maybe i am wrong.

                  So to summarize, i expect to use:
                  PIL -> ui.
                  ui -> PIL.
                  array -> ui.
                  ui -> array.
                  array -> PIL. (these i found in the docs how to do).
                  PIL -> array.

                  If i could avoid all these conversions, i'd love to, but it doesnt seem possible at first sight, if i want to use the built-in libraries. I did not expect that each lib module had its own image format, not compatible with the other ones...
                  I guess i am not the only one to face that type of question..?

                  Now if you can suggest a better way to achieve what i want, using only one library module, please let me know, i have no experience in Python. Btw, Pythonista is really fantastic, the possibilty + quality of the whole thing is just .. AWSOME! That is a incredible good job you have done here!

                  Thanks for your help!

                  1 Reply Last reply Reply Quote 0
                  • omz
                    omz last edited by

                    Have you tried using @tony's code, but replacing ip.format with 'PNG'?

                    1 Reply Last reply Reply Quote 0
                    • jmv38
                      jmv38 last edited by

                      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.

                      1 Reply Last reply Reply Quote 0
                      • omz
                        omz last edited by

                        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)
                        
                        1 Reply Last reply Reply Quote 0
                        • jmv38
                          jmv38 last edited by

                          @omz Bingo!!!
                          Thanks a lot!

                          1 Reply Last reply Reply Quote 0
                          • jmv38
                            jmv38 last edited by

                            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)
                            
                            
                            1 Reply Last reply Reply Quote 1
                            • ccc
                              ccc last edited by

                              Should np2pil() always return imgOut?

                              Should pil2np() always return arrayOut?

                              If the else clauses are supposed to return None then you should do that explicitly.

                              1 Reply Last reply Reply Quote 0
                              • jmv38
                                jmv38 last edited by

                                @ccc changes done. Thanks.

                                1 Reply Last reply Reply Quote 0
                                • jmv38
                                  jmv38 last edited by

                                  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.
                                  1 Reply Last reply Reply Quote 0
                                  • Tizzy
                                    Tizzy last edited by

                                    Helped me! I used your pil2ui(), thanks!

                                    http://omz-forums.appspot.com/edit-post/5291307131994112

                                    1 Reply Last reply Reply Quote 0
                                    • Webmaster4o
                                      Webmaster4o last edited by

                                      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

                                      1 Reply Last reply Reply Quote 0
                                      • ccc
                                        ccc last edited by

                                        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?

                                        1 Reply Last reply Reply Quote 0
                                        • Webmaster4o
                                          Webmaster4o last edited by

                                          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.

                                          1 Reply Last reply Reply Quote 0
                                          • Webmaster4o
                                            Webmaster4o last edited by

                                            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?

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors