public Vec2i GetKerning(char a, char b) { FTVector26Dot6 temp = font.GetKerning(a, b, KerningMode.Default); Vec2i kerning = new Vec2i(temp.X.Value, temp.Y.Value); return(kerning); }
private void getKernWidthHeight(Face face, FontInfo info, out int width, out int maxHeight, out int firstAdjust) { width = 0; maxHeight = 0; firstAdjust = 0; for (int i = 0; i < characters.Length; i++) { char character1 = characters[i]; uint index1 = face.GetCharIndex(character1); face.LoadGlyph(index1, LoadFlags.Default, LoadTarget.Normal); GlyphMetrics metrics = face.Glyph.Metrics; int yoffset = metrics.VerticalAdvance.ToInt32() - metrics.HorizontalBearingY.ToInt32(); int nheight = yoffset + metrics.Height.ToInt32(); int height = metrics.Height.ToInt32(); if (height > maxHeight) { maxHeight = height; //nheight; firstAdjust = yoffset; } for (int j = 0; j < characters.Length; j++) { char character2 = characters[j]; uint index2 = face.GetCharIndex(character2); FTVector26Dot6 kern = face.GetKerning(index1, index2, KerningMode.Default); int kernX = kern.X.ToInt32(); int kernY = kern.Y.ToInt32(); if (kernX != 0 || kernY != 0) { info.addKerning(new KerningInfo(character1, character2, kernX, kernY)); } } if (i + 1 == characters.Length) { width += metrics.Width.ToInt32() + metrics.HorizontalBearingX.ToInt32() + padX; } else { width += metrics.HorizontalAdvance.ToInt32() + padX; } } }
/// <summary> /// Convert a given glyph object to a bitmap glyph object. /// </summary> /// <remarks><para> /// This function does nothing if the glyph format isn't scalable. /// </para><para> /// The glyph image is translated with the ‘origin’ vector before rendering. /// </para><para> /// The first parameter is a pointer to an <see cref="Glyph"/> handle, that will be replaced by this function /// (with newly allocated data). Typically, you would use (omitting error handling): /// </para><para> /// --sample code ommitted-- /// </para></remarks> /// <param name="renderMode">An enumeration that describes how the data is rendered.</param> /// <param name="origin"> /// A pointer to a vector used to translate the glyph image before rendering. Can be 0 (if no translation). The /// origin is expressed in 26.6 pixels. /// </param> /// <param name="destroy"> /// A boolean that indicates that the original glyph image should be destroyed by this function. It is never /// destroyed in case of error. /// </param> public void ToBitmap(RenderMode renderMode, FTVector26Dot6 origin, bool destroy) { if (disposed) throw new ObjectDisposedException("Glyph", "Cannot access a disposed object."); IntPtr glyphRef = Reference; Error err = FT.FT_Glyph_To_Bitmap(ref glyphRef, renderMode, ref origin, destroy); Reference = glyphRef; if (err != Error.Ok) throw new FreeTypeException(err); }
internal static extern Error FT_Glyph_To_Bitmap(ref IntPtr the_glyph, RenderMode render_mode, ref FTVector26Dot6 origin, [MarshalAs(UnmanagedType.U1)] bool destroy);
internal static extern Error FT_Get_Kerning(IntPtr face, uint left_glyph, uint right_glyph, uint kern_mode, out FTVector26Dot6 akerning);
public void ExportFont(string outputPath) { // should this be user input? int padX = 5; int padY = 5; int atlas = 0; float posX = 0; float posY = 0; List <Bitmap> bitmaps = new List <Bitmap>(); Dictionary <string, List <Info> > infos = new Dictionary <string, List <Info> >(); Bitmap bitmap = new Bitmap(maxWidth, maxHeight, PixelFormat.Format32bppArgb); Graphics graphics = Graphics.FromImage(bitmap); graphics.Clear(Color.Transparent); string output = "module.font = {\n\tinformation = {\n"; output += "\t\tfamily = \"" + family + "\";\n"; output += "\t\tstyles = {" + string.Join(", ", getStyles()) + "};\n"; output += "\t\tsizes = {" + string.Join(", ", sizes) + "};\n"; output += "\t\tuseEnums = " + useEnums() + ";\n\t};\n"; output += "\tstyles = {\n"; foreach (Face face in faces) { infos[face.StyleName] = new List <Info>(); output += "\t\t[\"" + face.StyleName + "\"] = {\n"; foreach (int size in sizes) { Info info = new Info(face.StyleName, size); int lineAdvance = 0; int firstAdjust = 0; float width = 0; float height = 0; float lineHeight = 0; face.SetCharSize(size * 96 / 72, 0, 96, 96); for (int i = 0; i < characters.Length; i++) { char c = characters[i]; uint index = face.GetCharIndex(c); face.LoadGlyph(index, LoadFlags.Default, LoadTarget.Normal); width += (float)face.Glyph.Metrics.HorizontalAdvance; if (face.Glyph.Metrics.Height > lineHeight) { // Get extra space and subtract it from first line draw? firstAdjust = face.Glyph.Metrics.VerticalAdvance.ToInt32() - face.Glyph.Metrics.HorizontalBearingY.ToInt32(); lineHeight = (float)face.Glyph.Metrics.Height; } for (int j = 0; j < characters.Length; j++) { char k = characters[j]; uint index2 = face.GetCharIndex(k); FTVector26Dot6 kern = face.GetKerning(index, index2, KerningMode.Default); int kernx = kern.X.ToInt32(); int kerny = kern.Y.ToInt32(); if (kernx != 0 | kerny != 0) { info.addKerning(c, new Info.kerningInfo(k, kernx, kerny)); } } } if (width > maxWidth) { int overlaps = (int)Math.Truncate(width / maxWidth); width = maxWidth; height = ((overlaps + 1) * (lineHeight + padY)); } else { width = maxWidth; height = lineHeight + padY; } face.SetUnpatentedHinting(true); for (int i = 0; i < characters.Length; i++) { char c = characters[i]; uint index = face.GetCharIndex(c); face.LoadGlyph(index, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); if (c == ' ') { posX += (float)face.Glyph.Metrics.HorizontalAdvance + (float)padX; info.addCharacter(c, new Info.characterInfo(c, face.Glyph.Metrics.HorizontalAdvance.ToInt32(), 0, 0, 0, 0, 0, atlas)); continue; } if (posX + face.Glyph.Metrics.Width + face.Glyph.BitmapLeft + padX > width) { posX = 0; posY += lineHeight + padY; } if (posY > (maxHeight - (lineHeight + padY))) { bitmaps.Add(bitmap); bitmap = new Bitmap(maxWidth, maxHeight, PixelFormat.Format32bppArgb); graphics = Graphics.FromImage(bitmap); graphics.Clear(Color.Transparent); posX = 0; posY = 0; atlas += 1; } int xadvance = face.Glyph.Metrics.HorizontalAdvance.ToInt32(); int imgWidth = face.Glyph.Metrics.Width.ToInt32(); int imgHeight = face.Glyph.Metrics.Height.ToInt32(); int imgX = (int)posX; int imgY = (int)posY; int yoffset = face.Glyph.Metrics.VerticalAdvance.ToInt32() - face.Glyph.Metrics.HorizontalBearingY.ToInt32(); // some fonts that might be missing characters will leave open spaces because their bitmap is empty. if (face.Glyph.Bitmap.Width > 0) { FTBitmap ftbmp = face.Glyph.Bitmap; Bitmap copy = ftbmp.ToGdipBitmap(Color.White); graphics.DrawImageUnscaled(copy, imgX, imgY); } info.addCharacter(c, new Info.characterInfo(c, xadvance, imgX, imgY, yoffset, imgWidth, imgHeight, atlas)); posX += (float)imgWidth + (float)padX; lineAdvance = face.Glyph.Metrics.VerticalAdvance.ToInt32(); } posX = 0; posY += lineHeight + padY; info.lineHeight = lineAdvance; info.firstAdjust = firstAdjust; infos[face.StyleName].Add(info); output += info.buildLuaString("\t\t\t") + "\n"; } output += "\t\t};\n"; } output += "\t};\n};\n"; bitmaps.Add(bitmap); graphics.Dispose(); // create images int count = 0; foreach (Bitmap bmp in bitmaps) { count += 1; bmp.Save(outputPath + "\\" + family + "_" + count + ".png"); } string header = "--[[\n\t@Font " + family + "\n"; header += "\t@Sizes {" + string.Join(", ", sizes) + "}\n"; header += "\t@Author N/A\n"; header += "\t@Link N/A\n--]]\n\n"; header += "local module = {};\n\n"; header += "module.atlases = {\n"; for (int i = 1; i <= count; i++) { header += "\t[" + i + "] = \"rbxassetid://\";\n"; } header += "};\n\n" + output; header += "\n\nreturn module;"; File.WriteAllText(outputPath + "\\" + family + ".lua", header); }