zoukankan      html  css  js  c++  java
  • freetypeLCD显示


    title: freetypeLCD显示
    date: 2019/03/03 13:34:02
    toc: true

    freetypeLCD显示

    安装交叉编译环境

    参考文档 : 代码中的docs/INSTALL.CROSS

    #解压
    $ mkdir freetype-2.4.10_arm
    $ tar xjf freetype-2.4.10.tar.bz2 -C ./freetype-2.4.10_arm
    #查看说明 docs/INSTALL.CROSS
    cd docs/
    vi INSTALL.CROSS
    

    配置

    ./configure --host=arm-linux  --prefix=$PWD/tmp  //配置交叉编译,安装前缀
    make 
    make install
    --host 运行位置
    --prefix 安装前缀
    

    头文件和库的位置

    查看下交叉编译工具的位置

    book@100ask:docs$ echo $PATH
    /home/book/bin:/home/book/.local/bin:/opt/slickedit-pro2017/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin/:/opt/smartgit/bin/:/snap/bin
    book@100ask:docs$
    
    # /usr/local/arm/4.3.2/bin/
    

    看下编译工具的头文件是怎么放的,应该是要放到

    book@100ask:4.3.2$ pwd
    /usr/local/arm/4.3.2
    
    book@100ask:4.3.2$ ls
    arm-none-linux-gnueabi  bin  lib  libexec  share
    
    book@100ask:4.3.2$ find -name include
    ./arm-none-linux-gnueabi/include
    ./arm-none-linux-gnueabi/libc/usr/include
    ./lib/gcc/arm-none-linux-gnueabi/4.3.2/install-tools/include
    ./lib/gcc/arm-none-linux-gnueabi/4.3.2/include
    
    
    book@100ask:4.3.2$ find -name stdio.h
    ./arm-none-linux-gnueabi/include/c++/4.3.2/tr1/stdio.h
    ./arm-none-linux-gnueabi/libc/usr/include/bits/stdio.h
    ./arm-none-linux-gnueabi/libc/usr/include/stdio.h
    
    

    所以头文件应该是在这个位置

    /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
    

    查看下库的位置

    
    book@100ask:4.3.2$ find -name lib
    ./arm-none-linux-gnueabi/lib
    ./arm-none-linux-gnueabi/libc/usr/lib
    ./arm-none-linux-gnueabi/libc/armv4t/usr/lib
    ./arm-none-linux-gnueabi/libc/armv4t/lib
    ./arm-none-linux-gnueabi/libc/lib
    ./arm-none-linux-gnueabi/libc/thumb2/usr/lib
    ./arm-none-linux-gnueabi/libc/thumb2/lib
    ./lib
    
    

    库文件是在这个位置

    /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
    

    编译安装

    我们可以在配置的时候指定prefix,也可以在make install时指定安装位置

    book@100ask:freetype-2.4.10_arm$ cd freetype-2.4.10/
    book@100ask:freetype-2.4.10$ mkdir tmp
    book@100ask:freetype-2.4.10$ ./configure  --host=arm-linux
    
    book@100ask:freetype-2.4.10$make
    book@100ask:freetype-2.4.10$make DESTDIR=$PWD/tmp install 
    book@100ask:tmp$ ls
    usr
    
    

    最终的目录结构在tmp下这样的

    bin
    include
    	-freetype2
    		-....h
    	-ft2build.h
    lib
    	-libfreetype.a
    	-libfreetype.la
    	-libfreetype.so
    	-libfreetype.so.6
    	-libfreetype.so.6.9.0
    	-pkgconfig
    share
    

    复制到PC编译工具链

    # -d 保持链接属性
    sudo cp ./include/*  /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include  -rfd
    sudo cp ./lib/* /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib -rfd
    

    复制到文件系统

    这里只需要复制库,不需要头文件,头文件是在编译阶段被读取的,运行阶段只需要库就可以了

    cp ../../../demo_tar/freetype-2.4.10_arm/freetype-2.4.10/tmp/usr/local/lib/*.so /usr/lib/ -rfd
    

    运行测试

    ./example simsun.ttc 123
    

    LCD显示

    编码转换问题

    编译的时候提示

    cc1: error: failure to convert GBK to UTF-8
    

    查看下具体的帮助

    **-finput-charset=***charset*

    Set the input character set, used for translation from the character set of the input file to the source character set used by GCC . If the locale does not specify, or GCC cannot get this information from the locale, the default is UTF-8 . This can be overridden by either the locale or this command line option. Currently the command line option takes precedence if there's a conflict. charset can be any encoding supported by the system's "iconv" library routine.

    也就是说我们尝试使用命令来转换这个文件,

    iconv -f GBK -t UTF-8 show_font.c
    #没有-o选项 将转换后的utf-8格式打印到控制台
    

    这就会提示哪里不能转换,我们依次修改

    /* 128 0x80 'iconv: 未知 50380 处的非法输入序列
    

    接着修改makefile就可以顺利编译了

     arm-linux-gcc  -finput-charset=GBK -fexec-charset=GBK  -o show  show_font.c  -I /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include/freetype2 -lfreetype -lm
    

    简单显示

    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;
    
          //image[j][i] |= bitmap->buffer[q * bitmap->width + p];
          lcd_put_pixel(i,j,bitmap->buffer[q * bitmap->width + p]);
        }
      }
    }
    
    
    
    void ShowByFreetype(int argc,char **argv,int x ,int y )
    {
    
        FT_Library    library;
        FT_Face       face;
    
        FT_GlyphSlot  slot;
        FT_Matrix     matrix;                 /* transformation matrix */
        FT_Vector     pen;                    /* untransformed origin  */
        FT_Error      error;
        FT_Glyph  glyph;
        FT_BBox  bbox;
        int           target_height;
        int           n, num_chars;
    
        wchar_t * chinese_str=L"韦中aghp";
    
        if (argc!=2) {
            printf("Usage : %s <font_file>
    ",argv[0]);
            return ;
        }
    
    
        error = FT_Init_FreeType( &library );              /* initialize library */
        error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
        error = FT_Set_Pixel_Sizes(face,24,0);
    
        pen.x=x*64;
        pen.y=y*64;
    
        target_height=var.yres;
        slot = face->glyph;
    
        for ( n = 0; n < wcslen(chinese_str); n++ )
        {
          /* set transformation */
          FT_Set_Transform( face, 0, &pen );
    
          /* 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) */
    
    
          draw_bitmap( &slot->bitmap,
                       slot->bitmap_left,
                       target_height - slot->bitmap_top );
    
          /* increment pen position */
          pen.x += slot->advance.x;
          pen.y += slot->advance.y;
        }
    
        FT_Done_Face    ( face );
        FT_Done_FreeType( library );
    
    }
    
    
    int main(int argc, char **argv)
    {
    ....
        printf("chinese code: %02x %02x
    ", str[0], str[1]);
    	lcd_put_chinese(var.xres/2 + 8,  var.yres/2, str);
    	
        // 上面 var.xres/2 + 8  var.yres/2 是中文字的原点坐标 位于左上角
        
    	/* 确定座标:
    	 * lcd_x = var.xres/2 + 8 + 16    这里加16是因为 我们lcd之前用点阵的原点是左上角,现在笛卡尔坐标是左下角,差了16
    	 * lcd_y = var.yres/2 + 16
    	 * 笛卡尔座标系:
    	 * x = lcd_x = var.xres/2 + 8 + 16
    	 * y = var.yres - lcd_y = var.yres/2 - 16
    	 */
        ShowByFreetype(argc,argv,var.xres/2 + 8 + 16,var.yres/2 - 16);
    
    }
    

    角度旋转

    这里我们用第三个参数指定角度,使用strtoul来转换角度

    if (argc!=3) {
    printf("Usage : %s <font_file> angle 
    ",argv[0]);
    return ;
    }
    
    angle         = (1.0*strtoul(argv[2],NULL,0) / 360 ) * 3.14159 * 2;      /* use 25 degrees     */
    /* set up matrix */
    matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
    matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
    matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
    matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
    
    
    FT_Set_Transform( face, &matrix, &pen );
    

    测试如下

    ./show simsun.ttc  45
    ./show simsun.ttc  180
    

    mark

    这里会发现有遮挡,我们换个底色看一下

    mark

    解决方法可以见下一个文档05-freetype字形解析,刷新新字的时候如果颜色是0的时候要跳过去,不刷新

    换行显示

    所谓换行,也就是计算y的坐标

    x坐标我们可以用上一个字符的advanxe的x计算,y的坐标我们需要计算上一行字符advance.y的最大值来确定

    也就是通过FT_Glyph_Get_CBox来统计最小的yMin和最大的yMax,下一行的y就在最小的min-24即可,

    // 将槽转换为glyph
    FT_Get_Glyph( face->glyph, &glyph );
    //从glyph 提取边界信息
    FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );
    if (line_box_ymin > bbox.yMin)
        line_box_ymin = bbox.yMin;
    if (line_box_ymax < bbox.yMax)
        line_box_ymax = bbox.yMax;
    
    

    老师的代码是这么计算的line_box_ymax - line_box_ymin + 24也就是减去了整个边框的大小

    	/* 确定座标:
    	 * lcd_x = 0
    	 * lcd_y = line_box_ymax - line_box_ymin + 24
    	 * 笛卡尔座标系:
    	 * x = lcd_x = 0
    	 * y = var.yres - lcd_y = var.yres - (line_box_ymax - line_box_ymin + 24)
    	 */
    	pen.x = 0 * 64;
    	pen.y = (var.yres - (line_box_ymax - line_box_ymin + 24)) * 64;
    

    但是实际上从图上看出来,只有ymin才是在原点的下方的,所以可以这样

    	pen.x = 0 * 64;
    	pen.y = (line_box_ymin - 24) * 64;
    

    mark

    居中显示

    参考网址 https://www.freetype.org/freetype2/docs/tutorial/step2.html

    中文文档 第11页:https://wenku.baidu.com/view/060a0b44f12d2af90342e63a.html?from=search

    所谓居中显示,就是先计算字符长度,然后计算出原点的位置

    mark

    也就是先得到这一行字的所有外观数据,存起来,再去一次性去渲染显示它,流程简述如下

    1. 通过要显示的str 填充具体的 编码,外观(矢量信息),位置信息(基于(0,0)),统一用glyphs[]管理
    2. 遍历所有的外观,计算最大最小的框架信息
      这里得到的虽然是每个边框的信息,但是统计他们的最大最小也就是整体边框的最大最小点了
    3. 计算居中的位置pen
    4. 绘图
      1. 调整外观数据到具体的显示的位置
        FT_Glyph_Transform(glyphs[n].image, 0, &pen);
      2. 转换成位图
        FT_Glyph_To_Bitmap
      3. 显示位图
        draw_bitmap
    5. 内存销毁等
      FT_Done_Glyph

    注意

    这里需要调整两次位置信息

    • 第一次是在保存到全局数组的外观时,产生行数据是基于pen在(0,0)的位置FT_Glyph_Transform
    • 第二次是实际转换位图前,将实际的pen的位置与之前的位置计算偏移

    完整代码

    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <linux/fb.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    
    #include <string.h>
    #include <math.h>
    #include <wchar.h>
    #include <ft2build.h>
    #include <stdlib.h>
    #include FT_FREETYPE_H
    #include FT_GLYPH_H
    
    int fd_fb;
    struct fb_var_screeninfo var;	/* Current var */
    struct fb_fix_screeninfo fix;	/* Current fix */
    int screen_size;
    unsigned char *fbmem;
    unsigned int line_width;
    unsigned int pixel_width;
    
    
    /* color : 0x00RRGGBB */
    void lcd_put_pixel(int x, int y, unsigned int color)
    {
    	unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;
    	unsigned short *pen_16;	
    	unsigned int *pen_32;	
    
    	unsigned int red, green, blue;	
    
    	pen_16 = (unsigned short *)pen_8;
    	pen_32 = (unsigned int *)pen_8;
    
    	switch (var.bits_per_pixel)
    	{
    		case 8:
    		{
    			*pen_8 = color;
    			break;
    		}
    		case 16:
    		{
    			/* 565 */
    			red   = (color >> 16) & 0xff;
    			green = (color >> 8) & 0xff;
    			blue  = (color >> 0) & 0xff;
    			color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
    			*pen_16 = color;
    			break;
    		}
    		case 32:
    		{
    			*pen_32 = color;
    			break;
    		}
    		default:
    		{
    			printf("can't surport %dbpp
    ", var.bits_per_pixel);
    			break;
    		}
    	}
    }
    
    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;
    
          //image[j][i] |= bitmap->buffer[q * bitmap->width + p];
          lcd_put_pixel(i,j,bitmap->buffer[q * bitmap->width + p]);
        }
      }
    }
    
    
    
    typedef struct TGlyph_ { 
    	FT_UInt index; /* glyph index  字符编码*/ 
    	FT_Vector pos; /* glyph origin on the baseline   以(0,0)为原点的偏移点*/ 
    	FT_Glyph image; /* glyph image 矢量外观/*/                      
    } TGlyph, *PGlyph; 
    
    TGlyph g_glyphs[100];
    
    int Get_Glyphs_Frm_Wstr(FT_Face face, wchar_t * wstr, TGlyph glyphs[])
    {
        int n;
        TGlyph * glyph = glyphs;
        FT_GlyphSlot  slot = face->glyph;
        int pen_x = 0;
    	int pen_y = 0;
    	int error;
    
        //get encode 
        for (n = 0; n < wcslen(wstr); n++)
    	{
    		glyph->index = FT_Get_Char_Index( face, wstr[n]); 
    		/* store current pen position */ 
    		glyph->pos.x = pen_x; 
    		glyph->pos.y = pen_y;
    
            /* load时是把glyph放入插槽face->glyph */
    		error = FT_Load_Glyph(face, glyph->index, FT_LOAD_DEFAULT);
    
            FT_Get_Glyph(face->glyph, &glyph->image ); 
    
            /* translate the glyph image now */ 
    		/* 这使得glyph->image里含有位置信息 */
            // by layty  这里加入了pen 的位置信息
    		FT_Glyph_Transform(glyph->image, 0, &glyph->pos );
    
    		pen_x += slot->advance.x;  /* 1/64 point */
    
    		/* increment number of glyphs */ 
    		glyph++;
        }
        return n;
    }
    
    void calc_all_bbox(TGlyph glyphs[], int num_glyphs, FT_BBox *abbox )
    {
    	FT_BBox bbox; 
    	int n;
    	
    	bbox.xMin = bbox.yMin = 32000; 
    	bbox.xMax = bbox.yMax = -32000;
    
    	for ( n = 0; n < num_glyphs; n++ )
    	{
    		FT_BBox glyph_bbox;
    		
    		FT_Glyph_Get_CBox(glyphs[n].image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox );
    
    		if (glyph_bbox.xMin < bbox.xMin)
    			bbox.xMin = glyph_bbox.xMin;
    
    		if (glyph_bbox.yMin < bbox.yMin)
    			bbox.yMin = glyph_bbox.yMin;
    
    		if (glyph_bbox.xMax > bbox.xMax)
    			bbox.xMax = glyph_bbox.xMax;
    
    		if (glyph_bbox.yMax > bbox.yMax)
    			bbox.yMax = glyph_bbox.yMax;
    	}
    
    	*abbox = bbox;
    }
    
    void Draw_Glyphs(TGlyph glyphs[], int num_glyphs, FT_Vector pen)
    {
    	int n;
    	int error;
    	
    	for (n = 0; n < num_glyphs; n++)
    	{
            /**/
    		FT_Glyph_Transform(glyphs[n].image, 0, &pen);
    		/* convert glyph image to bitmap (destroy the glyph copy!) */ 
    		error = FT_Glyph_To_Bitmap(&glyphs[n].image, FT_RENDER_MODE_NORMAL, 0, /* no additional translation */ 
                                  		1 ); 		/* destroy copy in "image" */
    		if ( !error ) 
    		{ 
    			FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[n].image; 
    			draw_bitmap(&bit->bitmap, bit->left, var.yres - bit->top); 
    			FT_Done_Glyph(glyphs[n].image ); 
    		}
    	}
    }
    
    
    void ShowByFreetype(int argc,char **argv)
    {
    
        FT_Library    library;
        FT_Face       face;
        FT_Glyph  glyph;
    
        FT_GlyphSlot  slot;
        FT_Vector     pen;                    /* untransformed origin  */
        FT_Error      error;
    
        int           n;
    
        FT_BBox bbox;
    
    	int line_box_width;
    	int line_box_height;
    
    
        wchar_t * str_dis[]={
            L"韦中aghp",
            L"你1 www.baidu.com",
            L"你2 www.baidu.com",
            L"你3 www.baidu.com",
            L"你4 www.baidu.com",
        };
    
        // str[0][...]
        // str[1][...]
    
    
        wchar_t * pt=( wchar_t *)&str_dis[0];
        int line;
    
        if (argc!=2) {
            printf("Usage : %s <font_file>  
    ",argv[0]);
            return ;
        }
    
        error = FT_Init_FreeType( &library );              /* initialize library */
        error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
        error = FT_Set_Pixel_Sizes(face,24,0);
    
    
        printf("size of str=%d",sizeof(str_dis)/sizeof(wchar_t *));
    
        for (line=0;line<sizeof(str_dis)/sizeof(wchar_t *);line++) {
            n = Get_Glyphs_Frm_Wstr(face, str_dis[line], g_glyphs);
            calc_all_bbox(g_glyphs, n, &bbox);
            line_box_width  = bbox.xMax - bbox.xMin;
        	line_box_height = bbox.yMax - bbox.yMin;
        	pen.x = (var.xres - line_box_width)/2 * 64;
        	pen.y = ((var.yres - line_box_height)/2-line*24) * 64;
            Draw_Glyphs(g_glyphs, n, pen);
            ;
        }
    
        FT_Done_Face    ( face );
        FT_Done_FreeType( library );
    
    }
    
    
    int main(int argc, char **argv)
    {
    	unsigned char str[] = "中";
    	
    
    	fd_fb = open("/dev/fb0", O_RDWR);
    	if (fd_fb < 0)
    	{
    		printf("can't open /dev/fb0
    ");
    		return -1;
    	}
    
    	if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
    	{
    		printf("can't get var
    ");
    		return -1;
    	}
    
    	if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))
    	{
    		printf("can't get fix
    ");
    		return -1;
    	}
    
    	line_width  = var.xres * var.bits_per_pixel / 8;
    	pixel_width = var.bits_per_pixel / 8;
    	screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
    	fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
    	if (fbmem == (unsigned char *)-1)
    	{
    		printf("can't mmap
    ");
    		return -1;
    	}
    
    
    	/* 清屏: 全部设为黑色 */
    	memset(fbmem, 0, screen_size);
    
    
        /* 
            
            0 ---------------------->var.xres
            |
            |
            |           lcd 
            |
            |
            var.yres
            ^
            |
            |   
            |       freetype
            |
            |
            0--------------------->var.xres
        */
    
    
    
    
        /* 
             we set pen to first line , is to (0,24)  unit is 1/64 pixel
    	 */
        ShowByFreetype(argc, argv);
    
    	return 0;	
    }
    

    代码仓库

    移植到arm上的显示 到串口

    LCD 显示

    LCD换行显示

    LCD居中显示

  • 相关阅读:
    字体颜色和字体样式的演示
    消息的测试
    java泛型例子
    python画太阳花
    列出进程界面
    画蟒蛇
    同切圆的绘制
    IDEA 2019.3.1永久破解
    springMVC ——Controller配置方式
    SpringMVC——JSR303的数据校验Hibernate Validator方式实现
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10492469.html
Copyright © 2011-2022 走看看