zoukankan      html  css  js  c++  java
  • freetype之PC机体验


    title: freetype之PC机体验
    date: 2019/03/03 00:07:56
    toc: true

    freetype之PC机体验

    引入

    本节代码仓库 https://gitee.com/layty/project_for_linux/tree/master/02-freetype

    一个完整的字体库由两个部分组成

    • charmap 编码,也就是索引,通过指定的编码找到具体要显示的字形,一个字体可能支持多种编码
    • glyph字形,这里指的是如何去描绘(比如贝塞尔曲线)这个具体的文字

    中文教程

    FreeType2 教程的第二部分

    freetype使用详解(中文)

    数据结构中文

    官方教程

    I. Simple Glyph Loading

    II. Managing Glyphs

    代码结构

    mark

    API手册

    I. Components and APIs

    II. Public Objects and Classes

    III. Internal Objects and Classes

    字体概念

    mark

    PC上安装

    #解压
    tar xjf freetype-2.4.10.tar.bz2
    #重命名
    mv freetype-2.4.10 freetype-2.4.10_pc
    #配置
    cd freetype-2.4.10_pc/
     ./configure
     #编译
     make
     #安装到根目录 /usr/local/
    sudo make install          
    
    
    book@100ask:~/stu/repo/demo_tar/freetype-2.4.10_pc$ ls /usr/local/lib/
    libfreetype.a   libfreetype.so    libfreetype.so.6.9.0  python2.7
    libfreetype.la  libfreetype.so.6  pkgconfig             python3.5
    
    book@100ask:~/stu/repo/demo_tar/freetype-2.4.10_pc$ ls /usr/local/include/
    freetype2  ft2build.h
    

    官方例子

    例子在freetype-doc-2.4.10.tar.bz2freetype-2.4.10docs utorial,直接编译报错缺少头文件

    In file included from example1.c:11:0:
    /usr/local/include/ft2build.h:56:38: fatal error: freetype/config/ftheader.h: 没有那个文件或目录
    compilation terminated.
    

    但实际上local下是有这个文件的

    ls /usr/local/include/freetype2/freetype/config
    ftconfig.h  ftheader.h  ftmodule.h  ftoption.h  ftstdlib.h
    

    我们可以编译的时候用-I指定头文件路径

    # gcc -o example example1.c  -I /usr/local/include/freetype2
    /tmp/ccNUBZti.o:在函数‘main’中:
    example1.c:(.text+0x25b):对‘FT_Init_FreeType’未定义的引用
    example1.c:(.text+0x284):对‘FT_New_Face’未定义的引用
    example1.c:(.text+0x29d):对‘FT_Set_Pixel_Sizes’未定义的引用
    example1.c:(.text+0x2c4):对‘cos’未定义的引用
    example1.c:(.text+0x2f5):对‘sin’未定义的引用
    example1.c:(.text+0x332):对‘sin’未定义的引用
    example1.c:(.text+0x363):对‘cos’未定义的引用
    example1.c:(.text+0x3b6):对‘FT_Set_Transform’未定义的引用
    example1.c:(.text+0x3de):对‘FT_Load_Char’未定义的引用
    example1.c:(.text+0x465):对‘FT_Done_Face’未定义的引用
    example1.c:(.text+0x471):对‘FT_Done_FreeType’未定义的引用
    collect2: error: ld returned 1 exit status
    

    这里提示没有库文件,这里需要使用-l直接库的名字没有空格

    #gcc -o example example1.c  -I /usr/local/include/freetype2 -lfreetype
    /tmp/cchpuAJt.o:在函数‘main’中:
    example1.c:(.text+0x2c4):对‘cos’未定义的引用
    example1.c:(.text+0x2f5):对‘sin’未定义的引用
    example1.c:(.text+0x332):对‘sin’未定义的引用
    example1.c:(.text+0x363):对‘cos’未定义的引用
    collect2: error: ld returned 1 exit status
    
    

    这里提示没有数学库,这里加上-lm,m表示数学

    # gcc -o example example1.c  -I /usr/local/include/freetype2 -lfreetype -lm
    
    

    运行之后提示帮助,需要一个字体文件,可以去win下的C:WindowsFonts找到新宋体

    $ ./example
    usage: ./example font sample-text
    

    这里发现屏幕看的不是很清楚,主要是因为程序里设置了显示的分辨率,也就是一行出现640个点

    #define WIDTH   640
    #define HEIGHT  480
    

    我们这里修改下大小,同时取消字体的旋转,否则也显示不出来

    #define WIDTH   80   #横向80个点
    #define HEIGHT  90	 #纵向90个点
    

    同时也要修改显示的位置

    /* the pen position in 26.6 cartesian space coordinates; */
    /* start at (0,40) relative to the upper left corner  */
    pen.x = 0 * 64;
    pen.y = ( target_height - 40 ) * 64;
    
    
    angle         = (0.0 / 360 ) * 3.14159 * 2;      /* 取消旋转*/
    

    这个实验有时候在mobaxtem中显示不太好,可以保存到文件然后去查看

    ./example  simsun.ttc 123
    # 保存到文件看
    ./example  simsun.ttc 123 >123.txt
    

    mark

    代码位置

    宽字符保存显示中文

    我们以前是这么保存中文的,这里处理的时候需要判断是中文,则取两个字符,如果是英文取出一个字符,非常不方便,所以这里引入了宽字符的概念,注意:wchar_t在windows占2byte,在linux4bytes.

    char * str1="中文and english"
    

    参考的网页

    #include <stdio.h>
    #include <wchar.h>
    
    int main(int argc,char *argv[])
    {
        int i;
        wchar_t* chinese_str = L"中文123";
        unsigned int *p =(wchar_t*)chinese_str;
        for(i=0;i<wcslen(chinese_str);i++)
        {
            printf("0x%x ",p[i]);
        }
        printf("
    ");
    }
    

    打印显示是unicode编码

    $ ./a.out
    0x4e2d 0x6587 0x31 0x32 0x33
    

    我这里保存的是utf-8的格式,如果保存的是gbk的,则需要加上指定输入文件编码

    -finput-charset=GBK 
    

    接着我们用freetype打印中文,加上这里的代码

    for ( n = 0; n < wcslen(chinese_str); n++ )
    {
    	error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );
    }
    

    mark

    坐标框架体系

    上面我们设置了字体是24*24像素的大小,那么它实际上怎么显示的呢,这里我们在代码上加入打印坐标

    void show_image( void )
    {
      int  i, j;
      for ( i = 0; i < HEIGHT; i++ )
      {
        printf("%02d",i);
        for ( j = 0; j < WIDTH; j++ )
          putchar( image[i][j] == 0 ? ' ': image[i][j] < 128 ? '+': '*' );
        putchar( '
    ' );
      }
    }
        
    

    我们再来看下我们是怎么设置显示位置的,位置是在(0,40)显示的

    FT_Set_Pixel_Sizes(face,24,0)
      /* the pen position in 26.6 cartesian space coordinates; */
      /* start at (0,40) relative to the upper left corner  */
    pen.x = 0 * 64;
    pen.y = ( target_height - 40 ) * 64;
    

    但是很明显原点并不在这里

    mark

    为什么会这样,并且可以看出来,字符显示会到原点的下方?

    可以这么理解,我们先看下如下的字母,gpq等都在下方有显示,上图也能看出a的左下起始也是在横轴40的位置左右,实际上我们可以理解为基线.

    mark

    为了兼容中文英文以及其他字符,实际的画图是下面这样的

    mark

    advance有横向的也有纵向的数值,比如斜着的时候

    mark

    具体的代码我们是这么体现的,在写一个字符的时候

    slot = face->glyph;
    ....
    /* increment pen position */
    pen.x += slot->advance.x;
    pen.y += slot->advance.y;
    

    字符坐标信息获取

    那么我们如何得到字符的其他信息,比如ymax等,参考文档tutorial中可以看到Measuring the Glyph Image章节

      FT_EXPORT( void )
      FT_Glyph_Get_CBox( FT_Glyph  glyph,
                         FT_UInt   bbox_mode,
                         FT_BBox  *acbox );
    

    注意第一个参数是FT_Glyph,而我们之前是使用FT_GlyphSlot来转换成位图的.

    mark

    注意 我们提取本次字符的形状数据后,也就是获得字形槽后,上次的字形槽数据就被冲掉了,那么我们如何去获取上次的字形数据呢?

    参考 2. Managing Glyph Images

    #include FT_GLYPH_H
    
    FT_Glyph  glyph; /* a handle to the glyph image */
    
    
    ...
    error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NORMAL );
    if ( error ) { ... }
    
    error = FT_Get_Glyph( face->glyph, &glyph );   //从之前的插槽中取出FT_Glyph
    if ( error ) { ... }
    
    //--------实际代码如下--------------------------------------------
    /* load glyph image into the slot (erase previous one) */
    error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );
    if ( error )
        continue;                 /* ignore errors */
    /* now, draw to our target surface (convert position) */
    
    error = FT_Get_Glyph( face->glyph, &glyph );
    if (error) {
        printf("load from face->glyph is failed
    ");
        return -1;
    }
    FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );
    printf("
    
    unicode is %x
    ",chinese_str[n]);
    printf("lcd offset is [x]=%d,[y]=%d
    ",slot->bitmap_left,target_height - slot->bitmap_top);
    
    printf("[pen.x]=%ld,[pen.y]=%ld
    ",pen.x/64,pen.y/64);
    printf("glyph [xMin]=%ld,[yMin]=%ld,[xMax]=%ld,[ymax]=%ld
    ",bbox.xMin,bbox.yMin,bbox.xMax,bbox.yMax);
    printf("advance.x/64=%ld,y.advance/64=%ld
    ",slot->advance.x/64,slot->advance.y/64);// unit is 1/64 pixel
    
    

    我们可以打印出来看一下,这里加入笛卡尔的坐标打印

    可以看出来这里的韦字宽度是23,有点奇怪不是24哈哈 不过也是在框里的

    下一个字符的原点就是上一个字符的原点加上一个字符的advance

    # 韦的宽度是23长度是24
    unicode is 97e6
    lcd offset is [x]=1,[y]=20
    [pen.x]=0,[pen.y]=50
    glyph [xMin]=1,[yMin]=47,[xMax]=23,[ymax]=70
    advance.x/64=24,y.advance/64=0
    
    
    unicode is 4e2d
    lcd offset is [x]=27,[y]=20
    [pen.x]=24,[pen.y]=50
    glyph [xMin]=27,[yMin]=47,[xMax]=46,[ymax]=70
    advance.x/64=24,y.advance/64=0
    
    # a字母的宽度是12,长度是12
    unicode is 61
    lcd offset is [x]=49,[y]=29
    [pen.x]=48,[pen.y]=50
    glyph [xMin]=49,[yMin]=50,[xMax]=60,[ymax]=61
    advance.x/64=12,y.advance/64=0
    
    

    mark

  • 相关阅读:
    pythonldap 简单试用
    shell 将文件名读入数组
    pytest命令行传入自定义的参数到测试文件中
    Python实现在不同Linux主机之间拷贝文件
    使用minio搭建私有化对象存储服务
    CPU/GPU/NPU
    pytest 内置和自定义marker
    安装SQLite3引发的库问题
    C标准库——程序员等级
    这样还弄不死指针?
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10492463.html
Copyright © 2011-2022 走看看