internal Rect BoundGlyph(uint glyphIndex, StyleSimulations style) { var recip = 1 / (float)FtFace.UnitsPerEM; //var strength = 0.02f; var trm = AdjustGlyphWidth(glyphIndex); var m = new FTMatrix((int)trm.M11 * 65536, (int)trm.M21 * 65536, (int)trm.M12 * 65536, (int)trm.M22 * 65536); var v = new FTVector(Fixed16Dot16.FromDouble(trm.OffsetX * 65536), Fixed16Dot16.FromDouble(trm.OffsetY * 65536)); FtFace.SetCharSize(Fixed26Dot6.FromInt32(FtFace.UnitsPerEM), Fixed26Dot6.FromInt32(FtFace.UnitsPerEM), 72, 72); FtFace.SetTransform(m, v); FtFace.LoadGlyph(glyphIndex, LoadFlags.NoBitmap | LoadFlags.NoHinting, LoadTarget.Normal); /*if (style == StyleSimulations.BoldSimulation) * { * FtFace.Glyph.Outline.Embolden(Fixed26Dot6.FromDouble(strength * FtFace.UnitsPerEM)); * FtFace.Glyph.Outline.Translate((int) (-strength * 0.5 * FtFace.UnitsPerEM), (int) (-strength * 0.5 * FtFace.UnitsPerEM)); * }*/ var box = FtFace.Glyph.GetGlyph().GetCBox(GlyphBBoxMode.Pixels); var rect = new Rect(new Point(box.Left * recip, box.Top * recip), new Point(box.Right * recip, box.Bottom * recip)); if (rect.IsEmpty) { rect = new Rect(new Point(trm.OffsetX, trm.OffsetY), new Point(trm.OffsetX, trm.OffsetY)); } return(rect); }
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); }
/// <summary> /// Get the thickness of the underline. /// </summary> /// <param name="characterSize">Reference character size.</param> /// <returns>Underline thickness, in pixels.</returns> public float GetUnderlineThickness(int characterSize) { if (_face != null && SetCurrentSize(characterSize)) { // Return a fixed thickness if font is a bitmap font if (!_face.IsScalable) { return(characterSize / 14f); } return(Fixed16Dot16.Multiply(_face.UnderlineThickness, _face.Size.Metrics.ScaleY).ToSingle()); } else { return(0f); } }
/// <summary> /// Get the position of the underline. /// </summary> /// <param name="characterSize">Reference character size.</param> /// <returns>Underline position, in pixels.</returns> public float GetUnderlinePosition(int characterSize) { if (_face != null && SetCurrentSize(characterSize)) { // Return a fixed position if font is a bitmap font if (!_face.IsScalable) { return(characterSize / 10f); } return(-(Fixed16Dot16.Multiply(_face.UnderlinePosition, _face.Size.Metrics.ScaleY).ToSingle())); // / (float)(1 << 6); } else { return(0f); } }
public unsafe Fixed16Dot16[] GetAdvances(uint start, uint count, LoadFlags flags) { IntPtr advPtr; Error err = FT.FT_Get_Advances(Reference, start, count, flags, out advPtr); if (err != Error.Ok) throw new FreeTypeException(err); //create a new array and copy the data from the pointer over Fixed16Dot16[] advances = new Fixed16Dot16[count]; IntPtr* ptr = (IntPtr*)advPtr; for (int i = 0; i < count; i++) advances[i] = Fixed16Dot16.FromRawValue((int)ptr[i]); return advances; }
/// <summary> /// Return the track kerning for a given face object at a given size. /// </summary> /// <param name="pointSize">The point size in 16.16 fractional points.</param> /// <param name="degree">The degree of tightness.</param> /// <returns>The kerning in 16.16 fractional points.</returns> public Fixed16Dot16 GetTrackKerning(Fixed16Dot16 pointSize, int degree) { if (disposed) throw new ObjectDisposedException("face", "Cannot access a disposed object."); IntPtr kerning; Error err = FT.FT_Get_Track_Kerning(Reference, (IntPtr)pointSize.Value, degree, out kerning); if (err != Error.Ok) throw new FreeTypeException(err); return Fixed16Dot16.FromRawValue((int)kerning); }
public void GetPfrMetrics(out uint outlineResolution, out uint metricsResolution, out Fixed16Dot16 metricsXScale, out Fixed16Dot16 metricsYScale) { IntPtr tmpXScale, tmpYScale; Error err = FT.FT_Get_PFR_Metrics(Reference, out outlineResolution, out metricsResolution, out tmpXScale, out tmpYScale); metricsXScale = Fixed16Dot16.FromRawValue((int)tmpXScale); metricsYScale = Fixed16Dot16.FromRawValue((int)tmpYScale); if (err != Error.Ok) throw new FreeTypeException(err); }
/// <summary> /// Reset a stroker object's attributes. /// </summary> /// <remarks> /// The radius is expressed in the same units as the outline coordinates. /// </remarks> /// <param name="radius">The border radius.</param> /// <param name="lineCap">The line cap style.</param> /// <param name="lineJoin">The line join style.</param> /// <param name="miterLimit"> /// The miter limit for the <see cref="StrokerLineJoin.MiterFixed"/> and /// <see cref="StrokerLineJoin.MiterVariable"/> line join styles, expressed as 16.16 fixed point value. /// </param> public void Set(int radius, StrokerLineCap lineCap, StrokerLineJoin lineJoin, Fixed16Dot16 miterLimit) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); FT.FT_Stroker_Set(Reference, radius, lineCap, lineJoin, (IntPtr)miterLimit.Value); }
public static Fixed16Dot16 Cos(Fixed16Dot16 angle) { return Fixed16Dot16.FromRawValue((int)FT.FT_Cos((IntPtr)angle.Value)); }
public static Fixed16Dot16 CeilFix(Fixed16Dot16 a) { return Fixed16Dot16.FromRawValue((int)FT.FT_CeilFix((IntPtr)a.Value)); }
public static Fixed16Dot16 Atan2(Fixed16Dot16 x, Fixed16Dot16 y) { return Fixed16Dot16.FromRawValue((int)FT.FT_Atan2((IntPtr)x.Value, (IntPtr)y.Value)); }
public static Fixed16Dot16 AngleDiff(Fixed16Dot16 angle1, Fixed16Dot16 angle2) { return Fixed16Dot16.FromRawValue((int)FT.FT_Angle_Diff((IntPtr)angle1.Value, (IntPtr)angle2.Value)); }
public static Fixed16Dot16 MulFix(int a, Fixed16Dot16 b) { return Fixed16Dot16.FromRawValue((int)FT.FT_MulFix((IntPtr)a, (IntPtr)b.Value)); }
public static Fixed16Dot16 MulDiv(Fixed16Dot16 a, Fixed16Dot16 b, Fixed16Dot16 c) { return Fixed16Dot16.FromRawValue((int)FT.FT_MulDiv((IntPtr)a.Value, (IntPtr)b.Value, (IntPtr)c.Value)); }
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); }