예제 #1
0
 public static void CreateBitmapPerGlyph(GLFontGlyph[] sourceGlyphs, GLFontBitmap[] sourceBitmaps, out GLFontGlyph[]  destGlyphs, out GLFontBitmap[] destBitmaps)
 {
     destBitmaps = new GLFontBitmap[sourceGlyphs.Length];
     destGlyphs  = new GLFontGlyph[sourceGlyphs.Length];
     for (int i = 0; i < sourceGlyphs.Length; i++)
     {
         var sg = sourceGlyphs[i];
         destGlyphs[i]  = new GLFontGlyph(i, new Rectangle(0, 0, sg.Rect.Width, sg.Rect.Height), sg.YOffset, sg.Character);
         destBitmaps[i] = new GLFontBitmap(new Bitmap(sg.Rect.Width, sg.Rect.Height, PixelFormat.Format32bppArgb));
         GLFontBitmap.Blit(sourceBitmaps[sg.Page].bitmapData, destBitmaps[i].bitmapData, sg.Rect, 0, 0);
     }
 }
예제 #2
0
        public static Dictionary <String, int> CalculateKerning(char[] charSet, GLFontGlyph[] glyphs, List <GLFontBitmap> bitmapPages, GLFontKerningConfiguration 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 (!GLFontBitmap.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);
        }
예제 #3
0
        private static List <GLFontBitmap> GenerateBitmapSheetsAndRepack(GLFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out GLFontGlyph[] destGlyphs, int destMargin, bool usePowerOfTwo)
        {
            var pages = new List <GLFontBitmap>();

            destGlyphs = new GLFontGlyph[sourceGlyphs.Length];
            GLFontBitmap currentPage             = null;
            int          maxY                    = sourceGlyphs.Max(g => g.Rect.Height);
            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 GLFontBitmap(new Bitmap(width, height, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); // clear to white, but totally transparent
                        }
                        else
                        {
                            currentPage = new GLFontBitmap(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)
                            {
                                GLFontBitmap.Blit(sourceBitmaps[sourceGlyphs[i].Page], currentPage.bitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }
                            else
                            {
                                GLFontBitmap.BlitMask(sourceBitmaps[sourceGlyphs[i].Page], currentPage.bitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }

                            destGlyphs[i] = new GLFontGlyph(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);
        }
예제 #4
0
        private static void RetargetGlyphRectangleOutwards(BitmapData bitmapData, GLFontGlyph 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(GLFontBitmap.EmptyAlphaPixel(data, x, y, alphaTolerance)); }
            }
            ;
            else
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(GLFontBitmap.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;
            }
        }
예제 #5
0
        private static void RetargetGlyphRectangleInwards(BitmapData bitmapData, GLFontGlyph 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(GLFontBitmap.EmptyAlphaPixel(data, x, y, alphaTolerance)); }
            }
            ;
            else
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(GLFontBitmap.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 - 1; 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 - 1; 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;
            }
        }
예제 #6
0
        public void DownScale32(int newWidth, int newHeight)
        {
            GLFontBitmap newBitmap = new GLFontBitmap(new Bitmap(newWidth, newHeight, bitmap.PixelFormat));

            if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
            {
                throw new Exception("DownsScale32 only works on 32 bit images");
            }

            float xscale = (float)bitmapData.Width / newWidth;
            float yscale = (float)bitmapData.Height / newHeight;

            byte  r = 0, g = 0, b = 0, a = 0;
            float summedR = 0f;
            float summedG = 0f;
            float summedB = 0f;
            float summedA = 0f;

            int left, right, top, bottom;  //the area of old pixels covered by the new bitmap


            float targetStartX, targetEndX;
            float targetStartY, targetEndY;

            float leftF, rightF, topF, bottomF; //edges of new pixel in old pixel coords
            float weight;
            float weightScale       = xscale * yscale;
            float totalColourWeight = 0f;

            for (int m = 0; m < newHeight; m++)
            {
                for (int n = 0; n < newWidth; n++)
                {
                    leftF  = n * xscale;
                    rightF = (n + 1) * xscale;

                    topF    = m * yscale;
                    bottomF = (m + 1) * yscale;

                    left  = (int)leftF;
                    right = (int)rightF;

                    top    = (int)topF;
                    bottom = (int)bottomF;

                    if (left < 0)
                    {
                        left = 0;
                    }
                    if (top < 0)
                    {
                        top = 0;
                    }
                    if (right >= bitmapData.Width)
                    {
                        right = bitmapData.Width - 1;
                    }
                    if (bottom >= bitmapData.Height)
                    {
                        bottom = bitmapData.Height - 1;
                    }

                    summedR           = 0f;
                    summedG           = 0f;
                    summedB           = 0f;
                    summedA           = 0f;
                    totalColourWeight = 0f;

                    for (int j = top; j <= bottom; j++)
                    {
                        for (int i = left; i <= right; i++)
                        {
                            targetStartX = Math.Max(leftF, i);
                            targetEndX   = Math.Min(rightF, i + 1);

                            targetStartY = Math.Max(topF, j);
                            targetEndY   = Math.Min(bottomF, j + 1);

                            weight = (targetEndX - targetStartX) * (targetEndY - targetStartY);

                            GetPixel32(i, j, ref r, ref g, ref b, ref a);

                            summedA += weight * a;

                            if (a != 0)
                            {
                                summedR           += weight * r;
                                summedG           += weight * g;
                                summedB           += weight * b;
                                totalColourWeight += weight;
                            }
                        }
                    }

                    summedR /= totalColourWeight;
                    summedG /= totalColourWeight;
                    summedB /= totalColourWeight;
                    summedA /= weightScale;

                    if (summedR < 0)
                    {
                        summedR = 0f;
                    }
                    if (summedG < 0)
                    {
                        summedG = 0f;
                    }
                    if (summedB < 0)
                    {
                        summedB = 0f;
                    }
                    if (summedA < 0)
                    {
                        summedA = 0f;
                    }

                    if (summedR >= 256)
                    {
                        summedR = 255;
                    }
                    if (summedG >= 256)
                    {
                        summedG = 255;
                    }
                    if (summedB >= 256)
                    {
                        summedB = 255;
                    }
                    if (summedA >= 256)
                    {
                        summedA = 255;
                    }

                    newBitmap.PutPixel32(n, m, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
                }
            }

            this.Free();
            this.bitmap     = newBitmap.bitmap;
            this.bitmapData = newBitmap.bitmapData;
        }