首先需要打开一张bmp图片,将图片读入内存中。然后连接freetype类库,使用的是freetype2.4.9版本,VS2010。
为了简单处理,使用的bmp图片为24位位图,960*540大小的一张位图,直接用画图工具另存为就好,这样宽度默认就是4的倍数。
以下代码简单的实现了把字体嵌入到24位bmp图片的指定坐标位置上。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <ft2build.h>
#include <memory.h>
#include FT_FREETYPE_H
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>
using namespace std;
/*
//windows.h中已经定义了以下的这些东西,直接用就可以了
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef long LONG;
//位图文件头定义;
//其中不包含文件类型信息(由于结构体的内存结构决定,
//要是加了的话将不能正确读取文件信息)
typedef struct tagBITMAPFILEHEADER{
//WORD bfType;//文件类型,必须是0x424D,即字符“BM”
DWORD bfSize;//文件大小
WORD bfReserved1;//保留字
WORD bfReserved2;//保留字
DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数
}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;//信息头大小
LONG biWidth;//图像宽度
LONG biHeight;//图像高度
WORD biPlanes;//位平面数,必须为1
WORD biBitCount;//每像素位数
DWORD biCompression; //压缩类型
DWORD biSizeImage; //压缩图像大小字节数
LONG biXPelsPerMeter; //水平分辨率
LONG biYPelsPerMeter; //垂直分辨率
DWORD biClrUsed; //位图实际用到的色彩数
DWORD biClrImportant; //本位图中重要的色彩数
}BITMAPINFOHEADER; //位图信息头定义
typedef struct tagRGBQUAD{
BYTE rgbBlue; //该颜色的蓝色分量
BYTE rgbGreen; //该颜色的绿色分量
BYTE rgbRed; //该颜色的红色分量
BYTE rgbReserved; //保留值
}RGBQUAD;//调色板定义
*/
//像素信息
typedef struct tagIMAGEDATA
{
BYTE blue;
BYTE green;
BYTE red;
}IMAGEDATA;
//变量定义
BITMAPFILEHEADER strHead;
BITMAPINFOHEADER strInfo;
IMAGEDATA *arrayColor;
LONG nWidth;
LONG nHeight;
//显示位图文件头信息
void showBmpHead(BITMAPFILEHEADER pBmpHead){
cout<<"位图文件头:"<<endl;
cout<<"bfType value is "<<pBmpHead.bfType<<endl;
cout<<"文件大小:"<<pBmpHead.bfSize<<endl;
cout<<"保留字_1:"<<pBmpHead.bfReserved1<<endl;
cout<<"保留字_2:"<<pBmpHead.bfReserved2<<endl;
cout<<"实际位图数据的偏移字节数:"<<pBmpHead.bfOffBits<<endl<<endl;
}
void showBmpInforHead(tagBITMAPINFOHEADER pBmpInforHead){
cout<<"位图信息头:"<<endl;
cout<<"结构体的长度:"<<pBmpInforHead.biSize<<endl;
cout<<"位图宽:"<<pBmpInforHead.biWidth<<endl;
cout<<"位图高:"<<pBmpInforHead.biHeight<<endl;
cout<<"biPlanes平面数:"<<pBmpInforHead.biPlanes<<endl;
cout<<"biBitCount采用颜色位数:"<<pBmpInforHead.biBitCount<<endl;
cout<<"压缩方式:"<<pBmpInforHead.biCompression<<endl;
cout<<"biSizeImage实际位图数据占用的字节数:"<<pBmpInforHead.biSizeImage<<endl;
cout<<"X方向分辨率:"<<pBmpInforHead.biXPelsPerMeter<<endl;
cout<<"Y方向分辨率:"<<pBmpInforHead.biYPelsPerMeter<<endl;
cout<<"使用的颜色数:"<<pBmpInforHead.biClrUsed<<endl;
cout<<"重要颜色数:"<<pBmpInforHead.biClrImportant<<endl;
}
int WordInsertToBmp(char *strFile){
CJList *plist= new CJList();
FILE *fpi,*fpw;
fpi=fopen(strFile,"rb");
FT_Library pFTLib = NULL;
FT_Face pFTFace = NULL;
FT_Error error = 0 ;
//Init FreeType Lib to manage memory
error = FT_Init_FreeType( & pFTLib);
if (error)
{
pFTLib = 0 ;
printf( " There is some error when Init Library " );
return - 1 ;
}
//从字体文件创建face,simhei.ttf是黑体
error = FT_New_Face(pFTLib, "C:/Windows/Fonts/simhei.ttf" , 0 , & pFTFace);
if(error)
{
cout<<"字体打开失败"<<endl;
}
FT_Set_Char_Size(pFTFace, 0 , 16*64 , 300 , 300 );//设置字体大小
//FT_Set_Pixel_Sizes(pFTFace,0,16 );
FT_Glyph glyph;
char* szAnsi = "这里是123测试";//将中文转换为Unicode编码
//预转换,得到所需空间的大小
int wcsLen = ::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), NULL, 0);
cout<<"wcsLen="<<wcsLen<<endl;
//分配空间要给'\0'留个空间,MultiByteToWideChar不会给'\0'空间
wchar_t* wszString = new wchar_t[wcsLen + 1];
//转换
::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), wszString, wcsLen);
//最后加上'\0'
wszString[wcsLen] = '\0';
WORD word;
if(fpi!=NULL){
//读取bmp文件的文件头和信息头
fread(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpi);
if(0x4d42!=strHead.bfType){
cout<<"the file is not a bmp file!"<<endl;
return -1;
}
showBmpHead(strHead);//显示文件头
fread(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpi);
showBmpInforHead(strInfo);//显示文件信息头
//读出图片的像素数据
nWidth = strInfo.biWidth;
nHeight = strInfo.biHeight;
//计算像素总大小
DWORD size=nWidth*nHeight;
//动态分配数组大小,大小为实际图片位图高*位图宽
arrayColor=new IMAGEDATA[nWidth*nHeight];
//读取像素信息
fread(arrayColor,1,nWidth*nHeight*sizeof(IMAGEDATA),fpi);
//字体偏移量,用做字体显示
int bitmap_width_sum=0;
//for循环实现一个字一个字插入到图片中
for(int k=0;k<wcsLen;k++){
//复制内存块,把wszString中存储的文字一个一个取出来,复制到word中,已方便读取字体位图
memcpy(&word,wszString+k,2);
//读取一个字体位图到face中
FT_Load_Glyph(pFTFace, FT_Get_Char_Index(pFTFace,word), FT_LOAD_DEFAULT);
error = FT_Get_Glyph(pFTFace -> glyph, & glyph);
// convert glyph to bitmap with 256 gray
FT_Glyph_To_Bitmap( & glyph, ft_render_mode_normal, 0 , 1 );
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
//得到字体的bitmap位图
FT_Bitmap & bitmap = bitmap_glyph -> bitmap;
//把字插入到图片中,每个字中间间隔10个像素,并且离左上角x=100,y=100偏移量
for ( int i = 0 ; i < bitmap.rows; ++ i)
{
for ( int j = 0 ; j < bitmap.width; ++ j)
{
if(bitmap.buffer[i * bitmap.width + j]!=0)
{
//像素点存在,就置为红色,其他都为默认的白色
arrayColor[(i+100)*strInfo.biWidth+j+bitmap_width_sum+100].green=0;
arrayColor[(i+100)*strInfo.biWidth+j+bitmap_width_sum+100].blue=0;
}
}
}
bitmap_width_sum+=bitmap.width+15;
}
// free glyph
FT_Done_Glyph(glyph);
glyph = NULL;
// free face
FT_Done_Face(pFTFace);
pFTFace = NULL;
// free FreeType Lib
FT_Done_FreeType(pFTLib);
pFTLib = NULL;
fclose(fpi);
}
else{
cout<<"file open error!"<<endl;
return -1;
}
//保存bmp图片
if((fpw=fopen("b.bmp","wb"))==NULL){
cout<<"create the bmp file error!"<<endl;
return -1;
}
//写头文件,14位
fwrite(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpw);
//写头文件,40位头文件信息
strInfo.biHeight = -strInfo.biHeight;//正数是从数组的末尾开始扫描,负数表示从数组的开始端开始扫描
fwrite(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpw);
//保存修改后的像素数据
fwrite(arrayColor,1,nWidth*nHeight*sizeof(IMAGEDATA),fpw);
cout<<"保存文件成功"<<endl;
fclose(fpw);
return 0;
}
int main(){
char strFile[30];//bmp文件名
cout<<"请输入所要读取的文件名:"<<endl;
cin>>strFile;
WordInsertToBmp(strFile);
system("pause");
}
图片预览:bmp原始图片用的是纯白的底。