You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KivyMD中如何设置导入图片的位置并保持其原始朝向?

修复方案

前置依赖

先安装图片处理库Pillow:

pip install pillow

核心修改点

  1. 新增EXIF朝向处理逻辑:读取图片的EXIF元数据,自动将图片旋转到正确朝向
  2. 调整Image组件配置:开启比例保持,避免图片拉伸变形,同时通过pos_hint自定义图片位置
  3. 图片加载逻辑修改:将处理后的图片转为Kivy纹理直接赋值,避免临时文件读写

完整可运行代码

from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.core.window import Window
from kivy.graphics.texture import Texture
from plyer import filechooser
from PIL import Image as PILImage, ExifTags
import io

Window.size = (300, 530)

KV = """
MDBoxLayout:
    orientation: 'vertical'

    MDToolbar:
        id: progress_toolbar
        title: 'Progress'

    ScrollView:
        MDGridLayout:
            cols: 2
            adaptive_height: True
            spacing: (10, 15)
            padding: [25, 25]

            MDLabel:
                halign: 'center'
                text: 'Before'

            MDLabel:
                halign: 'center'
                text: 'Now'

            MDCard:
                ripple_behavior: True
                orientation: 'vertical'
                size_hint_y: None
                size: 120, 220
                elevation: 15
                radius: 8
                MDIconButton:
                    icon: "camera-outline"
                    user_font_size: "24sp"
                    pos_hint: {"center_x": .5, "center_y": .5}
                    on_release: app.file_chooser1()
                Image:
                    id: img1
                    allow_stretch: True
                    keep_ratio: True
                    size_hint: 0.9, 0.9
                    # 调整以下参数自定义图片位置
                    pos_hint: {"center_x": 0.5, "center_y": 0.4}

            MDCard:
                ripple_behavior: True
                orientation: 'vertical'
                size_hint_y: None
                size: 120, 220
                elevation: 15
                radius: 8
                MDIconButton:
                    icon: "camera-outline"
                    user_font_size: "24sp"
                    pos_hint: {"center_x": .5, "center_y": .5}
                    on_release: app.file_chooser2()
                Image:
                    id: img2
                    allow_stretch: True
                    keep_ratio: True
                    size_hint: 0.9, 0.9
                    # 调整以下参数自定义图片位置
                    pos_hint: {"center_x": 0.5, "center_y": 0.4}


            MDTextField:
                hint_text: 'Date'
                width: 100

            MDTextField:
                hint_text: 'Date'
                width: 100

"""

class Example(MDApp):
    def build(self):
        return Builder.load_string(KV)
    
    # 辅助函数:处理图片EXIF朝向
    def fix_image_orientation(self, img):
        try:
            for orientation in ExifTags.TAGS.keys():
                if ExifTags.TAGS[orientation]=='Orientation':
                    break
            exif = img._getexif()
            if exif is not None:
                orientation = exif[orientation]
                if orientation == 3:
                    img = img.rotate(180, expand=True)
                elif orientation == 6:
                    img = img.rotate(270, expand=True)
                elif orientation == 8:
                    img = img.rotate(90, expand=True)
        except (AttributeError, KeyError, IndexError):
            # 图片没有EXIF信息的情况直接返回原图
            pass
        return img
    
    # 辅助函数:将PIL图片转为Kivy纹理
    def pil_to_texture(self, pil_img):
        pil_img = pil_img.convert('RGBA')
        data = pil_img.tobytes()
        texture = Texture.create(size=pil_img.size, colorfmt='rgba')
        texture.blit_buffer(data, colorfmt='rgba', bufferfmt='ubyte')
        texture.flip_vertical()
        return texture

    def file_chooser1(self):
        filechooser.open_file(on_selection=self.selected1)

    def file_chooser2(self):
        filechooser.open_file(on_selection=self.selected2)

    def selected1(self, selection1):
        if not selection1:
            return
        # 读取并处理图片
        pil_img = PILImage.open(selection1[0])
        pil_img = self.fix_image_orientation(pil_img)
        self.root.ids.img1.texture = self.pil_to_texture(pil_img)

    def selected2(self, selection2):
        if not selection2:
            return
        # 读取并处理图片
        pil_img = PILImage.open(selection2[0])
        pil_img = self.fix_image_orientation(pil_img)
        self.root.ids.img2.texture = self.pil_to_texture(pil_img)

Example().run()

自定义位置说明

你可以直接修改每个Image组件的pos_hint参数调整位置:

  • center_x取值范围0~1,0为最左侧,1为最右侧,0.5为水平居中
  • center_y取值范围0~1,0为最底部,1为最顶部,0.5为垂直居中
    如果需要固定偏移量,也可以直接设置x和y属性指定绝对坐标。

内容的提问来源于stack exchange,提问作者Edwin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 12:39:01