利用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
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,这是一个比较复杂的问题,需要详细讲解。首先,B样条曲线是一种可以用于光滑插值和逼近曲线的数学方法。它的优点是可以对曲线进行细致的控制,并且可以通过增加节点来增加曲线的复杂度。因此,B样条曲线在计算机图形学和CAD等领域应用广泛。 对于给定的一组坐标,我们可以按照如下步骤绘制出三次B样条曲线: 1. 确定节点向量 节点向量是一个非严格递增的实数序列,用于确定B样条曲线的控制点。节点向量的长度需要满足一定的条件,可以参考B样条曲线的理论知识进行确定。 2. 确定控制点 控制点是B样条曲线的关键。可以将控制点看作是曲线的“骨架”,通过控制点可以对曲线进行细致的调整。在三次B样条曲线,控制点的个数需要满足一定的条件,可以参考B样条曲线的理论知识进行确定。 3. 计算权值 权值是B样条曲线的重要参数,它决定了每个控制点在曲线的影响力。在三次B样条曲线,权值需要满足一定的条件,可以参考B样条曲线的理论知识进行确定。 4. 计算曲线 通过节点向量、控制点和权值,可以计算出三次B样条曲线。具体的计算方法可以参考B样条曲线的理论知识进行理解。 5. 将曲线绘制出来 最后,我们可以将计算出的曲线绘制出来,以便进行进一步的分析和调整。可以使用计算机图形学的绘图工具进行绘制。 至于如何将这些步骤封装成一个函数,需要根据具体的编程语言和图形库进行设计。一般来说,需要设计一个可以接受坐标数组、节点向量、控制点和权值等参数的函数,并返回计算出的曲线。可以参考已有的B样条曲线库进行设计。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值