Show More
Commit Description:
Attribute Iosevka and fix links.
Commit Description:
Attribute Iosevka and fix links.
References:
File last commit:
Show/Diff file:
Action:
SpriteFontPlus/src/TtfFontBaker.cs
123 lines | 3.1 KiB | text/x-csharp | CSharpLexer
123 lines | 3.1 KiB | text/x-csharp | CSharpLexer
r0 | using SpriteFontPlus.Utility; | ||
using StbTrueTypeSharp; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
namespace SpriteFontPlus | |||
{ | |||
public static class TtfFontBaker | |||
{ | |||
public static TtfFontBakerResult Bake(Stream ttfStream, float fontPixelHeight, | |||
int bitmapWidth, int bitmapHeight, | |||
IEnumerable<CharacterRange> characterRanges) | |||
{ | |||
return Bake(ttfStream.ToByteArray(), fontPixelHeight, bitmapWidth, bitmapHeight, characterRanges); | |||
} | |||
public unsafe static TtfFontBakerResult Bake(byte[] ttf, float fontPixelHeight, | |||
int bitmapWidth, int bitmapHeight, | |||
IEnumerable<CharacterRange> characterRanges) | |||
{ | |||
if (ttf == null || ttf.Length == 0) | |||
{ | |||
throw new ArgumentNullException(nameof(ttf)); | |||
} | |||
if (fontPixelHeight <= 0) | |||
{ | |||
throw new ArgumentOutOfRangeException(nameof(fontPixelHeight)); | |||
} | |||
if (bitmapWidth <= 0) | |||
{ | |||
throw new ArgumentOutOfRangeException(nameof(bitmapWidth)); | |||
} | |||
if (bitmapHeight <= 0) | |||
{ | |||
throw new ArgumentOutOfRangeException(nameof(bitmapHeight)); | |||
} | |||
if (characterRanges == null) | |||
{ | |||
throw new ArgumentNullException(nameof(characterRanges)); | |||
} | |||
if (!characterRanges.Any()) | |||
{ | |||
throw new ArgumentException("characterRanges must have a least one value."); | |||
} | |||
byte[] pixels; | |||
var glyphs = new Dictionary<int, GlyphInfo>(); | |||
StbTrueType.stbtt_fontinfo fontInfo = new StbTrueType.stbtt_fontinfo(); | |||
fixed (byte* ttfPtr = ttf) | |||
{ | |||
if (StbTrueType.stbtt_InitFont(fontInfo, ttfPtr, 0) == 0) | |||
{ | |||
throw new Exception("Failed to init font."); | |||
} | |||
} | |||
float scaleFactor = StbTrueType.stbtt_ScaleForPixelHeight(fontInfo, fontPixelHeight); | |||
int ascent, descent, lineGap; | |||
StbTrueType.stbtt_GetFontVMetrics(fontInfo, &ascent, &descent, &lineGap); | |||
pixels = new byte[bitmapWidth * bitmapHeight]; | |||
StbTrueType.stbtt_pack_context pc = new StbTrueType.stbtt_pack_context(); | |||
fixed (byte* ttfPtr = ttf) | |||
fixed (byte* pixelsPtr = pixels) | |||
{ | |||
StbTrueType.stbtt_PackBegin(pc, pixelsPtr, bitmapWidth, | |||
bitmapHeight, bitmapWidth, 1, null); | |||
foreach (var range in characterRanges) | |||
{ | |||
if (range.Start > range.End) | |||
{ | |||
continue; | |||
} | |||
var cd = new StbTrueType.stbtt_packedchar[range.End - range.Start + 1]; | |||
for (var i = 0; i < cd.Length; ++i) | |||
{ | |||
cd[i] = new StbTrueType.stbtt_packedchar(); | |||
} | |||
fixed (StbTrueType.stbtt_packedchar* cdPtr = cd) | |||
{ | |||
StbTrueType.stbtt_PackFontRange(pc, ttfPtr, 0, fontPixelHeight, | |||
range.Start, | |||
range.End - range.Start + 1, | |||
cdPtr); | |||
} | |||
for (var i = 0; i < cd.Length; ++i) | |||
{ | |||
var yOff = cd[i].yoff; | |||
yOff += ascent * scaleFactor; | |||
var glyphInfo = new GlyphInfo | |||
{ | |||
X = cd[i].x0, | |||
Y = cd[i].y0, | |||
Width = cd[i].x1 - cd[i].x0, | |||
Height = cd[i].y1 - cd[i].y0, | |||
XOffset = (int)cd[i].xoff, | |||
YOffset = (int)Math.Round(yOff), | |||
XAdvance = (int)Math.Round(cd[i].xadvance) | |||
}; | |||
glyphs[(char)(i + range.Start)] = glyphInfo; | |||
} | |||
} | |||
} | |||
return new TtfFontBakerResult(glyphs, fontPixelHeight, pixels, bitmapWidth, bitmapHeight); | |||
} | |||
} | |||
} |