本文从微软雅黑字体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()
下图是运行结果:
西南大学周竹荣
今天的文章利用Python理解TTF矢量字体显示原理「建议收藏」分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/86498.html