kivy.uix.image Image. How to flip vertical or horizontal?

806 views
Skip to first unread message

snckmykek

unread,
Dec 9, 2021, 12:49:54 PM12/9/21
to Kivy users support
kivy.uix.image Image. How to flip vertical or horizontal?
mirror effect, left to right

I could not find the answer in google, documentation and on this forum, sorry

<Image>:
size_hint: None, None
source: "test.png"
size: dp(48), dp(48)

i need to flip horizontally

Elliot Garbus

unread,
Dec 9, 2021, 8:34:55 PM12/9/21
to kivy-...@googlegroups.com

I don’t have time to try this right now – but a few things come to mind:

If you want to rotate an image, you can look in the example directory for kivy and find an example.

 

To Mirror an image, I would try using Pillow.  https://note.nkmk.me/en/python-pillow-flip-mirror/

And then use in memory loading to load the mirrored texture.  https://kivy.org/doc/master/api-kivy.core.image.html?highlight=image#in-memory-image-loading

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/c6548659-63bc-4811-9828-52dd59786d8an%40googlegroups.com.

 

Robert

unread,
Dec 9, 2021, 8:51:44 PM12/9/21
to Kivy users support
Here is a simple way to mirror, I use it with Widget.
I suppose with Image it will just overwrite Image's default assignment of texture to canvas.
The code could be written at least two ways, but here is one

            if self.mirror:
                view_size = (-self.view_size[0], self.view_size[1])
                view_pos = (self.view_pos[0] + self.view_size[0], self.view_pos[1])
            else:
                view_size = self.view_size
                view_pos  = self.view_pos
            self.canvas.clear()
            with self.canvas:
                Color(1,1,1,1)
                Rectangle(texture= tex, size = view_size, pos = view_pos)

Elliot Garbus

unread,
Dec 10, 2021, 10:26:48 AM12/10/21
to kivy-...@googlegroups.com

Here is a version using PIL.  The file management here is good for a POC, but you would want to do something more robust for a production app. 

 

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.image import Image
from kivy.properties import BooleanProperty
from PIL import ImageOps
from PIL import Image as PImage

from pathlib import Path


kv =
"""
<MirrorImage>:
    keep_ratio: True
    allow_stretch: True


BoxLayout:
    orientation: 'vertical'
    Label:
        size_hint_y: None
        height: 48
        text: 'Mirror Image Test'
    MirrorImage:
        id: mi
        source:'ACESxp-30230 crop.jpg'  # replace with your image
    ToggleButton:
        size_hint_y: None
        height: 48
        text: 'Mirror'
        on_release: mi.mirror = False if self.state == 'normal' else True
"""


class MirrorImage(Image):
    mirror = BooleanProperty(
False)

   
def on_mirror(self, *args):
       
if self.mirror:
           
if not Path('mirror_' + self.source).exists():
               
# for production need more robust file naming and management
                # sufficient for proof of concept
               
im = PImage.open(self.source)
                image = ImageOps.mirror(im)
                image.save(
'mirror_' + self.source)
           
self.source = 'mirror_'+ self.source
       
else:
           
self.source = self.source[7:] # remove 'mirror_'


class MirrorImageApp(App):
   
def build(self):
       
return Builder.load_string(kv)


MirrorImageApp().run()

Elliot Garbus

unread,
Dec 10, 2021, 10:38:40 AM12/10/21
to kivy-...@googlegroups.com

Here is a version using Robert’s approach (Very Clever!!!), in kv.  This is based on a Widget, not an Image – so it does not maintain the ratio of the image.

 

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import BooleanProperty, ListProperty, StringProperty


kv =
"""
<MirrorImage>:
    view_size: self.size if not self.mirror else (-self.size[0], self.size[1])
    view_pos: self.pos if not self.mirror else (self.pos[0] + self.size[0], self.pos[1])
    canvas:
        Color:
            rgb: 1, 1, 1
        Rectangle:
            size: self.view_size
            pos: self.view_pos
            source: self.source

           

BoxLayout:
    orientation: 'vertical'
    Label:
        size_hint_y: None
        height: 48
        text: 'Mirror Image Test'
    MirrorImage:
        id: mi
        source:'ACESxp-30230 crop.jpg'  # replace with your image
    ToggleButton:
        size_hint_y: None
        height: 48
        text: 'Mirror'
        on_release: mi.mirror = False if self.state == 'normal' else True
"""


class MirrorImage(Widget):
    mirror = BooleanProperty(
False)
    view_size = ListProperty([
0,0])
    view_pos = ListProperty([
0,0])
    source = StringProperty()


snckmykek

unread,
Dec 10, 2021, 11:50:17 AM12/10/21
to Kivy users support

Thank you so much, this works great !!!!!!!!!!!
пятница, 10 декабря 2021 г. в 18:38:40 UTC+3, ElliotG:

snckmykek

unread,
Dec 10, 2021, 11:50:43 AM12/10/21
to Kivy users support
Thank you so much, this works great !!!!!!!!!!!

пятница, 10 декабря 2021 г. в 04:51:44 UTC+3, Robert:

Elliot Garbus

unread,
Dec 10, 2021, 4:30:21 PM12/10/21
to kivy-...@googlegroups.com

The need to create a temporary file bothered me – so I modified the code to use the io module to keep the mirror image in memory.

 

 from kivy.app import App
from kivy.lang import Builder
from kivy.uix.image import Image
from kivy.core.image import Image as CoreImage
from kivy.properties import BooleanProperty
from PIL import ImageOps
from PIL import Image as PImage

import io
from pathlib import Path


kv =
"""
<MirrorImage>:
    keep_ratio: True
    allow_stretch: True

BoxLayout:
    orientation: 'vertical'
    Label:
        size_hint_y: None
        height: 48
        text: 'Mirror Image Test'
    MirrorImage:
        id: mi
        source:'ACESxp-30230 crop.jpg'  # replace with your image
    ToggleButton:
        size_hint_y: None
        height: 48
        text: 'Mirror'
        on_release: mi.mirror = False if self.state == 'normal' else True
"""


class MirrorImage(Image):
    mirror = BooleanProperty(
False
)

   
def __init__(self, **kwargs):
       
super().__init__(**kwargs)
       
self.mirror_image = None
       
self.previous_filename = None
       
self.extension = {'.jpg': {'format': 'jpeg', 'ext': 'jpg'},
                          
'.png': {'format': 'png', 'ext': 'png'}}
       
# expand with required formats, see: https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html

   
def on_source(self, *args):
       
if not self.source or self.source == self.previous_filename: # if source is '' or same as previous
           
return
       
self.previous_filename = self.source  # else create texture
       
with PImage.open(self.source) as im:
            mirror_image = ImageOps.mirror(im)
        output = io.BytesIO()
        ext = Path(
self.source).suffix
        mirror_image.save(output,
format=self.extension[ext]['format'])
        output.seek(
0)
       
self.mirror_image = CoreImage(output, ext=self.extension[ext]['ext'])

   
def on_mirror(self, *args):
       
if self.mirror:
           
self.texture = self.mirror_image.texture
       
else:
           
self.reload()  # sets source to '' then back to name to fire source event.


Reply all
Reply to author
Forward
0 new messages