lhf 的窝

FreeType的光栅化功能

FreeType是一个字体格式开源工程。其中不但支持各种字体格式的解析,还提供了一个独立的光栅化引擎。

---------------------------下面的文字解释了什么是光栅化--------------------------------------------------------------------

现在流行的字体格式如TureType,Opentype等,其中描述的字形信息(就是字符的笔划信息)都是矢量的。

其中字符的每一个笔划都是由多条曲线或直线(直线可视为一次曲线)包围而形成的。一次曲线需要两个点来确定。

二次需要三个点,三次就需要四个点。字体内部就保存了这些点的坐标。显示字体的时候,因为显示器和打印机

都是点阵设备,所以必须将字符转化为用点阵来描述。这个过程就是光栅化。说白了,就是矢量描述转化为点阵描述。

不过字体的光栅化与与其它光栅化(如图形学中的Bresenham,DDA算法等)不同的是,它关心的是区域的点阵化,

即判断每个点属于那个区域。

----------------------------------------------------------------------------------------------------------------------------------------------

FreeType2.3.7实际提供了两个光栅化引擎。ft_grays_raster和ft_standard_raster。

分别位于:src\smooth\ftgrays.c 和 src\raster\ftraster.c 。二者的用法完全相同。FreeType自己用的是前者。

要想在FreeType之外独立使用两个引擎,我们分两个的步骤:

1、编译问题。把相关的文件加入工程,设置_STANDALONE_等宏。可能要修改代码,比如注释掉一些代码行等。

将int64_t 改为 __int64(for vc),等等。这些事,对于一个编程熟手来说,应该10分钟搞定了。我就不多啰嗦。

2、代码调用。主要的函数调用有三个: 

    ft_grays_raster.raster_new(memory,&raster);
    ft_grays_raster.raster_reset(raster,pool_base,pool_size);
    ft_grays_raster.raster_render(raster,&param);

   这三个调用中,头两个很easy。参数很简单: 

void*       memory = NULL;
FT_Raster   raster;

int    pool_size = 10240;
BYTE*  pool_base = new BYTE[pool_size];

ft_grays_raster.raster_new(memory,&raster);
ft_grays_raster.raster_reset(raster,pool_base,pool_size);

  第三个调用有点麻烦,先看一下参数param的如何设置: 

        FT_Raster_Params  param;

        param.target      = &bmp;
        param.source      = &outline;
        param.flags       = FT_RASTER_FLAG_AA;
        param.gray_spans  = NULL;
        param.black_spans = NULL;
        param.bit_test    = NULL;
        param.bit_set     = NULL;
        param.user        = NULL;

其中bmp和outline的定义如下: 

      FT_Bitmap bmp;   

      FT_Outline outline;

 这两个参数非常重要,一个是输出(位图格式),一个是输入(矢量格式)。

先看一下FT_Bitmap的格式,它描述了一个位图,其中的buffer是位图的位数据,是4字节对齐的,从上往下的数据(你必须先了解windows位图的格式才可以理解上面的话)。因此bmp应这样设置:

        FT_Bitmap bmp;

        bmp.width        = 16;//输出位图的size.
        bmp.rows         = 16;
        bmp.pitch        = 16;//每行需要的字节数,4字节对齐的.
        bmp.buffer       = new BYTE[bmp.rows*bmp.pitch];
        bmp.num_grays    = 256
        bmp.pixel_mode   = FT_PIXEL_MODE_GRAY;
        bmp.palette_mode = 0;
        bmp.palette      = NULL;

        memset(bmp.buffer,0,bmp.rows*bmp.pitch);

      FT_Outline的格式就比较复杂些。它描述了一系列的轮廓线。其n_contours和n_points成员是容易理解的,分别表示轮廓的数目和点的数目。轮廓指围成一个闭合区域的边界。比如字符”一“是一条轮廓,字符‘二’是两条轮廓。字符”十“是一条轮廓。对更复杂的字符,就不一定能直接看出有多少个轮廓,因为轮廓之间会有重叠。点的数目,是指末端点和首端点不重合情况下的数目。比如,对一个矩形,应该是4个端点,而不是5个。FreeType内部会自动将末端点连到首段点。

其它几个成员的含义如下: 

outline.points     = new FT_Vector[n_points];//点的坐标
outline.tags       = new char [n_points];    //每个点的类型.
outline.contours   = new short [n_contours]; //每条轮廓线占用的点数.
outline.flags      = FT_OUTLINE_OWNER|FT_OUTLINE_HIGH_PRECISION;

points,tags,contours描述了每条轮廓的具体数据。三者必须严格对应上。这三个数组的具体格式也就是本篇文章的意义所在了。

points数组,tags数组 一般可以从字体文件数据中得到。但是其中的单位可能会有不同。这个跟字体的格式有关。不行就多试几个比例值。只要看到任何一点输出(比如一个字的其中一个笔画),就离成功不远了,在附近多试几个比例值。很快就可以让字符和位图的大小能符合了。

contours数组描述了一个轮廓使用的点数。比如:

contours[0]如果为8,则表示points数组中,元素0-8,都是第一条轮廓线的。

然后point数组中,9-contours[1]都是第二条轮廓线的。

依次类推,第n条轮廓线的点是: contours[n-2]+1 到 contours[n-1] (其中n>=2)

很明显,最后一个轮廓线对应的 contours[x]元素,其值必定等于 n_points-1。因为points数组最后一个元素就是 points[n_points-1]。

如果不满足此条件,ft_grays_raster直接跳出,认为数据错误。