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 to set the image of an ImageView to an image from Pillow?
-
I have a image in the pillow format PIL.Image (generate via
Image.new()
) and I want to display it in aui.ImageView
component.ImageView
has animage
property, but it is of typeui.Image
, not of typePIL.Image
.What can I do? How do I convert
PIL.Image
toui.Image
?Thanks heaps for any pointers!
-
@halloleooo use
import io def pil2ui(imgIn): with io.BytesIO() as bIO: imgIn.save(bIO, 'PNG') imgOut = ui.Image.from_data(bIO.getvalue()) #del bIO return imgOut ui_image = pil2ui(pil_image)
-
@cvp, curious about the
del bIO
, what is it for? -
@mikael as usual, you're right, not needed at all.
Old statement before using "with"
Sorry @halloleooo ,now commented -
@cvp, very cool! Works perfectly. Thanks a lot!
-
with
will autoclose()bIO
so you do not need to callbIO.close()
but closing a file (in this case, an in-memory file) does not force the garbage collector to deallocate the memory.del bIO
is a strong suggestion to the garbage collector to deallocate the memory. If you are only picking one file, then you should have no worries. However, if you process many large image/movie files one-after-another in Pythonista, you might find that callingdel
will prevent out-of-memory crashes. -
@ccc thanks a lot. Sincerely, I like to get clear explanations of technical matters.
-
@halloleooo please, uncomment the del bio, thanks to @ccc
-
Hmm, not sure I agree.
bIO is defined within the scope of the function def. When the function returns, bIO falls out of scope. As we have created no other references to bIO, it's reference count should then be 0 and it should then be immediately deallocated.
Does defining bIO in a context manager create a reference cycle? I don't think so.
The context manager probably has a reference to bIO, but bIO doesn't have a reference to the context manager. As long as we don't create a reference cycle, the periodic gc is not needed to resolve . It might be different if you had this within a for loop, instead of a function (though I don't think so).I suppose it would be easy to use something like the objgraph module to check either way.
-
@JonB , @ccc and @mikael you're too amazing for me
the garbage collector reminds me of the days of basic on Tandy Trs80. Afterwards, I developed a lot on ibm mainframe and unix, in languages where you didn't have to think so much about memory problems. but it is true that in Pythonista, this kind of limitation often crashes my scripts which handle a lot of images.
-
@JonB Try to create a picture frame app and see if Pythonista can cycle thru the 50 most recent pictures in Photos without
del
and without crashing. -
-
@ccc I will post something in a few days when I clean some things up. I created an endless loop calling a function that wrote a large amount of data to a BytesIO. No crash. I downloaded objgraph, and this never showed any increase in BytesIO objects.
My attempt at writing an image viewer that uses pil2ui failed after 4 photos (with or without del bIO) because of apparently a bad image in my
photos
(at least one that PIL choked on). I will say that, in the case of displayingphotos
assets, one should be using.get_ui_image
instead of.get_image
. That avoids any round trip through PIL, which is probably where any leaks or bugs occur. A simple image viewer usingget_ui_image
ran for longer than I cared to wait without a crash.Creating ui.Images also requires some care, because these might not get gc'd automatically. I believe the best practice is to include a
with objc_util.autoreleasepool():
when many UIImages are created -- though I haven't had time to explore whether setting the imageview image causes the old image to get leaked (in which case it would be necessary to manually handle the deallocation of the UIImage object)