自己制作字体的试验(自制字体使用FontForge等)


  
首先推荐公益性项目:flexifont 北大研究生办的。

然后介绍自己所做的(点击这里下载)(注意其中svg_2/有更新,在本文最后):

先是写了个简单检查ttf文件的ttf_check.c(在ttf_check/文件夹下),主要参照《Windows图形编程》([美]Feng Yuan)和Apple网站的 TrueType Reference Manual及 微软网站的otf spec。写了个sh脚本用它检查Windows上的.ttf、.TTF文件,发现有些如中文黑体等中的字形 可以完全没有hinting(grid-fitting)指令的。所以自制字体就准备不用hinting指令了,因为听说hinting很难。

然后试用FontForge,我下载了Windows版本的在Win10上安装。
网上得知要导入.svg矢量图形文件(有用.eps文件的,不过不熟),所以先下载了sourceforge网站上的矢量化软件 potrace(后来见到Windows上的FontForge安装文件夹中带有一个potrace.exe),在cygwin环境下编译(配置时用了--disable-zlib), 看了一下--help,使用--svg选项将二值的位图转化为.svg文件,在FontForge编辑字形时即可导入。SVG文件是一种可读的文本XML文件, 可以自己直接编辑,可以直接用浏览器浏览。逐渐了解 SVG用了《SVG精髓》(第2版)一书。与potrace同类型的有autotrace,但我没用过。

二值的位图可以用Windows的画图保存生成,自动化时我选用ImageMagick的convert命令来生成,如:
	            convert in.jpg  -monochrome  out.jpg
    
看了一下,位图位深是1 bit的。

FontForge用Generate选项生成.ttf文件,Windows上右键点击该文件即可选用安装,缺省字体名类似为“Untitiled”,新建一word文档中输入 导入字形对应的文字,选中后改用试验字体,即可看到效果。

然后试验FontForge的脚本,试验结果发现用不多的几个命令即可用于基本实现自动化。(为了试验自动运行,我将fontforge.exe和所有 .dll都拷到一个文件夹fontforge_test/下)。要注意需解决两个问题:
第一个:FontForge缺省新建的文件只包含几十个字形的大概是 Latin-1的字体,脚本中New或Open文件之后需用
	     Reencode("gb2312"); 或 Reencode("unicode");
	
第二个,需要在fontforge运行的图形界面上点击Element |- Font Info |- OS/2 |- Charsets |- MS Code Pages里复选 (缺省仅为1252,Latin-1)936,Simplified Chinese。注意是复选,点击时需按住Ctrl键。这一点我现在还没找到脚本方案。 这一点我是在看网上视频:
           如何制作一款属于自己的字体?(FontForge字体制作教程)
	
中学到的。
创建文件脚本如test1.pe:
		#!/cygdrive/d/temp2/fontforge

		New();
		Select("C");
		Import("test5.svg");
		Generate("test.ttf");	
	

编辑文件脚本如test6.pe:
		#!/cygdrive/d/temp2/fontforge

		Open("test.ttf")
		#Reencode("gb2312");
		Select(0u4e00);
		Import("test6.svg")
		Select(0u4e01);
		Import("test5.svg");
		Select("C");
		Import("test5.svg");
		Select(0u56fd);
		Import("test2.svg");
		Generate("test.ttf");	
    
.pe后缀名我想或许来自FontForge的原名pfaedit的缩写。

然后在网上搜汉字的unicode码表,写unicode和汉字字形的相互对应程序(为了自动化)。逐渐了解到汉字的Unicode范围大概从0x4e00到 0x9FEA,最后选了网上的一篇文章(《汉字一、二级字库的汉字与unicode编码(十六进制)对照表,按照unicode的顺序排列》 - zhoukejun的专栏 - CSDN博客),写成文件夹unicode_Chinese/下的translate2.c文件,是一、二级汉字的Unicode对应,有6763个字。

然后开始试验自动化的流程,从扫描或拍照开始,所以文件夹命名为photo/。
(1)扫描或拍照
我是试验用手机拍照,在photo/1scan_or_snap/下,得到的是.jpg文件;
(2)转成BMP
在photo/2scan_bmp/下,为减少上传文件大小,我将其删掉了,生成即可;
(3)为每个字生成BMP
我试验时是用Windows画图剪切得到每个字的BMP,使用其相应的汉字命名,在photo/3scan_char_bmp/下;
(4)将每个位图转为二值位图
这因为potrace需要二值位图输入。写了photo/1bit.sh使用ImageMagick的convert批量转换,生成的BMP在photo/4bit1_bmp/下;
		#!/bin/bash

		INDIR="3scan_char_bmp"

		OUTDIR="4bit1_bmp"


		for i in `ls $INDIR/*.bmp` ; do
		   echo $i
		   FILENAME=`basename $i`
		   OUTFILE="$OUTDIR""/""$FILENAME"
		   echo $OUTFILE
		   
		   convert $i -monochrome $OUTFILE
		done
	
	
(5)用potrace批量转成SVG文件
写了photo/2svg.sh使用potrace批量转换,生成的SVG在photo/5svg/下;
		#!/bin/bash


		INDIR="4bit1_bmp"
		OUTDIR="5svg"


		POTRACE=/cygdrive/d/temp/potrace/potrace-1.15/src/potrace
		if ! [ -e $POTRACE  ] ; then
			echo "$POTRACE doesn't exist"
			exit
		fi


		for i in `ls $INDIR/*.bmp` ; do
		   echo $i
		   FILENAME=`basename $i  |  sed -e s/\.bmp/\.svg/g`
		   OUTFILE="$OUTDIR""/""$FILENAME"
		   echo $OUTFILE
		   
		   $POTRACE  $i  --svg -o $OUTFILE 
		done
	
	
这时写了photo/3check_unicode2.sh来检查一下文件名中的汉字是否能对应查询到下一步fontforge脚本所需要的Unicode码:
		#!/bin/bash

		INDIR="5svg"

		for i in `ls $INDIR/*.svg` ; do
		   #echo $i
		   FILENAME=`basename $i  |  sed -e s/\.svg//g`
		   UNICODE=`./translate2 to ${FILENAME}`
		   echo "$FILENAME  $UNICODE"    
		done
	
如果没有问题,就用下面写的photo/4gen_pfaedit.sh来生成批量导入已给汉字的fontforge脚本(起名为fontforge_script.pe):
photo\4gen_pfaedit.sh:
		#!/bin/bash

		INDIR="5svg"

		OUTFILE="fontforge_script.pe"
		rm -f $OUTFILE

		echo "#!/cygdrive/d/temp2/fontforge"    >>  $OUTFILE
		echo ""    >>  $OUTFILE
		echo "Open(\"test.ttf\");"    >>  $OUTFILE

		for i in `ls $INDIR/*.svg` ; do
		   #echo $i
		   FILENAME2=`basename $i`
		   FILENAME=`basename $i  |  sed -e s/\.svg//g`
		   UNICODE=`./translate2 to ${FILENAME}`
		   echo "$FILENAME  $UNICODE"    
		   
		   
		   UNICODE="0u""$UNICODE"
		   
		   SELECT="Select(""$UNICODE"");"
		   echo $SELECT     >>  $OUTFILE
		   
		   
		   IMPORT="Import(\"""${FILENAME2}""\");"
		   echo $IMPORT     >>  $OUTFILE
		done

		echo "Generate(\"test.ttf\");"    >>  $OUTFILE

	

(6)最后要生成.ttf了
用很简单的fontforge脚本photo/new.pe来新建一个.ttf文件test.ttf:
		#!/cygdrive/d/temp2/fontforge

		New();
		Reencode("gb2312");
		Generate("test.ttf");
	
	
生成后别忘了上面提出的第二个问题,Charsets要加入选项936 Simplified Chinese。也可待会编辑后再加,但总归要加。似乎这是 我还必须手工、没能自动化的一步。

建立文件夹6ttf/,拷贝上述第(5)步得到的所有.svg文件,刚新建的test.ttf,和fontforge_script.pe脚本, 运行该脚本,即打开ttf文件,批量导入汉字相应的SVG,并产生编辑后的ttf文件。该脚本大致如下:
		#!/cygdrive/d/temp2/fontforge

		Open("test.ttf");
		Select(0u7a0b);
		Import("程.svg");
		Select(0u6863);
		Import("档.svg");
		Select(0u7b2c);
		Import("第.svg");
		Select(0u4e01);
		Import("丁.svg");
		Select(0u9ad8);
		Import("高.svg");
		Select(0u56fd);
		Import("国.svg");
                    …………
		Select(0u6587);
		Import("文.svg");
		Select(0u4e0b);
		Import("下.svg");
		Select(0u5e8f);
		Import("序.svg");
		Select(0u4e00);
		Import("一.svg");
                    …………
		Import("载.svg");
		Select(0u4e2d);
		Import("中.svg");
		Select(0u684c);
		Import("桌.svg");
		Generate("test.ttf");
	
	


安装该ttf,新建word文档编辑,效果图如下:
五号:
        
    
三号:
        
    
小四号:
        
    
小五号:
        
    


自动化流程跑通了。但对字体图像的效果不太满意。效果不好的原因在于BMP图像有太多噪点。所以想是否能自己生成比较光顺的SVG图像。 这就要了解一点SVG使用的Bezier曲线了。看potrace生成的是三次Bezier曲线,所以考虑三次的就可以了。

以前在大学学过《数值分析》,老师讲过Bezier曲线和B样条,当时还努力看过《计算几何》的相关内容,但现在具体都不记得了,再看这些书 也对照不起以前的理解。一些计算机图形学的书倒是有所涉及,如《计算机图形学原理及算法教程(Visual.Cpp版)》(和青芳)等。还有人推荐 陈元琰的《计算机图形学实用技术》和蔡士杰的《计算机图形学》。
Bezier曲线及B样条参考网址:
  • Bezier、B样条曲线曲面
  • B样条曲线(B-spline Curves)
  • Introduction to Geometric Modeling
  • B样条
  • 插值与样条
  • 计算机图形学--------充分理解B样条曲线
  • B-spline Curves 学习之B样条曲线定义(4)
  • B-spline Curves 学习之B样条基函数的定义与性质(2)
  • B-spline Curves 学习之前言
  • B-spline Basis Functions: Computation Examples
  • Bezier曲线、B样条和NURBS的基本概念
  • Hermit曲线、Bezier曲线、B样条曲线有什么关系?有什么区别?各自的应用范围?
  • 数学图形(1.47)贝塞尔(Bézier)曲线
  • 样条之贝塞尔(Bezier)
  • 贝塞尔曲线
  • Bezier曲线及实现代码
  • Bezier曲线原理及实现代码(c++)
  • Bezier曲线原理
  • 贝塞尔曲线——cubic-bezier详解
  • Bezier曲线的构建
  • 用Bezier绘制圆滑曲线
  • 贝塞尔曲线理论
  • 基于三次Bezier原理的曲线拟合算法C++与OpenCV实现
  • 平滑曲线生成:贝塞尔曲线拟合
  • Bezier曲线和BSpline曲线的拟合问题
  • 谈谈贝塞尔曲线
  • 怎样确定 Bezier 曲线的控制点
  • 三次Beizer曲线拟合算法
  • 分段连续三次Bezier曲线控制点的构造算法

  • 直接使用了上文之中《基于三次Bezier原理的曲线拟合算法C++与OpenCV实现》(这里有一个我保存的 拷贝)中的数据点拟合的生成三次Bezier曲线控制点的代码,在我写的试验文件 svg/文件夹下的gen_control_point.cpp中:
    		void get_control_points(double x0, double y0, double x1, double y1, double x2, double y2,  
    			double& p1x, double& p1y, double& p2x, double& p2y, double t)  
    		{  
    			double d01 = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));  
    			double d12 = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));  
    		  
    			double fa = t * d01 / (d01 + d12);  
    			double fb = t * d12 / (d01 + d12);  
    		  
    			p1x = x1 - fa * (x2 - x0);  
    			p1y = y1 - fa * (y2 - y0);  
    			p2x = x1 + fb * (x2 - x0);  
    			p2y = y1 + fb * (y2 - y0);  
    		  
    			return;  
    		}  
    	
    	
    算法试验完成,我就开始写从二值位图到SVG矢量字形的编辑制作工具的代码了,采用浏览器中的PHP(Windows10上安装Apache httpd 2.4.38和PHP 7 64位)。 这就是svg_2/文件夹下的1.php、2.php、3.php,这三个PHP文件处理的输入是in.bmp、in.svg,输出是out.svg。in0.svg是一个空的模板,in.svg可以从拷贝 in0.svg开始,生成的out.svg如要进入下一步处理可将其重命名为in.svg。 在2.php中我将上述生成控制点的C++代码改成了javascript代码。
    比如处理以下位图:
            
        
    下图是2.php正在运行的画面:
            
        
    生成效果图如:out.svg




    (制作试验过程中记录的一些草稿)
            
            
            
            
            
            
            
            
            
            
            
            
        

    svg_2/已有更新为svg_2_2/(更新了2.php),下载在这里


      

    More powered by