Beispiel #1
0
        /// <summary>
        /// Function to build out the font data.
        /// </summary>
        /// <param name="graphics">The graphics context to use.</param>
        /// <param name="fontInfo">The information used to generate the font.</param>
        /// <param name="externalFonts">The external fonts provided by an application.</param>
        /// <returns>A new <see cref="GdiFontData"/> object.</returns>
        public static GdiFontData GetFontData(System.Drawing.Graphics graphics, IGorgonFontInfo fontInfo, IEnumerable <PrivateFontCollection> externalFonts)
        {
            var result = new GdiFontData();

            CharacterRange[] range =
            {
                new CharacterRange(0, 1)
            };

            System.Drawing.FontStyle style = System.Drawing.FontStyle.Regular;

            switch (fontInfo.FontStyle)
            {
            case FontStyle.Bold:
                style = System.Drawing.FontStyle.Bold;
                break;

            case FontStyle.Italics:
                style = System.Drawing.FontStyle.Italic;
                break;

            case FontStyle.BoldItalics:
                style = System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic;
                break;
            }

            FontFamily fontFamily = (externalFonts != null ? (externalFonts.SelectMany(item => item.Families).Concat(FontFamily.Families)) : FontFamily.Families)
                                    .FirstOrDefault(item => string.Equals(fontInfo.FontFamilyName, item.Name, StringComparison.InvariantCultureIgnoreCase));

            // If we cannot locate the font family by name, then fall back.
            if (fontFamily == null)
            {
                fontFamily = FontFamily.GenericSerif;
            }


            // Scale the font appropriately.
            if (fontInfo.FontHeightMode == FontHeightMode.Points)
            {
                // Convert the internal font to pixel size.
                result.Font = new Font(fontFamily,
                                       (fontInfo.Size * graphics.DpiY) / 72.0f,
                                       style,
                                       GraphicsUnit.Pixel);
            }
            else
            {
                result.Font = new Font(fontFamily, fontInfo.Size, style, GraphicsUnit.Pixel);
            }

            result.FontHeight = result.Font.GetHeight(graphics);

            result.StringFormat = new StringFormat(StringFormat.GenericTypographic)
            {
                FormatFlags   = StringFormatFlags.NoFontFallback | StringFormatFlags.MeasureTrailingSpaces,
                Alignment     = StringAlignment.Near,
                LineAlignment = StringAlignment.Near
            };
            result.StringFormat.SetMeasurableCharacterRanges(range);

            // Create a separate drawing format because some glyphs are being clipped when they have overhang
            // on the left boundary.
            result.DrawFormat = new StringFormat(StringFormat.GenericDefault)
            {
                FormatFlags   = StringFormatFlags.NoFontFallback | StringFormatFlags.MeasureTrailingSpaces,
                Alignment     = StringAlignment.Near,
                LineAlignment = StringAlignment.Near
            };
            result.DrawFormat.SetMeasurableCharacterRanges(range);

            return(result);
        }
Beispiel #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GlyphDraw"/> class.
 /// </summary>
 /// <param name="fontInfo">The font information used to create the font.</param>
 /// <param name="fontData">The font data for the glyphs.</param>
 public GlyphDraw(IGorgonFontInfo fontInfo, GdiFontData fontData)
 {
     _fontInfo = fontInfo;
     _fontData = fontData;
 }
Beispiel #3
0
        /// <summary>
        /// Function to create or update the font.
        /// </summary>
        /// <param name="externalFontCollections">The external font collections from the application.</param>
        /// <remarks>
        /// <para>
        /// This is used to generate a new set of font textures, and essentially "create" the font object.
        /// </para>
        /// <para>
        /// This method will clear all the glyphs and textures in the font and rebuild the font with the specified parameters. This means that any custom glyphs, texture mapping, and/or kerning will be lost.
        /// Users must find a way to remember and restore any custom font info when updating.
        /// </para>
        /// <para>
        /// Internal textures used by the glyph will be destroyed.  However, if there's a user defined texture or glyph using a user defined texture, then it will not be destroyed and clean up will be the
        /// responsibility of the user.
        /// </para>
        /// </remarks>
        /// <exception cref="GorgonException">Thrown when the texture size in the settings exceeds that of the capabilities of the feature level.
        /// <para>-or-</para>
        /// <para>Thrown when the font family name is <b>null</b> or Empty.</para>
        /// </exception>
        internal void GenerateFont(IEnumerable <System.Drawing.Text.PrivateFontCollection> externalFontCollections)
        {
            Bitmap setupBitmap = null;

            System.Drawing.Graphics graphics = null;
            GdiFontData             fontData = default;
            Dictionary <Bitmap, IEnumerable <GlyphInfo> > groupedByBitmap = null;

            try
            {
                // Temporary bitmap used to gather a graphics context.
                setupBitmap = new Bitmap(2, 2, PixelFormat.Format32bppArgb);

                // Get a context for the rasterizing surface.
                graphics          = System.Drawing.Graphics.FromImage(setupBitmap);
                graphics.PageUnit = GraphicsUnit.Pixel;

                // Build up the information using a GDI+ font.
                fontData = GdiFontData.GetFontData(graphics, Info, externalFontCollections);

                // Remove control characters and anything below a space.
                List <char> availableCharacters = GetAvailableCharacters();

                // Set up the code to draw glyphs to bitmaps.
                var glyphDraw = new GlyphDraw(Info, fontData);

                // Gather the boundaries for each glyph character.
                Dictionary <char, GlyphRegions> glyphBounds = glyphDraw.GetGlyphRegions(availableCharacters, HasOutline);

                // Because the dictionary above remaps characters (if they don't have a glyph or their rects are empty),
                // we'll need to drop these from our main list of characters.
                availableCharacters.RemoveAll(item => !glyphBounds.ContainsKey(item));

                // Get kerning and glyph advancement information.
                Dictionary <char, ABC> abcAdvances = GetKerningInformation(graphics, fontData.Font, availableCharacters);

                // Put the glyphs on packed bitmaps.
                Dictionary <char, GlyphInfo> glyphBitmaps = glyphDraw.DrawToPackedBitmaps(availableCharacters, glyphBounds, HasOutline);

                groupedByBitmap = (from glyphBitmap in glyphBitmaps
                                   where glyphBitmap.Value.GlyphBitmap != null
                                   group glyphBitmap.Value by glyphBitmap.Value.GlyphBitmap).ToDictionary(k => k.Key, v => v.Select(item => item));

                // Generate textures from the bitmaps.
                // We will pack each bitmap into a single arrayed texture up to the maximum number of array indices allowed.
                // Once that limit is reached a new texture will be used. This should help performance a little, although it
                // is much better to resize the texture so that it has a single array index and single texture.
                GenerateTextures(groupedByBitmap);

                // Finally, generate our glyphs.
                GenerateGlyphs(glyphBitmaps, abcAdvances);

                FontHeight = fontData.FontHeight;
                Ascent     = fontData.Ascent;
                Descent    = fontData.Descent;
                LineHeight = fontData.LineHeight;
            }
            finally
            {
                graphics?.Dispose();
                setupBitmap?.Dispose();

                fontData?.Dispose();

                if (groupedByBitmap != null)
                {
                    foreach (Bitmap glyphBitmap in groupedByBitmap.Keys)
                    {
                        glyphBitmap.Dispose();
                    }
                }
            }
        }