freetype 字形解析


title: freetype 字形解析
date: 2019/3/7 20:17:46
toc: true

freetype 字形解析

字体管理

管理字形,这里可以拆分为两个部分,一部分为管理字距,一部分为有效数据(位图信息).

比如字母g,蓝色框里的是有效的位图信息,但是排版的时候,是需要考虑字距的,否则虽然不重叠,但是不太好看.

mark

mark

数据结构

这里记住一个点

我们一般都是先转换到字符到字形槽,然后从字形槽提取位图,提取边界bbox

https://www.freetype.org/freetype2/docs/reference/ft2-index.html

这里有两个结构去描述

位图描述

  typedef struct  FT_Bitmap_
  {
    unsigned int    rows;	
    unsigned int    width;	
    int             pitch;	
    unsigned char*  buffer;
    unsigned short  num_grays;
    unsigned char   pixel_mode;
    unsigned char   palette_mode;
    void*           palette;

  } FT_Bitmap;

位图的定位点描述在字形槽里

  //字形槽
  typedef struct  FT_GlyphSlotRec_
  {
    FT_Library        library;
    FT_Face           face;
    FT_GlyphSlot      next;
    FT_UInt           reserved;       /* retained for binary compatibility */
    FT_Generic        generic;

    FT_Glyph_Metrics  metrics;
    FT_Fixed          linearHoriAdvance;
    FT_Fixed          linearVertAdvance;
    FT_Vector         advance;				//下个边界的原点

    FT_Glyph_Format   format;

    FT_Bitmap         bitmap;				//位图的描述
    FT_Int            bitmap_left;			//位图的左上角点
    FT_Int            bitmap_top;			//位图的左上角点

    FT_Outline        outline;

    FT_UInt           num_subglyphs;
    FT_SubGlyph       subglyphs;

    void*             control_data;
    long              control_len;

    FT_Pos            lsb_delta;
    FT_Pos            rsb_delta;

    void*             other;

    FT_Slot_Internal  internal;

  } FT_GlyphSlotRec;

位置的边界需要去手动获取

这里的参数是FT_Glyph glyph,可以由face中的槽来转换

//从face的字形槽中取得字形
//FT_EXPORT( FT_Error )FT_Get_Glyph( FT_GlyphSlot  slot,FT_Glyph     *aglyph );
//字形描述
  typedef struct  FT_GlyphRec_
  {
    FT_Library             library;
    const FT_Glyph_Class*  clazz;
    FT_Glyph_Format        format;
    FT_Vector              advance;

  } FT_GlyphRec;
error = FT_Get_Glyph( face->glyph, &glyph );

//从字形中取得bbox边界
FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );
  FT_EXPORT( void )
  FT_Glyph_Get_CBox( FT_Glyph  glyph,
                     FT_UInt   bbox_mode,
                     FT_BBox  *acbox );

//传入参数
  typedef struct  FT_GlyphRec_
  {
    FT_Library             library;
    const FT_Glyph_Class*  clazz;
    FT_Glyph_Format        format;
    FT_Vector              advance;

  } FT_GlyphRec;
// 传出参数
  typedef struct  FT_BBox_
  {
    FT_Pos  xMin, yMin;
    FT_Pos  xMax, yMax;

  } FT_BBox;

字体抽象

刚开始我想抽象出位图信息

长 
宽 
每个像素的bpp 
换行像素位置 
位图数据地址

那么除非我自己去控制字距,同时需要统计这一行的高度,来确定下一行文字的位置,但是这可能会排版成拥挤的上对齐,或者手动计算位图的大小,去布局,比如先设计一个32*32的边界,然后根据这个位图的大小居中摆放…想想就麻烦,而且这样的话设计字体旋转就没辙了

mark

再仔细看下freetype的布局,其实是创建了一个布局,接着再看下旋转,我们实际刷新数据的时候,一般还是从左到右,从上到下刷新点,没有颜色的数据应该不去刷新,我们看下之前的字体旋转,可以发现是遮挡了的,所以遇到没有颜色的数据,应该去跳过这些点,而不是去绘图.

蓝色框是点阵图,我们刷新像素的位置

红色框是边界,用来描述布局的

mark

我们之前的绘图是这样的

void draw_bitmap( FT_Bitmap*  bitmap,
             FT_Int      x,
             FT_Int      y)
{
  FT_Int  i, j, p, q;
  FT_Int  x_max = x + bitmap->width;
  FT_Int  y_max = y + bitmap->rows;
  for ( i = x, p = 0; i < x_max; i++, p++ )
  {
    for ( j = y, q = 0; j < y_max; j++, q++ )
    {
      if ( i < 0      || j < 0       ||
           i >= var.xres || j >= var.yres )
        continue;
		
      // 添加下面这句话即可  
      // if(bitmap->buffer[q * bitmap->width + p])
      lcd_put_pixel(i,j,bitmap->buffer[q * bitmap->width + p]);
    }
  }
}

这里对所有点都进行重绘,所以理论上应该会有字符的遮盖,上一节的实验也确实如此,可以看到h会把a遮挡了

mark

修改下代码,判断如果没有颜色,则不需要描点即可,这里可以设置freetype的bpp是1即可,具体字体的颜色另外绘图指定即可.

原文地址:https://www.cnblogs.com/zongzi10010/p/10492480.html