经过上一篇的叙述,基本原理搞清楚后,便需要对我们在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见上一篇
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 }
//转换函数,这里是一个区转换为一个图片
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;i<face->num_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 error.gb2312 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<height;i++) 222 { 223 pdata += leftblank * 3; 224 k = 7; 225 for(j=0;j<width;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<font_height;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源程序文件
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://blog.csdn.net/sloan6/article/details/9231373