利用Python理解TTF矢量字体显示原理

20 篇文章 3 订阅
17 篇文章 2 订阅

本文从微软雅黑字体MSYH.TTF中抽取出2次B样条曲线和直线的控制节点坐标数据,利用Python将汉字轮廓绘制出来。

MSYH字体轮廓是由2次B样条曲线和直线构成的,下图(fontforge软件获取)可见25-26-27三个控制点是一条曲线,27-28是一条曲线,从图中可以数出13条曲线,15条直线。

Python绘制B样条曲线(De Boor Cox)提供了用Python绘制B样条曲线的程序,本文在其基础上改进,利用读取TTF文件格式的轮廓信息一文中的C#程序获取汉字的控制节点坐标,绘制出汉字轮廓,有助于理解TTF矢量字体的原理

import matplotlib.pyplot as plt
import numpy as np
#from mpmath import diff

# 计算基函数,i为控制顶点序号,k为次数,u为代入的值,NodeVector为节点向量
# 该函数返回第i+1个k次基函数在u处的值

def b_spline_basis(i, k, u, nodeVector):
    # nodeVector = np.mat(nodeVector)  # 将输入的节点转化成能够计算的数组
    # k=0时,定义一次基函数
    if k == 0:
        if (nodeVector[i] < u) & (u <= nodeVector[i + 1]):  # 若u在两个节点之间,函数之为1,否则为0
            result = 1
        else:
            result = 0
    else:
        # 计算支撑区间长度
        length1 = nodeVector[i + k] - nodeVector[i]
        length2 = nodeVector[i + k + 1] - nodeVector[i + 1]
        # 定义基函数中的两个系数
        if length1 == 0:  # 特别定义 0/0 = 0
            length1 = 1
        alpha = (u - nodeVector[i]) / length1
        if length2 == 0:
            length2 = 1
        beta = (nodeVector[i + k + 1] - u) / length2
    # 递归定义
        result = alpha * b_spline_basis(i, k - 1, u, nodeVector) + beta * b_spline_basis(i + 1, k - 1, u, nodeVector)
    return result


# 画B样条函数图像
def draw_b_spline(n,k,nodeVector,X,Y):
    basis_i = np.zeros(100)  # 存放第i个基函数 生成100个0的矩阵
    rx = np.zeros(100)  # 存放B样条的横坐标
    ry = np.zeros(100)
    for i in range(n + 1):  # 计算第i个B样条基函数,
        #U = np.linspace(nodeVector[k], nodeVector[n+1], 100)  # 在节点向量收尾之间取100个点,u在这些点中取值,精度
        U = np.linspace(0, 1, 100)  # 在节点向量收尾之间取100个点,u在这些点中取值,精度
        j = 0
        for u in U:
            nodeVector = np.array(nodeVector) #转换为np矩阵
            basis_i[j] = b_spline_basis(i, k, u, nodeVector)  # 计算取u时的基函数的值
            j = j + 1
        rx = rx + X[i] * basis_i
        ry = ry + Y[i] * basis_i
    plt.plot(rx[1:], ry[1:])
    
def draw_line(X,Y):
    plt.plot(X,Y)

if __name__ == '__main__':
    
    n = 2  #一条曲线3个控制顶点 0-2
    k = 2  #2次B样条曲线    
    nodeVector = [0,0,0,1,1,1] #NodeVector为节点向量,其中元素称为节点,非递减
    plt.figure()
    
    #曲线控制节点坐标,每6个为一组,每组含三个节点坐标(x1,y1,x2,y2,x3,y3)
    s=[317.8,149.9,317.8,125.7,295.2,125.7,295.2,125.7,285.6,125.7,269.2,125.9,269.2,125.9,268,133.9,266.2,141.9,266.2,141.9,279.8,140.7,291.8,140.7,291.8,140.7,302.2,140.7,302.2,152.3,269.4,266.3,260.4,249.9,247.6,232.3,247.6,232.3,241.6,237.3,235.2,241.7,235.2,241.7,263,279.7,276.6,319.9,291.4,314.9,285.4,298.9,276.8,280.7,152.4,243.7,176.2,276.5,190.8,320.1,205.6,315.1,199.2,298.7,190.6,280.7,183.6,266.3,175,249.5,164.2,234.1,164.2,234.1,159.6,238.5,152.4,243.7]

    for i in range(0,len(s)-5,6):        
        X = s[i:i+6:2] #[x1,x2,x3]
        Y = s[i+1:i+6:2] #[y1,y2,y3]
        draw_b_spline(n,k,nodeVector,X,Y) #画曲线

    #直线控制节点坐标,每4个为一组,每组含两个端点坐标(x1,y1,x2,y2)
    s=[317.8,266.3,317.8,149.9,302.2,152.3,302.2,266.3,302.2,266.3,269.4,266.3,276.6,319.9,291.4,314.9,276.8,280.7,350.2,280.7,350.2,280.7,350.2,266.3,350.2,266.3,317.8,266.3,190.8,320.1,205.6,315.1,190.6,280.7,247,280.7,247,280.7,247,266.3,247,266.3,204,266.3,204,266.3,204,124.3,204,124.3,188.4,124.3,188.4,124.3,188.4,266.3,188.4,266.3,183.6,266.3]
        
    for i in range(0,len(s)-3,4):        
        X = s[i:i+4:2]#[x1,x2]
        Y = s[i+1:i+4:2]#[y1,y2]
        draw_line(X,Y) #画直线

    plt.show()
    


下图是运行结果:

西南大学周竹荣

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以按照以下步骤下载ttf字体文件: 1. 打开终端或命令提示符,并导航到Matplotlib的ttf目录。可以使用以下命令: ``` cd ~/.local/lib/python3.5/site-packages/matplotlib/mpl-data/fonts/ttf ``` 2. 复制你想要下载的ttf字体文件到ttf目录下。可以使用以下命令: ``` cp /mnt/hgfs/DirShare/SimHei.ttf . ``` 3. 清除Matplotlib的缓存文件。可以使用以下命令: ``` rm ~/.cache/matplotlib/fontlist-v300.json ``` 这样,你就成功下载了ttf字体文件,并可以在Matplotlib中使用它了。如果你想在Python中使用ttf字体文件,你可以使用以下代码: ``` import matplotlib.pyplot as plt plt.rcParams\['font.sans-serif'\] = \['SimHei'\] ``` 这样,你就可以在Matplotlib中使用SimHei字体了。希望对你有帮助!\[1\] #### 引用[.reference_title] - *1* [Python3 | UserWarning: findfont: Font family [‘SimHei‘] not found. Falling back to DejaVu Sans.](https://blog.csdn.net/Neutionwei/article/details/108311811)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [python游戏开发——字体文件下载](https://blog.csdn.net/weixin_63373973/article/details/130910522)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [python如何获取免费的可以商用的字体](https://blog.csdn.net/zhongkeyuanchongqing/article/details/120319566)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值