• 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即可,具体字体的颜色另外绘图指定即可.

  • 相关阅读:
    Redis简单实践-分布式锁
    Redis基础数据结构
    Redis介绍
    MakeGenericType方法,运行时传入泛型T参数,动态生成泛型类
    Visual Studio 2017 Ctrl+单击键会跳转到定义的设置
    10 分钟 创建分布式微服务
    nodejs 中自定义事件
    我是这么给娃娃取名的(使用 node.js )
    使用 Fiddler 上传微信公众账号 自定义菜单
    drf_yasg 简单使用
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10492480.html
Copyright © 2020-2023  润新知