FreeType 2.8字体引擎 + MFC实现

阿拉伯语有没人实现?实现了上代码啊


效果:

FreeType 2.8字体引擎 + MFC实现_第1张图片

#if 0
https://www.freetype.org/freetype2/docs/tutorial/step1.html
  https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html
  http://www.unixresources.net/linux/clf/kylix/archive/00/00/59/21/592188.html
#endif


别说程序规范不好,只是测试~_~


#define FONT_SIZE							18
#define VIEW_WIDTH							1000
#define VIEW_HEIGHT							600


void TestFreeType_02()
{
	FT_Error error = 0;
	FT_Library library;
	FT_Face face;
	FT_GlyphSlot slot;
	FT_Vector pen;
	FT_Matrix matrix;
	double angle = (0.0 / 360) * 3.1415926 * 2;

	long t1 = GetTickCount();

	error = FT_Init_FreeType(&library); // 创建FreeType的library并设置处理库,加载各个模块
	if (0 != error)
	{
		// 发生错误
	}

	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\msyh.ttc", 0, &face); // 雅黑
																					//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\dd\\msyh.ttf", 0, &face); // 雅黑
	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\Fonts\\segoeui.ttf", 0, &face); // 雅黑
	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\segoeui.ttf", 0, &face); // Segoe
	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\simsun.ttc", 0, &face); // 
	error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\simhei.ttf", 0, &face); // 黑体
	if (FT_Err_Unknown_File_Format == error) // 未知文件格式
	{
	}
	else if (FT_Err_Cannot_Open_Resource == error)
	{
	}
	else if (error)
	{
		// 发生错误
	}

	FT_Select_Charmap(face, FT_ENCODING_UNICODE); 
	//FT_Select_Charmap(face, FT_ENCODING_PRC);

	FT_CharMap charmap;
	slot = face->glyph;
	int num = face->num_glyphs; // 字体轮廓数量
	int num_charmaps = face->num_charmaps;
	for (int n = 0; n < face->num_charmaps; n++)
	{
		charmap = face->charmaps[n];
	}

#if 0
	error = FT_Set_Char_Size(face,
		0, // char_width in 1/64th of points
		FONT_SIZE * 64, // char_height in 1/64th of points
		VIEW_WIDTH, // 水平分辨率
		VIEW_HEIGHT); // 垂直分辨率
#else
	error = FT_Set_Pixel_Sizes(face,  /* handle to face object */
												FONT_SIZE,     /* pixel_width,0表示和高度一致 */
												0);  /* pixel_height */
#endif
	if (0 != error)
	{
	}

	matrix.xx = (FT_Fixed)(cos(angle) * 0x10000L);
	matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000L);
	matrix.yx = (FT_Fixed)(sin(angle) * 0x10000L);
	matrix.yy = (FT_Fixed)(cos(angle) * 0x10000L);

	wchar_t *str = L"FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎";
	//wchar_t *str = L"阿拉伯语:عربية‎ لغة ‎";

	CClientDC dc(this);
	CRect rect;
	GetClientRect(&rect);
	dc.FillSolidRect(&rect, RGB(0, 0, 0));

	CDC dcMem;                                                  //用于缓冲作图的内存DC
	CBitmap bmp;                                                 //内存中承载临时图象的位图
	dcMem.CreateCompatibleDC(&dc);               //依附窗口DC创建兼容内存DC
	bmp.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());//创建兼容位图
	CBitmap*pOldBitmap = dcMem.SelectObject(&bmp);                          //将位图选择进内存DC
	dcMem.FillSolidRect(rect, dc.GetBkColor());

	pen.x = 0;
	pen.y = 0;
	int ymin = 0;
	int ymax = 0;
	int topest = 0;
	int maxHeight = 0;

	int left = 0;
	int top = 0;
	int strLen = wcslen(str);

	for (int i = 0; i < strLen; i++)
	{
#if 0
		FT_Set_Transform(face, &matrix, &pen);

		error = FT_Load_Char(face, str[i], FT_LOAD_RENDER);
		if (0 != error)
		{
		}
#else
		FT_UInt index = FT_Get_Char_Index(face, str[i]);

		error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT/* | FT_LOAD_MONOCHROME*/); // 装载一个字形图像到字形槽中
		if (0 != error)
		{
		}

		if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
		{
			int aasdfsdaf = 0;
		}

		//error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); // 转换为位图
		error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); // 转换为位图
		if (0 != error)
		{
		}

#endif

		int bitmap_width = slot->bitmap.width;
		int bitmap_rows = slot->bitmap.rows;
		int pitch = slot->bitmap.pitch;

		/* now, draw to our target surface */
		//DrawBitmap(&slot->bitmap, pen.x, pen.y);

		// 测试,每显示一个字符,在其左边界画一条竖线
		//dc.MoveTo(slot->bitmap_left, 0);
		//dc.LineTo(slot->bitmap_left, 40);

		if (maxHeight < face->size->metrics.height / 64)
		{
			maxHeight = face->size->metrics.height / 64;
		}

		left = pen.x / 64;
		//int top = pen.y + face->size->metrics.ascender / 64 - slot->bitmap_top;
		
		if (left + bitmap_width >= VIEW_WIDTH)
		{
			pen.x = 0;
			pen.y += face->size->metrics.height / 64;

			left = pen.x / 64;
		}
		top = pen.y + maxHeight - slot->bitmap_top;

		//DrawBitmap(left, top, &slot->bitmap);
		DrawBitmap(left, top, &slot->bitmap, &dcMem);

		int width = left + slot->bitmap.width;
		int height = top + slot->bitmap.rows;

		if (top < topest)
			topest = top;


		//pen.x += slot->advance.x >> 6;
		//pen.y += slot->advance.y >> 6; /* not useful for now */
		pen.x += slot->advance.x;
		left = pen.x / 64;

		if (face->bbox.yMin < ymin)
			ymin = face->bbox.yMin;
		if (face->bbox.yMax > ymax)
			ymax = face->bbox.yMax;



		//dc.MoveTo(0, topest);
		//dc.LineTo(VIEW_WIDTH, topest);

		//pen.y += slot->advance.y;
	}
	
	//dc.MoveTo(0, maxHeight);
	//dc.LineTo(1400, maxHeight);
	//dc.MoveTo(0, (ymax + ymin) / 64);
	//dc.LineTo(1400, (ymax + ymin) / 64);

	FT_Done_Face(face);
	FT_Done_FreeType(library);

	long t2 = GetTickCount();
	long time = 0;
	time = t2 - t1;

	dc.SelectObject(pOldBitmap);
	dc.BitBlt(0, 0, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY);//将内存DC上的图象拷贝到前台

	dcMem.DeleteDC();                                       //删除DC
	bmp.DeleteObject();                                        //删除位图


	CString string;
	string.Format(L"Expend time: %ld(ms)", time); //将变量组装到字符串中
	MessageBox(string);
}


void DrawBitmap(int left, int top, FT_Bitmap *ftBitmap,  CDC *dc)
{
	int right = left + ftBitmap->width;
	int bottom = top + ftBitmap->rows;
	int x = 0;
	int columnIdx = 0;
	int y = 0;
	int rowIdx = 0;

	for (x = left; x < right; x++, columnIdx++)
	{
		if (x < 0 || x >= VIEW_WIDTH)
			continue;

		for (y = top, rowIdx = 0; y < bottom; y++, rowIdx++)
		{
			if (y < 0 || y >= VIEW_HEIGHT)
				continue;

			unsigned char color = ftBitmap->buffer[rowIdx * ftBitmap->width + columnIdx];

			dc->SetPixel(x, y, RGB(255 - color,255 - color,255 - color)); // 黑字
		}
	}
}


居中对齐

FreeType 2.8字体引擎 + MFC实现_第2张图片


自定义一个结构体,存放临时数据

typedef struct FT_BitmapAttr
{
	FT_Int bitmap_left;
	FT_Int bitmap_top;
	FT_Vector advance;
	FT_Bitmap bitmap;
} FT_BitmapAttr_t, *PFT_BitmapAttr_t;

void TestFreeType_05()
{

	FT_Error error = 0;
	FT_Library library;
	FT_Face face;
	FT_GlyphSlot slot;
	FT_Vector pen;
	FT_Matrix matrix;
	double angle = (0.0 / 360) * 3.1415926 * 2;

	long t1 = GetTickCount();

	error = FT_Init_FreeType(&library); // 创建FreeType的library并设置处理库,加载各个模块
	if (0 != error)
	{
		// 发生错误
	}

	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\msyh.ttc", 0, &face); // 雅黑
	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\dd\\msyh.ttf", 0, &face); // 雅黑
	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\Fonts\\segoeui.ttf", 0, &face); // 雅黑
	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\segoeui.ttf", 0, &face); // Segoe
	//error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\simsun.ttc", 0, &face); // 
	error = FT_New_Face(library, "C:\\Users\\FX\\Desktop\\YH\\simhei.ttf", 0, &face); // 黑体
	if (FT_Err_Unknown_File_Format == error) // 未知文件格式
	{
	}
	else if (FT_Err_Cannot_Open_Resource == error)
	{
	}
	else if (error)
	{
		// 发生错误
	}

	FT_Select_Charmap(face, FT_ENCODING_UNICODE);
	//FT_Select_Charmap(face, FT_ENCODING_PRC);

	FT_CharMap charmap;
	slot = face->glyph;
	int num = face->num_glyphs; // 字体轮廓数量
	int num_charmaps = face->num_charmaps;
	for (int n = 0; n < face->num_charmaps; n++)
	{
		charmap = face->charmaps[n];
	}

#if 0
	error = FT_Set_Char_Size(face,
		0, // char_width in 1/64th of points
		FONT_SIZE * 64, // char_height in 1/64th of points
		VIEW_WIDTH, // 水平分辨率
		VIEW_HEIGHT); // 垂直分辨率
#else
	error = FT_Set_Pixel_Sizes(face,  /* handle to face object */
		FONT_SIZE,     /* pixel_width,0表示和高度一致 */
		0);  /* pixel_height */
#endif
	if (0 != error)
	{
	}

	matrix.xx = (FT_Fixed)(cos(angle) * 0x10000L);
	matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000L);
	matrix.yx = (FT_Fixed)(sin(angle) * 0x10000L);
	matrix.yy = (FT_Fixed)(cos(angle) * 0x10000L);

	wchar_t *str = L"FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,包括TrueType, OpenType, Type1, CID, CFF, Windows FON/FNT, X11 PCF等。\r\n		0123456789abceefghijklmnopqrstuvwxyz ABCEFGHIJKLMNOPQRSTUVWXYZ		支持单色位图、反走样位图的渲染。FreeType库是高度模块化的程序库,虽然它是使用ANSI C开发,但是采用面向对象的思想,因此,FreeType的用户可以灵活地对它进行裁剪。1. FreeType 2 为访问字体文件提供了一套统一的、独立于字体文件类型的、简单而易用的API。另外,一些特别类型的API可以用来访问字体文件里的特殊数据。2. 与大多数同类的字库不同,FreeType 2 生来就支持类似TrueType 或者 Type 1的可缩放字体类型,并且可以将字体的大纲数据(控件介绍/提示)返回给各户应用程序。3. FreeType 2 的设计是基于模块的,这些模块可以在编译时被静态链接到库中或者在运行时根据需要加载。模块可以用来支持特殊的字体格式,或者甚至是新的符号图像类型!4. FreeType 2 特意使用嵌入式系统编写,这意味着它不使用静态可写数据(也就是说,它可以直接从ROM中运行),这样客户程序就可以只为他们自己提供内存管理和输入/输出流的实现。5. 客户程序自己的输入/输出流可以使你轻易地使用相同的API读取基于ROM或被压缩的或远程的字体文件。多个流实现可以并行的被一个FreeType 2 实例使用。6. 你可以只编译那些你的嵌入式工程或环境需要的模块,从而有效的减小FreeType 2 的代码大小。7. FreeType 2 默认支持下面的字体类型:TrueType 字体(集合)Type 1 字体CID-keyed Type 1 字体CFF 字体8. 通过一个给定的字形轮廓,FreeType 2 有能力产生一个高质量的单色位图或一幅使用年256阶灰度的不走样的像素图。这比Windows 9x/98/NT/2000 或 FreeType 1使用的5阶灰度像素图要好得多。9. FreeType 2 支持 TrueType 和 OpenType 规格定义的全部字符映射。同时,它也完全有能力自动合成Type 1 使用的那种Unicode字符表,这种表要求必须把一个那种令人头痛的供转换编码时使用的结束符放置在标的末尾——这在Type 1 使用的那种格式中是很常见的(当然,如果你需要,那种原始的编码方式也是可用的)。10. FreeType 2 的核心API提供了对访问字形名或调整数据中字符间距这样的高级信息的函数支持。11. 一个完整且有效率的TrueType字节码解释器。这个引擎可以用很小的点产生极好的输出。由于TrueType规格极其令人费解且十分含糊,这个组件想要成功完成输出是极其困难的。但无论如何,我们现在已经能使Windows的显示质量达到Mac的水平。12. 对于那些不需要或不希望为TrueType字体使用字节码解释器的人,我们开发了我们自己的自动提示模块。这种模块过去也曾被一些可缩放的字体使用过。13. FreeType 2 可以产生一些相似的字体引擎无法产生的信息,例如字距调整的位距、字符名、垂直度量之类的。由于它模块化的设计,可以很方便地通过可选的API更改FreeType库来提供另外的针对特定字体类型的信息。(例如,一个可选的API用来检索TrueType 和 OpenType 字体的SFNT表。14. 自从2.0.1版发布开始,FreeType 2 开始提供它自己的超高速缓存子系统。可以利用它缓存可变实例或字形图像,使它们拥有更高的效率。[1] ";
	//wchar_t *str = L"FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎";
	//wchar_t *str = L"FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,包括Tr";
	//wchar_t *str = L"FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,包括True";

	CClientDC dc(this);
	CRect rect(0, 0, VIEW_WIDTH, VIEW_HEIGHT);
	//GetClientRect(&rect);
	dc.FillSolidRect(&rect, RGB(0, 0, 0));

	CDC dcMem;                                                  //用于缓冲作图的内存DC
	CBitmap bmp;                                                 //内存中承载临时图象的位图
	dcMem.CreateCompatibleDC(&dc);               //依附窗口DC创建兼容内存DC
	bmp.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());//创建兼容位图
	CBitmap*pOldBitmap = dcMem.SelectObject(&bmp);                          //将位图选择进内存DC
	dcMem.FillSolidRect(rect, dc.GetBkColor());

	pen.x = 0;
	pen.y = 0;
	int ymin = 0;
	int ymax = 0;
	int topest = 0;
	int maxHeight = 0;

	int left = 0;
	int top = 0;
	int strLen = wcslen(str);
	vector bmpAttrs;

	slots.reserve(strLen);

	for (int i = 0; i < strLen; i++)
	{
#if 0
		FT_Set_Transform(face, &matrix, &pen);

		error = FT_Load_Char(face, str[i], FT_LOAD_RENDER);
		if (0 != error)
		{
		}
#else
		FT_UInt index = FT_Get_Char_Index(face, str[i]);

		error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT/* | FT_LOAD_MONOCHROME*/); // 装载一个字形图像到字形槽中
		if (0 != error)
		{
		}

		error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); // 转换为位图
		if (0 != error)
		{
		}

#endif

#if 1
		int bmpsize = slot->bitmap.width * slot->bitmap.rows;

		FT_BitmapAttr_t tmpAttr;
		tmpAttr.bitmap_left = slot->bitmap_left;
		tmpAttr.bitmap_top = slot->bitmap_top;
		tmpAttr.advance.x = slot->advance.x;
		tmpAttr.advance.y = slot->advance.y;

		memcpy((void *)(&tmpAttr.bitmap), (void *)(&slot->bitmap), sizeof(FT_Bitmap));
		tmpAttr.bitmap.buffer = new unsigned char[bmpsize];
		memset(tmpAttr.bitmap.buffer, 0, bmpsize);
		memcpy((void *)tmpAttr.bitmap.buffer, slot->bitmap.buffer, bmpsize);
		
		bmpAttrs.push_back(tmpAttr);

#else
		int bitmap_width = slot->bitmap.width;

		left = pen.x >> 6;
		if (left + bitmap_width >= VIEW_WIDTH)
		{
			pen.x = 0;
			pen.y += face->size->metrics.height >> 6;

			left = pen.x >> 6;
		}
		top = pen.y + face->size->metrics.ascender >> 6 - slot->bitmap_top;

		DrawBitmap(left, top, &slot->bitmap, &dcMem);

		pen.x += slot->advance.x;
#endif
	}

#if 1
	long totalWidth = 0;
	int totalLines = 0;
	int size = bmpAttrs.size();
	for (int is = 0; is < size; is++)
	{
		totalWidth += bmpAttrs[is].advance.x >> 6;
	}

	totalLines = totalWidth / VIEW_WIDTH;
	totalLines += (0 == totalWidth % VIEW_WIDTH) ? 0 : 1;

	int stringBlockHeight = totalLines * (face->size->metrics.height >> 6);
	int startTop = (VIEW_HEIGHT - stringBlockHeight) >> 1;

	int lineHeigth = face->size->metrics.height >> 6;
	if (1 < totalLines) // 超过1行
	{
		pen.x = 0;
		pen.y = startTop;
	}
	else // 只有一行
	{
		pen.x = ((VIEW_WIDTH - totalWidth) >> 1) << 6;
		pen.y = startTop;
	}

	for (int is = 0; is < size; is++)
	{
		FT_BitmapAttr_t &bmpAttr = bmpAttrs[is];

		left = pen.x >> 6;
		if (left + bmpAttr.bitmap.width > VIEW_WIDTH)
		{
			pen.x = 0;
			pen.y += lineHeigth;

			left = pen.x >> 6;
		}
		top = pen.y + lineHeigth - bmpAttr.bitmap_top;

		DrawBitmap(left, top, &bmpAttr.bitmap, &dcMem);

		pen.x += bmpAttr.advance.x;

		delete []bmpAttr.bitmap.buffer;
		bmpAttr.bitmap.buffer = NULL;
	}

	bmpAttrs.erase(bmpAttrs.begin(), bmpAttrs.end());
	bmpAttrs.clear();
#endif

	FT_Done_Face(face);
	FT_Done_FreeType(library);

	long t2 = GetTickCount();
	long time = 0;
	time = t2 - t1;

	dc.SelectObject(pOldBitmap);
	dc.BitBlt(0, 0, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY);//将内存DC上的图象拷贝到前台

	dcMem.DeleteDC();                                       //删除DC
	bmp.DeleteObject();                                        //删除位图

	CString string;
	string.Format(L"Expend time: %ld(ms)", time); //将变量组装到字符串中
	MessageBox(string);
}




你可能感兴趣的:(FreeType 2.8字体引擎 + MFC实现)