public ExampleForm() { InitializeComponent(); fontService = new FontService(); fontFolder = "Fonts/"; sampleText = "SharpFont"; // Some variations of the character set shown by the Windows Font Viewer //sampleText = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890.:,;'\"(!?)+-*//="; //sampleText = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890"; sampleText = "abcdefghijklmnopqrstuvwxyz"; fontService.Size = 62f; fontSize = 62f; mainMenuFontSize.Text = fontService.Size.ToString("0.0"); foreColor = Color.Black; backColor = Color.Transparent; decimal testValue = 12.1234567890123456M; Debug.Print("testValue : {0}", (double)testValue); // none of these keep the precision I was expecting... var f26 = new Fixed26Dot6(testValue); Debug.Print("Fixed 26.6 : {0}", (double)f26); Debug.Print("Fixed 26.6 : {0}", f26); var f16 = new Fixed16Dot16(testValue); Debug.Print("Fixed 16.16: {0}", (double)f16); Debug.Print("Fixed 16.16: {0}", f16); var f2 = new Fixed2Dot14((double)testValue); // decimal constructor crashes here Debug.Print("Fixed 2.14: {0}", (double)f2); Debug.Print("Fixed 2.14: {0}", f2); }
public void AddFallback(FreeTypeFace face) { faces.AddLast(face); face.SetCharSize(Fixed26Dot6.FromSingle(FontSize)); if (whitespace < face.FontMetrics.Width) { whitespace = face.FontMetrics.Width; } }
public void SetCharSize(Fixed26Dot6 size) { var err = FreeTypeNative.FT_Set_Char_Size(reference, IntPtr.Zero, (IntPtr)size.Value, 96, 96); CalculateMetrics(); if (err != 0) { throw FreeTypeException.Except(err); } }
public FontLoader( IContentProvider contentProvider = null, string defaultFont = null, int baseFontSize = 32, int textureSize = 512) { if (baseFontSize <= 1 || baseFontSize > textureSize) { throw new ArgumentOutOfRangeException(nameof(baseFontSize)); } if (textureSize <= 1) { throw new ArgumentOutOfRangeException(nameof(textureSize)); } _defaultFont = defaultFont ?? "Consola"; _contentProvider = contentProvider; _baseFontSize = baseFontSize; _textureSize = textureSize; _freetype = new Lazy <Library>(() => new Library()); }
public void SetFontSize(float fontSize) { FontSize = fontSize; foreach (var freeTypeFace in faces) { freeTypeFace.SetCharSize(Fixed26Dot6.FromSingle(fontSize)); if (whitespace < freeTypeFace.FontMetrics.Width) { whitespace = freeTypeFace.FontMetrics.Width; } } foreach (var spriteMap in spriteMaps) { spriteMap.Dispose(); } spriteMaps.Clear(); spriteReferences.Clear(); }
public static bool LoadFace(ref Texture_Font_T font, ref Library library, ref Face face, float size) { library = new Library(); if (library == null) { return(false); } face = new Face(library, font.Filename); if (face == null) { return(false); } face.SelectCharmap(Encoding.Unicode); face.SetCharSize(Fixed26Dot6.FromSingle(size), 0, DPI * HRES, HRES); FTMatrix matrix = new FTMatrix((int)(1.0 / HRES * 0x10000L), (int)(0.0 * 0x10000L), (int)(0.0 * 0x10000L), (int)(1.0 * 0x10000L)); face.SetTransform(matrix); return(true); }
public FontLoader( NuGetDependencyResolver nuget, IContentProvider contentProvider = null, string defaultFont = null, int baseFontSize = 72, int textureSize = 512) { if (nuget == null) { throw new ArgumentNullException(nameof(nuget)); } if (baseFontSize <= 1 || baseFontSize > textureSize) { throw new ArgumentOutOfRangeException(nameof(baseFontSize)); } if (textureSize <= 1) { throw new ArgumentOutOfRangeException(nameof(textureSize)); } this.dependencyResolver = nuget; this.defaultFont = defaultFont ?? "Consola"; this.contentProvider = contentProvider; this.baseFontSize = baseFontSize; this.textureSize = textureSize; this.freetype = new Lazy <Library>(LoadFreeTypeLibrary); }
public void SetCharSize(Fixed26Dot6 width, Fixed26Dot6 height, uint horizontalResolution, uint verticalResolution) { if (disposed) throw new ObjectDisposedException("face", "Cannot access a disposed object."); Error err = FT.FT_Set_Char_Size(Reference, (IntPtr)width.Value, (IntPtr)height.Value, horizontalResolution, verticalResolution); if (err != Error.Ok) throw new FreeTypeException(err); }
static int Div64(Fixed26Dot6 value) { return((int)Math.Ceiling(value.Value / 64.0)); }
/// <summary><para> /// Embolden an outline. The new outline will be at most 4 times ‘strength’ pixels wider and higher. You may /// think of the left and bottom borders as unchanged. /// </para><para> /// Negative ‘strength’ values to reduce the outline thickness are possible also. /// </para></summary> /// <remarks><para> /// The used algorithm to increase or decrease the thickness of the glyph doesn't change the number of points; /// this means that certain situations like acute angles or intersections are sometimes handled incorrectly. /// </para><para> /// If you need ‘better’ metrics values you should call <see cref="GetCBox"/> or <see cref="GetBBox"/>. /// </para></remarks> /// <example> /// FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); /// if ( face->slot->format == FT_GLYPH_FORMAT_OUTLINE ) /// FT_Outline_Embolden( &face->slot->outline, strength ); /// </example> /// <param name="strength">How strong the glyph is emboldened. Expressed in 26.6 pixel format.</param> public void Embolden(Fixed26Dot6 strength) { if (disposed) throw new ObjectDisposedException("Outline", "Cannot access a disposed object."); Error err = FT.FT_Outline_Embolden(reference, (IntPtr)strength.Value); if (err != Error.Ok) throw new FreeTypeException(err); }
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 Glyph LoadGlyph(int codePoint, int characterSize, bool bold, float outlineThickness) { Glyph glyph = new Glyph(); if (_face == null) { return(null); } // Set the character size if (!SetCurrentSize(characterSize)) { return(glyph); } // Load the glyph corresponding to the code point var flags = LoadFlags.ForceAutohint; if (outlineThickness != 0) { flags |= LoadFlags.NoBitmap; } _face.LoadChar((uint)codePoint, flags, SharpFont.LoadTarget.Normal); // Retrieve the glyph SharpFont.Glyph glyphDesc = _face.Glyph.GetGlyph(); // Apply bold if necessary -- first technique using outline (highest quality) SharpFont.Fixed26Dot6 weight = new SharpFont.Fixed26Dot6(1); bool outline = glyphDesc.Format == SharpFont.GlyphFormat.Outline; if (outline) { if (bold) { SharpFont.OutlineGlyph outlineGlyph = glyphDesc.ToOutlineGlyph(); outlineGlyph.Outline.Embolden(weight); } if (outlineThickness != 0) { _stroker.Set((int)(outlineThickness * Fixed26Dot6.FromInt32(1).Value), StrokerLineCap.Round, StrokerLineJoin.Round, Fixed16Dot16.FromSingle(0)); // This function returning a new instance of Glyph // Because the pointer may changed upon applying stroke to the glyph glyphDesc = glyphDesc.Stroke(_stroker, false); } } // Convert the glyph to a bitmap (i.e. rasterize it) glyphDesc.ToBitmap(SharpFont.RenderMode.Normal, new FTVector26Dot6(0, 0), true); SharpFont.FTBitmap bitmap = glyphDesc.ToBitmapGlyph().Bitmap; // Apply bold if necessary -- fallback technique using bitmap (lower quality) if (!outline) { if (bold) { bitmap.Embolden(_library, weight, weight); } if (outlineThickness != 0) { Logger.Warning("Failed to outline glyph (no fallback available)"); } } // Compute the glyph's advance offset glyph.Advance = _face.Glyph.Metrics.HorizontalAdvance.ToSingle(); if (bold) { glyph.Advance += weight.ToSingle(); } int width = bitmap.Width; int height = bitmap.Rows; if ((width > 0) && (height > 0)) { // Leave a small padding around characters, so that filtering doesn't // pollute them with pixels from neighbors int padding = 1; // Get the glyphs page corresponding to the character size Page page = _pages[characterSize]; // Find a good position for the new glyph into the texture glyph.TexCoords = FindGlyphRectangle(page, width + 2 * padding, height + 2 * padding); var texRect = glyph.TexCoords; // Make sure the texture data is positioned in the center // of the allocated texture rectangle glyph.TexCoords = new Rectangle(texRect.X + padding, texRect.Y + padding, texRect.Width - 2 * padding, texRect.Height - 2 * padding); // Compute the glyph's bounding box float boundsX = (float)(_face.Glyph.Metrics.HorizontalBearingX); float boundsY = -(float)(_face.Glyph.Metrics.HorizontalBearingY); float boundsWidth = (float)(_face.Glyph.Metrics.Width) + outlineThickness * 2; float boundsHeight = (float)(_face.Glyph.Metrics.Height) + outlineThickness * 2; glyph.Bounds = new RectangleF(boundsX, boundsY, boundsWidth, boundsHeight); // Extract the glyph's pixels from the bitmap byte[] pixelBuffer = new byte[width * height * 4]; for (int i = 0; i < pixelBuffer.Length; i++) { pixelBuffer[i] = 255; } unsafe { byte *pixels = (byte *)bitmap.Buffer.ToPointer(); if (bitmap.PixelMode == SharpFont.PixelMode.Mono) { // Pixels are 1 bit monochrome values for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { // The color channels remain white, just fill the alpha channel int index = (x + y * width) * 4 + 3; pixelBuffer[index] = (byte)((((pixels[x / 8]) & (1 << (7 - (x % 8)))) > 0) ? 255 : 0); } pixels += bitmap.Pitch; } } else { // Pixels are 8 bits gray levels for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { // The color channels remain white, just fill the alpha channel int index = (x + y * width) * 4 + 3; pixelBuffer[index] = pixels[x]; } pixels += bitmap.Pitch; } } } // Write the pixels to the texture int tx = glyph.TexCoords.Left; int ty = glyph.TexCoords.Top; int tw = glyph.TexCoords.Width; int th = glyph.TexCoords.Height; page.texture.Update(pixelBuffer, tx, ty, tw, th); } // Delete the FT glyph glyphDesc.Dispose(); return(glyph); }
/// <summary> /// Embolden a bitmap. The new bitmap will be about ‘xStrength’ pixels wider and ‘yStrength’ pixels higher. The /// left and bottom borders are kept unchanged. /// </summary> /// <remarks><para> /// The current implementation restricts ‘xStrength’ to be less than or equal to 8 if bitmap is of pixel_mode /// <see cref="SharpFont.PixelMode.Mono"/>. /// </para><para> /// If you want to embolden the bitmap owned by a <see cref="GlyphSlot"/>, you should call /// <see cref="GlyphSlot.OwnBitmap"/> on the slot first. /// </para></remarks> /// <param name="library">A handle to a library object.</param> /// <param name="xStrength"> /// How strong the glyph is emboldened horizontally. Expressed in 26.6 pixel format. /// </param> /// <param name="yStrength"> /// How strong the glyph is emboldened vertically. Expressed in 26.6 pixel format. /// </param> public void Embolden(Library library, Fixed26Dot6 xStrength, Fixed26Dot6 yStrength) { if (disposed) throw new ObjectDisposedException("FTBitmap", "Cannot access a disposed object."); if (library == null) throw new ArgumentNullException("library"); Error err = FT.FT_Bitmap_Embolden(library.Reference, Reference, (IntPtr)xStrength.Value, (IntPtr)yStrength.Value); if (err != Error.Ok) throw new FreeTypeException(err); }
public NISFont DrawT3BFontBitmap(char[] strings) { NISFont fnt_data = new NISFont(); Bitmap bmp = new Bitmap(Config.texture_width, Config.texture_height); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.FromArgb(0x00000000)); int x = 0, y = 0; int tile_w = Config.fontWidth; int tile_h = Config.fontHeight; int relativePositionX = 1; int relativePositionY = -2; int font_height = Config.fontSize; Library library = new Library(); string facename = Config.ttfName; Face face = library.NewFace(facename, 0); float left, right, top, bottom, FHT; int FHD, kx, ky; foreach (char currentChar0 in strings) { uint charid = uchar2code(currentChar0.ToString()); face.SetCharSize(0, font_height, 0, 72); if (charid < 0x7f) { font_height = Config.fontSize - 2; face.SetCharSize(0, font_height, 0, 72); } else { font_height = Config.fontSize; } face.SetPixelSizes((uint)0, (uint)font_height); uint glyphIndex = face.GetCharIndex(charid); //Console.WriteLine(glyphIndex); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Lcd); face.Glyph.Outline.Embolden(0.5); face.Glyph.RenderGlyph(RenderMode.Normal); FTBitmap ftbmp = face.Glyph.Bitmap; FTBitmap ftbmp2 = face.Glyph.Bitmap; left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = font_height; FHD = (int)Math.Ceiling(FHT); kx = x + (int)Math.Round(left); ky = (int)Math.Round((float)y + (float)Math.Ceiling(FHT) - (float)top); if (ftbmp.Width == 0 || glyphIndex < 0x20) { Face face1 = library.NewFace(Config.baseName, 0); face1.SetCharSize(0, font_height, 0, 72); face1.SetPixelSizes((uint)0, (uint)font_height); glyphIndex = face1.GetCharIndex(charid); face1.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Lcd); face1.Glyph.Outline.Embolden(Fixed26Dot6.FromDouble(0.4)); face1.Glyph.RenderGlyph(RenderMode.Normal); left = (float)face1.Glyph.Metrics.HorizontalBearingX; right = (float)face1.Glyph.Metrics.HorizontalBearingX + (float)face1.Glyph.Metrics.Width; top = (float)face1.Glyph.Metrics.HorizontalBearingY; bottom = (float)face1.Glyph.Metrics.HorizontalBearingY + (float)face1.Glyph.Metrics.Height; FHT = font_height; FHD = (int)Math.Ceiling(FHT); kx = x + (int)Math.Round(left); ky = (int)Math.Round((float)y + (float)Math.Ceiling(FHT) - (float)top); ftbmp = face1.Glyph.Bitmap; ftbmp2 = face1.Glyph.Bitmap; } fnt_data.charvalues.Add(new XYWH((int)uchar2code(currentChar0.ToString()), x, y, tile_w, tile_h, 0)); if (ftbmp2.Width == 0) { x += tile_w; if (x + tile_w > Config.texture_width) { x = 0; y += tile_h; } continue; } Bitmap cBmp = ftbmp2.ToGdipBitmap(Color.White); g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY); g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY); cBmp.Dispose(); x += tile_w; if (x + tile_w > Config.texture_width) { x = 0; y += tile_h; } } fnt_data.bitmap = bmp; return(fnt_data); }
internal unsafe void AddCharacter(GlyphCollection col, uint cp) { if (cp == (uint)'\t') { var spaceGlyph = col.GetGlyph((uint)' '); col.glyphs.Add(cp, new GlyphInfo(spaceGlyph.AdvanceX * 4, spaceGlyph.AdvanceY, spaceGlyph.CharIndex, spaceGlyph.Kerning)); } Face.SetCharSize(0, col.Size, 0, 96); var c_face = Face; bool dobold = emulate_bold; bool doitalics = emulate_italics; bool dokern = true; uint index = c_face.GetCharIndex(cp); if (index == 0) { //Glyph does not exist in font if (cp == (uint)'?') { throw new Exception("Font does not have required ASCII character '?'"); } var fallback = Platform.GetFallbackFace(ren.FT, cp); if ((index = fallback.GetCharIndex(cp)) != 0) { try { c_face = fallback; c_face.SetCharSize(0, col.Size, 0, 96); dobold = doitalics = dokern = false; } catch (Exception) { var qmGlyph = col.GetGlyph((uint)'?'); col.glyphs.Add(cp, qmGlyph); return; } } else { var qmGlyph = col.GetGlyph((uint)'?'); col.glyphs.Add(cp, qmGlyph); return; } } c_face.LoadGlyph(index, LoadFlags.Default | LoadFlags.ForceAutohint, LoadTarget.Normal); if (dobold) { //Automatically determine a strength var strength = (c_face.UnitsPerEM * c_face.Size.Metrics.ScaleY.Value) / 0x10000; strength /= 24; c_face.Glyph.Outline.Embolden(Fixed26Dot6.FromRawValue(strength)); } if (doitalics) { c_face.Glyph.Outline.Transform(new FTMatrix(0x10000, 0x0366A, 0x00000, 0x10000)); } c_face.Glyph.RenderGlyph(RenderMode.Normal); if (c_face.Glyph.Bitmap.Width == 0 || c_face.Glyph.Bitmap.Rows == 0) { col.glyphs.Add(cp, new GlyphInfo( (int)Math.Ceiling((float)c_face.Glyph.Advance.X), (int)Math.Ceiling((float)c_face.Glyph.Advance.Y), index, dokern && Face.HasKerning ) ); } else { if (c_face.Glyph.Bitmap.PixelMode != PixelMode.Gray) { throw new NotImplementedException(); } if (currentX + c_face.Glyph.Bitmap.Width > TEXTURE_SIZE) { currentX = 0; currentY += lineMax; lineMax = 0; } if (currentY + c_face.Glyph.Bitmap.Rows > TEXTURE_SIZE) { currentX = 0; currentY = 0; lineMax = 0; textures.Add(new Texture2D( TEXTURE_SIZE, TEXTURE_SIZE, false, SurfaceFormat.R8 )); FLLog.Debug("Text", string.Format("{0}@{1}, New Texture", facename, col.Size)); } lineMax = (int)Math.Max(lineMax, c_face.Glyph.Bitmap.Rows); var rect = new Rectangle( currentX, currentY, c_face.Glyph.Bitmap.Width, c_face.Glyph.Bitmap.Rows ); var tex = textures [textures.Count - 1]; GL.PixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); //Set tex.SetData(0, rect, c_face.Glyph.Bitmap.Buffer); GL.PixelStorei(GL.GL_UNPACK_ALIGNMENT, 4); currentX += c_face.Glyph.Bitmap.Width; col.glyphs.Add( cp, new GlyphInfo( tex, rect, (int)Math.Ceiling((float)c_face.Glyph.Advance.X), (int)Math.Ceiling((float)c_face.Glyph.Advance.Y), (int)Math.Ceiling((float)c_face.Glyph.Metrics.HorizontalAdvance), c_face.Glyph.BitmapLeft, c_face.Glyph.BitmapTop, index, dokern && Face.HasKerning ) ); } }
private static Single GetFloat(IntPtr ptr) => Fixed26Dot6.FromRawValue((Int32)ptr).Value / 64f;