您的位置:首页 > 编程语言 > C#

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文件并把所有字形安排到一张大贴图上的过程。

/// <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绘制文字了。下回再叙。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: