基于python3 flet库的对联生成工具

前言


python3 的 flet 库是一个非常好用的页面工具库,既可以作为软件也可以作为网页打开。

目前基于网络上找到的对联生成工具和flet页面,做了一个简单的对联生成工具,博君一笑。

如有侵权,请联系作者,谢谢。

正文


源代码
对联生成工具

代码结构:

font -- 字体路径
  书体坊颜体.ttf -- 字体文件

img -- 对联背景路径
  bg.png -- 对联背景

out_dir -- 输出路径
genWord.py -- 对联生成工具
main.py -- flet 主程序

genWord.py

import io
import numpy as np
import requests
from PIL import Image, ImageFont, ImageDraw

def genMyword(text, path_to_ttf = './font/书体坊颜体.ttf'):
    # 字体
    # path_to_ttf = './font/书体坊颜体.ttf'

    # font-TrueType字体文件。在Windows下,如果在该文件名中找不到该文件,则加载程序还会在Windows fonts /目录中查找。
    # size-请求的大小(以磅为单位)。
    # index-要加载的字体(默认为第一个可用的字体)。
    # encoding-使用哪种字体编码(默认为Unicode)。
    fontSize=400
    font = ImageFont.truetype(path_to_ttf, size=fontSize)

    # 透明图片
    imgSide=500
    # A-透明度
    img = Image.new('RGBA', (imgSide,imgSide), '#ffffff00')

    # 文字位置
    xPos = (imgSide - fontSize)/2+50
    # yPos = (imgSide - fontSize)/2
    yPos = 0 + 80
    print(xPos,yPos)

    # 写文字
    draw = ImageDraw.Draw(img)
    draw.text(xy=(xPos, yPos), text=text, font=font, fill=(0,0,0,255))

    # 输出
    # img.show()
    # img.convert("RGBA").save("tst.png")
    return img

def get_word(ch, quality, img="./img/bg.png", path_to_ttf = './font/书体坊颜体.ttf'):
    """获取单个汉字(字符)的图片
    ch          - 单个汉字或英文字母(仅支持大写)
    quality     - 单字分辨率,H-640像素,M-480像素,L-320像素
    """
    if ch == 'bg':
        # fp = io.BytesIO(requests.post(url='http://xufive.sdysit.com/tk', data={'ch':ch}).content)
        # im = Image.open(fp)
        im = Image.open(img)
    else:
        im = genMyword(ch, path_to_ttf)
    w, h = im.size
    print(ch,w,h)
    if quality == 'M':
        w, h = int(w*0.75), int(0.75*h)
    elif quality == 'L':
        w, h = int(w*0.5), int(0.5*h)
    
    return im.resize((w,h))

def get_bg(quality, img="./img/bg.png"):
    """获取春联背景的图片"""
    
    return get_word('bg', quality, img=img)


def write_couplets(text, HorV='V', quality='L', img="./img/bg.png", path_to_ttf = './font/书体坊颜体.ttf', out_file=None):
    """生成春联
    
    text        - 春联内容,以空格断行
    HorV        - H-横排,V-竖排
    quality     - 单字分辨率,H-640像素,M-480像素,L-320像素
    out_file    - 输出文件名
    """
    
    usize = {'H':(640,23), 'M':(480,18), 'L':(320,12)}
    bg_im = get_bg(quality)
    text_list = [list(item) for item in text.split()]
    rows = len(text_list)
    cols = max([len(item) for item in text_list])
    
    if HorV == 'V':
        ow, oh = 40+rows*usize[quality][0]+(rows-1)*10, 40+cols*usize[quality][0]
    else:
        ow, oh = 40+cols*usize[quality][0], 40+rows*usize[quality][0]+(rows-1)*10
    out_im = Image.new('RGBA', (ow, oh), '#f0f0f0')
    
    for row in range(rows):
        if HorV == 'V':
            row_im = Image.new('RGBA', (usize[quality][0], cols*usize[quality][0]), 'white')
            offset = (ow-(usize[quality][0]+10)*(row+1)-10, 20)
        else:
            row_im = Image.new('RGBA', (cols*usize[quality][0], usize[quality][0]), 'white')
            offset = (20, 20+(usize[quality][0]+10)*row)
        
        for col, ch in enumerate(text_list[row]):
            if HorV == 'V':
                pos = (0, col*usize[quality][0])
            else:
                pos = (col*usize[quality][0],0)
            
            # 获取纯文字
            ch_im = get_word(ch, quality, img=img, path_to_ttf=path_to_ttf)
            # 获取背景
            row_im.paste(bg_im, pos)
            # 拼合文字和背景
            row_im.paste(ch_im, (pos[0]+usize[quality][1], pos[1]+usize[quality][1]), mask=ch_im)
            
        out_im.paste(row_im, offset)
    
    if out_file:
        out_im.convert('RGB').save(out_file)
    out_im.show()


if __name__ == '__main__':
    # text = '普天同庆 欢度春节'
    # write_couplets(text, HorV='V', quality='M', out_file='普天同庆.jpg')
    # text = '这是横批'
    # write_couplets(text, HorV='H', quality='M', out_file=text+'.jpg')
    # text = '永'
    # write_couplets(text, HorV='V', quality='M', out_file='tst.jpg')
    
    text = '落霞与孤鹜齐飞 秋水共长天一色'
    write_couplets(text, HorV='V', quality='M', out_file='{0}.jpg'.format(text))

main.py

# -*- coding:utf-8 -*-
# 对联工具
import flet as ft
import os
from genWord import write_couplets

# 配置文件
class Conf(object):
    def __init__(self) -> None:
        self.font_dir = "./font"
        self.img_dir = "./img"
        self.out_dir = "./out_dir"
        self.image_name = "{0}/bg.png".format(self.img_dir)
        self.fonts = self.list_fonts()

    def list_fonts(self)->dict:
        """
        遍历文件夹中的字体名称
        """
        fonts = {}
        for file in os.listdir(self.font_dir):
            if os.path.isfile(os.path.join(self.font_dir, file)):
                fonts_name = os.path.splitext(os.path.basename(file))[0]
                fonts[fonts_name] = file
        return fonts
    

def main(page: ft.Page):
    page.title = "对联生成工具"
    conf = Conf()
    
    def btn_submit_clicked(e):
        """确认"""
        couplet_str = ""
        font = ""
        h_or_v = ""
        quality = "H"
        
        if not txt_couplet.value:
            txt_couplet.error_text = "请输入对联内容"
            page.update()
            return
        else:
            couplet_str = txt_couplet.value
        
        if not dropdown_fonts.value:
            dlg = ft.AlertDialog(
                title=ft.Text("Error"),
                content=ft.Text("请选择字体")
            )
            page.dialog = dlg
            dlg.open = True
            page.update()
            return
        
        font = dropdown_fonts.value
        
        if not dropdown_h_or_v.value:
            dlg = ft.AlertDialog(
                title=ft.Text("Error"),
                content=ft.Text("请选择对联方向")
            )
            page.dialog = dlg
            dlg.open = True
            page.update()
            return
        
        h_or_v = dropdown_h_or_v.value
        
        if not dropdown_quality.value:
            dlg = ft.AlertDialog(
                title=ft.Text("Error"),
                content=ft.Text("请选择对联画质")
            )
            page.dialog = dlg
            dlg.open = True
            page.update()
            return
        quality = dropdown_quality.value
        
        write_couplets(text=couplet_str,
                       HorV=h_or_v, 
                       quality=quality, 
                       img=conf.image_name,
                       path_to_ttf="{0}/{1}".format(conf.font_dir, font),
                       out_file="{0}/{1}.jpg".format(conf.out_dir, couplet_str))
    
    def btn_clean_clicked(e):
        """清空"""
        txt_couplet.value = ""
        page.update()
        return
    
    txt_couplet = ft.TextField(label="请输入对联内容,对联以空格作为间隔")
    # 字体下拉框提示
    txt_fonts = ft.Text("请选择字体: ")
    # 字体下拉框
    dropdown_fonts = ft.Dropdown(
        width=130,
        options=[ft.dropdown.Option(key=conf.fonts[i], text=i) for i in conf.fonts.keys()]
    )
    
    # 对联方向提示
    txt_h_or_v = ft.Text("请选择对联方向: ")
    # 对联方向下拉框
    dropdown_h_or_v = ft.Dropdown(
        width=100,
        options=[
            ft.dropdown.Option(key="V", text="竖向"),
            ft.dropdown.Option(key="H", text="横向")
        ]
    )
    
    # 画质提示
    txt_quality = ft.Text("请选择对联画质: ")
    # 画质下拉框
    dropdown_quality = ft.Dropdown(
        width=100,
        options=[
            ft.dropdown.Option(key="H", text="高"),
            ft.dropdown.Option(key="M", text="中"),
            ft.dropdown.Option(key="L", text="低")
        ]
    )
    
    # 确认按钮
    btn_submit = ft.ElevatedButton(text="确认", on_click=btn_submit_clicked)
    # 清空按钮
    btn_clean = ft.ElevatedButton(text="清空", on_click=btn_clean_clicked)
    
    page.add(
        # 标题
        txt_couplet,
        # 对联内容
        ft.Row(
            [
                txt_fonts,
                dropdown_fonts
                
            ]
        ),
        # 对联方向
        ft.Row(
            [
                txt_h_or_v,
                dropdown_h_or_v
            ]
        ),
        # 对联质量
        ft.Row(
            [
                txt_quality,
                dropdown_quality
            ]
        ),
        # 分割线
        ft.Divider()
        ,
        # 按钮
        ft.Row(
            [
                btn_submit,
                btn_clean
            ]
        )
        
    )

if __name__ == "__main__":
    # ft.app(target=main)
    ft.app(target=main, view=ft.AppView.WEB_BROWSER)

效果

posted @   BrianSun  阅读(51)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示