灵谷百科

中文OSD

灵谷百科

http://www.ccchp.com/sloan6/article/details/9231337

基础知识

为了简单起见,只显示GB2312(简体中文)字符

一、GB2312汉字编码

1.区位码

在国标GB2312—80中规定,所有的国标汉字及符号分配在一个94行、94列的方阵中,方阵的每一行称为一个“区”,编号为01区到94区,每一列称为一个“位”,编号为01位到94位,方阵中的每一个汉字和符号所在的区号和位号组合在一起形成的四个阿拉伯数字就是它们的“区位码”。区位码的前两位是它的区号,后两位是它的位号。用区位码就可以唯一地确定一个汉字或符号,反过来说,任何一个汉字或符号也都对应着一个唯一的区位码。汉字“母”字的区位码是3624,表明它在方阵的36区24位,问号“?”的区位码为0331,则它在03区31位。

2.机内码

汉字的机内码是指在计算机中表示一个汉字的编码。机内码与区位码稍有区别。如上所述,汉字区位码的区码和位码的取值均在1~94之间,如直接用区位码作为机内码,就会与基本ASCII码混淆。为了避免机内码与基本ASCII码的冲突,需要避开基本ASCII码中的控制码(00H~1FH),还需与基本ASCII码中的字符相区别。为了实现这两点,可以先在区码和位码分别加上20H,在此基础上再加80H(此处“H”表示前两位数字为十六进制数)。经过这些处理,用机内码表示一个汉字需要占两个字节,分别 称为高位字节和低位字节,这两位字节的机内码按如下规则表示:
高位字节 = 区码 + 20H + 80H(或区码 + A0H)
低位字节 = 位码 + 20H + 80H(或位码 + AOH)
由于汉字的区码与位码的取值范围的十六进制数均为01H~5EH(即十进制的01~94),所以汉字的高位字节与低位字节的取值范围则为A1H~FEH(即十进制的161~254)。
例如,汉字“啊”的区位码为1601,区码和位码分别用十六进制表示即为1001H,它的机内码的高位字节为B0H,低位字节为A1H,机内码就是B0A1H。

根据上面的概念,可以使用以下程序将所有的GB2312编码字符保存在一个文件中:

[cpp]  view plain copy print ?
  1. #include   
  2. int main()  
  3. {  
  4.     int area_code,location_code;  
  5.     unsigned char c[3]={0};  
  6.     FILE * fp = fopen("gb2312_table.c","wb");  
  7.     char buf[100];  
  8.     if(fp)  
  9.     {  
  10.         sprintf(buf,"#include \"gb2312.h\"\n\nunsigned short gb2312_table[]=\n{\n");  
  11.         fwrite(buf,1,strlen(buf),fp);  
  12.         for(area_code=1;area_code<95;area_code++)//区码为1-94  
  13.         {  
  14.             fputc('\t',fp);  
  15.             c[0]=area_code + 0xA0;//区码 + A0H 转换为机内码 高字节  
  16.             for(location_code=1;location_code<95;location_code++)//位码为1-94  
  17.             {  
  18.                 c[1]=location_code+0xA0;//位码 + A0H 转换为机内码 低字节  
  19.                 if(area_code == 1 && location_code == 1)  
  20.                     sprintf(buf," 0x%02X%02X",c[0],c[1]);  
  21.                 else  
  22.                     sprintf(buf,",0x%02X%02X",c[0],c[1]);  
  23.                 fwrite(buf,1,strlen(buf),fp);  
  24.             }  
  25.             fputc('\n',fp);//每区一行  
  26.         }  
  27.         sprintf(buf,"\n};\n\nint GetGB2312TableLen()\n{\n\treturn sizeof(gb2312_table)/sizeof(unsigned short);\n}\n");  
  28.         fwrite(buf,1,strlen(buf),fp);  
  29.         fclose(fp);  
  30.     }  
  31.     return 0;  
  32. }  

这里多生成了一个函数GetGB2312TableLen,用于获取gb2312_table大小.

下面是一个GB2312区位码查询、转换、区位码全表网址:
http://www.ccchp.com/classcode/tools/QuWeiMa.asp

二、UNICODE编码

Unicode是一个涵盖了目前全世界使用的所有已知字符的单一编码方案,也就是说Unicode为每一个字符提供唯一的编码。UTF-16是unicode的16位编码方式,是一种定长多字节编码,用2个字节表示一个unicode字符,AF16UTF16是UTF-16编码字符集。
UTF-8是unicode的8位编码方式,是一种变长多字节编码,这种编码可以用1、2、3个字节表示一个unicode字符,AL32UTF8,UTF8、UTFE是UTF-8编码字符集.
为了方便编码之间的转换,下面的实现均在linux下进行,因为在linux下有libiconv库供我们进行编码转换使用,这里还需要注意,通过使用iconv函数转换编码为unicode宽字符时,如果不是转换为utf-16be或者utf-16le指定的字节序,转换后的字符串最前面会多两个字节用于识别unicode字符串的字节序,开头两个字节为FE FF时为Big-Endian,为FF FE时为Little-Endian.
下面是两个编码转换函数,在具体实现中需要包含iconv.h头文件,如果iconv_open函数失败,perror打印错误信息为"无效参数",解决方法参考博文: http://www.ccchp.com/zxwangyun/article/details/9171057
这个函数将UTF8编码字符串转换为GB2312字符串,转换后的每个字符用2Byte存储,高位在前低位在后
[cpp]  view plain copy print ?
  1. static int Utf8ToGb2312(char *sOut, int iMaxOutLen/*BYTE*/const char *sIn, int iInLen/*BYTE*/)  
  2. {    
  3.     char *pIn = (char *)sIn;    
  4.     char *pOut = sOut;    
  5.     size_t ret;    
  6.     size_t iLeftLen=iMaxOutLen;    
  7.     iconv_t cd = iconv_open("gb2312""utf-8");    
  8.     if (cd == (iconv_t) - 1)    
  9.     {    
  10.         perror("iconv_open()");  
  11.         return -1;    
  12.     }    
  13.     size_t iSrcLen=iInLen;  
  14.     ret = iconv(cd, &pIn,&iSrcLen, &pOut,&iLeftLen);    
  15.     if (ret == (size_t) - 1)    
  16.     {    
  17.         perror("iconv()");  
  18.         iconv_close(cd);    
  19.         return -1;    
  20.     }    
  21.     iconv_close(cd);    
  22.     return (iMaxOutLen - iLeftLen);    
  23. }  

有些字符串中可能还包含有ASCII字符,转换后的GB2312编码的字符串可用下面的代码进行检测字符为中文还是ASCII字符
[cpp]  view plain copy print ?
  1. len = Utf8ToGb2312((char*)gb2312,sizeof(gb2312),utf8,strlen(utf8));  
  2. printf("UTF8 TEXT LEN:%d converted len=%d\n",strlen(utf8),len);  
  3. for(i=0;i
  4. {  
  5.     if(gb2312[i]<128)//为ANSC字符,每个字符用1个Byte存储  
  6.     {  
  7.         printf("ASCII Encode \t-- code:%c \n",gb2312[i]);  
  8.     }  
  9.     else//为GB2312(简体中文),每个字用两个Byte存储  
  10.     {  
  11.         printf("GB2312 Encode \t-- Area code:%02d%02d Machine code:0x%04x\n",gb2312[i]- 0xA0,gb2312[i+1]-0xA0,(gb2312[i]<<8)|gb2312[i+1]);  
  12.         i++;//别忘了GB2312字符需要2个Byte  
  13.     }  
  14. }  

这个函数将GB2312编码字符串转换为UTF-16BE(大端字节序)字符串,转换后的每个字符用2Byte存储,高位在前低位在后
[cpp]  view plain copy print ?
  1. static int Gb2312ToUtf16be(char *sOut, int iMaxOutLen/*BYTE*/const char *sIn, int iInLen/*BYTE*/)  
  2. {    
  3.     char *pIn = (char *)sIn;    
  4.     char *pOut = sOut;    
  5.     size_t ret;    
  6.     size_t iLeftLen=iMaxOutLen;    
  7.     iconv_t cd = iconv_open("UTF-16BE""gb2312");    
  8.     if (cd == (iconv_t) - 1)    
  9.     {    
  10.         perror("iconv_open()");  
  11.         return -1;    
  12.     }    
  13.     size_t iSrcLen=iInLen;  
  14.     ret = iconv(cd, &pIn,&iSrcLen, &pOut,&iLeftLen);    
  15.     if (ret == (size_t) - 1)    
  16.     {    
  17.         perror("iconv()");  
  18.         iconv_close(cd);    
  19.         return -1;    
  20.     }    
  21.     iconv_close(cd);    
  22.     return (iMaxOutLen - iLeftLen);    
  23. }  

UNICODE字符串区分ASCII字符和中文字符很简单,如果是UTF-16BE编码的Unicode字符串(每个字符都用2个Byte来存储),只需要看高8位是否为0即可,如果为0,则为ASCII字符

三、ASCII编码

ASCII字符中的可见字符为33-126(ASCII值)共94个字符(0-31为控制字符,32为空格,略过),以下为94个ascii可见字符:
[plain]  view plain copy print ?
  1. !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  

四、freetype2入门

参看 http://www.ccchp.com/uid-190095-id-3123383.html 中的例子即可对ft2进行简单使用
这里是一个更详细的ft2的文档: http://www.ccchp.com/s/blog_4ab2ba570100y7fm.html

五、ffmpeg libswscale库简单使用

libswscale库使用很简单,下面是一个一幅24bit的bmp图片数据转换为yuv数据的例子,这里将yuv数据直接存储在了一个数组并保存在一个文件中.
需要注意的是,如果直接将YUV数据进行显示,可能和原bmp图片相比是上下颠倒的,所以在转换前,最好将该24bit的bmp图片进行垂直翻转后再进行转换.

[cpp]  view plain copy print ?
  1. #include   
  2. #include "bmp_header.h"  
  3.   
  4. //包含swscale.h头文件  
  5. #ifdef __cplusplus  
  6. extern "C"{  
  7. #endif  
  8. #include "libavformat/avformat.h"  
  9. #include "libswscale/swscale.h"  
  10. #ifdef __cplusplus  
  11. }  
  12. #endif  
  13.   
  14. int save_bgr24_to_yuv420p(const char * src_bmp24_file,const char * dst_yuv_data_file)  
  15. {  
  16.     FILE *fp = NULL;  
  17.     struct SwsContext *pSwsCtx=NULL;  
  18.     uint8_t * bmp_data = NULL;  
  19.     int data_size = 0;  
  20.     int w=0,h=0;  
  21.   
  22.     fp = fopen(src_bmp24_file, "rb");//打开图片  
  23.     if(fp)  
  24.     {  
  25.         // 位图文件头  
  26. #ifdef _WIN32  
  27.         BITMAPFILEHEADER bmpheader={0};  
  28.         BITMAPINFO bmpinfo={0};  
  29.         fread(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp);  
  30.         fread(&bmpinfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);  
  31.         w = bmpinfo.bmiHeader.biWidth;  
  32.         h = bmpinfo.bmiHeader.biHeight;  
  33.         data_size = bmpheader.bfSize - bmpheader.bfOffBits;  
  34. #else  
  35.         FileHead bmp_head;  
  36.         Infohead bmp_info;  
  37.         fread(&bmp_head,sizeof(FileHead),1,fp);  
  38.         fread(&bmp_info,sizeof(Infohead),1,fp);  
  39.         w = bmp_info.biWidth;  
  40.         h = bmp_info.biHeight;  
  41.         data_size = bmp_head.bfSize - bmp_head.bfOffBits;  
  42. #endif  
  43.         if(h<0)h=-h;  
  44.         if(data_size != w * h * 3)  
  45.         {  
  46.             printf("not 24 bit bmp,file size = %d,w=%d,h=%d\n",data_size,w,h);  
  47.             fclose(fp);  
  48.             return -1;  
  49.         }  
  50.         bmp_data = (uint8_t *)malloc(data_size);  
  51.         memset(bmp_data,0,data_size);  
  52.         if(bmp_data)  
  53.         {  
  54.             fread(bmp_data,data_size,1,fp);  
  55.         }  
  56.         fclose(fp);  
  57.         fp = NULL;  
  58.     }  
  59.     if(bmp_data)  
  60.     {  
  61.         pSwsCtx = sws_getContext(  
  62.             w,  
  63.             h,  
  64.             PIX_FMT_BGR24,  
  65.             w,  
  66.             h,  
  67.             PIX_FMT_YUV420P,  
  68.             SWS_POINT/*SWS_BILINEAR*/,  
  69.             NULL,  
  70.             NULL,  
  71.             NULL);  
  72.         if(pSwsCtx)  
  73.         {  
  74.             uint8_t *data[4]={bmp_data,NULL,NULL,NULL};  
  75.             int linesize[4]    ={w*3,0,0,0};  
  76.             int height        = 0;  
  77.             uint8_t * buffer    = NULL;  
  78.             AVFrame * yuv_frame = avcodec_alloc_frame();  
  79.             buffer = (unsigned char *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P,w,h));  
  80.             memset(buffer,0,avpicture_get_size(PIX_FMT_YUV420P,w,h));  
  81.             avpicture_fill((AVPicture*)yuv_frame,(uint8_t *)buffer,PIX_FMT_YUV420P,w,h);  
  82.             height = sws_scale(  
  83.                 pSwsCtx,  
  84.                 data,  
  85.                 linesize,  
  86.                 0,  
  87.                 h,  
  88.                 yuv_frame ->data,  
  89.                 yuv_frame ->linesize);  
  90.             fp = fopen(dst_yuv_data_file,"w");  
  91.             if(fp)  
  92.             {  
  93.                 char buf[1024]={0};  
  94.                 int i=0;  
  95.                 sprintf(buf,"/*********************Y***************************/\nunsigned char data_Y[]={");  
  96.                 fwrite(buf,1,strlen(buf),fp);  
  97.                 for(i=0;ilinesize[0]*height;i++)  
  98.                 {  
  99.                     if(!(i%16))  
  100.                     {  
  101.                         sprintf(buf,"\n\t");  
  102.                         fwrite(buf,strlen(buf),1,fp);  
  103.                     }  
  104.                     if(i)  
  105.                     {  
  106.                         sprintf(buf,",0x%02X",*(yuv_frame ->data[0]+i));  
  107.                     }  
  108.                     else  
  109.                     {  
  110.                         sprintf(buf," 0x%02X",*(yuv_frame ->data[0]+i));  
  111.                     }  
  112.                     fwrite(buf,strlen(buf),1,fp);  
  113.                 }  
  114.                 sprintf(buf,"\n};\n//%d bytes\n/**************end of Y***************************/\n\n",yuv_frame ->linesize[0]*h);  
  115.                 fwrite(buf,strlen(buf),1,fp);  
  116.                 sprintf(buf,"/********************UV***************************/\nunsigned char data_UV[]={");  
  117.                 fwrite(buf,1,strlen(buf),fp);  
  118.                 for(i=0;ilinesize[1]*height/2;i++)  
  119.                 {  
  120.                     if(!(i%8))  
  121.                     {  
  122.                         sprintf(buf,"\n\t");  
  123.                         fwrite(buf,strlen(buf),1,fp);  
  124.                     }  
  125.                     if(i)  
  126.                     {  
  127.                         sprintf(buf,",0x%02X,0x%02X",*(yuv_frame ->data[1]+i),*(yuv_frame ->data[2]+i));  
  128.                     }  
  129.                     else  
  130.                     {  
  131.                         sprintf(buf," 0x%02X,0x%02X",*(yuv_frame ->data[1]+i),*(yuv_frame ->data[2]+i));  
  132.                     }  
  133.                     fwrite(buf,strlen(buf),1,fp);  
  134.                 }  
  135.                 sprintf(buf,"\n};\n//%d bytes\n/*************end of UV***************************/\n\n",yuv_frame ->linesize[1]*h);  
  136.                 fwrite(buf,strlen(buf),1,fp);  
  137.                 fclose(fp);  
  138.                 fp = NULL;  
  139.             }  
  140.             av_free(yuv_frame);  
  141.             av_free(buffer);  
  142.   
  143.             sws_freeContext(pSwsCtx);  
  144.             pSwsCtx = NULL;  
  145.         }  
  146.         free(bmp_data);  
  147.         bmp_data = NULL;  
  148.     }  
  149.     return 0;  
  150. }  

其中bmp_header.h定义linux下的BMP头结构体,定义如下

[cpp]  view plain copy print ?
  1. #ifndef __BMP_HEADER_H__  
  2. #define __BMP_HEADER_H__  
  3.   
  4. #ifndef _WIN32  
  5. typedef long BOOL;  
  6. typedef long LONG;  
  7. typedef unsigned char BYTE;  
  8. typedef unsigned long DWORD;  
  9. typedef unsigned short WORD;  
  10. typedef struct {  
  11.     WORD    bfType;//2  
  12.     DWORD   bfSize;//4  
  13.     WORD    bfReserved1;//2  
  14.     WORD    bfReserved2;//2  
  15.     DWORD   bfOffBits;//4  
  16. }__attribute__((packed))FileHead;  
  17.   
  18. typedef struct{  
  19.     DWORD      biSize;//4  
  20.     LONG       biWidth;//4  
  21.     LONG       biHeight;//4  
  22.     WORD       biPlanes;//2  
  23.     WORD       biBitCount;//2  
  24.     DWORD      biCompress;//4  
  25.     DWORD      biSizeImage;//4  
  26.     LONG       biXPelsPerMeter;//4  
  27.     LONG       biYPelsPerMeter;//4  
  28.     DWORD      biClrUsed;//4  
  29.     DWORD      biClrImportant;//4  
  30. }__attribute__((packed))Infohead;  
  31.   
  32. #endif//_WIN32  
  33.   
  34. #endif //__BMP_HEADER_H__  

基本数据准备

http://www.ccchp.com/sloan6/article/details/9231373

经过上一篇的叙述,基本原理搞清楚后,便需要对我们在OSD上显示中文作数据准备,
首先是需要将gb2312关键区(也就是实际有文字存在的区)中的汉字转换为图片,在实际的转换中,并不像上一篇中GB2312编码转换为UNICODE描述一样,
使用libiconv库中的iconv函数将94x94的gb2312编码表直接传递给iconv函数会转换失败(错误提示不完整的多字节字符或宽字符).为了简化这其中的转换难度,目前使用的是查表的方法将GB2312编码转换为UNICODE编码,
这样就要求先准备好GB2312 UNICODE对照表,这个表网上有各种形式的,但是通过我花了很长时间查找也没有找到合适自己需求的,主要是网上的GB2312区位码不全,都会丢掉某些区中的某些编码,这样会有个问题,
就是我们转换后的数据需要记录我们中间丢失了哪些编码,对应的位置等等.会造成后续程序执行效率降低和设计难度加大.这里我是直接将94x94个GB2312编码都转换为对应的unicode编码,保存在一个数组中(很占篇幅,这里不贴实际数据了),通过查找下标的方式查找对应的UNICODE编码.
将对应的GB2312编码转换为UNICODE编码后,接下来就是使用Freetype2将该UNICODE码提取出对应的字符映像,并转换为位图,保存在磁盘上了,下面是其中的核心程序:
//linux下保存24位bmp图像,数据结构FileHead、Infohead见上一篇

[cpp]  view plain copy print ?
  1. int save_bmp24(char * filename,int width,int height,unsigned char *data)  
  2. {  
  3.     FileHead bmp_head;  
  4.     Infohead bmp_info;  
  5.     int size = width*height*3;  
  6.     FILE *fp = fopen(filename,"wb");  
  7.     if(!fp)  
  8.     {  
  9.         perror("open file error");  
  10.         return -1;  
  11.     }  
  12.   
  13.     bmp_head.bfType=0x4d42;  
  14.     bmp_head.bfSize=size+sizeof(FileHead)+sizeof(Infohead);//24+head+info no quad      
  15.     bmp_head.bfReserved1=bmp_head.bfReserved2=0;  
  16.     bmp_head.bfOffBits=bmp_head.bfSize-size;  
  17.   
  18.     bmp_info.biSize=40;  
  19.     bmp_info.biWidth=width;  
  20.     bmp_info.biHeight=-height;//如果为正数,转换出来的图片还需要进行垂直翻转  
  21.     bmp_info.biPlanes=1;  
  22.     bmp_info.biBitCount = 24;  
  23.     bmp_info.biCompress=0;  
  24.     bmp_info.biSizeImage=size;  
  25.     bmp_info.biXPelsPerMeter=0;  
  26.     bmp_info.biYPelsPerMeter=0;  
  27.     bmp_info.biClrUsed=0;  
  28.     bmp_info.biClrImportant=0;  
  29.   
  30.     fwrite(&bmp_head,1,sizeof(FileHead),fp);  
  31.     fwrite(&bmp_info,1,sizeof(Infohead),fp);  
  32.     fwrite(data,1,size,fp);  
  33.     fclose(fp);  
  34.     return 0;  
  35. }  

//转换函数,这里是一个区转换为一个图片
[cpp]  view plain copy print ?
  1. int convert(const char * font_file,int font_width,int font_height)  
  2. {  
  3.     FT_Library library = NULL;  
  4.     FT_Face face = NULL;  
  5.     int error;  
  6.     int char_index;  
  7.     int char_code;  
  8.       
  9.     unsigned char * bmpdata = NULL,*pdata;//保存一个字的图片数据  
  10.     int isVert = 0;//是否垂直布局,中文为垂直布局  
  11.     FT_Bitmap *ft_bmp;  
  12.       
  13.     unsigned short  unicode;//用于存储unicode  
  14.     int index=0;  
  15.     int area,location;  
  16.     char testfilename[100];  
  17.       
  18.     unsigned char *image = NULL, *pimage;//一个区转换为一张图片  
  19.     int temp;  
  20.       
  21.     if(font_width <= 0 && font_height <= 0)  
  22.     {  
  23.         printf("invalidate font size.\n");  
  24.         return -1;  
  25.     }  
  26.     if(font_width <= 0)  
  27.         font_width = font_height;  
  28.     if(font_height <= 0)  
  29.         font_height = font_width;  
  30.     if(font_width % 2)//4字节对齐,这里先保证宽度为4pixel对齐  
  31.     {  
  32.         printf("invalidate font size.\n");  
  33.         return -1;  
  34.     }  
  35.     setlocale(LC_ALL,"zh_CN.UTF-8");  
  36.   
  37.     do  
  38.     {  
  39.         //下面开始初始化FT2库  
  40.         error = FT_Init_FreeType(&library);  
  41.         if (error)  
  42.         {  
  43.             printf("can not init free type library!\n");  
  44.             break;  
  45.         }  
  46.   
  47.         error = FT_New_Face(library, font_file, 0, &face);  
  48.         if (error)  
  49.         {  
  50.             printf("create new face falied!\n");  
  51.             break;  
  52.         }  
  53.         isVert = FT_HAS_VERTICAL(face);      
  54.         error = FT_Set_Pixel_Sizes(face, font_width, font_height);//设置字体大小  
  55.         if (error)  
  56.         {  
  57.             printf("set font size error!\n");  
  58.             break;  
  59.         }  
  60.         bmpdata = malloc(font_width * font_height * 3);  
  61.         if(!bmpdata)  
  62.         {  
  63.             printf("outof memory.\n");  
  64.             break;  
  65.         }  
  66.         image = malloc(94 * font_width * font_height * 3);//这里要求font_size必须为偶数  
  67.         if(!image)  
  68.         {  
  69.             printf("outof memory.\n");  
  70.             break;  
  71.         }  
  72.   
  73. #if 0  
  74.         //打印字体相关信息  
  75.         printf("file has %d faces\n", face->num_faces);  
  76.         printf("%s  italic or oblique,%s bold\n", face->style_flags & FT_STYLE_FLAG_ITALIC ?"support":"not support",face->style_flags & FT_STYLE_FLAG_BOLD ?"support":"not support");  
  77.         printf("file family name %s\n", face->family_name);  
  78.         printf("file style name %s\n", face->style_name);  
  79.         printf("face index %d\n", face->face_index);  
  80.         printf("number of char %d\n", face->num_glyphs);  
  81.         printf("number of fixed bitmap %d\n", face->num_fixed_sizes);  
  82.         printf("Char size %d\n", face->size);  
  83.         printf("has %d fixed sizes\n",face->num_fixed_sizes);  
  84.         for(i=0;inum_fixed_sizes;i++)  
  85.         {  
  86.             printf("supported size %d:width=%d,heigh=%d\n",i+1,face->available_sizes[i].width,face->available_sizes[i].height);  
  87.         }  
  88. #endif  
  89.         error = FT_Select_Charmap(face,FT_ENCODING_UNICODE);//这里使用UNICODE映射表,便于使用UNICODE码(char code)来获取char index  
  90.         if(error)  
  91.         {  
  92.             printf("select char map error.\n");  
  93.             break;  
  94.         }  
  95.         //printf("code %x\n",face ->charmap ->encoding);  
  96.         switch(face ->charmap ->encoding)  
  97.         {  
  98.             case FT_ENCODING_MS_GB2312:    printf("USE GB2312 CODE\n");break;  
  99.             case FT_ENCODING_MS_BIG5:    printf("USE BIG5 CODE\n");break;  
  100.             case FT_ENCODING_UNICODE:    printf("USE UNICODE CODE\n");break;  
  101.             default:  
  102.                 printf("UNKNOWN CODE\n");  
  103.                 goto done;  
  104.                 break;  
  105.         }  
  106.           
  107.         //实际有字体的区码为(0-8) (15-86)区(区号从0开始 ) = 9 + 72 = 81个区  
  108.         for(area = 0;area < 87;area ++)//1- 87区  
  109.         {  
  110.             if( (area >8 && area < 15)/* 8 - 15区跳过*/  
  111.                 ||(area > 86 && area < 94)/* 87 - 94 区跳过*/  
  112.             )  
  113.             {  
  114.                 continue;  
  115.             }  
  116.             memset(image,0,94 * font_width * font_height * 3);  
  117.             pimage = image;  
  118.             for(location = 0;location < 94;location++)//1 - 94位  
  119.             {  
  120.                 index = area * 94 + location;  
  121.                 if(Gb2312ToUnicode(gb2312_table[index],&unicode) < 0)  
  122.                 {  
  123.                     printf("get unicode code www.ccchp.com2312 code 0x%04X\n",gb2312_table[index]);  
  124.                     continue;  
  125.                 }  
  126.                 char_code = unicode;  
  127.                 if(!char_code)  
  128.                 {  
  129.                     printf("\ninvalidate char code.\n");  
  130.                     continue;  
  131.                 }  
  132.                 char_index = FT_Get_Char_Index(face,char_code);  
  133.                 error = FT_Load_Glyph(face, char_index,  FT_LOAD_DEFAULT | FT_LOAD_MONOCHROME);  
  134.                 if (error)  
  135.                 {  
  136.                     printf("\nload char error!\n");  
  137.                     goto done;  
  138.                 }  
  139.                 if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)  
  140.                 {  
  141.                     error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);  
  142.                     if (error)  
  143.                     {  
  144.                         printf("\nrender char failed!\n");  
  145.                         goto done;  
  146.                     }  
  147.                 }  
  148.   
  149.                 /* 
  150.                 单色位图图像数据的表示方法: 
  151.                 在单色位图图像中,只有两种颜色,黑色或白色,每一个像素只需要一个比特就能够完成表示,为了清楚比特0或1具体表示哪一种颜色,可以通过查询调色板。 
  152.                 在单色位图图像中,调色板只包含两种颜色,每一种颜色用R G B 0 四个字节表示 (在实际的字节流中,顺序是 B G R 0) 
  153.                 所以,位图图像数据中的0 代表调色板中 第一种颜色的颜色值, 1 代表调色板中 第二种颜色的颜色值。 
  154.                 一行单色位图数据的存储格式规定: 
  155.                 每一扫描行的字节数必需是4的整倍数,当不够4的整数倍时,需要加0补齐 
  156.                 以 720 × 450 的单色位图图像为例 
  157.                 水平扫描行的长度为720,则需要720比特来表示一个扫描行,即需要 720/8=90字节来表示,但是 90不是 4 的整数倍,因此需要用0补齐,直至为4的整数倍,即需要额外的2个填充字节。 
  158.                 最终,长度为720的水平扫描行使用了 92 个字节来表示。 
  159.                 NOTE:非8位位图可用函数FT_Bitmap_Convert进行转换 
  160.                 */  
  161.                 //转换为4字节对齐  
  162.                 ft_bmp = &face->glyph->bitmap;  
  163. #if 0  
  164.                 //dump位图信息  
  165.                 printf("bit_map_left %d bit_map_top %d\n", face->glyph->bitmap_left,face->glyph->bitmap_top);  
  166.                 printf("int rows:%d\n",ft_bmp ->rows);  
  167.                 printf("int width:%d\n",ft_bmp ->width);  
  168.                 printf("int pitch:%d\n",ft_bmp ->pitch);  
  169.                 printf("short num_grays:%d\n",ft_bmp ->num_grays);  
  170.                 printf("char pixel_mode:%d\n",ft_bmp ->pixel_mode);  
  171.                 if(isVert)  
  172.                 {  
  173.                     printf("VERT:(w:%ld h:%ld)(bearingX:%ld bearingY:%ld Advance:%ld)\n",face->glyph->metrics.width/64,face->glyph->metrics.height/64,  
  174.                         face->glyph->metrics.vertBearingX/64,face->glyph->metrics.vertBearingY/64,face->glyph->metrics.horiAdvance/64);  
  175.                 }  
  176.                 else  
  177.                 {  
  178.                     printf("HORI:(w:%ld h:%ld)(bearingX:%ld bearingY:%ld Advance:%ld)\n",face->glyph->metrics.width/64,face->glyph->metrics.height/64,  
  179.                         face->glyph->metrics.horiBearingX/64,face->glyph->metrics.horiBearingY/64,face->glyph->metrics.vertAdvance/64);  
  180.                 }  
  181.                 printf("xMin=%ld, yMin=%ld, xMax=%ld, yMax=%ld\n",face ->bbox.xMin,face ->bbox.yMin,face ->bbox.xMax,face ->bbox.yMax);  
  182. #endif          
  183.   
  184.                 switch(ft_bmp ->pixel_mode)  
  185.                 {  
  186.                     case FT_PIXEL_MODE_MONO://单色位图  
  187.                         {  
  188.                             //将数据转换到24位  
  189.                             int topblank     = 0;//字型顶部距离位图顶部空行数目  
  190.                             int leftblank     = 0;//字型左边距离位图左边空列数目  
  191.                             int rightblank     = 0;//字型右边距离位图右边空列数目  
  192.                             int pitch     = 0;//每个扫描行占用几个字节  
  193.                             int width    = ft_bmp ->width;//实际字型宽度  
  194.                             int height    = ft_bmp ->rows; //实际字型高度  
  195.                             unsigned char * ft_bmp_buff = ft_bmp ->buffer;  
  196.                             int i,j,k;  
  197.                             if(isVert)  
  198.                             {  
  199.                                 topblank     = face->glyph->metrics.vertBearingY/64;  
  200.                                 leftblank     = font_width/2 + face->glyph->metrics.vertBearingX/64;  
  201.                             }  
  202.                             else  
  203.                             {  
  204.                                 topblank    = font_height * 2 /3 - face->glyph->metrics.horiBearingY/64;  
  205.                                 leftblank     = face->glyph->metrics.horiBearingX/64;  
  206.                             }  
  207.                             if(topblank < 0)topblank     = 0;  
  208.                             if(leftblank < 0)leftblank     = 0;  
  209.                             rightblank = font_width - width - leftblank;  
  210.                             if(rightblank < 0)rightblank    = 0;  
  211.                             pitch =  ft_bmp ->width / 8;  
  212.                             if(pitch% ft_bmp ->pitch)  
  213.                                 pitch = pitch + (ft_bmp ->pitch - pitch %ft_bmp ->pitch);  
  214.                             //printf("PITCH=%d\n",pitch);  
  215.                   
  216.                             //转换1bit位图数据到24bit位图数据  
  217.                             printf("begin convert.area %d ----> %d\r",area,location);  
  218.                             memset(bmpdata,0,font_width * font_height * 3);  
  219.                             pdata = bmpdata;  
  220.                             pdata += topblank *font_width * 3;//跳过上边距  
  221.                             for(i=0;i
  222.                             {  
  223.                                 pdata += leftblank * 3;  
  224.                                 k = 7;  
  225.                                 for(j=0;j
  226.                                 {  
  227.                                     if(ft_bmp_buff[j/8] & (1 << k) )  
  228.                                     {  
  229.                                         //pdata[0] = 255;//蓝  
  230.                                         pdata[1] = 255;//绿  
  231.                                         pdata[2] = 255;//红  
  232.                                     }  
  233.                                     k--;  
  234.                                     if(k<0)k=7;  
  235.                                     pdata += 3;  
  236.                                 }  
  237.                                 ft_bmp_buff += pitch;  
  238.                                 pdata += rightblank * 3;  
  239.                             }  
  240.                             /*if(!(font_width %4)) 
  241.                             { 
  242.                                 sprintf(testfilename,"./testbmp/%d_%d.bmp",area,location ); 
  243.                                 printf("\nsave bmp file [%s]\n",testfilename); 
  244.                                 if(save_bmp24(testfilename,font_width ,font_height,bmpdata)) 
  245.                                 { 
  246.                                     printf("save bmp file [%s] error.\n",testfilename); 
  247.                                 } 
  248.                             }*/  
  249.       
  250.                         }  
  251.                         break;  
  252.                     default:  
  253.                         printf("位图为非单色图片.\n");  
  254.                         goto done;  
  255.                         break;  
  256.                 }//switch  
  257.                 pdata = bmpdata;  
  258.                 pimage = image + location * font_width * 3;                  
  259.                 for(temp=0;temp
  260.                 {  
  261.                     memcpy(pimage,pdata,font_width * 3);  
  262.                     pdata += font_width * 3;  
  263.                     pimage += 94 * font_width *3;  
  264.                 }  
  265. #ifndef _WIN32  
  266.                 usleep(10);  
  267. #else  
  268.                 Sleep(10);  
  269. #endif  
  270.             }//for( 1 - 94 位 )  
  271.             //保存图片  
  272.             sprintf(testfilename,"./testbmp/area%d_%dx%d.bmp",area,font_width,font_height);  
  273.             //printf("\nsave bmp file [%s]\n",testfilename);  
  274.             if(save_bmp24(testfilename,94 * font_width,font_height,image))  
  275.             {  
  276.                 printf("save bmp file [%s] error.\n",testfilename);  
  277.             }  
  278.         }//for( 1 - 94 区)  
  279.         printf("\nConvert Done.\n");  
  280.   
  281.     }while (0);  
  282. done:  
  283. #if 0    //出现莫名其妙的错误,注释了  
  284.     fprintf(stderr,"begin cleanup.\n");  
  285.     if(bmpdata)  
  286.     {  
  287.         free(bmpdata);  
  288.         bmpdata = NULL;  
  289.     }  
  290.     if(image)  
  291.     {  
  292.         free(image);  
  293.         image = NULL;  
  294.     }  
  295.     if(face)  
  296.     {  
  297.         FT_Done_Face(face);  
  298.         face = NULL;  
  299.     }  
  300.     if(library)  
  301.     {  
  302.         FT_Done_FreeType(library);  
  303.         library = NULL;  
  304.     }  
  305. #endif  
  306.     return 0;  
  307. }  

这里上传几个程序转换的图片:

14x16:

16x18:


20x24:

28x32:

将编码转换为图片后,需要将bmp24图片数据转换为yuv420p数据,利用libswscale库进行转换的核心代码已经在上一篇贴了,这里不再重贴.
下面是转换后的结果,当然也可以直接将数据保存为一个二进制文件,而不是一个C源程序文件
[cpp]  view plain copy print ?
  1. /*********************Y***************************/  
  2. unsigned char data_Y[]={  
  3.      0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10  
  4.     ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10  
  5.     ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10  
  6.     ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10  
  7.     ......  
  8.     ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10  
  9.     ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10  
  10.     ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10  
  11.     ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10  
  12. };  
  13. //37224 bytes  
  14. /**************end of Y***************************/  
  15.   
  16. /********************UV***************************/  
  17. unsigned char data_UV[]={  
  18.      0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80  
  19.     ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80  
  20.     ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80  
  21.     ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80  
  22.     ......  
  23.     ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80  
  24.     ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80  
  25.     ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x12,0x92,0x80,0x80,0x80,0x80  
  26.     ,0x80,0x80,0x80,0x80  
  27. };  
  28. //18612 bytes  
  29. /*************end of UV***************************/  


实战

http://www.ccchp.com/sloan6/article/details/9231413

通过数据准备篇,将数据准备好后,其实剩下的工作已经很简单了,通过以下几个步骤即可把一个中文显示在OSD画面上:
1. 使用SWOSD_setBmpchangeWinXYPrm函数设置好OSD显示坐标位置;
2. 设置SWOSD_Hndl句柄中SWOSD_BmpWinPrm类型成员数组中对应的窗口的width,height,lineOffset对应的值,width是OSD窗口宽度,如果yuv数据来自的是32x32的bmp图片,则width=n*32,其中n为字符个数,height为OSD窗口高度,lineOffset为每个扫描行Y数据所占字节数;

3. 通过SWOSD_setBmpWinAddr函数设置对应窗口的Y数据和UV数据地址.

注:1、2中如果某些值设置不对,会提示以下错误:

SWOSD_winDraw():baseI fail or baseJ fail xxx  xxx  for window id xxx

下面是两个测试图片:



发表评论 (已有0条评论)

还木有评论哦,快来抢沙发吧~