利用Python理解TTF矢量字体显示原理「建议收藏」

利用Python理解TTF矢量字体显示原理「建议收藏」本文从微软雅黑字体MSYH.TTF中抽取出2次B样条曲线和直线的控制节点坐标数据,利用Python将汉字轮廓绘制出来

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

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

利用Python理解TTF矢量字体显示原理「建议收藏」

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()
    


下图是运行结果:

利用Python理解TTF矢量字体显示原理「建议收藏」

西南大学周竹荣

今天的文章利用Python理解TTF矢量字体显示原理「建议收藏」分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/86498.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注