static void Main(string[] args) { Console.WriteLine("Version string: " + HB.VersionString); Version v = HB.Version; Console.WriteLine("Version: " + v.Major + "." + v.Minor + "." + v.Build); Console.WriteLine("VersionCheck: " + HB.VersionAtLeast(v)); var lib = new Library(); var face = new SharpFont.Face(lib, @"C:\Windows\Fonts\tahoma.ttf"); face.SetCharSize(0, 50, 72, 72); var font = HarfBuzz.Font.FromFTFace(face); var buf = new HarfBuzz.Buffer(); buf.Direction = Direction.RightToLeft; buf.Script = Script.Arabic; buf.AddText("متن"); font.Shape(buf); var glyphInfos = buf.GlyphInfo(); var glyphPositions = buf.GlyphPositions(); int height = (face.MaxAdvanceHeight - face.Descender) >> 6; int width = 0; for (int i = 0; i < glyphInfos.Length; ++i) { width += glyphPositions[i].xAdvance >> 6; } Bitmap bmp = new Bitmap(width, height); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.Gray); int penX = 0, penY = face.MaxAdvanceHeight >> 6; //draw the string for (int i = 0; i < glyphInfos.Length; ++i) { face.LoadGlyph(glyphInfos[i].codepoint, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); Bitmap cBmp = face.Glyph.Bitmap.ToGdipBitmap(Color.Firebrick); g.DrawImageUnscaled(cBmp, penX + (glyphPositions[i].xOffset >> 6) + face.Glyph.BitmapLeft, penY - (glyphPositions[i].yOffset >> 6) - face.Glyph.BitmapTop); penX += glyphPositions[i].xAdvance >> 6; penY -= glyphPositions[i].yAdvance >> 6; } g.Dispose(); bmp.Save("output.bmp"); }
private void listBoxFont_SelectedIndexChanged(object sender, EventArgs e) { fontFace = new Face(lib, Path.Combine(Path.GetFullPath(fontFolder), (string)listBoxFont.SelectedItem)); fontFace.SetCharSize(0, 62, 0, 96); dataGridView1.Columns.Add("PlatformId", "PlatformId"); dataGridView1.Columns.Add("Encoding", "Encoding"); dataGridView1.Columns.Add("EncodingId", "EncodingId"); CharMap[] cmaps = fontFace.CharMaps; foreach(CharMap cmap in cmaps) { dataGridView1.Rows.Add(cmap.PlatformId, cmap.Encoding, cmap.EncodingId); } Header headerTable = (Header)fontFace.GetSfntTable(SfntTag.Header); HoriHeader horiHeaderTable = (HoriHeader)fontFace.GetSfntTable(SfntTag.HorizontalHeader); MaxProfile maxpTable = (MaxProfile)fontFace.GetSfntTable(SfntTag.MaxProfile); OS2 os2Table = (OS2)fontFace.GetSfntTable(SfntTag.OS2); Pclt PcltTable = (Pclt)fontFace.GetSfntTable(SfntTag.Pclt); Postscript postTable = (Postscript)fontFace.GetSfntTable(SfntTag.Postscript); VertHeader vertTable = (VertHeader)fontFace.GetSfntTable(SfntTag.VertHeader); pictureBoxText.Invalidate(); }
private void SetFontFaceSize(Face fontFace, Vector2 size) { // calculate and set the size of the font // size is in 26.6 factional points (that is in 1/64th of points) // 72 => the sizes are in "points" (=1/72 inch), setting resolution to 72 dpi let us specify the size in pixels directly fontFace.SetCharSize((int)Math.Ceiling(size.X * 64), (int)Math.Ceiling(size.Y * 64), 72, 72); }
void BuildTextureOld() { #region attribution // Significant parts of this method were based off the following example: // https://github.com/Robmaister/SharpFont/blob/master/Source/Examples/Program.cs // The following license and attribution applies to those parts: /*Copyright (c) 2012 Robert Rouhani <*****@*****.**> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ #endregion Face face = new Face(ftLib, "C:\\Windows\\Fonts\\segoeui.ttf"); face.SetCharSize(0, 14, 72, 72); //face.SetPixelSizes(0, 14); const LoadFlags loadFlags = LoadFlags.Default; const LoadTarget loadTarget = LoadTarget.Light; const RenderMode renderMode = RenderMode.Light; float cx = 0, cy = 0, tw = 0, th = 0; // base size face.LoadGlyph(face.GetCharIndex('A'), loadFlags, loadTarget); th = (float)face.Glyph.Metrics.Height; for (int i = 0; i < text.Length; i++) { char c = text[i]; uint cnum = face.GetCharIndex(c); face.LoadGlyph(cnum, loadFlags, loadTarget); tw += (float)face.Glyph.Advance.X; if (face.HasKerning && i < text.Length - 1) tw += (float)face.GetKerning(cnum, face.GetCharIndex(text[i + 1]), KerningMode.Default).X; th = Math.Max(th, (float)face.Glyph.Metrics.Height); } if (tw == 0) tw = th; Bitmap bmp = new Bitmap((int)Math.Ceiling(tw), (int)Math.Ceiling(th*2)); // assumption that any downstem is at most half the height of a capital letter cy = th * 0.5f; // adjustment for such //Bitmap bmp = new Bitmap(128, 32); System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp); g.Clear(System.Drawing.Color.Transparent); //g.Clear(System.Drawing.Color.DimGray); for (int i = 0; i < text.Length; i++) { char c = text[i]; uint cnum = face.GetCharIndex(c); face.LoadGlyph(cnum, loadFlags, loadTarget); face.Glyph.RenderGlyph(renderMode); if (c == ' ') { cx += (float)face.Glyph.Advance.X; // omitted an if statement that didn't seem to do anything relevant?? cy += (float)face.Glyph.Advance.Y; continue; } FTBitmap ftb = face.Glyph.Bitmap; // lol ftb Bitmap cb = ftb.ToGdipBitmap(System.Drawing.Color.White); g.DrawImageUnscaled(cb, (int)Math.Round(cx + face.Glyph.BitmapLeft), (int)Math.Round(cy + (Math.Ceiling(th) - face.Glyph.BitmapTop))); // th and not bitmap.height cx += (float)face.Glyph.Metrics.HorizontalAdvance; cy += (float)face.Glyph.Advance.Y; if (face.HasKerning && i < text.Length - 1) cx += (float)face.GetKerning(cnum, face.GetCharIndex(text[i + 1]), KerningMode.Default).X; } g.Dispose(); if (texture != null) texture.Dispose(); //texture = GraphicsManager.ConvertToPreMultipliedAlphaGPU(GetTexture(GraphicsManager.device, bmp)); texture = GetTexture(GraphicsManager.device, bmp); }
private void InitFont(float scaleFactor) { try { System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); ScaleFactor = scaleFactor; YOffsetScaled = YOffset * scaleFactor; // Reset everything Clear(); Font = new Face(FontManager.Library, FilePath); // Go on float size = Size.Scale(ScaleFactor); Fixed26Dot6 sz = new Fixed26Dot6(size / 64); Font.SetCharSize(sz, sz, 72, 72); int pixelSize = (size * 1.3334).Ceil(); Font.SetPixelSizes((uint)pixelSize, (uint)pixelSize); GlyphCount = Font.GlyphCount; int glyphCount = GlyphCount; Monospace = Font.FaceFlags.HasFlag(FaceFlags.FixedWidth); string tmpName = Font.GetPostscriptName(); if (!String.IsNullOrEmpty(tmpName)) { Name = tmpName; } // We support 4 different glyph loading strategies: // // (1) All: all glyphs loaded at once on start // (2) Filtered: all filtered glyphs loaded at once on start // (3) OnDemand: no glyphs loaded at start, all glyphs on demand if (OnDemand) { // Startegy (3) GlyphCount = 0; } else if (Filter > GlyphFilterFlags.OnDemand) { // Startegy (2) // If we have a Filter set, let's count the number of valid glyphs // to minimize graphics memory. uint glyphindex; uint cc = Font.GetFirstChar(out glyphindex); int count = 0; while (glyphindex > 0) { char c = (char)cc; if (Filter.IsValid(c)) { count++; } cc = Font.GetNextChar(cc, out glyphindex); } GlyphCount = count; } else { // Strategy (1), loading the entire font } m_Textures = new int[Math.Max(32, GlyphCount)]; CharMap = new ThreadSafeDictionary <char, GlyphInfo>(Math.Max(31, GlyphCount)); if (!OnDemand) { // Strategy (1) + (2): Load all or filtered glyphs m_ListBase = GL.GenLists(GlyphCount); GL.GenTextures(GlyphCount, m_Textures); uint glyphindex; uint cc = Font.GetFirstChar(out glyphindex); while (glyphindex > 0) { char c = (char)cc; if (!CharMap.ContainsKey(c) && Filter.IsValid(c)) { try { CharMap.Add(c, CompileCharacter(Font, glyphindex, c)); } catch (Exception ex) { ex.LogWarning(); } } cc = Font.GetNextChar(cc, out glyphindex); } CharMap.TryGetValue(SpecialCharacters.Ellipsis, out m_EllipsisGlyphIndex); } else { try { GetGlyphIndex(SpecialCharacters.Ellipsis, out m_EllipsisGlyphIndex); } catch (Exception ex) { ex.LogError(); } } //if (Height <= 1) //Height = pixelSize.NextPowerOf2(); //Height = pixelSize * 1.33335f; Height = pixelSize; float fscale = Height / Font.Height * 1.33334f; //float fscale = Height / Font.Height * 0.776f; Ascender = Font.Ascender * fscale; Descender = Font.Descender * fscale; //HalfHeight = Height / 2; Height = (Ascender).Ceil(); HalfHeight = (int)(Height / 2); //LineHeight = Height * 1.42f * LineSpacing; LineHeight = (int)((Height * 1.42f * LineSpacing) + 0.5f); //TextBoxHeight = ((Height * 2f) + (ScaleFactor * 2f)).Ceil(); //TextBoxHeight = (int)(Height * 1.85f + 0.5f); TextBoxHeight = (int)(Height * 1.85f + 2); CaptionHeight = (int)(Height * 1.55 + 2); YOffsetScaled = (YOffset * ScaleFactor) - HalfHeight; if (OnDemand) { Count.LogInformation("Font {0} ({1}), {2}/{3} glyphs pre-loaded in {4} ms, more glyphs are loaded on demand.", Name, Size, Count, glyphCount, sw.ElapsedMilliseconds); } else { Count.LogInformation("Font {0} ({1}), {2}/{3} glyphs loaded in {4} ms.", Name, Size, Count, glyphCount, sw.ElapsedMilliseconds); } } catch (Exception ex) { ex.LogError(); } finally { if (!OnDemand && Font != null) { Font.Dispose(); Font = null; } } }
private void listBoxFont_SelectedIndexChanged(object sender, EventArgs e) { fontFace = new Face(lib, Path.Combine(Path.GetFullPath(fontFolder), (string)listBoxFont.SelectedItem)); fontFace.SetCharSize(0, 62, 0, 96); pictureBoxText.Invalidate(); }
protected override void OnLoad(EventArgs e) { base.OnLoad(e); string hello = "The quick brown fox jumps over the lazy dog."; charCache = new Dictionary<char, GlyphData>(); Library lib = new Library(); Face fontFace = new Face(lib, "fonts/roboto-regular.ttf"); fontFace.SetCharSize(0, 18 * 64, 0, 96); int wX = 0; int wY = 0; int xB = 0; int pX = 0; int pY = 0; uint current = 0; uint previous = 0; GlyphData data; DateTime iTimeS = DateTime.Now; foreach (var item in hello) { current = fontFace.GetCharIndex(item); if (!charCache.ContainsKey(item)) { fontFace.LoadGlyph(current, LoadFlags.Default, LoadTarget.Normal); fontFace.Glyph.RenderGlyph(RenderMode.Normal); FTBitmap bitmap = fontFace.Glyph.Bitmap; data = new GlyphData(); if (item != ' ') data.buffer = bitmap.BufferData; data.charIndex = current; data.metrics = fontFace.Glyph.Metrics; data.height = fontFace.Glyph.Metrics.Height / 64; data.width = fontFace.Glyph.Metrics.Width / 64; data.pitch = fontFace.Glyph.BitmapTop; data.forward = fontFace.Glyph.BitmapLeft; data.aX = fontFace.Glyph.Metrics.HorizontalAdvance; data.aY = fontFace.Glyph.Metrics.VerticalAdvance; charCache.Add(item, data); } else { data = charCache[item]; } wX += data.aX / 64; if (fontFace.HasKerning && previous != 0 && current != 0) { var kInfo = fontFace.GetKerning(previous, current, KerningMode.Default); wX += kInfo.X / 64; data.kX = kInfo.X / 64; data.kY = kInfo.Y / 64; } previous = current; } xB = Math.Abs(fontFace.Size.Metrics.Descender / 64); wY = fontFace.Size.Metrics.Height / 64; DateTime iTimeF = DateTime.Now; Console.WriteLine("Time in letting freetype render the glyphs: {0} milliseconds.", (iTimeF - iTimeS).TotalMilliseconds); bmp = new Bitmap(wX, wY); int[] map = new int[wX * wY]; for (int i = 0; i < map.Length; i++ ) { map[i] = 0; } current = 0; previous = 0; DateTime timeS = DateTime.Now; for (int i = 0; i < hello.Length; i++) { GlyphData pdata = charCache[hello[i]]; for (int y = 0; y < pdata.height; y++) { for (int x = 0; x < pdata.width; x++) { int fx = x + pX + pdata.forward; int fy = wY - pdata.pitch + y - xB; fy = y + (wY - pdata.pitch - xB); if (fy < 0 || fy >= wY) { //Console.WriteLine("Overflow on fy! :("); continue; } if (fx < 0 || fx >= wX) { //Console.WriteLine("Overflow on fx! :("); continue; } int fdata = pdata.buffer[y * pdata.width + x] + map[fy * wX + fx]; if (fdata >= 255) fdata = 255; map[fy * wX + fx] = (fdata << 24); } } pX += pdata.aX / 64; pX += pdata.kX; } BitmapData bData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); Marshal.Copy(map, 0, bData.Scan0, map.Length); bmp.UnlockBits(bData); map = null; DateTime timeF = DateTime.Now; Console.WriteLine("Time in mapping them pixels: {0} milliseconds.", (timeF- timeS).TotalMilliseconds); GC.Collect(); ClientSize = new System.Drawing.Size(wX, wY); StartPosition = FormStartPosition.CenterScreen; BackColor = Color.White; Invalidate(); }