Display image thumbnails

304 views
Skip to first unread message

Antonio Cuni

unread,
Jun 27, 2016, 8:39:47 AM6/27/16
to Kivy users support
Hi,
I am developing an app which, among the other things, needs to display the pictures taken from the camera.

Currently I am using AsyncImage to load and display the images in a specific folder; something like this:

import sys
import glob
import os.path
from kivy.app import App
from kivy.factory import Factory
from kivy.lang import Builder

Builder.load_string('''
<Thumbnail@AsyncImage>:
   canvas.before:
       Color:
           rgb: 0.1, 0.1, 0.1
       Rectangle:
           pos: self.pos
           size: self.size

    size_hint: 0.25, None
   height: self.width


<PictureGrid@StackLayout>:
   spacing: "2dp"

''')

class PicShowApp(App):

    def build(self):
       root = Factory.PictureGrid()
       dirpath = sys.argv[1]
       files = glob.glob(os.path.join(dirpath, '*.jpg'))
       for f in files:
           root.add_widget(Factory.Thumbnail(source=f))
       return root

if __name__ == "__main__":
   app = PicShowApp()
   app.run()

However, I noticed that the process consumes an incredible amount of memory (I measured ~1GB to display 8 3840x2160 images).
I investigated and I saw that even if the AsyncImage widget are tiny, they keep a reference to the whole, full-resolution, uncompressed texture.
One thing I tried was to create the thumbnail whenever we change the texture of AsyncImage:

class MyAsyncImage(AsyncImage):

    def on_texture(self, obj, texture):
       if texture.size > tuple(self.size):
           buf = BytesIO()
           texture.save(buf)
           buf.seek(0)
           img = PILImage.open(buf)
           img.thumbnail(self.size)
           newtex = texture.create(size=self.size)
           newtex.blit_buffer(img.tostring(), colorfmt=img.mode.lower())
           self.texture = newtex
           self._coreimage = None

However, it doesn't work because I get garbled images. I suppose that I do something wrong to create the texture from the PIL image.
I know that I could simply save the thumbnails on disk and display those (and I might go for this solution after all), but now I would like to know if there is a solution which does not require to save data to disk.

So, basically I have two questions:

1) What is the best way to achieve my goal?
2) What is wrong in the MyAsyncImage example? How do I convert a PIL image to a texture?

thank you,
Antonio

ZenCODE

unread,
Jun 28, 2016, 9:15:18 AM6/28/16
to Kivy users support
You definitely want to set the 'asyn_image.nocache=True' to prevent a cache buildup. But not sure if that will solve your issues. I did something similar below, but used the CLock to do background disk image creation that you are trying to avoid. Here it is anyway...


Good luck

Antonio Cuni

unread,
Jun 29, 2016, 12:45:26 PM6/29/16
to kivy-...@googlegroups.com
Thank you,
at the end I choose exactly this strategy. I found that opening the image with PIL+create/save the thumbnail+load the thumbnail is much faster than loading the big image directly. And it's even faster the second time, because the thumbnail has already been created :)

ciao,
Anto

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages