C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图
2015-08-07 17:30
447 查看
[b]C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图 [/b]
+BIT祝威+悄悄在此留下版了个权的信息说:
最近需要用OpenGL绘制文字,这是个很费时费力的事。一般的思路就是解析TTF文件从而得到字形的贴图,然后通过OpenGL绘制贴图的方式显示文字。
本篇记录了解析TTF文件并把所有字形安排到一张大贴图上的过程。
生成贴图
.png]
下面展示了获取某些中文字符的情形。
下面展示了获取所有unicode字符的情形。由于整个unicode字符太多,所以只显示了一部分。
改进了UI,可以一次指定多个TTF文件,开始计算后有进度条展示进度。下图展示的是生成多个TTF文件的汉字部分贴图。此版下载地址在这里。
+BIT祝威+悄悄在此留下版了个权的信息说:
+BIT祝威+悄悄在此留下版了个权的信息说:
最近需要用OpenGL绘制文字,这是个很费时费力的事。一般的思路就是解析TTF文件从而得到字形的贴图,然后通过OpenGL绘制贴图的方式显示文字。
本篇记录了解析TTF文件并把所有字形安排到一张大贴图上的过程。
/// <summary> /// 用一个纹理绘制ASCII表上所有可见字符(具有指定的高度和字体) /// </summary> public class ModernSingleTextureFont { private string fontFullname; private char firstChar; private char lastChar; private int maxWidth; private int fontHeight; private int textureWidth; private int textureHeight; Dictionary<char, CharacterInfo> charInfoDict = new Dictionary<char, CharacterInfo>(); /// <summary> /// 用一个纹理绘制ASCII表上所有可见字符(具有指定的高度和字体) /// </summary> /// <param name="fontFullname"></param> /// <param name="fontHeight">此值越大,绘制文字的清晰度越高,但占用的纹理资源就越多。</param> /// <param name="firstChar"></param> /// <param name="lastChar"></param> /// <param name="maxWidth">生成的纹理的最大宽度。</param> public ModernSingleTextureFont(string fontFullname, int fontHeight, char firstChar, char lastChar, int maxWidth) { this.fontFullname = fontFullname; this.fontHeight = fontHeight; this.firstChar = firstChar; this.lastChar = lastChar; this.maxWidth = maxWidth; } public System.Drawing.Bitmap GetBitmap() { // 初始化FreeType库:创建FreeType库指针 FreeTypeLibrary library = new FreeTypeLibrary(); // 初始化字体库 FreeTypeFace face = new FreeTypeFace(library, this.fontFullname); GetTextureBlueprint(face, this.fontHeight, this.maxWidth, out this.textureWidth, out this.textureHeight); System.Drawing.Bitmap bigBitmap = GetBigBitmap(face, this.maxWidth, this.textureWidth, this.textureHeight); face.Dispose(); library.Dispose(); return bigBitmap; } private System.Drawing.Bitmap GetBigBitmap(FreeTypeFace face, int maxTextureWidth, int widthOfTexture, int heightOfTexture) { System.Drawing.Bitmap bigBitmap = new System.Drawing.Bitmap(widthOfTexture, heightOfTexture); Graphics graphics = Graphics.FromImage(bigBitmap); //for (int i = (int)this.firstChar; i <= (int)this.lastChar; i++) for (char c = this.firstChar; c <= this.lastChar; c++) { //char c = Convert.ToChar(i); FreeTypeBitmapGlyph glyph = new FreeTypeBitmapGlyph(face, c, this.fontHeight); bool zeroSize = (glyph.obj.bitmap.rows == 0 && glyph.obj.bitmap.width == 0); bool zeroBuffer = glyph.obj.bitmap.buffer == IntPtr.Zero; if (zeroSize && (!zeroBuffer)) { throw new Exception(); } if ((!zeroSize) && zeroBuffer) { throw new Exception(); } if (!zeroSize) { int size = glyph.obj.bitmap.width * glyph.obj.bitmap.rows; byte[] byteBitmap = new byte[size]; Marshal.Copy(glyph.obj.bitmap.buffer, byteBitmap, 0, byteBitmap.Length); CharacterInfo cInfo; if (this.charInfoDict.TryGetValue(c, out cInfo)) { if (cInfo.width > 0) { System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(cInfo.width, cInfo.height); for (int tmpRow = 0; tmpRow < cInfo.height; ++tmpRow) { for (int tmpWidth = 0; tmpWidth < cInfo.width; ++tmpWidth) { byte color = byteBitmap[tmpRow * cInfo.width + tmpWidth]; bitmap.SetPixel(tmpWidth, tmpRow, Color.FromArgb(color, color, color)); } } int baseLine = this.fontHeight / 4 * 3; graphics.DrawImage(bitmap, cInfo.xoffset, cInfo.yoffset + baseLine - glyph.obj.top); } } else { throw new Exception(string.Format("Not support for display the char [{0}]", c)); } } } graphics.Dispose(); return bigBitmap; } private void GetTextureBlueprint(FreeTypeFace face, int fontHeight, int maxTextureWidth, out int widthOfTexture, out int heightOfTexture) { widthOfTexture = 0; heightOfTexture = this.fontHeight; int glyphX = 0; int glyphY = 0; for (int i = (int)this.firstChar; i <= (int)this.lastChar; i++) { char c = Convert.ToChar(i); FreeTypeBitmapGlyph glyph = new FreeTypeBitmapGlyph(face, c, fontHeight); bool zeroSize = (glyph.obj.bitmap.rows == 0 && glyph.obj.bitmap.width == 0); bool zeroBuffer = glyph.obj.bitmap.buffer == IntPtr.Zero; if (zeroSize && (!zeroBuffer)) { throw new Exception(); } if ((!zeroSize) && zeroBuffer) { throw new Exception(); } if (zeroSize) { continue; } int glyphWidth = glyph.obj.bitmap.width; int glyphHeight = glyph.obj.bitmap.rows; if (glyphX + glyphWidth + 1 > maxTextureWidth) { heightOfTexture += this.fontHeight; glyphX = 0; glyphY = heightOfTexture - this.fontHeight; CharacterInfo cInfo = new CharacterInfo(); cInfo.xoffset = glyphX; cInfo.yoffset = glyphY; cInfo.width = glyphWidth; cInfo.height = glyphHeight; this.charInfoDict.Add(c, cInfo); } else { widthOfTexture = Math.Max(widthOfTexture, glyphX + glyphWidth + 1); CharacterInfo cInfo = new CharacterInfo(); cInfo.xoffset = glyphX; cInfo.yoffset = glyphY; cInfo.width = glyphWidth; cInfo.height = glyphHeight; this.charInfoDict.Add(c, cInfo); } glyphX += glyphWidth + 1; } } }
生成贴图
开源TTF2Bmps下载
根据本篇记录的内容,我写了TTF2Bmps这个程序,可以将任何一个TTF文件解析为BMP图片。你可以在此下载。.png]
2015-08-08
TTF2Bmps现在能够获取所有unicode字符的字形,对输入方式也做了改进。新版的下载地址在此。下面展示了获取某些中文字符的情形。
下面展示了获取所有unicode字符的情形。由于整个unicode字符太多,所以只显示了一部分。
改进了UI,可以一次指定多个TTF文件,开始计算后有进度条展示进度。下图展示的是生成多个TTF文件的汉字部分贴图。此版下载地址在这里。
2015-08-10
改进了UI,可以详细显示进度。可以生成贴图对应的Xml文件(包含贴图每个字形的位置信息)。贴图增加红色虚线标识各行的界限。可选择生成各个字形及其位置信息的列表(多个PNG)。此版下载地址在这里。2015-08-12
特殊处理空格、tab。调整UI。修复若干bug。+BIT祝威+悄悄在此留下版了个权的信息说:
总结
有了贴图,下一步就可以用OpenGL绘制文字了。下回再叙。相关文章推荐
- C#事件与委托详解
- c# ros
- 实习第9天 C# 跨线程操作了主线程的控件
- 深入C#内存管理来分析值类型&引用类型,装箱&拆箱,堆栈几个概念组合之间的区别
- c#中动态对象的RuntimeTypeHandle
- 《VC#2008核心编程》读书笔记
- C# 委托及各种写法
- C# 获取当前路径方法
- 用IKVMC将jar转成dll供c#调用
- C# Excel 条件格式
- C#高级编程七十八天----自定义特性
- C#之Lambda不得不说的用法
- C# string类型和byte[]类型相互转换
- C# Unicode 编码转换
- PDF之itextsharp的使用开发历程2
- C# 队列
- C# 堆栈
- c# 下载网页图片
- CLR via C# 读书笔记 1-2 创建线程的成本
- C#中泛型的详细介绍