使用freetype库将文字嵌入到bmp图片中 学习笔记

首先需要打开一张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原始图片用的是纯白的底。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值