コード例 #1
0
ファイル: FontCharSet.cs プロジェクト: ChrisLakeZA/duality
 /// <summary>
 /// Merges two character sets to form a new one that contains both of their characters without duplicates.
 /// </summary>
 /// <param name="second"></param>
 /// <returns></returns>
 public FontCharSet MergedWith(FontCharSet second)
 {
     return new FontCharSet(
         chars:             MergeCharList(this.chars,             (second != null) ? second.chars             : null),
         charBaseLineRef:   MergeCharList(this.charBaseLineRef,   (second != null) ? second.charBaseLineRef   : null),
         charDescentRef:    MergeCharList(this.charDescentRef,    (second != null) ? second.charDescentRef    : null),
         charBodyAscentRef: MergeCharList(this.charBodyAscentRef, (second != null) ? second.charBodyAscentRef : null)
     );
 }
コード例 #2
0
        /// <summary>
        /// Renders the <see cref="Duality.Resources.FontRasterizer"/> using the specified system font.
        /// This method assumes that the system font's size and style match the one specified in
        /// the specified Duality font.
        /// </summary>
        private FontData RenderGlyphs(SysDrawFont internalFont, FontCharSet charSet, FontRenderMode renderMode, bool antialiazing, bool monospace)
        {
            if (renderMode == FontRenderMode.ClearType)
            {
                return(RenderGlyphsCleartype(internalFont, charSet, monospace));
            }

            FontGlyphData[] glyphs = new FontGlyphData[charSet.Chars.Length];
            for (int i = 0; i < glyphs.Length; i++)
            {
                glyphs[i].Glyph = charSet.Chars[i];
            }

            int bodyAscent = 0;
            int baseLine   = 0;
            int descent    = 0;
            int ascent     = 0;

            TextRenderingHint textRenderingHint;

            if (antialiazing)
            {
                textRenderingHint = TextRenderingHint.AntiAliasGridFit;
            }
            else
            {
                textRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
            }

            int cols;
            int rows;

            cols = rows = (int)Math.Ceiling(Math.Sqrt(glyphs.Length));

            PixelData pixelLayer = new PixelData(
                MathF.RoundToInt(cols * internalFont.Size * 1.2f),
                MathF.RoundToInt(rows * internalFont.Height * 1.2f),
                ColorRgba.TransparentBlack);
            Bitmap measureBm = new Bitmap(1, 1);

            Rect[]      atlas        = new Rect[glyphs.Length];
            PixelData[] glyphBitmaps = new PixelData[glyphs.Length];
            using (Graphics measureGraphics = Graphics.FromImage(measureBm)) {
                Brush fntBrush = new SolidBrush(Color.Black);

                StringFormat formatDef = StringFormat.GenericDefault;
                formatDef.LineAlignment = StringAlignment.Near;
                formatDef.FormatFlags   = 0;
                StringFormat formatTypo = StringFormat.GenericTypographic;
                formatTypo.LineAlignment = StringAlignment.Near;

                int x = 1;
                int y = 1;
                for (int i = 0; i < glyphs.Length; ++i)
                {
                    string str      = glyphs[i].Glyph.ToString(CultureInfo.InvariantCulture);
                    bool   isSpace  = str == " ";
                    SizeF  charSize = measureGraphics.MeasureString(str, internalFont, pixelLayer.Width, formatDef);

                    // Rasterize a single glyph for rendering
                    Bitmap bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), internalFont.Height + 1);
                    using (Graphics glyphGraphics = Graphics.FromImage(bm)) {
                        glyphGraphics.Clear(Color.Transparent);
                        glyphGraphics.TextRenderingHint = textRenderingHint;
                        glyphGraphics.DrawString(str, internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatDef);
                    }
                    glyphBitmaps[i] = new PixelData();
                    glyphBitmaps[i].FromBitmap(bm);

                    // Rasterize a single glyph in typographic mode for metric analysis
                    PixelData glyphTempTypo;
                    if (!isSpace)
                    {
                        Point2 glyphTempOpaqueTopLeft;
                        Point2 glyphTempOpaqueSize;
                        glyphBitmaps[i].GetOpaqueBoundaries(out glyphTempOpaqueTopLeft, out glyphTempOpaqueSize);

                        glyphBitmaps[i].SubImage(glyphTempOpaqueTopLeft.X, 0, glyphTempOpaqueSize.X, glyphBitmaps[i].Height);

                        if (charSet.CharBodyAscentRef.Contains(glyphs[i].Glyph))
                        {
                            bodyAscent += glyphTempOpaqueSize.Y;
                        }
                        if (charSet.CharBaseLineRef.Contains(glyphs[i].Glyph))
                        {
                            baseLine += glyphTempOpaqueTopLeft.Y + glyphTempOpaqueSize.Y;
                        }
                        if (charSet.CharDescentRef.Contains(glyphs[i].Glyph))
                        {
                            descent += glyphTempOpaqueTopLeft.Y + glyphTempOpaqueSize.Y;
                        }

                        bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), internalFont.Height + 1);
                        using (Graphics glyphGraphics = Graphics.FromImage(bm)) {
                            glyphGraphics.Clear(Color.Transparent);
                            glyphGraphics.TextRenderingHint = textRenderingHint;
                            glyphGraphics.DrawString(str, internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatTypo);
                        }
                        glyphTempTypo = new PixelData();
                        glyphTempTypo.FromBitmap(bm);
                        glyphTempTypo.Crop(true, false);
                    }
                    else
                    {
                        glyphTempTypo = glyphBitmaps[i];
                    }

                    // Update xy values if it doesn't fit anymore
                    if (x + glyphBitmaps[i].Width + 2 > pixelLayer.Width)
                    {
                        x  = 1;
                        y += internalFont.Height + MathF.Clamp((int)MathF.Ceiling(internalFont.Height * 0.1875f), 3, 10);
                    }

                    // Memorize atlas coordinates & glyph data
                    glyphs[i].Size     = glyphBitmaps[i].Size;
                    glyphs[i].Offset.X = glyphBitmaps[i].Width - glyphTempTypo.Width;
                    glyphs[i].Offset.Y = 0; // TTF fonts are rendered on blocks that are the whole size of the height - so no need for offset
                    if (isSpace)
                    {
                        glyphs[i].Size.X   /= 2;
                        glyphs[i].Offset.X /= 2;
                    }
                    glyphs[i].Advance = glyphs[i].Size.X - glyphs[i].Offset.X;

                    atlas[i].X = x;
                    atlas[i].Y = y;
                    atlas[i].W = glyphBitmaps[i].Width;
                    atlas[i].H = (internalFont.Height + 1);

                    // Draw it onto the font surface
                    glyphBitmaps[i].DrawOnto(pixelLayer, BlendMode.Solid, x, y);

                    x += glyphBitmaps[i].Width + MathF.Clamp((int)MathF.Ceiling(internalFont.Height * 0.125f), 2, 10);
                }
            }

            // White out texture except alpha channel.
            for (int i = 0; i < pixelLayer.Data.Length; i++)
            {
                pixelLayer.Data[i].R = 255;
                pixelLayer.Data[i].G = 255;
                pixelLayer.Data[i].B = 255;
            }

            // Monospace offset and advance adjustments
            if (monospace)
            {
                float maxGlyphWidth = 0;
                for (int i = 0; i < glyphs.Length; i++)
                {
                    maxGlyphWidth = Math.Max(maxGlyphWidth, glyphs[i].Size.X);
                }
                for (int i = 0; i < glyphs.Length; ++i)
                {
                    glyphs[i].Offset.X -= (int)Math.Round((maxGlyphWidth - glyphs[i].Size.X) / 2.0f);
                    glyphs[i].Advance   = maxGlyphWidth;
                }
            }

            // Determine Font properties
            {
                float lineSpacing = internalFont.FontFamily.GetLineSpacing(internalFont.Style);
                float emHeight    = internalFont.FontFamily.GetEmHeight(internalFont.Style);
                float cellAscent  = internalFont.FontFamily.GetCellAscent(internalFont.Style);
                float cellDescent = internalFont.FontFamily.GetCellDescent(internalFont.Style);

                ascent      = (int)Math.Round(cellAscent * internalFont.Size / emHeight);
                bodyAscent /= charSet.CharBodyAscentRef.Length;
                baseLine   /= charSet.CharBaseLineRef.Length;
                descent     = (int)Math.Round(((float)descent / charSet.CharDescentRef.Length) - (float)baseLine);
            }

            // Aggregate rendered and generated data into our return value
            FontMetrics metrics = new FontMetrics(
                size: internalFont.SizeInPoints,
                height: (int)internalFont.Height,
                ascent: ascent,
                bodyAscent: bodyAscent,
                descent: descent,
                baseLine: baseLine,
                monospace: monospace);

            // Determine kerning pairs
            FontKerningPair[] kerningPairs = null;
            if (monospace)
            {
                kerningPairs = null;
            }
            else
            {
                kerningPairs = this.GatherKerningPairs(glyphs, metrics, glyphBitmaps);
            }

            return(new FontData(pixelLayer, atlas, glyphs, metrics, kerningPairs));
        }
コード例 #3
0
        private FontData RenderGlyphsCleartype(SysDrawFont internalFont, FontCharSet charSet, bool monospace)
        {
            FontGlyphData[] glyphs = new FontGlyphData[charSet.Chars.Length];
            for (int i = 0; i < glyphs.Length; i++)
            {
                glyphs[i].Glyph = charSet.Chars[i];
            }

            int bodyAscent = 0;
            int baseLine   = 0;
            int descent    = 0;
            int ascent     = 0;

            int cols;
            int rows;

            cols = rows = (int)Math.Ceiling(Math.Sqrt(glyphs.Length));

            IntPtr hFont = internalFont.ToHfont();

            PixelData pixelLayer = new PixelData(
                MathF.RoundToInt(cols * internalFont.Size * 1.2f),
                MathF.RoundToInt(rows * internalFont.Height * 1.2f),
                ColorRgba.TransparentBlack);
            Bitmap measureBm = new Bitmap(1, 1);

            Rect[]      atlas        = new Rect[glyphs.Length];
            PixelData[] glyphBitmaps = new PixelData[glyphs.Length];
            using (Graphics measureGraphics = Graphics.FromImage(measureBm)) {
                IntPtr measureHdc = measureGraphics.GetHdc();

                int x = 1;
                int y = 1;
                for (int i = 0; i < glyphs.Length; ++i)
                {
                    string str     = glyphs[i].Glyph.ToString(CultureInfo.InvariantCulture);
                    bool   isSpace = str == " ";

                    Size charSize;
                    GetTextExtentPoint32(measureHdc, str, str.Length, out charSize);

                    // Rasterize a single glyph for rendering
                    Bitmap bm = new Bitmap(Math.Max(1, charSize.Width), internalFont.Height + 1);
                    using (Graphics glyphGraphics = Graphics.FromImage(bm)) {
                        glyphGraphics.Clear(SystemColors.Window);

                        IntPtr hdc = glyphGraphics.GetHdc();
                        SelectObject(hdc, hFont);
                        SetTextColor(hdc, (0 /*B*/ << 16) | (0 /*G*/ << 8) | 0 /*R*/);
                        TextOut(hdc, 0, 0, str, str.Length);
                        glyphGraphics.ReleaseHdc(hdc);
                    }
                    glyphBitmaps[i] = new PixelData();
                    glyphBitmaps[i].FromBitmap(bm);

                    PixelData glyphTempTypo = glyphBitmaps[i];

                    // Update xy values if it doesn't fit anymore
                    if (x + glyphBitmaps[i].Width + 2 > pixelLayer.Width)
                    {
                        x  = 1;
                        y += internalFont.Height + MathF.Clamp((int)MathF.Ceiling(internalFont.Height * 0.1875f), 3, 10);
                    }

                    // Memorize atlas coordinates & glyph data
                    glyphs[i].Size     = glyphBitmaps[i].Size;
                    glyphs[i].Offset.X = glyphBitmaps[i].Width - glyphTempTypo.Width;
                    glyphs[i].Offset.Y = 0; // TTF fonts are rendered on blocks that are the whole size of the height - so no need for offset
                    if (isSpace)
                    {
                        glyphs[i].Size.X   /= 2;
                        glyphs[i].Offset.X /= 2;
                    }
                    glyphs[i].Advance = glyphs[i].Size.X - glyphs[i].Offset.X;

                    atlas[i].X = x;
                    atlas[i].Y = y;
                    atlas[i].W = glyphBitmaps[i].Width;
                    atlas[i].H = (internalFont.Height + 1);

                    // Draw it onto the font surface
                    glyphBitmaps[i].DrawOnto(pixelLayer, BlendMode.Solid, x, y);

                    x += glyphBitmaps[i].Width + MathF.Clamp((int)MathF.Ceiling(internalFont.Height * 0.125f), 2, 10);
                }

                measureGraphics.ReleaseHdc(measureHdc);
            }

            // ToDo: finally
            DeleteObject(hFont);

            // Monospace offset and advance adjustments
            if (monospace)
            {
                float maxGlyphWidth = 0;
                for (int i = 0; i < glyphs.Length; i++)
                {
                    maxGlyphWidth = Math.Max(maxGlyphWidth, glyphs[i].Size.X);
                }
                for (int i = 0; i < glyphs.Length; ++i)
                {
                    glyphs[i].Offset.X -= (int)Math.Round((maxGlyphWidth - glyphs[i].Size.X) / 2.0f);
                    glyphs[i].Advance   = maxGlyphWidth;
                }
            }

            // Determine Font properties
            {
                float lineSpacing = internalFont.FontFamily.GetLineSpacing(internalFont.Style);
                float emHeight    = internalFont.FontFamily.GetEmHeight(internalFont.Style);
                float cellAscent  = internalFont.FontFamily.GetCellAscent(internalFont.Style);
                float cellDescent = internalFont.FontFamily.GetCellDescent(internalFont.Style);

                ascent      = (int)Math.Round(cellAscent * internalFont.Size / emHeight);
                bodyAscent /= charSet.CharBodyAscentRef.Length;
                baseLine   /= charSet.CharBaseLineRef.Length;
                descent     = (int)Math.Round(((float)descent / charSet.CharDescentRef.Length) - (float)baseLine);
            }

            // Aggregate rendered and generated data into our return value
            FontMetrics metrics = new FontMetrics(
                size: internalFont.SizeInPoints,
                height: (int)internalFont.Height,
                ascent: ascent,
                bodyAscent: bodyAscent,
                descent: descent,
                baseLine: baseLine,
                monospace: monospace);

            // Determine kerning pairs
            FontKerningPair[] kerningPairs = null;
            if (monospace)
            {
                kerningPairs = null;
            }
            else
            {
                kerningPairs = this.GatherKerningPairs(glyphs, metrics, glyphBitmaps);
            }

            return(new FontData(pixelLayer, atlas, glyphs, metrics, kerningPairs));
        }
コード例 #4
0
        /// <summary>
        /// Renders the <see cref="Duality.Resources.FontRasterizer"/> using the specified system font family.
        /// </summary>
        private FontData RenderGlyphs(FontFamily fontFamily, float emSize, FontStyle style, FontCharSet extendedSet, FontRenderMode renderMode, bool antialiasing, bool monospace)
        {
            // Determine System.Drawing font style
            SysDrawFontStyle systemStyle = SysDrawFontStyle.Regular;

            if (style.HasFlag(FontStyle.Bold))
            {
                systemStyle |= SysDrawFontStyle.Bold;
            }
            if (style.HasFlag(FontStyle.Italic))
            {
                systemStyle |= SysDrawFontStyle.Italic;
            }

            // Create a System.Drawing font
            SysDrawFont internalFont = null;

            if (fontFamily != null)
            {
                try { internalFont = new SysDrawFont(fontFamily, emSize, systemStyle); } catch (Exception e) {
                    Console.WriteLine(
                        "Failed to create System Font '{1} {2}, {3}' for rendering: {0}",
                        /*LogFormat.Exception(*/ e /*)*/,
                        fontFamily.Name,
                        emSize,
                        style);
                }
            }

            // If creating the font failed, fall back to a default one
            if (internalFont == null)
            {
                internalFont = new SysDrawFont(FontFamily.GenericMonospace, emSize, systemStyle);
            }

            // Render the font's glyphs
            using (internalFont) {
                return(this.RenderGlyphs(
                           internalFont,
                           FontCharSet.Default.MergedWith(extendedSet),
                           renderMode,
                           antialiasing,
                           monospace));
            }
        }
コード例 #5
0
        /// <summary>
        /// Renders the <see cref="Duality.Resources.FontRasterizer"/> based on its embedded TrueType representation.
        /// <param name="extendedSet">Extended set of characters for renderning.</param>
        /// </summary>
        private FontData RenderGlyphs(string fontFamily, float emSize, FontStyle style, FontCharSet extendedSet, FontRenderMode renderMode, bool antialiasing, bool monospace)
        {
            FontFamily family = new FontFamily(fontFamily);

            // Render the font's glyphs
            return(this.RenderGlyphs(
                       family,
                       emSize,
                       style,
                       extendedSet,
                       renderMode,
                       antialiasing,
                       monospace));
        }
コード例 #6
0
        /// <summary>
        /// Renders the <see cref="Duality.Resources.Font"/> using the specified system font.
        /// This method assumes that the system font's size and style match the one specified in
        /// the specified Duality font.
        /// </summary>
        private RenderedFontData RenderGlyphs(SysDrawFont internalFont, FontCharSet charSet, bool antialiazing, bool monospace)
        {
            DualityFont.GlyphData[] glyphs = new DualityFont.GlyphData[charSet.Chars.Length];
            for (int i = 0; i < glyphs.Length; i++)
            {
                glyphs[i].Glyph = charSet.Chars[i];
            }

            int bodyAscent = 0;
            int baseLine = 0;
            int descent = 0;
            int ascent = 0;

            TextRenderingHint textRenderingHint;
            if (antialiazing)
                textRenderingHint = TextRenderingHint.AntiAliasGridFit;
            else
                textRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;

            int cols;
            int rows;
            cols = rows = (int)Math.Ceiling(Math.Sqrt(glyphs.Length));

            PixelData pixelLayer = new PixelData(
                MathF.RoundToInt(cols * internalFont.Size * 1.2f),
                MathF.RoundToInt(rows * internalFont.Height * 1.2f),
                ColorRgba.TransparentBlack);
            PixelData glyphTemp;
            PixelData glyphTempTypo;
            Bitmap bm;
            Bitmap measureBm = new Bitmap(1, 1);
            Rect[] atlas = new Rect[glyphs.Length];
            using (Graphics measureGraphics = Graphics.FromImage(measureBm))
            {
                Brush fntBrush = new SolidBrush(Color.Black);

                StringFormat formatDef = StringFormat.GenericDefault;
                formatDef.LineAlignment = StringAlignment.Near;
                formatDef.FormatFlags = 0;
                StringFormat formatTypo = StringFormat.GenericTypographic;
                formatTypo.LineAlignment = StringAlignment.Near;

                int x = 1;
                int y = 1;
                for (int i = 0; i < glyphs.Length; ++i)
                {
                    string str = glyphs[i].Glyph.ToString(CultureInfo.InvariantCulture);
                    bool isSpace = str == " ";
                    SizeF charSize = measureGraphics.MeasureString(str, internalFont, pixelLayer.Width, formatDef);

                    // Rasterize a single glyph for rendering
                    bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), internalFont.Height + 1);
                    using (Graphics glyphGraphics = Graphics.FromImage(bm))
                    {
                        glyphGraphics.Clear(Color.Transparent);
                        glyphGraphics.TextRenderingHint = textRenderingHint;
                        glyphGraphics.DrawString(str, internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatDef);
                    }
                    glyphTemp = new PixelData();
                    glyphTemp.FromBitmap(bm);

                    // Rasterize a single glyph in typographic mode for metric analysis
                    if (!isSpace)
                    {
                        Point2 glyphTempOpaqueTopLeft;
                        Point2 glyphTempOpaqueSize;
                        glyphTemp.GetOpaqueBoundaries(out glyphTempOpaqueTopLeft, out glyphTempOpaqueSize);

                        glyphTemp.SubImage(glyphTempOpaqueTopLeft.X, 0, glyphTempOpaqueSize.X, glyphTemp.Height);

                        if (charSet.CharBodyAscentRef.Contains(glyphs[i].Glyph))
                            bodyAscent += glyphTempOpaqueSize.Y;
                        if (charSet.CharBaseLineRef.Contains(glyphs[i].Glyph))
                            baseLine += glyphTempOpaqueTopLeft.Y + glyphTempOpaqueSize.Y;
                        if (charSet.CharDescentRef.Contains(glyphs[i].Glyph))
                            descent += glyphTempOpaqueTopLeft.Y + glyphTempOpaqueSize.Y;

                        bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), internalFont.Height + 1);
                        using (Graphics glyphGraphics = Graphics.FromImage(bm))
                        {
                            glyphGraphics.Clear(Color.Transparent);
                            glyphGraphics.TextRenderingHint = textRenderingHint;
                            glyphGraphics.DrawString(str, internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatTypo);
                        }
                        glyphTempTypo = new PixelData();
                        glyphTempTypo.FromBitmap(bm);
                        glyphTempTypo.Crop(true, false);
                    }
                    else
                    {
                        glyphTempTypo = glyphTemp;
                    }

                    // Update xy values if it doesn't fit anymore
                    if (x + glyphTemp.Width + 2 > pixelLayer.Width)
                    {
                        x = 1;
                        y += internalFont.Height + MathF.Clamp((int)MathF.Ceiling(internalFont.Height * 0.1875f), 3, 10);
                    }

                    // Memorize atlas coordinates & glyph data
                    glyphs[i].Width = glyphTemp.Width;
                    glyphs[i].Height = glyphTemp.Height;
                    glyphs[i].OffsetX = glyphTemp.Width - glyphTempTypo.Width;
                    glyphs[i].OffsetY = 0; // ttf fonts are rendered on blocks that are the whole size of the height - so no need for offset
                    if (isSpace)
                    {
                        glyphs[i].Width /= 2;
                        glyphs[i].OffsetX /= 2;
                    }
                    atlas[i].X = x;
                    atlas[i].Y = y;
                    atlas[i].W = glyphTemp.Width;
                    atlas[i].H = (internalFont.Height + 1);

                    // Draw it onto the font surface
                    glyphTemp.DrawOnto(pixelLayer, BlendMode.Solid, x, y);

                    x += glyphTemp.Width + MathF.Clamp((int)MathF.Ceiling(internalFont.Height * 0.125f), 2, 10);
                }
            }

            // White out texture except alpha channel.
            for (int i = 0; i < pixelLayer.Data.Length; i++)
            {
                pixelLayer.Data[i].R = 255;
                pixelLayer.Data[i].G = 255;
                pixelLayer.Data[i].B = 255;
            }

            // Monospace offset adjustments
            if (monospace)
            {
                int maxGlyphWidth = 0;
                for (int i = 0; i < glyphs.Length; i++)
                {
                    maxGlyphWidth = Math.Max(maxGlyphWidth, glyphs[i].Width);
                }
                for (int i = 0; i < glyphs.Length; ++i)
                {
                    glyphs[i].OffsetX -= (int)Math.Round((maxGlyphWidth - glyphs[i].Width) / 2.0f);
                }
            }

            // Determine Font properties
            {
                float lineSpacing = internalFont.FontFamily.GetLineSpacing(internalFont.Style);
                float emHeight = internalFont.FontFamily.GetEmHeight(internalFont.Style);
                float cellAscent = internalFont.FontFamily.GetCellAscent(internalFont.Style);
                float cellDescent = internalFont.FontFamily.GetCellDescent(internalFont.Style);

                ascent = (int)Math.Round(cellAscent * internalFont.Size / emHeight);
                bodyAscent /= charSet.CharBodyAscentRef.Length;
                baseLine /= charSet.CharBaseLineRef.Length;
                descent = (int)Math.Round(((float)descent / charSet.CharDescentRef.Length) - (float)baseLine);
            }

            // Aggregate rendered and generated data into our return value
            FontMetrics metrics = new FontMetrics(
                size:       internalFont.SizeInPoints,
                height:     (int)internalFont.Height,
                ascent:     ascent,
                bodyAscent: bodyAscent,
                descent:    descent,
                baseLine:   baseLine,
                monospace:  monospace);
            return new RenderedFontData
            {
                Bitmap = pixelLayer,
                Atlas = atlas,
                GlyphData = glyphs,
                Metrics = metrics
            };
        }
コード例 #7
0
        /// <summary>
        /// Renders the <see cref="Duality.Resources.Font"/> using the specified system font family.
        /// </summary>
        private RenderedFontData RenderGlyphs(FontFamily fontFamily, float emSize, FontStyle style, FontCharSet extendedSet, bool antialiasing, bool monospace)
        {
            // Determine System.Drawing font style
            SysDrawFontStyle systemStyle = SysDrawFontStyle.Regular;
            if (style.HasFlag(FontStyle.Bold)) systemStyle |= SysDrawFontStyle.Bold;
            if (style.HasFlag(FontStyle.Italic)) systemStyle |= SysDrawFontStyle.Italic;

            // Create a System.Drawing font
            SysDrawFont internalFont = null;
            if (fontFamily != null)
            {
                try { internalFont = new SysDrawFont(fontFamily, emSize, systemStyle); }
                catch (Exception e)
                {
                    Log.Editor.WriteError(
                        "Failed to create System Font '{1} {2}, {3}' for rendering Duality Font glyphs: {0}",
                        Log.Exception(e),
                        fontFamily.Name,
                        emSize,
                        style);
                }
            }

            // If creating the font failed, fall back to a default one
            if (internalFont == null)
                internalFont = new SysDrawFont(FontFamily.GenericMonospace, emSize, systemStyle);

            // Render the font's glyphs
            using (internalFont)
            {
                return this.RenderGlyphs(
                    internalFont,
                    FontCharSet.Default.MergedWith(extendedSet),
                    antialiasing,
                    monospace);
            }
        }
コード例 #8
0
        /// <summary>
        /// Renders the <see cref="Duality.Resources.Font"/> based on its embedded TrueType representation.
        /// <param name="extendedSet">Extended set of characters for renderning.</param>
        /// </summary>
        private RenderedFontData RenderGlyphs(byte[] trueTypeFontData, float emSize, FontStyle style, FontCharSet extendedSet, bool antialiasing, bool monospace)
        {
            if (this.fontManagers == null)
                this.fontManagers = new Dictionary<int, PrivateFontCollection>();

            // Allocate one PrivateFontCollection for each embedded TrueType Font
            // This is an unfortunate requirement to keep track of which Font is which,
            // since a byte[] doesn't give it away, and a Font collection won't tell us
            // which one we just added.
            PrivateFontCollection manager;
            int fontId = trueTypeFontData.GetHashCode();
            if (!this.fontManagers.TryGetValue(fontId, out manager))
            {
                manager = new PrivateFontCollection();
                this.fontManagers.Add(fontId, manager);
            }

            // Load custom font family using System.Drawing
            if (manager.Families.Length == 0)
            {
                IntPtr fontBuffer = Marshal.AllocCoTaskMem(trueTypeFontData.Length);
                Marshal.Copy(trueTypeFontData, 0, fontBuffer, trueTypeFontData.Length);
                manager.AddMemoryFont(fontBuffer, trueTypeFontData.Length);
            }

            // Render the font's glyphs
            return this.RenderGlyphs(
                manager.Families.FirstOrDefault(),
                emSize,
                style,
                extendedSet,
                antialiasing,
                monospace);

            // Yes, we have a minor memory leak here - both the Font buffer and the private
            // Font collection. Unfortunately though, GDI+ won't let us dispose them
            // properly due to aggressive Font caching, see here:
            //
            // http://stackoverflow.com/questions/25583394/privatefontcollection-addmemoryfont-producing-random-errors-on-windows-server-20
            //
            // "Standard GDI+ lossage, disposing a Font does not actually destroy it.
            // It gets put back into a cache, with the assumption that it will be used again.
            // An important perf optimization, creating fonts is pretty expensive. That ends
            // poorly for private fonts when you destroy their home, the font will use
            // released memory. Producing bewildering results, including hard crashes. You'll
            // need to keep the collection around, as well as the IntPtr."
            // – Hans Passant Aug 30 '14 at 16:13
        }