Search code examples
pythonpython-3.xkivypython-zipfile

Load an In Memory ZipFile Object to as a KivyImage


I am testing out the ability of loading a zipfile containing multiple images to a kivy image and proofing out that it will cycle through all the images.

I have previously tried out these examples:

https://groups.google.com/forum/#!topic/kivy-users/t_iKvpgLIzE https://kivy.org/docs/api-kivy.core.image.html

I can get these to work, however, I cannot find an example of loading a .zip file or .gif file under those circumstances.

I request to see if it is possible to load a zipfile containing images if the zipfile is located in memory. Or if it's possible to create the animation from images loaded from memory.

import io
import zipfile
from kivy.core.image import Image as CoreImage
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class testApp(App):

    def get_image_from_memory(self):
        with io.BytesIO(open("archer_F_idle.zip", "rb").read()) as f:
            imgzip = f.read()
            print(imgzip)
            zipped_imgs = zipfile.ZipFile(f)
            print(zipped_imgs, zipped_imgs.namelist(),zipped_imgs.filename)


        return Image(source=zipped_imgs)


    def build(self):
        self.b = BoxLayout()
        self.b.add_widget(self.get_image_from_memory())
        return self.b

if __name__ == '__main__':  
    testApp().run()

Here is the following error:

ValueError: Image.source accept only str

Solution

  • Here's working example. Make sure you changed zip filename and image exc/filename to yours:

    import io
    import zipfile
    from kivy.core.image import Image as CoreImage
    from kivy.uix.image import Image
    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    
    
    class testApp(App):    
        def get_image_from_memory(self):
            with zipfile.ZipFile("C:/Users/gmn/Downloads/Cover.zip") as myzip:
                with myzip.open('Cover.jpg') as myfile:
                    ci = CoreImage(io.BytesIO(myfile.read()), ext="jpg")
                    return Image(texture=ci.texture)
    
        def build(self):
            self.b = BoxLayout()
            self.b.add_widget(self.get_image_from_memory())
            return self.b
    
    
    if __name__ == '__main__':
        testApp().run()
    

    Upd:

    Zip file should contain one or more images.

    import io
    import zipfile
    from itertools import cycle
    
    from kivy.clock import Clock
    from kivy.core.image import Image as CoreImage
    from kivy.uix.image import Image
    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.properties import StringProperty
    
    
    class ZipAnimationImage(Image):
        zip_source = StringProperty('')
    
        def __init__(self, **kwargs):
            self._cycle = None
            super(Image, self).__init__(**kwargs)
            Clock.schedule_interval(self._update, 1.0)
    
        def _update(self, *args):
            if self._cycle:
                self.texture = next(self._cycle).texture
    
        def on_zip_source(self, *args):
            cis = []
            with zipfile.ZipFile(self.zip_source) as z:
                names = z.namelist()
                for name in names:
                    ext = name.split('.')[-1]
                    with z.open(name) as f:
                        ci = CoreImage(io.BytesIO(f.read()), ext=ext)
                        cis.append(ci)
            self._cycle = cycle(cis) if cis else None
    
    
    class testApp(App):
        def build(self):
            self.b = BoxLayout()
            self.b.add_widget(ZipAnimationImage(zip_source='C:/Users/gmn/Downloads/test.zip'))
            return self.b
    
    
    if __name__ == '__main__':
        testApp().run()