int save_bmp24(char * filename,int width,int height,unsigned char *data) { FileHead bmp_head; Infohead bmp_info; int size = width*height*3; FILE *fp = fopen(filename,"wb"); if(!fp) { perror("open file error"); return -1; } bmp_head.bfType=0x4d42; bmp_head.bfSize=size+sizeof(FileHead)+sizeof(Infohead);//24+head+info no quad bmp_head.bfReserved1=bmp_head.bfReserved2=0; bmp_head.bfOffBits=bmp_head.bfSize-size; bmp_info.biSize=40; bmp_info.biWidth=width; bmp_info.biHeight=-height;//如果为正数,转换出来的图片还需要进行垂直翻转 bmp_info.biPlanes=1; bmp_info.biBitCount = 24; bmp_info.biCompress=0; bmp_info.biSizeImage=size; bmp_info.biXPelsPerMeter=0; bmp_info.biYPelsPerMeter=0; bmp_info.biClrUsed=0; bmp_info.biClrImportant=0; fwrite(&bmp_head,1,sizeof(FileHead),fp); fwrite(&bmp_info,1,sizeof(Infohead),fp); fwrite(data,1,size,fp); fclose(fp); return 0; }
int convert(const char * font_file,int font_width,int font_height) { FT_Library library = NULL; FT_Face face = NULL; int error; int char_index; int char_code; unsigned char * bmpdata = NULL,*pdata;//保存一个字的图片数据 int isVert = 0;//是否垂直布局,中文为垂直布局 FT_Bitmap *ft_bmp; unsigned short unicode;//用于存储unicode int index=0; int area,location; char testfilename[100]; unsigned char *image = NULL, *pimage;//一个区转换为一张图片 int temp; if(font_width <= 0 && font_height <= 0) { printf("invalidate font size.\n"); return -1; } if(font_width <= 0) font_width = font_height; if(font_height <= 0) font_height = font_width; if(font_width % 2)//4字节对齐,这里先保证宽度为4pixel对齐 { printf("invalidate font size.\n"); return -1; } setlocale(LC_ALL,"zh_CN.UTF-8"); do { //下面开始初始化FT2库 error = FT_Init_FreeType(&library); if (error) { printf("can not init free type library!\n"); break; } error = FT_New_Face(library, font_file, 0, &face); if (error) { printf("create new face falied!\n"); break; } isVert = FT_HAS_VERTICAL(face); error = FT_Set_Pixel_Sizes(face, font_width, font_height);//设置字体大小 if (error) { printf("set font size error!\n"); break; } bmpdata = malloc(font_width * font_height * 3); if(!bmpdata) { printf("outof memory.\n"); break; } image = malloc(94 * font_width * font_height * 3);//这里要求font_size必须为偶数 if(!image) { printf("outof memory.\n"); break; } #if 0 //打印字体相关信息 printf("file has %d faces\n", face->num_faces); 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"); printf("file family name %s\n", face->family_name); printf("file style name %s\n", face->style_name); printf("face index %d\n", face->face_index); printf("number of char %d\n", face->num_glyphs); printf("number of fixed bitmap %d\n", face->num_fixed_sizes); printf("Char size %d\n", face->size); printf("has %d fixed sizes\n",face->num_fixed_sizes); for(i=0;i<face->num_fixed_sizes;i++) { printf("supported size %d:width=%d,heigh=%d\n",i+1,face->available_sizes[i].width,face->available_sizes[i].height); } #endif error = FT_Select_Charmap(face,FT_ENCODING_UNICODE);//这里使用UNICODE映射表,便于使用UNICODE码(char code)来获取char index if(error) { printf("select char map error.\n"); break; } //printf("code %x\n",face ->charmap ->encoding); switch(face ->charmap ->encoding) { case FT_ENCODING_MS_GB2312: printf("USE GB2312 CODE\n");break; case FT_ENCODING_MS_BIG5: printf("USE BIG5 CODE\n");break; case FT_ENCODING_UNICODE: printf("USE UNICODE CODE\n");break; default: printf("UNKNOWN CODE\n"); goto done; break; } //实际有字体的区码为(0-8) (15-86)区(区号从0开始 ) = 9 + 72 = 81个区 for(area = 0;area < 87;area ++)//1- 87区 { if( (area >8 && area < 15)/* 8 - 15区跳过*/ ||(area > 86 && area < 94)/* 87 - 94 区跳过*/ ) { continue; } memset(image,0,94 * font_width * font_height * 3); pimage = image; for(location = 0;location < 94;location++)//1 - 94位 { index = area * 94 + location; if(Gb2312ToUnicode(gb2312_table[index],&unicode) < 0) { printf("get unicode code error.gb2312 code 0x%04X\n",gb2312_table[index]); continue; } char_code = unicode; if(!char_code) { printf("\ninvalidate char code.\n"); continue; } char_index = FT_Get_Char_Index(face,char_code); error = FT_Load_Glyph(face, char_index, FT_LOAD_DEFAULT | FT_LOAD_MONOCHROME); if (error) { printf("\nload char error!\n"); goto done; } if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) { error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); if (error) { printf("\nrender char failed!\n"); goto done; } } /* 单色位图图像数据的表示方法: 在单色位图图像中,只有两种颜色,黑色或白色,每一个像素只需要一个比特就能够完成表示,为了清楚比特0或1具体表示哪一种颜色,可以通过查询调色板。 在单色位图图像中,调色板只包含两种颜色,每一种颜色用R G B 0 四个字节表示 (在实际的字节流中,顺序是 B G R 0) 所以,位图图像数据中的0 代表调色板中 第一种颜色的颜色值, 1 代表调色板中 第二种颜色的颜色值。 一行单色位图数据的存储格式规定: 每一扫描行的字节数必需是4的整倍数,当不够4的整数倍时,需要加0补齐 以 720 × 450 的单色位图图像为例 水平扫描行的长度为720,则需要720比特来表示一个扫描行,即需要 720/8=90字节来表示,但是 90不是 4 的整数倍,因此需要用0补齐,直至为4的整数倍,即需要额外的2个填充字节。 最终,长度为720的水平扫描行使用了 92 个字节来表示。 NOTE:非8位位图可用函数FT_Bitmap_Convert进行转换 */ //转换为4字节对齐 ft_bmp = &face->glyph->bitmap; #if 0 //dump位图信息 printf("bit_map_left %d bit_map_top %d\n", face->glyph->bitmap_left,face->glyph->bitmap_top); printf("int rows:%d\n",ft_bmp ->rows); printf("int width:%d\n",ft_bmp ->width); printf("int pitch:%d\n",ft_bmp ->pitch); printf("short num_grays:%d\n",ft_bmp ->num_grays); printf("char pixel_mode:%d\n",ft_bmp ->pixel_mode); if(isVert) { printf("VERT:(w:%ld h:%ld)(bearingX:%ld bearingY:%ld Advance:%ld)\n",face->glyph->metrics.width/64,face->glyph->metrics.height/64, face->glyph->metrics.vertBearingX/64,face->glyph->metrics.vertBearingY/64,face->glyph->metrics.horiAdvance/64); } else { printf("HORI:(w:%ld h:%ld)(bearingX:%ld bearingY:%ld Advance:%ld)\n",face->glyph->metrics.width/64,face->glyph->metrics.height/64, face->glyph->metrics.horiBearingX/64,face->glyph->metrics.horiBearingY/64,face->glyph->metrics.vertAdvance/64); } printf("xMin=%ld, yMin=%ld, xMax=%ld, yMax=%ld\n",face ->bbox.xMin,face ->bbox.yMin,face ->bbox.xMax,face ->bbox.yMax); #endif switch(ft_bmp ->pixel_mode) { case FT_PIXEL_MODE_MONO://单色位图 { //将数据转换到24位 int topblank = 0;//字型顶部距离位图顶部空行数目 int leftblank = 0;//字型左边距离位图左边空列数目 int rightblank = 0;//字型右边距离位图右边空列数目 int pitch = 0;//每个扫描行占用几个字节 int width = ft_bmp ->width;//实际字型宽度 int height = ft_bmp ->rows; //实际字型高度 unsigned char * ft_bmp_buff = ft_bmp ->buffer; int i,j,k; if(isVert) { topblank = face->glyph->metrics.vertBearingY/64; leftblank = font_width/2 + face->glyph->metrics.vertBearingX/64; } else { topblank = font_height * 2 /3 - face->glyph->metrics.horiBearingY/64; leftblank = face->glyph->metrics.horiBearingX/64; } if(topblank < 0)topblank = 0; if(leftblank < 0)leftblank = 0; rightblank = font_width - width - leftblank; if(rightblank < 0)rightblank = 0; pitch = ft_bmp ->width / 8; if(pitch% ft_bmp ->pitch) pitch = pitch + (ft_bmp ->pitch - pitch %ft_bmp ->pitch); //printf("PITCH=%d\n",pitch); //转换1bit位图数据到24bit位图数据 printf("begin convert.area %d ----> %d\r",area,location); memset(bmpdata,0,font_width * font_height * 3); pdata = bmpdata; pdata += topblank *font_width * 3;//跳过上边距 for(i=0;i<height;i++) { pdata += leftblank * 3; k = 7; for(j=0;j<width;j++) { if(ft_bmp_buff[j/8] & (1 << k) ) { //pdata[0] = 255;//蓝 pdata[1] = 255;//绿 pdata[2] = 255;//红 } k--; if(k<0)k=7; pdata += 3; } ft_bmp_buff += pitch; pdata += rightblank * 3; } /*if(!(font_width %4)) { sprintf(testfilename,"./testbmp/%d_%d.bmp",area,location ); printf("\nsave bmp file [%s]\n",testfilename); if(save_bmp24(testfilename,font_width ,font_height,bmpdata)) { printf("save bmp file [%s] error.\n",testfilename); } }*/ } break; default: printf("位图为非单色图片.\n"); goto done; break; }//switch pdata = bmpdata; pimage = image + location * font_width * 3; for(temp=0;temp<font_height;temp++) { memcpy(pimage,pdata,font_width * 3); pdata += font_width * 3; pimage += 94 * font_width *3; } #ifndef _WIN32 usleep(10); #else Sleep(10); #endif }//for( 1 - 94 位 ) //保存图片 sprintf(testfilename,"./testbmp/area%d_%dx%d.bmp",area,font_width,font_height); //printf("\nsave bmp file [%s]\n",testfilename); if(save_bmp24(testfilename,94 * font_width,font_height,image)) { printf("save bmp file [%s] error.\n",testfilename); } }//for( 1 - 94 区) printf("\nConvert Done.\n"); }while (0); done: #if 0 //出现莫名其妙的错误,注释了 fprintf(stderr,"begin cleanup.\n"); if(bmpdata) { free(bmpdata); bmpdata = NULL; } if(image) { free(image); image = NULL; } if(face) { FT_Done_Face(face); face = NULL; } if(library) { FT_Done_FreeType(library); library = NULL; } #endif return 0; }
这里上传几个程序转换的图片:
14x16:
16x18:
/*********************Y***************************/ unsigned char data_Y[]={ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 ...... ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 ,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 }; //37224 bytes /**************end of Y***************************/ /********************UV***************************/ unsigned char data_UV[]={ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 ...... ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 ,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x12,0x92,0x80,0x80,0x80,0x80 ,0x80,0x80,0x80,0x80 }; //18612 bytes /*************end of UV***************************/