zoukankan      html  css  js  c++  java
  • 2.3freetype矢量字体

    1.简介

    将汉字的笔划边缘用直线段描述成封闭的曲线,并将线段各端点的坐标经压缩存储 
    矢量字库由两部分组成,一部分是汉字的索引信息,一部分是汉字的字形(glyph)数据
    当显示文字时,便取出各端点,并通过贝塞尔曲线连接各坐标,最后填充封闭空间
    

    2.freetype在电脑上的体验

    PC上安装到(/usr/local/)

    1.解压
        tar -xjf freetype-2.4.10.tar.bz2
    2.重命名
        mv freetype-2.4.10   freetype-2.4.10_pc
    3.配置
        cd freetype-2.4.10_pc
        ./configure
    4.编译
        make
    5.安装到根目录
        sudo make install      //直接将库安装到根目录/usr/local/里,所以需要加sudo
    

    编译文件时

    eg:编译例程:example1.c(关于freetype的代码)
        gcc -o example1 example1.c  -I /usr/local/include/freetype2/   -lfreetype  -lm
    解析:
        -I /usr/local/include/freetype2/    指定头文件目录
        -lfreetype  -lm                     链接文件,链接freetype库中的函数;链接数学库中的函数
    

    运行

    eg:
        ./example1   simsun.ttc  agf        /*    运行example1,使用宋体。显示agf    */
        宋体:链接:https://pan.baidu.com/s/12c8IR4phYh2ZITTGojSfHg 
    

    提取码:82wo

    3.安装freetype到交叉编译目录中去(供arm-linux-gcc编译)

    1.查看arm-linux-gcc的位置

    a.通过$PATH找到arm-linu-gcc交叉编译位于:
        /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/bin
    然后进入.../arm/4.3.2/目录,通过find查找stdio.h文件,找到:
    

    所以编译出来的头文件应该放入:
        /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
    b.通过find查找lib,找到:
    

    由于ARM9属于ARMv4T架构,所以编译出来的库文件应该放入:
    /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
    

    2.安装

    1.解压

    mkdir freetype-2.4.10_arm
    tar -xjf freetype-2.4.10.tar.bz2 -C ./freetype-2.4.10_arm
    注:
        -C 指定目录
    

    2.配置

    cd freetype-2.4.10_arm
    mkdir tmp        // 创建安装的临时目录,后面会拷贝到交叉编译目录里
    ./configure --host=arm-linux  --prefix=$PWD/tmp  //配置交叉编译,安装前缀
    注:
        --host=arm-linux        编译出来的程序是在arm-linux下使用
        --prefix=$PWD/tmp       --prefix指定安装路径。配置交叉编译器安装前缀
    

    3.编译安装

    make
    make DESTDIR=$PWD/tmp install    
    

    4.拷贝

    cd tmp/
    cp  ./include/*  /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include/ -rfd         //将include下的头文件拷贝到交叉编译里去
    cp lib/*  /work/tools/arm-linux-gcc-4.3.2/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/  -rfd               //将lib下的库文件拷贝到交叉编译里去
    cp lib/ * /work/nfs_root/3.4_fs_mini_mdev/lib/  -rfd    //将lib下的库文件拷贝到nfs文件系统去
    

    2.如何使用freetype

    1.包含头文件
    2.加载初始化库
    3.加载face对象
    4.设置字体的大小,位置等
    5.1获取编码
    5.2通过编码获取到字符图像,存到字形槽glygph slot
        字形槽:每次只能存储一个图像
        每个face对象都有一个字形槽,位于face->glyph
    6.转换位图
    

    1.包含头文件

        #include <ft2build.h>
        #include FT_FREETYPE_H
    

    2.加载初始化库

        使用FT_Init_FreeType()函数初始化一个FT_Library类型的变量
        eg:
            FT_Library library;                // 库的句柄
            error = FT_Init_FreeType(&library);
            if(error)
            {
                /*    初始化失败    */
            }
    

    3.加载face对象

        通过FT_New_Face()打开一个字体文件,然后提取该文件的一个FT_Face类型的Face变量
        eg:
            FT_Library library;        // 库的句柄
            FT_Face    face;           // face对象的句柄
            error = FT_Init_FreeTyte(&library)
            if(error)
            {
                ...
            }
            ...
            error = FT_New_Face(library, "usr/share/fonts/truetype/arial.ttf", 0, &face);
            注释:usr/share/fonts/truetype/arial.ttf。这里是字形文件。这里我们是上传的自己找到的字体文件
    

    4.1设置字体的大小

        方法一:
        FT_Set_Char_Size(FT_Face    face, 
                         FT_F26Dot6 char_width,         // 字符宽度,单位为1/64点
                         FT_F26Dot6 char_height,        // 字符高度,单位为1/64点
                         FT_UInt     horz_resolution,   // 水平分辨率
                         FT_UInt     vert_resolution ); // 垂直分辨率
        字符宽度和高度以1/64点为单位表示。点是物理上的距离。一个点代表1/72英寸。1/64像素,所以乘64表示一个点
        分辨率以dpi为单位表示,表示一个英寸有多少像素
        eg:
            error = FT_Set_Char_Size( face, 50 * 64, 0,100, 0 );    //0表示与另一个尺寸值相等
            解析:
                字符的物理大小为:50 * 64 *(1/64)*(1/72)
                字符与的像素位:50 * 64*(1/64)*(1/72)*100
        方法二:
        FT_Set_Pixel_Sizes(   FT_Face  face,
                              FT_UInt  pixel_width,     //像素宽度
                              FT_UInt  pixel_height );  //像素高低
        eg:
            error = FT_Set_Pixel_Sizes( face, 0,16);      //把字符像素设置为16*16像素, 0表示与另一个尺寸值相等。
    

    4.2设置字体的位置,以及旋转度数(不设置的话,表示远点位于(0,0))

        error = FT_Set_Transform(face        /*    目标face对象*/
                                 &matrix,    /*    指向2*2矩阵的指针,写0表示不旋转,使用正矩形    */
                                 &delta );    /*    字体坐标位置(使用的是笛卡尔坐标),以1/64像素为单位表示,写0表示原点是(0,0)    */
        注意:
            因为我们的LCD坐标原点位于左上方,笛卡尔坐标位于左下方所以转化之前填写坐标需要转换下
        eg:旋转25度,在(300,200)处显示
            FT_Vector pen;
            FT_Matrix matrix;
            angle = ( 25.0 / 360 ) * 3.14159 * 2;      /* use 25 degrees,转换为弧度制  */
            
            /*    将文字坐标转化为笛卡尔坐标    */
            pen.x = 300 * 64;
            pen.y = ( target_height - 200 ) * 64;    // target_height: LCD总高度
    
            /*    设置 矩形参数    */
            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 )
    

    5.1获取编码

        通过FT_Get_Char_Inde()函数将字符编码转换为一个字形(glyph)索引   (Freetype默认是utf-16编码类型)
        eg:
            glyph_index = FT_Get_Char_Index( face, charcode ); 
        若glyph_index为NULL,表示没找到字形(glyph)索引
        如果使用其它字符编码,则通过FT_Select_Charmap()来获取,例如获取big5编码;
            error = FT_Select_Charmap(
                                        face,                /* 目标face对象 */
                                        FT_ENCODING_BIG5 ); /* big5编码 */
    
                                                  //FT_ENCODING_BIG5枚举定义在FT_FREETYPE_H中
                                                 //FT_ENCODING_GB2312 :GB2312编码
                                                //该函数头文件位于:FT_FREETYPE_H (freetype/freetype.h).
    

    5.2通过编码索引从face中加载字形

        获得字形索引后,接下来便根据字形索引,来将字形图像存储到字形槽(glyph slot)中.
        字形槽:每次只能存储一个字形图像,每个face对象都有一个字形槽,位于face->glyph通过FT_Load_Glyph()来加载一个字形图像到字形槽:
            error = FT_Load_Glyph(
            face, /* face对象的句柄 */
            glyph_index, /* 字形索引 */
            load_flags ); /* 装载标志,一般填FT_LOAD_DEFAULT*/
        并更新face->glyph下的其它成员,比如:
            FT_Int            bitmap_left;            //该字形图像的最左边的X值
            FT_Int            bitmap_top;            //该字形图像的最上边的Y值
    

    6.转换位图

        通过FT_Render_Glyph()函数,将字形槽的字形图像转为位图,并存到 face->glyph->bitmap->buffer[]里
            error = FT_Render_Glyph( face->glyph, /* 字形槽 */
                                     render_mode ); /* 渲染模式 */
        render_mode标志可以设为以下几种:
            FT_RENDER_MODE_NORMAL:表示生成位图每个像素是RGB888的
            FT_RENDER_MODE_MONO :表示生成位图每个像素是1位的(黑白图
        并更新face->glyph->bitmap下的其它成员,比如:
            int rows;         //该位图总高度,有多少行
            int width;        //该位图总宽度,有多少列像素点
            int pitch:        //指一行的数据跨度(字节数),比如对于24位(3字节)的24*30汉字,则pitch=24*3
    
            char pixel_mode    //像素模式,1 指单色的,8 表示反走样灰度值
            unsigned char*  buffer        //glyph 的点阵位图内存绶冲区
    

    也可以直接使用FT_Load_Char()来代替FT_Get_Char_Index()、FT_Get_Load_Glyph()和FT_Render_Glyph().

    eg:
        error = FT_Load_Char( face, charcode, FT_LOAD_RENDER );
    其中FT_LOAD_RENDER:表示直接将图像转为位图,所以不需要使用FT_Render_Glyph()函数 
    该函数默认生成的位图是默认生成的FT_RENDER_MODE_NORMAL类型,RGB888的。若想生成FT_RENDER_MODE_MONO(黑白图)类型,操作如下:
        error = FT_Load_Char( face, charcode, FT_LOAD_RENDER | FT_LOAD_MONOCHROME );
    生成出来的位图像素,每8个像素点便表示 face->glyph->bitmap->buffer[]里的一个字节.
    

    7.多行显示

    1.从左上角开始显示

    流程

    1.先在左上角上显示第一行
    2.显示时保留y轴最大和最小值
    3.根据y轴的最大,最小值可以确定第二行的原点
    

    简析

    x坐标我们可以用一个字符的advance的x计算,y的坐标我们需要计算上一行字符advance的最大值(或者使用最小值)来确定。使用FT_Get_Glyph( face->glyph, &glyph )将face对象槽中的形状保存到glyph ; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox )从glyph中提取信息到bbox 。
    

    2.居中显示

    简析

    先计算字符长度,然后计算出原点的位置
    

    流程

    1.通过要显示的str填充的具体编码,外观(矢量信息),位置信息基于(0,0),统一用glyohs[]进行管理
    2.遍历所有外观,计算最大最小的框架信息
    3.计算居中的位置
    4.绘图
    5.内存销毁
    

    注:

    这里需要调整两次位置信息,
    1.第一次是在保持全局数组的外观是,产生行数据是基于pen在(0,0的位置)
    2.第二次是实际转换为图前,将实际的pen的位置与之前的位置计算偏移
    

    8.代码解析

    1.居中显示一个矢量字体

    #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 <math.h>
    #include <wchar.h>
    #include <stdlib.h>
    
    #include <ft2build.h>
    #include FT_FREETYPE_H
    #include FT_GLYPH_H
    
    #define FONTDATAMAX 4096
    
    static const unsigned char fontdata_8x16[FONTDATAMAX] = {
    	/*	ASCII编码	*/
    };
    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;
    
    int fd_hzk16;
    struct stat hzk_stat;
    unsigned char *hzkmem;
    
    
    
    /* 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 lcd_put_ascii(int x, int y, unsigned char c)
    {
    	unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
    	int i, b;
    	unsigned char byte;
    
    	for (i = 0; i < 16; i++)
    	{
    		byte = dots[i];
    		for (b = 7; b >= 0; b--)
    		{
    			if (byte & (1<<b))
    			{
    				/* show */
    				lcd_put_pixel(x+7-b, y+i, 0xffffff); /* 白 */
    			}
    			else
    			{
    				/* hide */
    				lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
    			}
    		}
    	}
    }
    
    void lcd_put_chinese(int x, int y, unsigned char *str)
    {
    	unsigned int area  = str[0] - 0xA1;
    	unsigned int where = str[1] - 0xA1;
    	unsigned char *dots = hzkmem + (area * 94 + where)*32;
    	unsigned char byte;
    
    	int i, j, b;
    	for (i = 0; i < 16; i++)
    		for (j = 0; j < 2; j++)
    		{
    			byte = dots[i*2 + j];
    			for (b = 7; b >=0; b--)
    			{
    				if (byte & (1<<b))
    				{
    					/* show */
    					lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff); /* 白 */
    				}
    				else
    				{
    					/* hide */
    					lcd_put_pixel(x+j*8+7-b, y+i, 0); /* 黑 */
    				}
    				
    			}
    		}
    	
    }
    
    
    
    /* Replace this function with something useful. */
    
    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;
    
    	//printf("x = %d, y = %d
    ", x, y);
    
      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];
                //bitmap->buffer[q * bitmap->width + p  颜色
          lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);
        }
      }
    }
    
    
    int main(int argc, char **argv)
    {
    	unsigned char str[] = "中";
    
    	/*	wchar_t 和L一起使用。
    	 *	wchar为宽字符对字母和汉字都采用两字节去保存
    	 *	使用时就会跟加方便,不必去区分到底为字符还是汉字
    	 */	
    	wchar_t *chinese_str = L"繁";
    
    	FT_Library	  library;
    	FT_Face 	  face;
    	int error;
        FT_Vector     pen;
    	FT_GlyphSlot  slot;
    	FT_Matrix	  matrix;				  /* transformation matrix */
    	double        angle;
    
    	if (argc != 3)
    	{
    		printf("Usage : %s <font_file> <angle>
    ", argv[0]);
    		return -1;
    	}
    		
    	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;
    	}
    
    	fd_hzk16 = open("HZK16", O_RDONLY);
    	if (fd_hzk16 < 0)
    	{
    		printf("can't open HZK16
    ");
    		return -1;
    	}
    	if(fstat(fd_hzk16, &hzk_stat))
    	{
    		printf("can't get fstat
    ");
    		return -1;
    	}
    	hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
    	if (hzkmem == (unsigned char *)-1)
    	{
    		printf("can't mmap for hzk16
    ");
    		return -1;
    	}
    
    	/* 清屏: 全部设为黑色 */
    	memset(fbmem, 0, screen_size);
    
    	lcd_put_ascii(var.xres/2, var.yres/2, 'A');
    
    	printf("chinese code: %02x %02x
    ", str[0], str[1]);
    	lcd_put_chinese(var.xres/2 + 8,  var.yres/2, str);
    
    
    	/* 显示矢量字体 */
    	error = FT_Init_FreeType( &library );			   /* initialize library */
    	/* error handling omitted */
    
    	/*	加载字体文件到face,argv[1]为字体文件名	*/
    	error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
    	/* error handling omitted */	
    
    	/*	保存字形	*/
    	slot = face->glyph;
    
    	FT_Set_Pixel_Sizes(face, 24, 0);
    
    	/* 确定座标:
    	 * lcd_x = var.xres/2 + 8 + 16
    	 * lcd_y = var.yres/2 + 16
    	 * 笛卡尔座标系:
    	 * x = lcd_x = var.xres/2 + 8 + 16
    	 * y = var.yres - lcd_y = var.yres/2 - 16
    	 */
    	pen.x = (var.xres/2 + 8 + 16) * 64;
    	pen.y = (var.yres/2 - 16) * 64;
    
    	/*	string to unsigned long	
    	 */
    	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 );
    
    	/* set transformation */
    	FT_Set_Transform( face, &matrix, &pen);
    
    	/* load glyph image into the slot (erase previous one) */
    	error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER );
    	if (error)
    	{
    		printf("FT_Load_Char error
    ");
    		return -1;
    	}
    
    	/*	左上角的点	*/
    	draw_bitmap( &slot->bitmap,
    				 slot->bitmap_left,
    				 var.yres - slot->bitmap_top);
    
    	return 0;	
    }
    

    测试:

    arm-linux-gcc -finput-charset=GBK -fexec-charset=GBK -o show_font show_font.c -lfreetype -lm 
    这里指定输入和输出都是GBK码。
    因为unsigned char str[] = "中";        //输入的是GBK,输出的也是GBK;后面代码也是使用的GBK编码的方式进行解码的
        wchar_t chinese_str[] = L"繁";    //输入的是GBK,输出的是UTF-8;
    

    2.从左上角开始显示多行文字

    #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 <math.h>
    #include <wchar.h>
    
    #include <ft2build.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;
    		}
    	}
    }
    
    
    
    /* Replace this function with something useful. */
    
    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;
    
    	//printf("x = %d, y = %d
    ", x, y);
    
      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]);
    	}
      }
    }
    
    
    int main(int argc, char **argv)
    {
    	wchar_t *wstr1 = L"百问网gif";
    	wchar_t *wstr2 = L"www.100ask.net";
    
    	FT_Library	  library;
    	FT_Face 	  face;
    	int error;
    	FT_Vector     pen;
    	FT_GlyphSlot  slot;
    	int i;
    	FT_BBox bbox;
    	FT_Glyph  glyph;
    
    	int line_box_ymin = 10000;
    	int line_box_ymax = 0;
    
    	if (argc != 2)
    	{
    		printf("Usage : %s <font_file>
    ", argv[0]);
    		return -1;
    	}
    		
    
    	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);
    
    	/* 显示矢量字体 */
    	error = FT_Init_FreeType( &library );			   /* initialize library */
    	/* error handling omitted */
    	
    	error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
    	/* error handling omitted */	
    	slot = face->glyph;
    
    	FT_Set_Pixel_Sizes(face, 24, 0);
    
    	/* 确定座标:
    	 * lcd_x = 0
    	 * lcd_y = 24
    	 * 笛卡尔座标系:
    	 * x = lcd_x = 0
    	 * y = var.yres - lcd_y = var.yres - 24
    	 */
    	pen.x = 0 * 64;
    	pen.y = (var.yres - 24) * 64;
    
    	for (i = 0; i < wcslen(wstr1); i++)
    	{
    		/* set transformation */
    		FT_Set_Transform( face, 0, &pen);
    
    		/* load glyph image into the slot (erase previous one) */
    		error = FT_Load_Char( face, wstr1[i], FT_LOAD_RENDER );
    		if (error)
    		{
    			printf("FT_Load_Char error
    ");
    			return -1;
    		}
    
    		error = FT_Get_Glyph( face->glyph, &glyph );
    		if (error)
    		{
    			printf("FT_Get_Glyph error!
    ");
    			return -1;
    		}
    		
    		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;
    		
    		draw_bitmap( &slot->bitmap,
    					 slot->bitmap_left,
    					 var.yres - slot->bitmap_top);
    
    		/* increment pen position */
    		pen.x += slot->advance.x;
    		//pen.y += slot->advance.y;
    
    	}
    
    
    	/* 确定座标:
    	 * 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;
    
    	for (i = 0; i < wcslen(wstr2); i++)
    	{
    		/* set transformation */
    		FT_Set_Transform( face, 0, &pen);
    
    		/* load glyph image into the slot (erase previous one) */
    		error = FT_Load_Char( face, wstr2[i], FT_LOAD_RENDER );
    		if (error)
    		{
    			printf("FT_Load_Char error
    ");
    			return -1;
    		}
    
    		error = FT_Get_Glyph( face->glyph, &glyph );
    		if (error)
    		{
    			printf("FT_Get_Glyph error!
    ");
    			return -1;
    		}
    		
    		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;
    		
    		draw_bitmap( &slot->bitmap,
    					 slot->bitmap_left,
    					 var.yres - slot->bitmap_top);
    
    		/* increment pen position */
    		pen.x += slot->advance.x;
    		//pen.y += slot->advance.y;
    
    	}
    	return 0;	
    }
    

    3.居中显示多行文字

    #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 <math.h>
    #include <wchar.h>
    
    #include <ft2build.h>
    #include FT_FREETYPE_H
    #include FT_GLYPH_H
    
    typedef struct TGlyph_ { 
    	FT_UInt index; /* glyph index */ 
    	FT_Vector pos; /* glyph origin on the baseline */ 
    	FT_Glyph image; /* glyph image */ 
    } TGlyph, *PGlyph; 
    
    
    #define MAX_GLYPHS	100
    
    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;
    		}
    	}
    }
    
    
    
    /* Replace this function with something useful. */
    
    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;
    
    	//printf("x = %d, y = %d
    ", x, y);
    
      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]);
    	}
      }
    }
    
    
    /*	把wstr中的字,从字体文件中取出其字形
     *	并把其存在数组中
     */
    int Get_Glyphs_Frm_Wstr(FT_Face face, wchar_t * wstr, TGlyph glyphs[])
    {
    	int n;
    	PGlyph glyph = glyphs;
    	int pen_x = 0;
    	int pen_y = 0;
    	int error;
    	FT_GlyphSlot  slot = face->glyph;;
    	
    		
    	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);
    		if ( error ) 
    			continue;
    
    		/*	注意加载和get	*/
    		error = FT_Get_Glyph(face->glyph, &glyph->image ); 
    		if ( error ) 
    			continue;
    
    		/* translate the glyph image now 
    		 *  这使得glyph->image里含有位置信息 
    		 *	把原来在(x,y)的字形数据变换为现在glyph->pos中地址的位置
    		 */
    		FT_Glyph_Transform(glyph->image, 0, &glyph->pos );
    
    		pen_x += slot->advance.x;  /* 1/64 point */
    
    		/* increment number of glyphs */ 
    		glyph++;		
    	}
    
    	/* count number of glyphs loaded */ 
    	return (glyph - glyphs);
    }
    
    /*	计算x.min, x.max, y.min, y.max	*/
    void compute_string_bbox(TGlyph glyphs[], FT_UInt 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[], FT_UInt num_glyphs, FT_Vector pen)
    {
    	int n;
    	int error;
    	
    	for (n = 0; n < num_glyphs; n++)
    	{
    		/*	把原来在原点的字形数据变换为现在pen中地址的位置	*/
    		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 ); 
    		}
    	}
    }
    
    int main(int argc, char **argv)
    {
    	wchar_t *wstr1 = L"百问网gif";
    	wchar_t *wstr2 = L"www.100ask.net";
    
    	FT_Library	  library;
    	FT_Face 	  face;
    	int error;
    	FT_Vector	  pen;
    	FT_GlyphSlot  slot;
    	int i;
    	FT_BBox bbox;
    
    	int line_box_ymin = 10000;
    	int line_box_ymax = 0;
    
    	int line_box_width;
    	int line_box_height;
    
    	TGlyph glyphs[MAX_GLYPHS]; /* glyphs table */ 
    	FT_UInt num_glyphs;
    
    
    	if (argc != 2)
    	{
    		printf("Usage : %s <font_file>
    ", argv[0]);
    		return -1;
    	}
    		
    
    	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);
    
    	/* 显示矢量字体 */
    	error = FT_Init_FreeType( &library );			   /* initialize library */
    	/* error handling omitted */
    	
    	error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
    	/* error handling omitted */	
    	slot = face->glyph;
    
    	FT_Set_Pixel_Sizes(face, 24, 0);
    
    	/* wstr1 */
    	num_glyphs = Get_Glyphs_Frm_Wstr(face, wstr1, glyphs);
    	
    	compute_string_bbox(glyphs, num_glyphs, &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 * 64;
    
    	/*	画图像	*/
    	Draw_Glyphs(glyphs, num_glyphs, pen);
    
    	/* wstr2 */
    	num_glyphs = Get_Glyphs_Frm_Wstr(face, wstr2, glyphs);
    
    	compute_string_bbox(glyphs, num_glyphs, &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 = pen.y - 24 * 64;
    	Draw_Glyphs(glyphs, num_glyphs, pen);
    
    
    	return 0;	
    }
  • 相关阅读:
    Qt多表格滚动条同步
    Trie树
    计算机网络笔记--网络层--ICMP协议
    计算机网络笔记--网络层--NAT
    计算机网络笔记--IP地址
    计算机网络笔记--网络层--ARP协议
    计算机网络笔记--网络层1IP协议
    const与指针
    c/c++笔记--指向数组的指针与二维数组
    机试笔记9--二叉树的遍历
  • 原文地址:https://www.cnblogs.com/huangdengtao/p/12297247.html
Copyright © 2011-2022 走看看