/// <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) { Error err = FT.FT_Outline_Embolden(Reference, (IntPtr)strength.Value); if (err != Error.Ok) { throw new FreeTypeException(err); } }
/// <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); } }
/// <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 (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); } }
/// <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); } }
/// <summary> /// Initializes a new instance of the <see cref="FTVector26Dot6"/> struct. /// </summary> /// <param name="x">The horizontal coordinate.</param> /// <param name="y">The vertical coordinate.</param> public FTVector26Dot6(Fixed26Dot6 x, Fixed26Dot6 y) : this() { this.x = (IntPtr)x.Value; this.y = (IntPtr)y.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); }