Пример #1
0
        public void Deserialize(List <String> input, out int pageCount, out char[] charSet)
        {
            CharSetMapping = new Dictionary <char, QFontGlyph>();
            var charSetList = new List <char>();

            try
            {
                pageCount = int.Parse(input[0]);
                int glyphCount = int.Parse(input[1]);

                for (int i = 0; i < glyphCount; i++)
                {
                    var vals  = input[2 + i].Split(' ');
                    var glyph = new QFontGlyph(int.Parse(vals[1]), new Rectangle(int.Parse(vals[2]), int.Parse(vals[3]), int.Parse(vals[4]), int.Parse(vals[5])), int.Parse(vals[6]));

                    CharSetMapping.Add(vals[0][0], glyph);
                    charSetList.Add(vals[0][0]);
                }
            }
            catch (Exception e)
            {
                throw new Exception("Failed to parse qfont file. Invalid format.", e);
            }

            charSet = charSetList.ToArray();
        }
Пример #2
0
        public void Deserialize(List<String> input, out int pageCount, out char[] charSet)
        {
            CharSetMapping = new Dictionary<char, QFontGlyph>();
            var charSetList = new List<char>();

            try
            {
                pageCount = int.Parse(input[0]);
                int glyphCount = int.Parse(input[1]);

                for (int i = 0; i < glyphCount; i++)
                {
                    var vals = input[2 + i].Split(' ');
                    var glyph = new QFontGlyph(int.Parse(vals[1]), new Rectangle(int.Parse(vals[2]), int.Parse(vals[3]), int.Parse(vals[4]), int.Parse(vals[5])), int.Parse(vals[6]));

                    CharSetMapping.Add(vals[0][0], glyph);
                    charSetList.Add(vals[0][0]);
                }

            }
            catch (Exception e)
            {
                throw new Exception("Failed to parse qfont file. Invalid format.",e);
            }

            charSet = charSetList.ToArray();
        }
Пример #3
0
        private float MeasureNextlineLength(string text)
        {
            float xOffset = 0;

            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];

                if (c == '\r' || c == '\n')
                {
                    break;
                }


                if (IsMonospacingActive)
                {
                    xOffset += MonoSpaceWidth;
                }
                else
                {
                    //space
                    if (c == ' ')
                    {
                        xOffset += (float)Math.Ceiling(fontData.meanGlyphWidth * Options.WordSpacing);
                    }
                    //normal character
                    else if (fontData.CharSetMapping.ContainsKey(c))
                    {
                        QFontGlyph glyph = fontData.CharSetMapping[c];
                        xOffset += (float)Math.Ceiling(glyph.rect.Width + fontData.meanGlyphWidth * Options.CharacterSpacing + fontData.GetKerningPairCorrection(i, text, null));
                    }
                }
            }
            return(xOffset);
        }
Пример #4
0
        /*
         * private SizeF GetMaxGlyphSize(Font font)
         * {
         *  Bitmap bmp = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
         *  Graphics graph = Graphics.FromImage(bmp);
         *
         *  SizeF maxSize = new SizeF(0f, 0f);
         *  for (int i = 0; i < charSet.Length; i++)
         *  {
         *      var charSize = graph.MeasureString("" + charSet[i], font);
         *
         *      if (charSize.Width > maxSize.Width)
         *          maxSize.Width = charSize.Width;
         *
         *      if (charSize.Height > maxSize.Height)
         *          maxSize.Height = charSize.Height;
         *  }
         *
         *  graph.Dispose();
         *  bmp.Dispose();
         *
         *  return maxSize;
         * }*/


        private Bitmap CreateInitialBitmap(Font font, SizeF maxSize, int initialMargin, out QFontGlyph[] glyphs)
        {
            glyphs = new QFontGlyph[charSet.Length];

            int      spacing = (int)Math.Ceiling(maxSize.Width) + 2 * initialMargin;
            Bitmap   bmp     = new Bitmap(spacing * charSet.Length, (int)Math.Ceiling(maxSize.Height) + 2 * initialMargin, PixelFormat.Format24bppRgb);
            Graphics graph   = Graphics.FromImage(bmp);

            graph.TextRenderingHint = TextRenderingHint.AntiAlias;

            int xOffset = initialMargin;

            for (int i = 0; i < charSet.Length; i++)
            {
                graph.DrawString("" + charSet[i], font, Brushes.White, xOffset, initialMargin);
                var charSize = graph.MeasureString("" + charSet[i], font);
                glyphs[i] = new QFontGlyph(0, new Rectangle(xOffset - initialMargin, 0, (int)charSize.Width + initialMargin * 2, (int)charSize.Height + initialMargin * 2), 0);
                xOffset  += (int)charSize.Width + initialMargin * 2;
            }

            graph.Flush();
            graph.Dispose();

            return(bmp);
        }
Пример #5
0
        private static int Kerning(QFontGlyph g1, QFontGlyph g2, XLimits[] lim1, XLimits[] lim2)
        {
            int yOffset1 = g1.yOffset;
            int yOffset2 = g2.yOffset;

            int startY = Math.Max(yOffset1, yOffset2);
            int endY   = Math.Min(g1.rect.Height + yOffset1, g2.rect.Height + yOffset2);

            int w1 = g1.rect.Width;

            int worstCase = w1;

            //TODO - offset startY, endY by yOffset1 so that lim1[j-yOffset1] can be written as lim1[j], will need another var for yOffset2

            for (int j = startY; j < endY; j++)
            {
                worstCase = Math.Min(worstCase, w1 - lim1[j - yOffset1].Max + lim2[j - yOffset2].Min);
            }


            worstCase = Math.Min(worstCase, g1.rect.Width);
            worstCase = Math.Min(worstCase, g2.rect.Width);

            return(worstCase);
        }
Пример #6
0
        private void RenderWord(float x, float y, TextNode node, ref Rectangle clippingRectangle)
        {
            if (node.Type != TextNodeType.Word)
            {
                return;
            }

            int  charGaps      = node.Text.Length - 1;
            bool isCrumbleWord = CrumbledWord(node);

            if (isCrumbleWord)
            {
                charGaps++;
            }

            int pixelsPerGap   = 0;
            int leftOverPixels = 0;

            if (charGaps != 0)
            {
                pixelsPerGap   = (int)node.LengthTweak / charGaps;
                leftOverPixels = (int)node.LengthTweak - pixelsPerGap * charGaps;
            }

            for (int i = 0; i < node.Text.Length; i++)
            {
                char c = node.Text[i];
                if (_font.FontData.CharSetMapping.ContainsKey(c))
                {
                    QFontGlyph glyph = _font.FontData.CharSetMapping[c];

                    RenderGlyph(x, y, c, _font, CurrentVertexRepr, clippingRectangle);


                    if (IsMonospacingActive)
                    {
                        x += MonoSpaceWidth;
                    }
                    else
                    {
                        x +=
                            (int)
                            Math.Ceiling(glyph.rect.Width + _font.FontData.meanGlyphWidth * this.Options.CharacterSpacing + _font.FontData.GetKerningPairCorrection(i, node.Text, node));
                    }

                    x += pixelsPerGap;
                    if (leftOverPixels > 0)
                    {
                        x += 1.0f;
                        leftOverPixels--;
                    }
                    else if (leftOverPixels < 0)
                    {
                        x -= 1.0f;
                        leftOverPixels++;
                    }
                }
            }
        }
Пример #7
0
        private static Dictionary<char, QFontGlyph> CreateCharGlyphMapping(QFontGlyph[] glyphs)
        {
            var dict = new Dictionary<char, QFontGlyph>();
            for (int i = 0; i < glyphs.Length; i++)
                dict.Add(glyphs[i].character, glyphs[i]);

            return dict;
        }
Пример #8
0
        private static void RetargetGlyphRectangleInwards(BitmapData bitmapData, QFontGlyph glyph, bool setYOffset, byte alphaTolerance)
        {
            int startX, endX;
            int startY, endY;

            var rect = glyph.rect;

            EmptyDel emptyPix;

            if (bitmapData.PixelFormat == PixelFormat.Format32bppArgb)
                emptyPix = delegate(BitmapData data, int x, int y) { return QBitmap.EmptyAlphaPixel(data, x, y, alphaTolerance); };
            else
                emptyPix = delegate(BitmapData data, int x, int y) { return QBitmap.EmptyPixel(data, x, y); };


            unsafe
            {

                for (startX = rect.X; startX < bitmapData.Width; startX++)
                    for (int j = rect.Y; j < rect.Y + rect.Height; j++)
                        if (!emptyPix(bitmapData, startX, j))
                            goto Done1;
                Done1:

                for (endX = rect.X + rect.Width; endX >= 0; endX--)
                    for (int j = rect.Y; j < rect.Y + rect.Height; j++)
                        if (!emptyPix(bitmapData, endX, j))
                            goto Done2;
                Done2:

                for (startY = rect.Y; startY < bitmapData.Height; startY++)
                    for (int i = startX; i < endX; i++)
                        if (!emptyPix(bitmapData, i, startY))
                            goto Done3;
                            
                Done3:

                for (endY = rect.Y + rect.Height; endY >= 0; endY--)
                    for (int i = startX; i < endX; i++)
                        if (!emptyPix(bitmapData, i, endY))
                            goto Done4;
                Done4:;


            }

            if (endY < startY)
                startY = endY = rect.Y;

            if (endX < startX)
                startX = endX = rect.X;

            glyph.rect = new Rectangle(startX, startY, endX - startX + 1, endY - startY + 1);

            if (setYOffset)
                glyph.yOffset = glyph.rect.Y;

        }
Пример #9
0
 private void RenderDropShadow(float x, float y, char c, QFontGlyph nonShadowGlyph, QFont shadowFont, ref Rectangle clippingRectangle)
 {
     //note can cast drop shadow offset to int, but then you can't move the shadow smoothly...
     if (shadowFont != null && this.Options.DropShadowActive)
     {
         float xOffset = (_font.FontData.meanGlyphWidth * this.Options.DropShadowOffset.X + nonShadowGlyph.rect.Width * 0.5f);
         float yOffset = (_font.FontData.meanGlyphWidth * this.Options.DropShadowOffset.Y + nonShadowGlyph.rect.Height * 0.5f + nonShadowGlyph.yOffset);
         this.RenderGlyph(x + xOffset, y + yOffset, c, shadowFont, this.ShadowVertexRepr, clippingRectangle);
     }
 }
Пример #10
0
 public static void CreateBitmapPerGlyph(QFontGlyph[] sourceGlyphs, QBitmap[] sourceBitmaps, out QFontGlyph[]  destGlyphs, out QBitmap[] destBitmaps){
     destBitmaps = new QBitmap[sourceGlyphs.Length];
     destGlyphs = new QFontGlyph[sourceGlyphs.Length];
     for(int i = 0; i < sourceGlyphs.Length; i++){
         var sg = sourceGlyphs[i];
         destGlyphs[i] = new QFontGlyph(i,new Rectangle(0,0,sg.rect.Width,sg.rect.Height),sg.yOffset,sg.character);
         destBitmaps[i] = new QBitmap(new Bitmap(sg.rect.Width,sg.rect.Height,PixelFormat.Format32bppArgb));
         QBitmap.Blit(sourceBitmaps[sg.page].bitmapData,destBitmaps[i].bitmapData,sg.rect,0,0);
     }
 }
Пример #11
0
 public static void CreateBitmapPerGlyph(QFontGlyph[] sourceGlyphs, QBitmap[] sourceBitmaps, out QFontGlyph[]  destGlyphs, out QBitmap[] destBitmaps)
 {
     destBitmaps = new QBitmap[sourceGlyphs.Length];
     destGlyphs = new QFontGlyph[sourceGlyphs.Length];
     for(int i = 0; i < sourceGlyphs.Length; i++){
         var sg = sourceGlyphs[i];
         destGlyphs[i] = new QFontGlyph(i,new Rectangle(0,0,sg.rect.Width,sg.rect.Height),sg.yOffset,sg.character);
         destBitmaps[i] = new QBitmap(new Bitmap(sg.rect.Width,sg.rect.Height,PixelFormat.Format32bppArgb));
         QBitmap.Blit(sourceBitmaps[sg.page].BitmapData,destBitmaps[i].BitmapData,sg.rect,0,0);
     }
 }
Пример #12
0
 private void RenderDropShadow(float x, float y, char c, QFontGlyph nonShadowGlyph, QFontData shadowFont,
                               ref Rectangle clippingRectangle)
 {
     //note can cast drop shadow offset to int, but then you can't move the shadow smoothly...
     if (shadowFont != null && Options.DropShadowActive)
     {
         var xOffset = Font.meanGlyphWidth * Options.DropShadowOffset.X +
                       nonShadowGlyph.rect.Width * 0.5f;
         var yOffset = Font.meanGlyphWidth * Options.DropShadowOffset.Y +
                       nonShadowGlyph.rect.Height * 0.5f + nonShadowGlyph.yOffset;
         RenderGlyph(x + xOffset, y + yOffset, c, shadowFont, ShadowVertexRepr, ref clippingRectangle);
     }
 }
Пример #13
0
        /// <summary>
        /// Creates the initial font bitmap. This is simply a long thin strip of all glyphs in a row
        /// </summary>
        /// <param name="font">The <see cref="IFont"/> object to build the initial bitmap from</param>
        /// <param name="maxSize">The maximum glyph size of the font</param>
        /// <param name="initialMargin">The initial bitmap margin (used for all four sides)</param>
        /// <param name="glyphs">A collection of <see cref="QFontGlyph"/>s corresponding to the initial bitmap</param>
        /// <param name="renderHint">The font rendering hint to use</param>
        /// <returns></returns>
        private Bitmap CreateInitialBitmap(IFont font, SizeF maxSize, int initialMargin, out QFontGlyph[] glyphs, TextGenerationRenderHint renderHint)
        {
            glyphs = new QFontGlyph[_charSet.Length];

            int      spacing = (int)Math.Ceiling(maxSize.Width) + 2 * initialMargin;
            Bitmap   bmp     = new Bitmap(spacing * _charSet.Length, (int)Math.Ceiling(maxSize.Height) + 2 * initialMargin, PixelFormat.Format24bppRgb);
            Graphics graph   = Graphics.FromImage(bmp);

            switch (renderHint)
            {
            case TextGenerationRenderHint.SizeDependent:
                graph.TextRenderingHint = font.Size <= 12.0f  ? TextRenderingHint.ClearTypeGridFit : TextRenderingHint.AntiAlias;
                break;

            case TextGenerationRenderHint.AntiAlias:
                graph.TextRenderingHint = TextRenderingHint.AntiAlias;
                break;

            case TextGenerationRenderHint.AntiAliasGridFit:
                graph.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                break;

            case TextGenerationRenderHint.ClearTypeGridFit:
                graph.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                break;

            case TextGenerationRenderHint.SystemDefault:
                graph.TextRenderingHint = TextRenderingHint.SystemDefault;
                break;
            }

            // enable high quality graphics
            graph.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            graph.SmoothingMode      = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            graph.CompositingMode    = System.Drawing.Drawing2D.CompositingMode.SourceOver;

            int xOffset = initialMargin;

            for (int i = 0; i < _charSet.Length; i++)
            {
                var offset   = font.DrawString("" + _charSet[i], graph, Brushes.White, xOffset, initialMargin);
                var charSize = font.MeasureString("" + _charSet[i], graph);
                glyphs[i] = new QFontGlyph(0, new Rectangle(xOffset - initialMargin + offset.X, initialMargin + offset.Y, (int)charSize.Width + initialMargin * 2, (int)charSize.Height + initialMargin * 2), 0, _charSet[i]);
                xOffset  += (int)charSize.Width + initialMargin * 2;
            }

            graph.Flush();
            graph.Dispose();

            return(bmp);
        }
Пример #14
0
        /*
         * private SizeF GetMaxGlyphSize(Font font)
         * {
         * Bitmap bmp = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
         * Graphics graph = Graphics.FromImage(bmp);
         *
         * SizeF maxSize = new SizeF(0f, 0f);
         * for (int i = 0; i < charSet.Length; i++)
         * {
         * var charSize = graph.MeasureString("" + charSet[i], font);
         *
         * if (charSize.Width > maxSize.Width)
         *  maxSize.Width = charSize.Width;
         *
         * if (charSize.Height > maxSize.Height)
         *  maxSize.Height = charSize.Height;
         * }
         *
         * graph.Dispose();
         * bmp.Dispose();
         *
         * return maxSize;
         * }*/

        //The initial bitmap is simply a long thin strip of all glyphs in a row
        private Bitmap CreateInitialBitmap(Font font, SizeF maxSize, int initialMargin, out QFontGlyph[] glyphs, TextGenerationRenderHint renderHint)
        {
            glyphs = new QFontGlyph[charSet.Length];

            int      spacing = (int)Math.Ceiling(maxSize.Width) + 2 * initialMargin;
            Bitmap   bmp     = new Bitmap(spacing * charSet.Length, (int)Math.Ceiling(maxSize.Height) + 2 * initialMargin, PixelFormat.Format24bppRgb);
            Graphics graph   = Graphics.FromImage(bmp);

            switch (renderHint)
            {
            case TextGenerationRenderHint.SizeDependent:
                graph.TextRenderingHint = font.Size <= 12.0f ? TextRenderingHint.ClearTypeGridFit : TextRenderingHint.AntiAlias;
                break;

            case TextGenerationRenderHint.AntiAlias:
                graph.TextRenderingHint = TextRenderingHint.AntiAlias;
                break;

            case TextGenerationRenderHint.AntiAliasGridFit:
                graph.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                break;

            case TextGenerationRenderHint.ClearTypeGridFit:
                graph.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                break;

            case TextGenerationRenderHint.SystemDefault:
                graph.TextRenderingHint = TextRenderingHint.SystemDefault;
                break;
            }



            int xOffset = initialMargin;

            for (int i = 0; i < charSet.Length; i++)
            {
                graph.DrawString("" + charSet[i], font, Brushes.White, xOffset, initialMargin);
                var charSize = graph.MeasureString("" + charSet[i], font);
                glyphs[i] = new QFontGlyph(0, new Rectangle(xOffset - initialMargin, 0, (int)charSize.Width + initialMargin * 2, (int)charSize.Height + initialMargin * 2), 0, charSet[i]);
                xOffset  += (int)charSize.Width + initialMargin * 2;
            }

            graph.Flush();
            graph.Dispose();

            return(bmp);
        }
Пример #15
0
        private void RenderDropShadow(float x, float y, char c, QFontGlyph nonShadowGlyph)
        {
            //note can cast drop shadow offset to int, but then you can't move the shadow smoothly...
            if (fontData.dropShadow != null && Options.DropShadowActive)
            {
                //make sure fontdata font's options are synced with the actual options
                if (fontData.dropShadow.Options != Options)
                {
                    fontData.dropShadow.Options = Options;
                }

                fontData.dropShadow.RenderGlyph(
                    x + (fontData.meanGlyphWidth * Options.DropShadowOffset.X + nonShadowGlyph.rect.Width * 0.5f),
                    y + (fontData.meanGlyphWidth * Options.DropShadowOffset.Y + nonShadowGlyph.rect.Height * 0.5f + nonShadowGlyph.yOffset), c, true);
            }
        }
Пример #16
0
        /// <summary>
        /// Calculate the kerning between two glyphs
        /// </summary>
        /// <param name="g1">The first glyph</param>
        /// <param name="g2">The second glyph</param>
        /// <param name="lim1">The first glyph limits</param>
        /// <param name="lim2">The second glyph limits</param>
        /// <param name="config">The kerning configuration to use</param>
        /// <param name="font">The glyph's <see cref="IFont"/></param>
        /// <returns>The x coordinate kerning offset</returns>
        private static int Kerning(QFontGlyph g1, QFontGlyph g2, XLimits[] lim1, XLimits[] lim2, QFontKerningConfiguration config, IFont font)
        {
            // Use kerning information from the font if it exists
            if (font != null && font.HasKerningInformation)
            {
                return(font.GetKerning(g1.Character, g2.Character));
            }

            // Otherwise, calculate our own kerning
            int yOffset1 = g1.YOffset;
            int yOffset2 = g2.YOffset;

            int startY = Math.Max(yOffset1, yOffset2);
            int endY   = Math.Min(g1.Rect.Height + yOffset1, g2.Rect.Height + yOffset2);

            int w1 = g1.Rect.Width;

            int worstCase = w1;

            //TODO - offset startY, endY by yOffset1 so that lim1[j-yOffset1] can be written as lim1[j], will need another var for yOffset2

            for (int j = startY; j < endY; j++)
            {
                worstCase = Math.Min(worstCase, w1 - lim1[j - yOffset1].Max + lim2[j - yOffset2].Min);
            }

            worstCase = Math.Min(worstCase, g1.Rect.Width);
            worstCase = Math.Min(worstCase, g2.Rect.Width);

            //modify by character kerning rules
            CharacterKerningRule kerningRule = config.GetOverridingCharacterKerningRuleForPair("" + g1.Character + g2.Character);

            switch (kerningRule)
            {
            case CharacterKerningRule.Zero:
                return(1);

            case CharacterKerningRule.NotMoreThanHalf:
                return(1 - (int)Math.Min(Math.Min(g1.Rect.Width, g2.Rect.Width) * 0.5f, worstCase));
            }

            return(1 - worstCase);
        }
        private static int Kerning(QFontGlyph g1, QFontGlyph g2, XLimits[] lim1, XLimits[] lim2, QFontKerningConfiguration config)
        {
            int yOffset1 = g1.yOffset;
            int yOffset2 = g2.yOffset;

            int startY = Math.Max(yOffset1, yOffset2);
            int endY   = Math.Min(g1.rect.Height + yOffset1, g2.rect.Height + yOffset2);

            int w1 = g1.rect.Width;

            int worstCase = w1;

            //TODO - offset startY, endY by yOffset1 so that lim1[j-yOffset1] can be written as lim1[j], will need another var for yOffset2

            for (int j = startY; j < endY; j++)
            {
                worstCase = Math.Min(worstCase, w1 - lim1[j - yOffset1].Max + lim2[j - yOffset2].Min);
            }


            worstCase = Math.Min(worstCase, g1.rect.Width);
            worstCase = Math.Min(worstCase, g2.rect.Width);


            //modify by character kerning rules
            CharacterKerningRule kerningRule = config.GetOverridingCharacterKerningRuleForPair("" + g1.character + g2.character);

            if (kerningRule == CharacterKerningRule.Zero)
            {
                return(0);
            }
            else if (kerningRule == CharacterKerningRule.NotMoreThanHalf)
            {
                return((int)Math.Min(Math.Min(g1.rect.Width, g2.rect.Width) * 0.5f, worstCase));
            }


            return(worstCase);
        }
Пример #18
0
        private static int Kerning(QFontGlyph g1, QFontGlyph g2, XLimits[] lim1, XLimits[] lim2, QFontKerningConfiguration config)
        {
            int yOffset1 = g1.yOffset;
            int yOffset2 = g2.yOffset;

            int startY = Math.Max(yOffset1, yOffset2);
            int endY = Math.Min(g1.rect.Height + yOffset1, g2.rect.Height + yOffset2);

            int w1 = g1.rect.Width;

            int worstCase = w1;

            //TODO - offset startY, endY by yOffset1 so that lim1[j-yOffset1] can be written as lim1[j], will need another var for yOffset2

            for (int j = startY; j < endY; j++)
                worstCase = Math.Min(worstCase, w1 - lim1[j-yOffset1].Max + lim2[j-yOffset2].Min);


            worstCase = Math.Min(worstCase, g1.rect.Width);
            worstCase = Math.Min(worstCase, g2.rect.Width);


            //modify by character kerning rules
            CharacterKerningRule kerningRule = config.GetOverridingCharacterKerningRuleForPair(""+g1.character + g2.character);
            if (kerningRule == CharacterKerningRule.Zero)
            {
                return 0;
            }
            else if (kerningRule == CharacterKerningRule.NotMoreThanHalf)
            {
                return (int)Math.Min(Math.Min(g1.rect.Width,g2.rect.Width)*0.5f, worstCase);
            }


            return worstCase;
        }
Пример #19
0
        private static List <QBitmap> GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin)
        {
            var pages = new List <QBitmap>();

            destGlyphs = new QFontGlyph[sourceGlyphs.Length];

            QBitmap currentPage = null;

            int maxY = 0;

            foreach (var glph in sourceGlyphs)
            {
                maxY = Math.Max(glph.rect.Height, maxY);
            }

            int finalPageIndex          = 0;
            int finalPageRequiredWidth  = 0;
            int finalPageRequiredHeight = 0;

            for (int k = 0; k < 2; k++)
            {
                bool pre = k == 0;  //first iteration is simply to determine the required size of the final page, so that we can crop it in advance

                int xPos       = 0;
                int yPos       = 0;
                int maxYInRow  = 0;
                int totalTries = 0;

                for (int i = 0; i < sourceGlyphs.Length; i++)
                {
                    if (!pre && currentPage == null)
                    {
                        if (finalPageIndex == pages.Count)
                        {
                            int width  = Math.Min(destSheetWidth, finalPageRequiredWidth);
                            int height = Math.Min(destSheetHeight, finalPageRequiredHeight);

                            currentPage = new QBitmap(new Bitmap(width, height, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        else
                        {
                            currentPage = new QBitmap(new Bitmap(destSheetWidth, destSheetHeight, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        pages.Add(currentPage);
                    }

                    totalTries++;

                    if (totalTries > 10 * sourceGlyphs.Length)
                    {
                        throw new Exception("Failed to fit font into texture pages");
                    }

                    var rect = sourceGlyphs[i].rect;

                    if (xPos + rect.Width + 2 * destMargin <= destSheetWidth && yPos + rect.Height + 2 * destMargin <= destSheetHeight)
                    {
                        if (!pre)
                        {
                            //add to page
                            if (sourceBitmaps[sourceGlyphs[i].page].PixelFormat == PixelFormat.Format32bppArgb)
                            {
                                QBitmap.Blit(sourceBitmaps[sourceGlyphs[i].page], currentPage.bitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }
                            else
                            {
                                QBitmap.BlitMask(sourceBitmaps[sourceGlyphs[i].page], currentPage.bitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }

                            destGlyphs[i] = new QFontGlyph(pages.Count - 1, new Rectangle(xPos + destMargin, yPos + destMargin, rect.Width, rect.Height), sourceGlyphs[i].yOffset, sourceGlyphs[i].character);
                        }
                        else
                        {
                            finalPageRequiredWidth  = Math.Max(finalPageRequiredWidth, xPos + rect.Width + 2 * destMargin);
                            finalPageRequiredHeight = Math.Max(finalPageRequiredHeight, yPos + rect.Height + 2 * destMargin);
                        }

                        xPos     += rect.Width + 2 * destMargin;
                        maxYInRow = Math.Max(maxYInRow, rect.Height);

                        continue;
                    }

                    if (xPos + rect.Width + 2 * destMargin > destSheetWidth)
                    {
                        i--;

                        yPos += maxYInRow + 2 * destMargin;
                        xPos  = 0;

                        if (yPos + maxY + 2 * destMargin > destSheetHeight)
                        {
                            yPos = 0;

                            if (!pre)
                            {
                                currentPage = null;
                            }
                            else
                            {
                                finalPageRequiredWidth  = 0;
                                finalPageRequiredHeight = 0;
                                finalPageIndex++;
                            }
                        }
                        continue;
                    }
                }
            }

            return(pages);
        }
Пример #20
0
        private static void RetargetGlyphRectangleOutwards(BitmapData bitmapData, QFontGlyph glyph, bool setYOffset, byte alphaTolerance)
        {
            int startX, endX;
            int startY, endY;

            var rect = glyph.rect;

            EmptyDel emptyPix;

            if (bitmapData.PixelFormat == PixelFormat.Format32bppArgb)
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(QBitmap.EmptyAlphaPixel(data, x, y, alphaTolerance)); }
            }
            ;
            else
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(QBitmap.EmptyPixel(data, x, y)); }
            };

            unsafe
            {
                for (startX = rect.X; startX >= 0; startX--)
                {
                    bool foundPix = false;
                    for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
                    {
                        if (!emptyPix(bitmapData, startX, j))
                        {
                            foundPix = true;
                            break;
                        }
                    }

                    if (!foundPix)
                    {
                        startX++;
                        break;
                    }
                }

                for (endX = rect.X + rect.Width; endX < bitmapData.Width; endX++)
                {
                    bool foundPix = false;
                    for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
                    {
                        if (!emptyPix(bitmapData, endX, j))
                        {
                            foundPix = true;
                            break;
                        }
                    }

                    if (!foundPix)
                    {
                        endX--;
                        break;
                    }
                }

                for (startY = rect.Y; startY >= 0; startY--)
                {
                    bool foundPix = false;
                    for (int i = startX; i <= endX; i++)
                    {
                        if (!emptyPix(bitmapData, i, startY))
                        {
                            foundPix = true;
                            break;
                        }
                    }

                    if (!foundPix)
                    {
                        startY++;
                        break;
                    }
                }

                for (endY = rect.Y + rect.Height; endY < bitmapData.Height; endY++)
                {
                    bool foundPix = false;
                    for (int i = startX; i <= endX; i++)
                    {
                        if (!emptyPix(bitmapData, i, endY))
                        {
                            foundPix = true;
                            break;
                        }
                    }

                    if (!foundPix)
                    {
                        endY--;
                        break;
                    }
                }
            }

            glyph.rect = new Rectangle(startX, startY, endX - startX + 1, endY - startY + 1);

            if (setYOffset)
            {
                glyph.yOffset = glyph.rect.Y;
            }
        }
Пример #21
0
		public void RetargetGlyphRectangleOutwards (QFontGlyph glyph, bool setYOffset, byte alphaTolerance)
		{
			int startX,endX;
			int startY,endY;

			var rect = glyph.rect;

			EmptyDel emptyPix;

			if (mBitmapData.PixelFormat == PixelFormat.Format32bppArgb)
				emptyPix = delegate(BitmapData data, int x, int y) { return QBitmapData.EmptyAlphaPixel(data, x, y, alphaTolerance); };
			else
				emptyPix = delegate(BitmapData data, int x, int y) { return QBitmapData.EmptyPixel(data, x, y); };


			unsafe
			{

				for (startX = rect.X; startX >= 0; startX--)
				{
					bool foundPix = false;
					for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
					{
						if (!emptyPix(mBitmapData, startX, j))
						{
							foundPix = true;
							break;
						}
					}

					if (!foundPix)
					{
						startX++;
						break;
					}
				}


				for (endX = rect.X + rect.Width; endX < mBitmapData.Width; endX++)
				{
					bool foundPix = false;
					for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
					{
						if (!emptyPix(mBitmapData, endX, j))
						{
							foundPix = true;
							break; 
						}
					}

					if (!foundPix)
					{
						endX--;
						break;
					}
				}



				for (startY = rect.Y; startY >= 0; startY--)
				{
					bool foundPix = false;
					for (int i = startX; i <= endX; i++)
					{
						if (!emptyPix(mBitmapData, i, startY))
						{
							foundPix = true;
							break;
						}
					}

					if (!foundPix)
					{
						startY++;
						break;
					}
				}



				for (endY = rect.Y + rect.Height; endY < mBitmapData.Height; endY++)
				{
					bool foundPix = false;
					for (int i = startX; i <= endX; i++)
					{
						if (!emptyPix(mBitmapData, i, endY))
						{
							foundPix = true;
							break;
						}
					}

					if (!foundPix)
					{
						endY--;
						break;
					}
				}



			}



			glyph.rect = new Rectangle(startX, startY, endX - startX + 1, endY - startY + 1);

			if (setYOffset)
				glyph.yOffset = glyph.rect.Y;

		}
Пример #22
0
        private SizeF PrintOrMeasure(string text, QFontAlignment alignment, bool measureOnly)
        {
            var popRequired = false;

            if (!measureOnly && !ProjectionStack.Begun && Options.TransformToViewport != null)
            {
                GL.PushMatrix();
                popRequired = true;
                GL.Scale(1 / fontData.scaleDueToTransformToViewport, 1 / fontData.scaleDueToTransformToViewport, 0);
            }


            float maxXpos = float.MinValue;
            float minXPos = float.MaxValue;

            if (!measureOnly)
            {
                GL.Color4(1.0f, 1.0f, 1.0f, 1.0f);
                GL.Enable(EnableCap.Texture2D);
                GL.Enable(EnableCap.Blend);

                if (Options.UseDefaultBlendFunction)
                {
                    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                }
            }

            float xOffset = 0f;
            float yOffset = 0f;

            text = text.Replace("\r\n", "\r");

            if (alignment == QFontAlignment.Right)
            {
                xOffset -= MeasureNextlineLength(text);
            }
            else if (alignment == QFontAlignment.Centre)
            {
                xOffset -= (int)(0.5f * MeasureNextlineLength(text));
            }

            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];


                //newline
                if (c == '\r' || c == '\n')
                {
                    yOffset += LineSpacing;
                    xOffset  = 0f;

                    if (alignment == QFontAlignment.Right)
                    {
                        xOffset -= MeasureNextlineLength(text.Substring(i + 1));
                    }
                    else if (alignment == QFontAlignment.Centre)
                    {
                        xOffset -= (int)(0.5f * MeasureNextlineLength(text.Substring(i + 1)));
                    }
                }
                else
                {
                    minXPos = Math.Min(xOffset, minXPos);

                    //normal character
                    if (c != ' ' && fontData.CharSetMapping.ContainsKey(c))
                    {
                        QFontGlyph glyph = fontData.CharSetMapping[c];
                        if (!measureOnly)
                        {
                            RenderGlyph(xOffset, yOffset, c, false);
                        }
                    }


                    if (IsMonospacingActive)
                    {
                        xOffset += MonoSpaceWidth;
                    }
                    else
                    {
                        if (c == ' ')
                        {
                            xOffset += (float)Math.Ceiling(fontData.meanGlyphWidth * Options.WordSpacing);
                        }
                        //normal character
                        else if (fontData.CharSetMapping.ContainsKey(c))
                        {
                            QFontGlyph glyph = fontData.CharSetMapping[c];
                            xOffset += (float)Math.Ceiling(glyph.rect.Width + fontData.meanGlyphWidth * Options.CharacterSpacing + fontData.GetKerningPairCorrection(i, text, null));
                        }
                    }

                    maxXpos = Math.Max(xOffset, maxXpos);
                }
            }

            float maxWidth = 0f;

            if (minXPos != float.MaxValue)
            {
                maxWidth = maxXpos - minXPos;
            }


            if (popRequired)
            {
                GL.PopMatrix();
            }


            return(new SizeF(maxWidth, yOffset + LineSpacing));
        }
Пример #23
0
        private static List<QBitmap> GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin, bool usePowerOfTwo)
        {
            var pages = new List<QBitmap>();
            destGlyphs = new QFontGlyph[sourceGlyphs.Length];

            QBitmap currentPage = null;

            int maxY = 0;
            foreach (var glph in sourceGlyphs)
                maxY = Math.Max(glph.rect.Height, maxY);

            int finalPageIndex = 0;
            int finalPageRequiredWidth = 0;
            int finalPageRequiredHeight = 0;

            for (int k = 0; k < 2; k++)
            {
                bool pre = k == 0;  //first iteration is simply to determine the required size of the final page, so that we can crop it in advance

                int xPos = 0;
                int yPos = 0;
                int maxYInRow = 0;
                int totalTries = 0;

                for (int i = 0; i < sourceGlyphs.Length; i++)
                {

                    if(!pre && currentPage == null){

                        if (finalPageIndex == pages.Count)
                        {
                            int width = Math.Min(destSheetWidth, usePowerOfTwo ? PowerOfTwo(finalPageRequiredWidth) : finalPageRequiredWidth);
                            int height = Math.Min(destSheetHeight, usePowerOfTwo ? PowerOfTwo(finalPageRequiredHeight) : finalPageRequiredHeight);

                            currentPage = new QBitmap(new Bitmap(width, height, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        else
                        {
                            currentPage = new QBitmap(new Bitmap(destSheetWidth, destSheetHeight, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        pages.Add(currentPage);

                    }

                    totalTries++;

                    if (totalTries > 10 * sourceGlyphs.Length)
                        throw new Exception("Failed to fit font into texture pages");

                    var rect = sourceGlyphs[i].rect;

                    if (xPos + rect.Width + 2 * destMargin <= destSheetWidth && yPos + rect.Height + 2 * destMargin <= destSheetHeight)
                    {
                        if (!pre)
                        {
                            //add to page
                            if(sourceBitmaps[sourceGlyphs[i].page].PixelFormat == PixelFormat.Format32bppArgb)
                                QBitmap.Blit(sourceBitmaps[sourceGlyphs[i].page], currentPage.BitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            else
                                QBitmap.BlitMask(sourceBitmaps[sourceGlyphs[i].page], currentPage.BitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);

                            destGlyphs[i] = new QFontGlyph(pages.Count - 1, new Rectangle(xPos + destMargin, yPos + destMargin, rect.Width, rect.Height), sourceGlyphs[i].yOffset, sourceGlyphs[i].character);
                        }
                        else
                        {
                            finalPageRequiredWidth = Math.Max(finalPageRequiredWidth, xPos + rect.Width + 2 * destMargin);
                            finalPageRequiredHeight = Math.Max(finalPageRequiredHeight, yPos + rect.Height + 2 * destMargin);
                        }

                        xPos += rect.Width + 2 * destMargin;
                        maxYInRow = Math.Max(maxYInRow, rect.Height);

                        continue;
                    }

                    if (xPos + rect.Width + 2 * destMargin > destSheetWidth)
                    {
                        i--;

                        yPos += maxYInRow + 2 * destMargin;
                        xPos = 0;

                        if (yPos + maxY + 2 * destMargin > destSheetHeight)
                        {
                            yPos = 0;

                            if (!pre)
                            {
                                currentPage = null;
                            }
                            else
                            {
                                finalPageRequiredWidth = 0;
                                finalPageRequiredHeight = 0;
                                finalPageIndex++;
                            }
                        }
                        continue;
                    }

                }

            }

            return pages;
        }
Пример #24
0
        private Dictionary<char, QFontGlyph> CreateCharGlyphMapping(QFontGlyph[] glyphs)
        {
            var dict = new Dictionary<char, QFontGlyph>();
            for (int i = 0; i < charSet.Length; i++)
                dict.Add(charSet[i], glyphs[i]);

            return dict;
        }
Пример #25
0
        private SizeF PrintOrMeasure(string text, QFontAlignment alignment, bool measureOnly, Rectangle clippingRectangle = default(Rectangle))
        {
            float maxWidth = 0f;
            float xOffset  = 0f;
            float yOffset  = 0f;

            float maxXpos = float.MinValue;
            float minXPos = float.MaxValue;

            text = text.Replace("\r\n", "\r");
#if DEBUG
            _DisplayText_dbg = text;
#endif
            if (alignment == QFontAlignment.Right)
            {
                xOffset -= MeasureNextlineLength(text);
            }
            else if (alignment == QFontAlignment.Centre)
            {
                xOffset -= (int)(0.5f * MeasureNextlineLength(text));
            }

            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];

                //newline
                if (c == '\r' || c == '\n')
                {
                    yOffset += LineSpacing;
                    xOffset  = 0f;

                    if (alignment == QFontAlignment.Right)
                    {
                        xOffset -= MeasureNextlineLength(text.Substring(i + 1));
                    }
                    else if (alignment == QFontAlignment.Centre)
                    {
                        xOffset -= (int)(0.5f * MeasureNextlineLength(text.Substring(i + 1)));
                    }
                }
                else
                {
                    minXPos = Math.Min(xOffset, minXPos);

                    //normal character
                    if (c != ' ' && _font.FontData.CharSetMapping.ContainsKey(c))
                    {
                        if (!measureOnly)
                        {
                            RenderGlyph(xOffset, yOffset, c, _font, CurrentVertexRepr, clippingRectangle);
                        }
                    }

                    if (IsMonospacingActive)
                    {
                        xOffset += MonoSpaceWidth;
                    }
                    else
                    {
                        if (c == ' ')
                        {
                            xOffset += (float)Math.Ceiling(_font.FontData.meanGlyphWidth * this.Options.WordSpacing);
                        }
                        //normal character
                        else if (_font.FontData.CharSetMapping.ContainsKey(c))
                        {
                            QFontGlyph glyph = _font.FontData.CharSetMapping[c];
                            xOffset +=
                                (float)
                                Math.Ceiling(glyph.rect.Width + _font.FontData.meanGlyphWidth * this.Options.CharacterSpacing + _font.FontData.GetKerningPairCorrection(i, text, null));
                        }
                    }

                    maxXpos = Math.Max(xOffset, maxXpos);
                }
            }

            if (minXPos != float.MaxValue)
            {
                maxWidth = maxXpos - minXPos;
            }

            LastSize = new SizeF(maxWidth, yOffset + LineSpacing);
            return(LastSize);
        }
Пример #26
0
 private void RenderDropShadow(float x, float y, char c, QFontGlyph nonShadowGlyph, QFont shadowFont, ref Rectangle clippingRectangle)
 {
     //note can cast drop shadow offset to int, but then you can't move the shadow smoothly...
     if (shadowFont != null && this.Options.DropShadowActive)
     {
         float xOffset = (_font.FontData.meanGlyphWidth*this.Options.DropShadowOffset.X + nonShadowGlyph.rect.Width*0.5f);
         float yOffset = (_font.FontData.meanGlyphWidth*this.Options.DropShadowOffset.Y + nonShadowGlyph.rect.Height*0.5f + nonShadowGlyph.yOffset);
         this.RenderGlyph(x + xOffset, y + yOffset, c, shadowFont, this.ShadowVertexRepr, clippingRectangle);
     }
 }
Пример #27
0
        public static Dictionary<String, int> CalculateKerning(char[] charSet, QFontGlyph[] glyphs, List<QBitmap> bitmapPages, QFontKerningConfiguration config)
        {
            var kerningPairs = new Dictionary<String, int>();



            //we start by computing the index of the first and last non-empty pixel in each row of each glyph
            XLimits[][] limits = new XLimits[charSet.Length][];
            int maxHeight = 0;
            for (int n = 0; n < charSet.Length; n++)
            {
                var rect = glyphs[n].rect;
                var page = bitmapPages[glyphs[n].page];

                limits[n] = new XLimits[rect.Height];

                maxHeight = Math.Max(rect.Height, maxHeight);

                int yStart = rect.Y;
                int yEnd = rect.Y + rect.Height;
                int xStart = rect.X;
                int xEnd = rect.X + rect.Width;

                for (int j = yStart; j < yEnd; j++)
                {
                    int last = xStart;

                    bool yetToFindFirst = true;
                    for (int i = xStart; i < xEnd; i++)
                    {
                        if (!QBitmap.EmptyAlphaPixel(page.bitmapData, i, j,config.alphaEmptyPixelTolerance))
                        {

                            if (yetToFindFirst)
                            {
                                limits[n][j - yStart].Min = i - xStart;
                                yetToFindFirst = false;
                            }
                            last = i;
                        }
                    }

                    limits[n][j - yStart].Max = last - xStart;

                    if (yetToFindFirst)
                        limits[n][j - yStart].Min = xEnd - 1;
                }
            }


            //we now bring up each row to the max (or min) of it's two adjacent rows, this is to stop glyphs sliding together too closely
            var tmp = new XLimits[maxHeight];

            for (int n = 0; n < charSet.Length; n++)
            {
                //clear tmp 
                for (int j = 0; j < limits[n].Length; j++)
                    tmp[j] = limits[n][j];

                for (int j = 0; j < limits[n].Length; j++)
                {
                    if(j != 0){
                        tmp[j].Min = Math.Min(limits[n][j - 1].Min, tmp[j].Min);
                        tmp[j].Max = Math.Max(limits[n][j - 1].Max, tmp[j].Max);
                    }

                    if (j != limits[n].Length - 1)
                    {
                        tmp[j].Min = Math.Min(limits[n][j + 1].Min, tmp[j].Min);
                        tmp[j].Max = Math.Max(limits[n][j + 1].Max, tmp[j].Max);
                    }
                    
                }

                for (int j = 0; j < limits[n].Length; j++)
                    limits[n][j] = tmp[j];

            }

            for (int i = 0; i < charSet.Length; i++)
                for (int j = 0; j < charSet.Length; j++)
                    kerningPairs.Add("" + charSet[i] + charSet[j], 1-Kerning(glyphs[i], glyphs[j], limits[i], limits[j],config));

            return kerningPairs;
        }
Пример #28
0
        /*
        private SizeF GetMaxGlyphSize(Font font)
        {
            Bitmap bmp = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
            Graphics graph = Graphics.FromImage(bmp);

            SizeF maxSize = new SizeF(0f, 0f);
            for (int i = 0; i < charSet.Length; i++)
            {
                var charSize = graph.MeasureString("" + charSet[i], font);

                if (charSize.Width > maxSize.Width)
                    maxSize.Width = charSize.Width;

                if (charSize.Height > maxSize.Height)
                    maxSize.Height = charSize.Height;
            }

            graph.Dispose();
            bmp.Dispose();

            return maxSize;
        }*/
        //The initial bitmap is simply a long thin strip of all glyphs in a row
        private Bitmap CreateInitialBitmap(Font font, SizeF maxSize, int initialMargin, out QFontGlyph[] glyphs, TextGenerationRenderHint renderHint)
        {
            glyphs = new QFontGlyph[charSet.Length];

            int spacing = (int)Math.Ceiling(maxSize.Width) + 2 * initialMargin;
            Bitmap bmp = new Bitmap(spacing * charSet.Length, (int)Math.Ceiling(maxSize.Height) + 2 * initialMargin, PixelFormat.Format24bppRgb);
            Graphics graph = Graphics.FromImage(bmp);

            switch(renderHint){
                case TextGenerationRenderHint.SizeDependent:
                    graph.TextRenderingHint = font.Size <= 12.0f  ? TextRenderingHint.ClearTypeGridFit : TextRenderingHint.AntiAlias;
                    break;
                case TextGenerationRenderHint.AntiAlias:
                    graph.TextRenderingHint = TextRenderingHint.AntiAlias;
                    break;
                case TextGenerationRenderHint.AntiAliasGridFit:
                    graph.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                    break;
                case TextGenerationRenderHint.ClearTypeGridFit:
                    graph.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                    break;
                case TextGenerationRenderHint.SystemDefault:
                    graph.TextRenderingHint = TextRenderingHint.SystemDefault;
                    break;
            }

            int xOffset = initialMargin;
            for (int i = 0; i < charSet.Length; i++)
            {
                graph.DrawString("" + charSet[i], font, Brushes.White, xOffset, initialMargin);
                var charSize = graph.MeasureString("" + charSet[i], font);
                glyphs[i] = new QFontGlyph(0, new Rectangle(xOffset - initialMargin, 0, (int)charSize.Width + initialMargin * 2, (int)charSize.Height + initialMargin * 2), 0, charSet[i]);
                xOffset += (int)charSize.Width + initialMargin * 2;
            }

            graph.Flush();
            graph.Dispose();

            return bmp;
        }
        private static int Kerning(QFontGlyph g1, QFontGlyph g2, XLimits[] lim1, XLimits[] lim2)
        {
            int yOffset1 = g1.yOffset;
            int yOffset2 = g2.yOffset;

            int startY = Math.Max(yOffset1, yOffset2);
            int endY = Math.Min(g1.rect.Height + yOffset1, g2.rect.Height + yOffset2);

            int w1 = g1.rect.Width;

            int worstCase = w1;

            //TODO - offset startY, endY by yOffset1 so that lim1[j-yOffset1] can be written as lim1[j], will need another var for yOffset2

            for (int j = startY; j < endY; j++)
                worstCase = Math.Min(worstCase, w1 - lim1[j-yOffset1].Max + lim2[j-yOffset2].Min);

            worstCase = Math.Min(worstCase, g1.rect.Width);
            worstCase = Math.Min(worstCase, g2.rect.Width);

            return worstCase;
        }
Пример #30
0
        /// <summary>
        /// Generates the final bitmap sheet for the font
        /// </summary>
        /// <param name="sourceGlyphs">A collection of <see cref="QFontGlyph"/>s. These are written to the final bitmap</param>
        /// <param name="sourceBitmaps"> The source bitmaps for the font (initial bitmap)</param>
        /// <param name="destSheetWidth">The destination bitmap width</param>
        /// <param name="destSheetHeight">The destination bitmap height</param>
        /// <param name="destGlyphs">A collection of <see cref="QFontGlyph"/>s that are placed on the final bitmap sheet</param>
        /// <param name="destMargin">The margin for the final bitmap sheet</param>
        /// <returns>A collection of <see cref="QBitmap"/>s. These are the final bitmap sheets</returns>
        private static List <QBitmap> GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin)
        {
            var pages = new List <QBitmap>();

            destGlyphs = new QFontGlyph[sourceGlyphs.Length];

            QBitmap currentPage = null;

            int maxY = 0;

            foreach (var glph in sourceGlyphs)
            {
                maxY = Math.Max(glph.Rect.Height, maxY);
            }

            int finalPageIndex          = 0;
            int finalPageRequiredWidth  = 0;
            int finalPageRequiredHeight = 0;

            // We loop through the whole process twice. The first time is to determine
            // the size of the final page, so that we can crop it in advance
            for (int k = 0; k < 2; k++)
            {
                // Whether this is the pre-processing step
                bool pre = k == 0;

                int xPos       = 0;
                int yPos       = 0;
                int maxYInRow  = 0;
                int totalTries = 0;

                // Loop through all the glyphs
                for (int i = 0; i < sourceGlyphs.Length; i++)
                {
                    // If this is the second stage and we don't already have a bitmap page, create one
                    if (!pre && currentPage == null)
                    {
                        if (finalPageIndex == pages.Count)
                        {
                            int width  = Math.Min(destSheetWidth, finalPageRequiredWidth);
                            int height = Math.Min(destSheetHeight, finalPageRequiredHeight);

                            currentPage = new QBitmap(new Bitmap(width, height, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        else
                        {
                            currentPage = new QBitmap(new Bitmap(destSheetWidth, destSheetHeight, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        pages.Add(currentPage);
                    }

                    // Keep track of the number of times we've tried to fit the font onto the texture page
                    totalTries++;

                    if (totalTries > 10 * sourceGlyphs.Length)
                    {
                        throw new Exception("Failed to fit font into texture pages");
                    }

                    var rect = sourceGlyphs[i].Rect;

                    // If we can fit the glyph onto the page, place it
                    if (xPos + rect.Width + 2 * destMargin <= destSheetWidth && yPos + rect.Height + 2 * destMargin <= destSheetHeight)
                    {
                        if (!pre)
                        {
                            // Add to page
                            if (sourceBitmaps[sourceGlyphs[i].Page].PixelFormat == PixelFormat.Format32bppArgb)
                            {
                                QBitmap.Blit(sourceBitmaps[sourceGlyphs[i].Page], currentPage.BitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }
                            else
                            {
                                QBitmap.BlitMask(sourceBitmaps[sourceGlyphs[i].Page], currentPage.BitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }

                            // Add to destination glyph collection
                            destGlyphs[i] = new QFontGlyph(pages.Count - 1, new Rectangle(xPos + destMargin, yPos + destMargin, rect.Width, rect.Height), sourceGlyphs[i].YOffset, sourceGlyphs[i].Character);
                        }
                        else
                        {
                            // Update the final dimensions
                            finalPageRequiredWidth  = Math.Max(finalPageRequiredWidth, xPos + rect.Width + 2 * destMargin);
                            finalPageRequiredHeight = Math.Max(finalPageRequiredHeight, yPos + rect.Height + 2 * destMargin);
                        }

                        // Update the current x position
                        xPos += rect.Width + 2 * destMargin;

                        // Update the maximum row height so far
                        maxYInRow = Math.Max(maxYInRow, rect.Height);

                        continue;
                    }

                    // If we reach this, haven't been able to fit glyph onto row
                    // Move down one row and try again
                    if (xPos + rect.Width + 2 * destMargin > destSheetWidth)
                    {
                        // Retry the current glyph on the next row
                        i--;

                        // Change coordinates to next row
                        yPos += maxYInRow + 2 * destMargin;
                        xPos  = 0;

                        // Is the next row off the bitmap sheet?
                        if (yPos + maxY + 2 * destMargin > destSheetHeight)
                        {
                            // Reset y position
                            yPos = 0;

                            if (!pre)
                            {
                                // If this is not the second stage, reset the currentPage
                                // This will create a new one on next loop
                                currentPage = null;
                            }
                            else
                            {
                                // If this is the pre-processing stage, update
                                // the finalPageIndex. Reset width and height
                                // since we clearly need one full page and extra
                                finalPageRequiredWidth  = 0;
                                finalPageRequiredHeight = 0;
                                finalPageIndex++;
                            }
                        }
                    }
                }
            }

            return(pages);
        }
Пример #31
0
        private static void RetargetGlyphRectangleInwards(BitmapData bitmapData, QFontGlyph glyph, bool setYOffset)
        {
            int startX, endX;
            int startY, endY;

            var rect = glyph.rect;

            EmptyDel emptyPix;

            if (bitmapData.PixelFormat == PixelFormat.Format32bppArgb)
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(QBitmap.EmptyAlphaPixel(data, x, y)); }
            }
            ;
            else
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(QBitmap.EmptyPixel(data, x, y)); }
            };


            unsafe
            {
                for (startX = rect.X; startX < bitmapData.Width; startX++)
                {
                    for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
                    {
                        if (!emptyPix(bitmapData, startX, j))
                        {
                            goto Done1;
                        }
                    }
                }
Done1:

                for (endX = rect.X + rect.Width; endX >= 0; endX--)
                {
                    for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
                    {
                        if (!emptyPix(bitmapData, endX, j))
                        {
                            goto Done2;
                        }
                    }
                }
Done2:

                for (startY = rect.Y; startY < bitmapData.Height; startY++)
                {
                    for (int i = startX; i <= endX; i++)
                    {
                        if (!emptyPix(bitmapData, i, startY))
                        {
                            goto Done3;
                        }
                    }
                }

Done3:

                for (endY = rect.Y + rect.Height; endY >= 0; endY--)
                {
                    for (int i = startX; i <= endX; i++)
                    {
                        if (!emptyPix(bitmapData, i, endY))
                        {
                            goto Done4;
                        }
                    }
                }
                Done4 :;
            }



            glyph.rect = new Rectangle(startX, startY, endX - startX + 1, endY - startY + 1);

            if (setYOffset)
            {
                glyph.yOffset = glyph.rect.Y;
            }
        }
Пример #32
0
 private void RenderDropShadow(float x, float y, char c, QFontGlyph nonShadowGlyph)
 {
     //note can cast drop shadow offset to int, but then you can't move the shadow smoothly...
     if (fontData.dropShadow != null && Options.DropShadowActive)
     {
         fontData.dropShadow.RenderGlyph(
             x + (fontData.meanGlyphWidth * Options.DropShadowOffset.X + nonShadowGlyph.rect.Width * 0.5f),
             y + (fontData.meanGlyphWidth * Options.DropShadowOffset.Y + nonShadowGlyph.rect.Height * 0.5f + nonShadowGlyph.yOffset), c);
     }
 }
Пример #33
0
        /// <summary>
        /// Renders the glyph at the position given.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <param name="c">The character to print.</param>
        internal void RenderGlyph(float x, float y, char c, QFont font, IList <QVertex> store, Rectangle clippingRectangle)
        {
            QFontGlyph glyph = font.FontData.CharSetMapping[c];

            //note: it's not immediately obvious, but this combined with the paramteters to
            //RenderGlyph for the shadow mean that we render the shadow centrally (despite it being a different size)
            //under the glyph
            if (font.FontData.isDropShadow)
            {
                x -= (int)(glyph.rect.Width * 0.5f);
                y -= (int)(glyph.rect.Height * 0.5f + glyph.yOffset);
            }
            else
            {
                RenderDropShadow(x, y, c, glyph, font.FontData.dropShadowFont, ref clippingRectangle);
            }

            y = -y;

            TexturePage sheet = font.FontData.Pages[glyph.page];

            float tx1 = (float)(glyph.rect.X) / sheet.Width;
            float ty1 = (float)(glyph.rect.Y) / sheet.Height;
            float tx2 = (float)(glyph.rect.X + glyph.rect.Width) / sheet.Width;
            float ty2 = (float)(glyph.rect.Y + glyph.rect.Height) / sheet.Height;

            float vx      = x + PrintOffset.X;
            float vy      = y - glyph.yOffset + PrintOffset.Y;
            float vwidth  = glyph.rect.Width;
            float vheight = glyph.rect.Height;

            if (clippingRectangle != default(Rectangle) && ScissorsTest(ref vx, ref vy, ref vwidth, ref vheight, ref tx1, ref ty1, ref tx2, ref ty2, clippingRectangle))
            {
                return;
            }

            var tv1 = new Vector2(tx1, ty1);
            var tv2 = new Vector2(tx1, ty2);
            var tv3 = new Vector2(tx2, ty2);
            var tv4 = new Vector2(tx2, ty1);

            Vector3 v1 = new Vector3(vx, vy, PrintOffset.Z);
            Vector3 v2 = new Vector3(vx, vy - vheight, PrintOffset.Z);
            Vector3 v3 = new Vector3(vx + vwidth, vy - vheight, PrintOffset.Z);
            Vector3 v4 = new Vector3(vx + vwidth, vy, PrintOffset.Z);

            Color color;

            if (font.FontData.isDropShadow)
            {
                color = this.Options.DropShadowColour;
            }
            else
            {
                color = this.Options.Colour;
            }

            Vector4 colour = Helper.ToVector4(color);

            store.Add(new QVertex()
            {
                Position = v1, TextureCoord = tv1, VertexColor = colour
            });
            store.Add(new QVertex()
            {
                Position = v2, TextureCoord = tv2, VertexColor = colour
            });
            store.Add(new QVertex()
            {
                Position = v3, TextureCoord = tv3, VertexColor = colour
            });

            store.Add(new QVertex()
            {
                Position = v1, TextureCoord = tv1, VertexColor = colour
            });
            store.Add(new QVertex()
            {
                Position = v3, TextureCoord = tv3, VertexColor = colour
            });
            store.Add(new QVertex()
            {
                Position = v4, TextureCoord = tv4, VertexColor = colour
            });
        }
Пример #34
0
        private SizeF PrintOrMeasure(string text, QFontAlignment alignment, bool measureOnly)
        {
            float maxWidth = 0f;
            float xOffset  = 0f;
            float yOffset  = 0f;

            var caps = new EnableCap[] { };

            if (!UsingVertexBuffers)
            {
                caps = new EnableCap[] { EnableCap.Texture2D, EnableCap.Blend }
            }
            ;

            Helper.SafeGLEnable(caps, () =>
            {
                float maxXpos = float.MinValue;
                float minXPos = float.MaxValue;

                if (!UsingVertexBuffers)
                {
                    GL.Color4(1.0f, 1.0f, 1.0f, 1.0f);

                    if (Options.UseDefaultBlendFunction)
                    {
                        GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                    }
                }

                text = text.Replace("\r\n", "\r");

                if (alignment == QFontAlignment.Right)
                {
                    xOffset -= MeasureNextlineLength(text);
                }
                else if (alignment == QFontAlignment.Centre)
                {
                    xOffset -= (int)(0.5f * MeasureNextlineLength(text));
                }

                for (int i = 0; i < text.Length; i++)
                {
                    char c = text[i];


                    //newline
                    if (c == '\r' || c == '\n')
                    {
                        yOffset += LineSpacing;
                        xOffset  = 0f;

                        if (alignment == QFontAlignment.Right)
                        {
                            xOffset -= MeasureNextlineLength(text.Substring(i + 1));
                        }
                        else if (alignment == QFontAlignment.Centre)
                        {
                            xOffset -= (int)(0.5f * MeasureNextlineLength(text.Substring(i + 1)));
                        }
                    }
                    else
                    {
                        minXPos = Math.Min(xOffset, minXPos);

                        //normal character
                        if (c != ' ' && fontData.CharSetMapping.ContainsKey(c))
                        {
                            QFontGlyph glyph = fontData.CharSetMapping[c];
                            if (!measureOnly)
                            {
                                RenderGlyph(xOffset, yOffset, c, false);
                            }
                        }


                        if (IsMonospacingActive)
                        {
                            xOffset += MonoSpaceWidth;
                        }
                        else
                        {
                            if (c == ' ')
                            {
                                xOffset += (float)Math.Ceiling(fontData.meanGlyphWidth * Options.WordSpacing);
                            }
                            //normal character
                            else if (fontData.CharSetMapping.ContainsKey(c))
                            {
                                QFontGlyph glyph = fontData.CharSetMapping[c];
                                xOffset         += (float)Math.Ceiling(glyph.rect.Width + fontData.meanGlyphWidth * Options.CharacterSpacing + fontData.GetKerningPairCorrection(i, text, null));
                            }
                        }

                        maxXpos = Math.Max(xOffset, maxXpos);
                    }
                }

                if (minXPos != float.MaxValue)
                {
                    maxWidth = maxXpos - minXPos;
                }
            });

            return(new SizeF(maxWidth, yOffset + LineSpacing));
        }
Пример #35
0
        /*
        private SizeF GetMaxGlyphSize(Font font)
        {
            Bitmap bmp = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
            Graphics graph = Graphics.FromImage(bmp);

            SizeF maxSize = new SizeF(0f, 0f);
            for (int i = 0; i < charSet.Length; i++)
            {
                var charSize = graph.MeasureString("" + charSet[i], font);

                if (charSize.Width > maxSize.Width)
                    maxSize.Width = charSize.Width;

                if (charSize.Height > maxSize.Height)
                    maxSize.Height = charSize.Height;
            }

            graph.Dispose();
            bmp.Dispose();

            return maxSize;
        }*/
        private Bitmap CreateInitialBitmap(Font font, SizeF maxSize, int initialMargin, out QFontGlyph[] glyphs)
        {
            glyphs = new QFontGlyph[charSet.Length];

            int spacing = (int)Math.Ceiling(maxSize.Width) + 2 * initialMargin;
            Bitmap bmp = new Bitmap(spacing * charSet.Length, (int)Math.Ceiling(maxSize.Height) + 2 * initialMargin, PixelFormat.Format24bppRgb);
            Graphics graph = Graphics.FromImage(bmp);

            graph.TextRenderingHint = TextRenderingHint.AntiAlias;

            int xOffset = initialMargin;
            for (int i = 0; i < charSet.Length; i++)
            {

                graph.DrawString("" + charSet[i], font, Brushes.White, xOffset, initialMargin);
                var charSize = graph.MeasureString("" + charSet[i], font);
                glyphs[i] = new QFontGlyph(0, new Rectangle(xOffset - initialMargin, 0, (int)charSize.Width + initialMargin*2, (int)charSize.Height + initialMargin*2), 0);
                xOffset += (int)charSize.Width + initialMargin * 2;
            }

            graph.Flush();
            graph.Dispose();

            return bmp;
        }
Пример #36
0
        private static QFont BuildDropShadow(List<QBitmap> sourceFontSheets, QFontGlyph[] sourceFontGlyphs, QFontShadowConfiguration shadowConfig, char[] charSet, byte alphaTolerance)
        {
            QFontGlyph[] newGlyphs;

            var sourceBitmapData = new List<BitmapData>();
            foreach(var sourceSheet in sourceFontSheets)
                sourceBitmapData.Add(sourceSheet.bitmapData);

            var bitmapSheets = GenerateBitmapSheetsAndRepack(sourceFontGlyphs, sourceBitmapData.ToArray(), shadowConfig.PageMaxTextureSize, shadowConfig.PageMaxTextureSize, out newGlyphs, shadowConfig.GlyphMargin + shadowConfig.blurRadius*3);

            //scale up in case we wanted bigger/smaller shadows
            if (shadowConfig.Scale != 1.0f)
                ScaleSheetsAndGlyphs(bitmapSheets, newGlyphs, shadowConfig.Scale); //no point in retargeting yet, since we will do it after blur

            //whiten and blur
            foreach (var bitmapSheet in bitmapSheets)
            {
                bitmapSheet.Colour32(255, 255, 255);
                if (shadowConfig.Type == ShadowType.Blurred)
                    bitmapSheet.BlurAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);
                else
                    bitmapSheet.ExpandAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);
            }

            //retarget after blur and scale
            RetargetAllGlyphs(bitmapSheets, newGlyphs, alphaTolerance);

            //create list of texture pages
            var newTextureSheets = new List<TexturePage>();
            foreach (var page in bitmapSheets)
                newTextureSheets.Add(new TexturePage(page.bitmapData));

            var fontData = new QFontData();
            fontData.CharSetMapping = new Dictionary<char, QFontGlyph>();
            for(int i = 0; i < charSet.Length; i++)
                fontData.CharSetMapping.Add(charSet[i],newGlyphs[i]);

            fontData.Pages = newTextureSheets.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();

            foreach (var sheet in bitmapSheets)
                sheet.Free();

            fontData.isDropShadow = true;
            return new QFont(fontData);
        }
Пример #37
0
 private static void RetargetAllGlyphs(List<QBitmap> pages, QFontGlyph[] glyphs, byte alphaTolerance)
 {
     foreach (var glyph in glyphs)
         RetargetGlyphRectangleOutwards(pages[glyph.page].BitmapData, glyph, false, alphaTolerance);
 }
Пример #38
0
        private static QFontData BuildDropShadow(List<QBitmap> sourceFontSheets, QFontGlyph[] sourceFontGlyphs, QFontShadowConfiguration shadowConfig, char[] charSet, byte alphaTolerance)
        {
            QFontGlyph[] newGlyphs;

            var sourceBitmapData = new List<BitmapData>();
            foreach(var sourceSheet in sourceFontSheets)
                sourceBitmapData.Add(sourceSheet.BitmapData);

            //GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin, bool usePowerOfTwo)

            var bitmapSheets = GenerateBitmapSheetsAndRepack(sourceFontGlyphs, sourceBitmapData.ToArray(), shadowConfig.PageWidth, shadowConfig.PageHeight, out newGlyphs, shadowConfig.GlyphMargin + shadowConfig.blurRadius*3, shadowConfig.ForcePowerOfTwo);

            //scale up in case we wanted bigger/smaller shadows
            if (shadowConfig.Scale != 1.0f)
                ScaleSheetsAndGlyphs(bitmapSheets, newGlyphs, shadowConfig.Scale); //no point in retargeting yet, since we will do it after blur

            //blacken and blur
            foreach (var bitmapSheet in bitmapSheets)
            {
                bitmapSheet.Colour32(0, 0, 0);
                bitmapSheet.BlurAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);

            }

            //retarget after blur and scale
            RetargetAllGlyphs(bitmapSheets, newGlyphs, alphaTolerance);

            var fontData = new QFontData();
            fontData.CharSetMapping = new Dictionary<char, QFontGlyph>();
            for(int i = 0; i < charSet.Length; i++)
                fontData.CharSetMapping.Add(charSet[i],newGlyphs[i]);

            fontData.Pages = bitmapSheets.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();

            return fontData;
        }
Пример #39
0
        private void RenderDropShadow(float x, float y, char c, QFontGlyph nonShadowGlyph)
        {
            //note can cast drop shadow offset to int, but then you can't move the shadow smoothly...
            if (fontData.dropShadow != null && Options.DropShadowActive)
            {
                //make sure fontdata font's options are synced with the actual options
                if (fontData.dropShadow.Options != Options)
                    fontData.dropShadow.Options = Options;

                fontData.dropShadow.RenderGlyph(
                    x + (fontData.meanGlyphWidth * Options.DropShadowOffset.X + nonShadowGlyph.rect.Width * 0.5f),
                    y + (fontData.meanGlyphWidth * Options.DropShadowOffset.Y + nonShadowGlyph.rect.Height * 0.5f + nonShadowGlyph.yOffset), c, true);
            }
        }
Пример #40
0
        private static void RetargetGlyphRectangleInwards(BitmapData bitmapData, QFontGlyph glyph, bool setYOffset, byte alphaTolerance)
        {
            int startX, endX;
            int startY, endY;

            var rect = glyph.rect;

            EmptyDel emptyPix;

            if (bitmapData.PixelFormat == PixelFormat.Format32bppArgb)
                emptyPix = delegate(BitmapData data, int x, int y) { return QBitmap.EmptyAlphaPixel(data, x, y, alphaTolerance); };
            else
                emptyPix = delegate(BitmapData data, int x, int y) { return QBitmap.EmptyPixel(data, x, y); };

            unsafe
            {

                for (startX = rect.X; startX < bitmapData.Width; startX++)
                    for (int j = rect.Y; j < rect.Y + rect.Height; j++)
                        if (!emptyPix(bitmapData, startX, j))
                            goto Done1;
                Done1:

                for (endX = rect.X + rect.Width; endX >= 0; endX--)
                    for (int j = rect.Y; j < rect.Y + rect.Height; j++)
                        if (!emptyPix(bitmapData, endX, j))
                            goto Done2;
                Done2:

                for (startY = rect.Y; startY < bitmapData.Height; startY++)
                    for (int i = startX; i < endX; i++)
                        if (!emptyPix(bitmapData, i, startY))
                            goto Done3;

                Done3:

                for (endY = rect.Y + rect.Height; endY >= 0; endY--)
                    for (int i = startX; i < endX; i++)
                        if (!emptyPix(bitmapData, i, endY))
                            goto Done4;
                Done4:;

            }

            if (endY < startY)
                startY = endY = rect.Y;

            if (endX < startX)
                startX = endX = rect.X;

            glyph.rect = new Rectangle(startX, startY, endX - startX + 1, endY - startY + 1);

            if (setYOffset)
                glyph.yOffset = glyph.rect.Y;
        }
Пример #41
0
        private static void ScaleSheetsAndGlyphs(List<QBitmap> pages, QFontGlyph[] glyphs, float scale)
        {
            foreach (var page in pages)
                page.DownScale32((int)(page.Bitmap.Width * scale), (int)(page.Bitmap.Height * scale));

            foreach (var glyph in glyphs)
            {
                glyph.rect = new Rectangle((int)(glyph.rect.X * scale), (int)(glyph.rect.Y * scale), (int)(glyph.rect.Width * scale), (int)(glyph.rect.Height * scale));
                glyph.yOffset = (int)(glyph.yOffset * scale);

            }
        }
Пример #42
0
        private SizeF PrintOrMeasure(string text, QFontAlignment alignment, bool measureOnly)
        {
            float maxWidth = 0f;

            GL.Color4(1.0f, 1.0f, 1.0f, 1.0f);
            GL.Enable(EnableCap.Texture2D);
            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

            float xOffset = 0f;
            float yOffset = 0f;

            text = text.Replace("\r\n", "\r");

            if (alignment == QFontAlignment.Right)
            {
                xOffset -= MeasureNextlineLength(text);
            }
            else if (alignment == QFontAlignment.Centre)
            {
                xOffset -= (int)(0.5f * MeasureNextlineLength(text));
            }

            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];


                //newline
                if (c == '\r' || c == '\n')
                {
                    yOffset += LineSpacing;
                    xOffset  = 0f;

                    if (alignment == QFontAlignment.Right)
                    {
                        xOffset -= MeasureNextlineLength(text.Substring(i + 1));
                    }
                    else if (alignment == QFontAlignment.Centre)
                    {
                        xOffset -= (int)(0.5f * MeasureNextlineLength(text.Substring(i + 1)));
                    }
                }
                else
                {
                    //normal character
                    if (c != ' ' && fontData.CharSetMapping.ContainsKey(c))
                    {
                        QFontGlyph glyph = fontData.CharSetMapping[c];
                        if (!measureOnly)
                        {
                            RenderGlyph(xOffset, yOffset, c, false);
                        }
                    }


                    if (IsMonospacingActive)
                    {
                        xOffset += MonoSpaceWidth;
                    }
                    else
                    {
                        if (c == ' ')
                        {
                            xOffset += (float)Math.Ceiling(fontData.meanGlyphWidth * options.WordSpacing);
                        }
                        //normal character
                        else if (fontData.CharSetMapping.ContainsKey(c))
                        {
                            QFontGlyph glyph = fontData.CharSetMapping[c];
                            xOffset += (float)Math.Ceiling(glyph.rect.Width + fontData.meanGlyphWidth * options.CharacterSpacing + fontData.GetKerningPairCorrection(i, text, null));
                        }
                    }

                    maxWidth = Math.Max(xOffset, maxWidth);
                }
            }


            return(new SizeF(maxWidth, yOffset + LineSpacing));
        }