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

如何修改tkinter canvas文本对象的宽高比实现单字符定向缩放效果

Tkinter Canvas 文本非等比缩放形变解决方案

问题根因

Tkinter 原生 canvas.create_text() 渲染的文本属于矢量字形对象,canvas.scale() 方法的坐标变换仅会修改文本的绘制位置,不会作用于字形本身的轮廓,因此无法实现单独缩放宽度/高度的形变效果。

实现方案

借助 Pillow 库将字符渲染为位图图像,对位图做非等比缩放后再贴到 Canvas 上,即可实现自定义形变效果:

  • 保留原有的线段绘制逻辑,canvas.scale() 对线形元素生效,可直接跟随缩放参数调整
  • 保留宽度调整高度(前倾/绕地平线旋转效果):x轴缩放比例固定为1,动态修改y轴缩放比例
  • 保留高度调整宽度(侧向旋转效果):y轴缩放比例固定为1,动态修改x轴缩放比例

依赖安装

pip install pillow

完整可运行代码

import tkinter as tk
from PIL import Image, ImageDraw, ImageFont, ImageTk

class FlipDigit():
    def __init__(self,master):
        self.master = master
        self.canvas_width = 150
        self.canvas_height = 150
        self.digit = tk.Canvas(master, width=self.canvas_width, height=self.canvas_height, bg='black')
        # 预先生成原始字符位图,避免多次缩放失真
        self.font_size = 150
        self.font = ImageFont.truetype("calibri.ttf", self.font_size)
        self.raw_char = 'A'
        # 生成原始透明位图
        self.raw_img = Image.new('RGBA', (self.canvas_width, self.canvas_height), (0,0,0,0))
        draw = ImageDraw.Draw(self.raw_img)
        # 居中绘制字符
        text_bbox = draw.textbbox((0,0), self.raw_char, font=self.font)
        text_x = (self.canvas_width - (text_bbox[2] - text_bbox[0])) // 2
        text_y = (self.canvas_height - (text_bbox[3] - text_bbox[1])) // 2
        draw.text((text_x, text_y), self.raw_char, font=self.font, fill='white')
        
        # 初始化字符显示为原始尺寸
        self.tk_img = ImageTk.PhotoImage(self.raw_img)
        self.letter = self.digit.create_image(self.canvas_width//2, self.canvas_height//2, image=self.tk_img)
        
        # 保留原有的两侧线段
        self.digit.create_line(5,25,5,125,width=10,fill='#808080')
        self.digit.create_line(145,25,145,125,width=10,fill='#808080')
        self.digit.pack()        
        
        self.count = 0
        self.master.after(50, self.Bump)

    def Bump(self):
        y_scale = .8
        if self.count > 10:
            y_scale = 1.25
        if self.count > 20:
            self.count = -1
        self.count += 1
        
        # 位图非等比缩放:x轴比例固定1,y轴按参数缩放
        scaled_img = self.raw_img.resize((self.canvas_width, int(self.canvas_height * y_scale)), Image.Resampling.LANCZOS)
        self.tk_img = ImageTk.PhotoImage(scaled_img)
        # 更新canvas上的字符图像
        self.digit.itemconfig(self.letter, image=self.tk_img)
        # 缩放两侧线段
        self.digit.scale('all', 75, 75, 1, y_scale)
        self.master.after(150, self.Bump)

if __name__ == '__main__':
    root = tk.Tk()
    Digit = FlipDigit(root)
    root.mainloop()

扩展说明

如果需要实现保留高度调整宽度的侧向旋转效果,只需修改缩放逻辑:将y轴缩放比例固定为1,动态调整x轴的缩放比例即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 07:27:04