CalculateMaxHeight() публичный метод

public CalculateMaxHeight ( ) : void
Результат void
Пример #1
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);
            }

            //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);

            //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();
            }

            return(new QFont(fontData));
        }
Пример #2
0
        public static QFontData LoadQFontDataFromFile(string filePath, float downSampleFactor, QFontConfiguration loaderConfig)
        {
            var          lines  = new List <String>();
            StreamReader reader = new StreamReader(filePath);
            string       line;

            while ((line = reader.ReadLine()) != null)
            {
                lines.Add(line);
            }
            reader.Close();

            var data      = new QFontData();
            int pageCount = 0;

            char[] charSet;
            data.Deserialize(lines, out pageCount, out charSet);

            string namePrefix = filePath.Replace(".qfont", "").Replace(" ", "");

            var bitmapPages = new List <QBitmap>();

            if (pageCount == 1)
            {
                bitmapPages.Add(new QBitmap(namePrefix + ".png"));
            }
            else
            {
                for (int i = 0; i < pageCount; i++)
                {
                    bitmapPages.Add(new QBitmap(namePrefix + "_sheet_" + i));
                }
            }

            foreach (var glyph in data.CharSetMapping.Values)
            {
                RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].bitmapData, glyph, false, loaderConfig.KerningConfig.alphaEmptyPixelTolerance);
            }

            var intercept = FirstIntercept(data.CharSetMapping);

            if (intercept != null)
            {
                throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. If you are texturing your font without locking pixel opacity, then consider using a larger glyph margin. This can be done by setting QFontBuilderConfiguration myQfontBuilderConfig.GlyphMargin, and passing it into CreateTextureFontFiles.");
            }

            if (downSampleFactor > 1.0f)
            {
                foreach (var page in bitmapPages)
                {
                    page.DownScale32((int)(page.bitmap.Width * downSampleFactor), (int)(page.bitmap.Height * downSampleFactor));
                }

                foreach (var glyph in data.CharSetMapping.Values)
                {
                    glyph.rect = new Rectangle((int)(glyph.rect.X * downSampleFactor),
                                               (int)(glyph.rect.Y * downSampleFactor),
                                               (int)(glyph.rect.Width * downSampleFactor),
                                               (int)(glyph.rect.Height * downSampleFactor));
                    glyph.yOffset = (int)(glyph.yOffset * downSampleFactor);
                }
            }
            else if (downSampleFactor < 1.0f)
            {
                // If we were simply to shrink the entire texture, then at some point we will make glyphs overlap, breaking the font.
                // For this reason it is necessary to copy every glyph to a separate bitmap, and then shrink each bitmap individually.
                QFontGlyph[] shrunkGlyphs;
                QBitmap[]    shrunkBitmapsPerGlyph;
                CreateBitmapPerGlyph(Helper.ToArray(data.CharSetMapping.Values), bitmapPages.ToArray(), out shrunkGlyphs, out shrunkBitmapsPerGlyph);

                //shrink each bitmap
                for (int i = 0; i < shrunkGlyphs.Length; i++)
                {
                    var bmp = shrunkBitmapsPerGlyph[i];
                    bmp.DownScale32(Math.Max((int)(bmp.bitmap.Width * downSampleFactor), 1), Math.Max((int)(bmp.bitmap.Height * downSampleFactor), 1));
                    shrunkGlyphs[i].rect    = new Rectangle(0, 0, bmp.bitmap.Width, bmp.bitmap.Height);
                    shrunkGlyphs[i].yOffset = (int)(shrunkGlyphs[i].yOffset * downSampleFactor);
                }

                var shrunkBitmapData = new BitmapData[shrunkBitmapsPerGlyph.Length];
                for (int i = 0; i < shrunkBitmapsPerGlyph.Length; i++)
                {
                    shrunkBitmapData[i] = shrunkBitmapsPerGlyph[i].bitmapData;
                }

                //use roughly the same number of pages as before..
                int newWidth  = (int)(bitmapPages[0].bitmap.Width * (0.1f + downSampleFactor));
                int newHeight = (int)(bitmapPages[0].bitmap.Height * (0.1f + downSampleFactor));

                //free old bitmap pages since we are about to chuck them away
                for (int i = 0; i < pageCount; i++)
                {
                    bitmapPages[i].Free();
                }

                QFontGlyph[] shrunkRepackedGlyphs;
                bitmapPages         = GenerateBitmapSheetsAndRepack(shrunkGlyphs, shrunkBitmapData, newWidth, newHeight, out shrunkRepackedGlyphs, 4);
                data.CharSetMapping = CreateCharGlyphMapping(shrunkRepackedGlyphs);

                foreach (var bmp in shrunkBitmapsPerGlyph)
                {
                    bmp.Free();
                }

                pageCount = bitmapPages.Count;
            }

            data.Pages = new TexturePage[pageCount];
            for (int i = 0; i < pageCount; i++)
            {
                data.Pages[i] = new TexturePage(bitmapPages[i].bitmapData);
            }

            if (downSampleFactor != 1.0f)
            {
                foreach (var glyph in data.CharSetMapping.Values)
                {
                    RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].bitmapData, glyph, false, loaderConfig.KerningConfig.alphaEmptyPixelTolerance);
                }

                intercept = FirstIntercept(data.CharSetMapping);
                if (intercept != null)
                {
                    throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This occurred only after resizing your texture font, implying that there is a bug in QFont. ");
                }
            }

            var glyphList = new List <QFontGlyph>();

            foreach (var c in charSet)
            {
                glyphList.Add(data.CharSetMapping[c]);
            }

            if (loaderConfig.ShadowConfig != null)
            {
                data.dropShadowFont = BuildDropShadow(bitmapPages, glyphList.ToArray(), loaderConfig.ShadowConfig, Helper.ToArray(charSet), loaderConfig.KerningConfig.alphaEmptyPixelTolerance);
            }

            data.KerningPairs = KerningCalculator.CalculateKerning(Helper.ToArray(charSet), glyphList.ToArray(), bitmapPages, loaderConfig.KerningConfig);

            data.CalculateMeanWidth();
            data.CalculateMaxHeight();

            for (int i = 0; i < pageCount; i++)
            {
                bitmapPages[i].Free();
            }

            return(data);
        }
Пример #3
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));
        }
Пример #4
0
        public QFontData BuildFontData(string saveName)
        {
            if (config.SuperSampleLevels <= 0 || config.SuperSampleLevels > 8)
            {
                throw new ArgumentOutOfRangeException("SuperSampleLevels = [" + config.SuperSampleLevels + "] is an unsupported value. Please use values in the range [1,8]");
            }

            int margin      = 3; //margin in initial bitmap (don't bother to make configurable - likely to cause confusion
            int glyphMargin = config.GlyphMargin * config.SuperSampleLevels;

            QFontGlyph[] initialGlyphs;
            var          sizes             = GetGlyphSizes(font);
            var          maxSize           = GetMaxGlyphSize(sizes);
            var          initialBmp        = CreateInitialBitmap(font, maxSize, margin, out initialGlyphs, config.TextGenerationRenderHint);
            var          initialBitmapData = initialBmp.LockBits(new Rectangle(0, 0, initialBmp.Width, initialBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int minYOffset = int.MaxValue;

            foreach (var glyph in initialGlyphs)
            {
                RetargetGlyphRectangleInwards(initialBitmapData, glyph, true, config.KerningConfig.alphaEmptyPixelTolerance);
                minYOffset = Math.Min(minYOffset, glyph.yOffset);
            }
            minYOffset--; //give one pixel of breathing room?

            foreach (var glyph in initialGlyphs)
            {
                glyph.yOffset -= minYOffset;
            }

            Size pagesize = GetOptimalPageSize(initialBmp.Width * config.SuperSampleLevels, initialBmp.Height * config.SuperSampleLevels, config.PageMaxTextureSize);

            QFontGlyph[]   glyphs;
            List <QBitmap> bitmapPages = GenerateBitmapSheetsAndRepack(initialGlyphs, new BitmapData[1] {
                initialBitmapData
            }, pagesize.Width, pagesize.Height, out glyphs, glyphMargin);

            initialBmp.UnlockBits(initialBitmapData);
            initialBmp.Dispose();

            if (config.SuperSampleLevels != 1)
            {
                ScaleSheetsAndGlyphs(bitmapPages, glyphs, 1.0f / config.SuperSampleLevels);
                RetargetAllGlyphs(bitmapPages, glyphs, config.KerningConfig.alphaEmptyPixelTolerance);
            }

            //create list of texture pages
            var pages = new List <TexturePage>();

            foreach (var page in bitmapPages)
            {
                pages.Add(new TexturePage(page.bitmapData));
            }

            var fontData = new QFontData();

            fontData.CharSetMapping = CreateCharGlyphMapping(glyphs);
            fontData.Pages          = pages.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();
            fontData.KerningPairs        = KerningCalculator.CalculateKerning(charSet.ToCharArray(), glyphs, bitmapPages, config.KerningConfig);
            fontData.naturallyMonospaced = IsMonospaced(sizes);

            if (saveName != null)
            {
                if (bitmapPages.Count == 1)
                {
                    bitmapPages[0].bitmap.UnlockBits(bitmapPages[0].bitmapData);
                    bitmapPages[0].bitmap.Save(saveName + ".png", ImageFormat.Png);
                    bitmapPages[0] = new QBitmap(bitmapPages[0].bitmap);
                }
                else
                {
                    for (int i = 0; i < bitmapPages.Count; i++)
                    {
                        bitmapPages[i].bitmap.UnlockBits(bitmapPages[i].bitmapData);
                        bitmapPages[i].bitmap.Save(saveName + "_sheet_" + i + ".png", ImageFormat.Png);
                        bitmapPages[i] = new QBitmap(bitmapPages[i].bitmap);
                    }
                }
            }

            if (config.ShadowConfig != null)
            {
                fontData.dropShadowFont = BuildDropShadow(bitmapPages, glyphs, config.ShadowConfig, charSet.ToCharArray(), config.KerningConfig.alphaEmptyPixelTolerance);
            }

            foreach (var page in bitmapPages)
            {
                page.Free();
            }

            //validate glyphs
            var intercept = FirstIntercept(fontData.CharSetMapping);

            if (intercept != null)
            {
                throw new Exception("Failed to create glyph set. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This is could be due to an error in the font, or a bug in Graphics.MeasureString().");
            }

            return(fontData);
        }
Пример #5
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;
        }
Пример #6
0
        public static QFontData LoadQFontDataFromFile(string filePath, float downSampleFactor, QFontLoaderConfiguration loaderConfig)
        {
            var lines = new List<String>();
            StreamReader reader = new StreamReader(filePath);
            string line;
            while((line = reader.ReadLine()) != null)
                lines.Add(line);
            reader.Close();

            var data = new QFontData();
            int pageCount = 0;
            char[] charSet;
            data.Deserialize(lines, out pageCount, out charSet);

            string namePrefix = filePath.Replace(".qfont","").Replace(" ", "");

            var bitmapPages = new List<QBitmap>();

            if (pageCount == 1)
            {
                bitmapPages.Add(new QBitmap(namePrefix + ".png"));
            }
            else
            {
                for (int i = 0; i < pageCount; i++)
                    bitmapPages.Add(new QBitmap(namePrefix + "_sheet_" + i));
            }

            foreach (var glyph in data.CharSetMapping.Values)
                RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].BitmapData, glyph, false, loaderConfig.KerningConfig.alphaEmptyPixelTolerance);

            var intercept = FirstIntercept(data.CharSetMapping);
            if (intercept != null)
            {
                throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. If you are texturing your font without locking pixel opacity, then consider using a larger glyph margin. This can be done by setting QFontBuilderConfiguration myQfontBuilderConfig.GlyphMargin, and passing it into CreateTextureFontFiles.");
            }

            if (downSampleFactor > 1.0f)
            {
                foreach (var page in bitmapPages)
                    page.DownScale32((int)(page.Bitmap.Width * downSampleFactor), (int)(page.Bitmap.Height * downSampleFactor));

                foreach (var glyph in data.CharSetMapping.Values)
                {

                    glyph.rect = new Rectangle((int)(glyph.rect.X * downSampleFactor),
                                                (int)(glyph.rect.Y * downSampleFactor),
                                                (int)(glyph.rect.Width * downSampleFactor),
                                                (int)(glyph.rect.Height * downSampleFactor));
                    glyph.yOffset = (int)(glyph.yOffset * downSampleFactor);
                }
            }
            else if (downSampleFactor < 1.0f )
            {
                // If we were simply to shrink the entire texture, then at some point we will make glyphs overlap, breaking the font.
                // For this reason it is necessary to copy every glyph to a separate bitmap, and then shrink each bitmap individually.
                QFontGlyph[] shrunkGlyphs;
                QBitmap[] shrunkBitmapsPerGlyph;
                CreateBitmapPerGlyph(Helper.ToArray(data.CharSetMapping.Values), bitmapPages.ToArray(), out shrunkGlyphs, out shrunkBitmapsPerGlyph);

                //shrink each bitmap
                for (int i = 0; i < shrunkGlyphs.Length; i++)
                {
                    var bmp = shrunkBitmapsPerGlyph[i];
                    bmp.DownScale32(Math.Max((int)(bmp.Bitmap.Width * downSampleFactor),1), Math.Max((int)(bmp.Bitmap.Height * downSampleFactor),1));
                    shrunkGlyphs[i].rect = new Rectangle(0, 0, bmp.Bitmap.Width, bmp.Bitmap.Height);
                    shrunkGlyphs[i].yOffset = (int)(shrunkGlyphs[i].yOffset * downSampleFactor);
                }

                var shrunkBitmapData = new BitmapData[shrunkBitmapsPerGlyph.Length];
                for(int i = 0; i < shrunkBitmapsPerGlyph.Length; i ++ ){
                    shrunkBitmapData[i] = shrunkBitmapsPerGlyph[i].BitmapData;
                }

                //use roughly the same number of pages as before..
                int newWidth = (int)(bitmapPages[0].Bitmap.Width * (0.1f + downSampleFactor));
                int newHeight = (int)(bitmapPages[0].Bitmap.Height * (0.1f + downSampleFactor));

                //free old bitmap pages since we are about to chuck them away
                for (int i = 0; i < pageCount; i++)
                    bitmapPages[i].Free();

                QFontGlyph[] shrunkRepackedGlyphs;
                bitmapPages = GenerateBitmapSheetsAndRepack(shrunkGlyphs, shrunkBitmapData, newWidth, newHeight, out shrunkRepackedGlyphs, 4, false);
                data.CharSetMapping = CreateCharGlyphMapping(shrunkRepackedGlyphs);

                pageCount = bitmapPages.Count;
            }

            data.Pages = bitmapPages.ToArray();

            if (downSampleFactor != 1.0f)
            {
                foreach (var glyph in data.CharSetMapping.Values)
                    RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].BitmapData, glyph, false, loaderConfig.KerningConfig.alphaEmptyPixelTolerance);

                intercept = FirstIntercept(data.CharSetMapping);
                if (intercept != null)
                {
                    throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This occurred only after resizing your texture font, implying that there is a bug in QFont. ");
                }
            }

            var glyphList = new List<QFontGlyph>();

            foreach (var c in charSet)
                glyphList.Add(data.CharSetMapping[c]);

            if (loaderConfig.ShadowConfig != null)
                data.dropShadow = BuildDropShadow(bitmapPages, glyphList.ToArray(), loaderConfig.ShadowConfig, Helper.ToArray(charSet),loaderConfig.KerningConfig.alphaEmptyPixelTolerance);

            data.KerningPairs = KerningCalculator.CalculateKerning(Helper.ToArray(charSet), glyphList.ToArray(), bitmapPages, loaderConfig.KerningConfig);

            data.CalculateMeanWidth();
            data.CalculateMaxHeight();

            return data;
        }
Пример #7
0
        public QFontData BuildFontData(string saveName)
        {
            if (config.ForcePowerOfTwo && config.SuperSampleLevels != PowerOfTwo(config.SuperSampleLevels))
            {
                throw new ArgumentOutOfRangeException("SuperSampleLevels must be a power of two when using ForcePowerOfTwo.");
            }

            if (config.SuperSampleLevels <= 0 || config.SuperSampleLevels > 8)
            {
                throw new ArgumentOutOfRangeException("SuperSampleLevels = [" + config.SuperSampleLevels + "] is an unsupported value. Please use values in the range [1,8]");
            }

            int margin = 2; //margin in initial bitmap (don't bother to make configurable - likely to cause confusion
            int pageWidth = config.PageWidth * config.SuperSampleLevels; //texture page width
            int pageHeight = config.PageHeight * config.SuperSampleLevels; //texture page height
            bool usePowerOfTwo = config.ForcePowerOfTwo;
            int glyphMargin = config.GlyphMargin * config.SuperSampleLevels;

            QFontGlyph[] initialGlyphs;
            var sizes = GetGlyphSizes(font);
            var maxSize = GetMaxGlyphSize(sizes);
            var initialBmp = CreateInitialBitmap(font, maxSize, margin, out initialGlyphs,config.TextGenerationRenderHint);
            var initialBitmapData = initialBmp.LockBits(new Rectangle(0, 0, initialBmp.Width, initialBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int minYOffset = int.MaxValue;
            foreach (var glyph in initialGlyphs){
                RetargetGlyphRectangleInwards(initialBitmapData, glyph, true, config.KerningConfig.alphaEmptyPixelTolerance);
                minYOffset = Math.Min(minYOffset,glyph.yOffset);
            }
            minYOffset--; //give one pixel of breathing room?

            foreach (var glyph in initialGlyphs)
                glyph.yOffset -= minYOffset;

            QFontGlyph[] glyphs;
            var bitmapPages = GenerateBitmapSheetsAndRepack( initialGlyphs,new BitmapData[1] { initialBitmapData},pageWidth, pageHeight, out glyphs, glyphMargin, usePowerOfTwo);

            initialBmp.UnlockBits(initialBitmapData);
            initialBmp.Dispose();

            if (config.SuperSampleLevels != 1)
            {
                ScaleSheetsAndGlyphs(bitmapPages, glyphs, 1.0f / config.SuperSampleLevels);
                RetargetAllGlyphs(bitmapPages, glyphs,config.KerningConfig.alphaEmptyPixelTolerance);
            }

            //create list of texture pages
            var fontData = new QFontData();
            fontData.CharSetMapping = CreateCharGlyphMapping(glyphs);
            fontData.Pages = bitmapPages.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();
            fontData.KerningPairs = KerningCalculator.CalculateKerning(charSet.ToCharArray(), glyphs, bitmapPages,config.KerningConfig);
            fontData.naturallyMonospaced = IsMonospaced(sizes);

            if (saveName != null)
            {
                if (bitmapPages.Count == 1)
                    bitmapPages[0].Bitmap.Save(saveName + ".png", System.Drawing.Imaging.ImageFormat.Png);
                else
                {
                    for (int i = 0; i < bitmapPages.Count; i++)
                        bitmapPages[i].Bitmap.Save(saveName + "_sheet_" + i + ".png", System.Drawing.Imaging.ImageFormat.Png);
                }
            }

            if (config.ShadowConfig != null)
                fontData.dropShadow = BuildDropShadow(bitmapPages, glyphs, config.ShadowConfig, charSet.ToCharArray(),config.KerningConfig.alphaEmptyPixelTolerance);

            //validate glyphs
            var intercept = FirstIntercept(fontData.CharSetMapping);
            if (intercept != null)
                throw new Exception("Failed to create glyph set. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This is could be due to an error in the font, or a bug in Graphics.MeasureString().");

            return fontData;
        }
Пример #8
0
        /*
         * public static QFontData LoadQFontDataFromFile(string filePath)
         * {
         *  return LoadQFontDataFromFile(filePath, 1.0f);
         * }*/

        public static QFontData LoadQFontDataFromFile(string filePath, float downSampleFactor, QFontShadowConfiguration shadowConfig)
        {
            var          lines  = new List <String>();
            StreamReader reader = new StreamReader(filePath);
            string       line;

            while ((line = reader.ReadLine()) != null)
            {
                lines.Add(line);
            }
            reader.Close();

            var data      = new QFontData();
            int pageCount = 0;

            char[] charSet;
            data.Deserialize(lines, out pageCount, out charSet);


            string namePrefix = filePath.Replace(".qfont", "").Replace(" ", "");

            data.Pages = new TexturePage[pageCount];
            var bitmapPages = new List <QBitmap>();



            if (pageCount == 1)
            {
                bitmapPages.Add(new QBitmap(namePrefix + ".png"));
            }
            else
            {
                for (int i = 0; i < pageCount; i++)
                {
                    bitmapPages.Add(new QBitmap(namePrefix + "_sheet_" + i));
                }
            }


            if (downSampleFactor != 1.0f)
            {
                foreach (var page in bitmapPages)
                {
                    page.DownScale32((int)(page.bitmap.Width * downSampleFactor), (int)(page.bitmap.Height * downSampleFactor));
                }
            }

            for (int i = 0; i < pageCount; i++)
            {
                data.Pages[i] = new TexturePage(bitmapPages[i].bitmapData);
            }


            foreach (var glyph in data.CharSetMapping.Values)
            {
                glyph.rect = new Rectangle((int)(glyph.rect.X * downSampleFactor),
                                           (int)(glyph.rect.Y * downSampleFactor),
                                           (int)(glyph.rect.Width * downSampleFactor),
                                           (int)(glyph.rect.Height * downSampleFactor));

                RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].bitmapData, glyph, false);
                glyph.yOffset = (int)(glyph.yOffset * downSampleFactor);
            }


            var intercept = FirstIntercept(data.CharSetMapping);

            if (intercept != null)
            {
                throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. If you are texturing your font without locking pixel opacity, then consider using a larger glyph margin. This can be done by setting QFontBuilderConfiguration myQfontBuilderConfig.GlyphMargin, and passing it into CreateTextureFontFiles.");
            }



            var glyphList = new List <QFontGlyph>();

            foreach (var c in charSet)
            {
                glyphList.Add(data.CharSetMapping[c]);
            }

            if (shadowConfig != null)
            {
                data.dropShadow = BuildDropShadow(bitmapPages, glyphList.ToArray(), shadowConfig, charSet.ToArray());
            }


            data.KerningPairs = KerningCalculator.CalculateKerning(charSet.ToArray(), glyphList.ToArray(), bitmapPages);



            data.CalculateMeanWidth();
            data.CalculateMaxHeight();


            for (int i = 0; i < pageCount; i++)
            {
                bitmapPages[i].Free();
            }


            return(data);
        }
Пример #9
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);
        }
Пример #10
0
        /*
        public static QFontData LoadQFontDataFromFile(string filePath)
        {
            return LoadQFontDataFromFile(filePath, 1.0f);
        }*/
        public static QFontData LoadQFontDataFromFile(string filePath, float downSampleFactor, QFontShadowConfiguration shadowConfig)
        {
            var lines = new List<String>();
            StreamReader reader = new StreamReader(filePath);
            string line;
            while((line = reader.ReadLine()) != null)
                lines.Add(line);
            reader.Close();

            var data = new QFontData();
            int pageCount = 0;
            char[] charSet;
            data.Deserialize(lines, out pageCount, out charSet);

            string namePrefix = filePath.Replace(".qfont","").Replace(" ", "");
            data.Pages = new TexturePage[pageCount];
            var bitmapPages = new List<QBitmap>();

            if (pageCount == 1)
            {
                bitmapPages.Add(new QBitmap(namePrefix + ".png"));
            }
            else
            {
                for (int i = 0; i < pageCount; i++)
                    bitmapPages.Add(new QBitmap(namePrefix + "_sheet_" + i));
            }

            if (downSampleFactor != 1.0f)
            {
                foreach (var page in bitmapPages)
                    page.DownScale32((int)(page.bitmap.Width * downSampleFactor), (int)(page.bitmap.Height * downSampleFactor));
            }

            for(int i = 0; i < pageCount; i ++ )
                data.Pages[i] = new TexturePage(bitmapPages[i].bitmapData);

            foreach (var glyph in data.CharSetMapping.Values)
            {

                glyph.rect = new Rectangle((int)(glyph.rect.X * downSampleFactor),
                                           (int)(glyph.rect.Y * downSampleFactor),
                                           (int)(glyph.rect.Width * downSampleFactor),
                                           (int)(glyph.rect.Height * downSampleFactor));

                RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].bitmapData, glyph,false);
                glyph.yOffset = (int)(glyph.yOffset * downSampleFactor);
            }

            var intercept = FirstIntercept(data.CharSetMapping);

            if (intercept != null)
            {
                throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. If you are texturing your font without locking pixel opacity, then consider using a larger glyph margin. This can be done by setting QFontBuilderConfiguration myQfontBuilderConfig.GlyphMargin, and passing it into CreateTextureFontFiles.");
            }

            var glyphList = new List<QFontGlyph>();

            foreach (var c in charSet)
                glyphList.Add(data.CharSetMapping[c]);

            if (shadowConfig != null)
                data.dropShadow = BuildDropShadow(bitmapPages, glyphList.ToArray(), shadowConfig, charSet.ToArray());

            data.KerningPairs = KerningCalculator.CalculateKerning(charSet.ToArray(), glyphList.ToArray(), bitmapPages);

            data.CalculateMeanWidth();
            data.CalculateMaxHeight();

            for (int i = 0; i < pageCount; i++)
                bitmapPages[i].Free();

            return data;
        }
Пример #11
0
        /// <summary>
        /// Builds the font data
        /// </summary>
        /// <param name="saveName">The filename to save the font texture files too. If null, the texture files are not saved</param>
        /// <returns>A <see cref="QFontData"/></returns>
        public QFontData BuildFontData(string saveName = null)
        {
            // Check super sample level range
            if (_config.SuperSampleLevels <= 0 || _config.SuperSampleLevels > 8)
            {
                throw new ArgumentOutOfRangeException("SuperSampleLevels = [" + _config.SuperSampleLevels + "] is an unsupported value. Please use values in the range [1,8]");
            }

            int margin      = 3; //margin in initial bitmap (don't bother to make configurable - likely to cause confusion
            int glyphMargin = _config.GlyphMargin * _config.SuperSampleLevels;

            QFontGlyph[] initialGlyphs;
            var          sizes      = GetGlyphSizes(_font);
            var          maxSize    = GetMaxGlyphSize(sizes);
            var          initialBmp = CreateInitialBitmap(_font, maxSize, margin, out initialGlyphs, _config.TextGenerationRenderHint);

#if DEBUG
            // print bitmap with bounds to debug it
            var debugBmp = initialBmp.Clone() as Bitmap;
            var graphics = Graphics.FromImage(debugBmp);
            var pen      = new Pen(Color.Red, 1);

            foreach (var g in initialGlyphs)
            {
                graphics.DrawRectangle(pen, g.Rect);
            }

            graphics.Flush();
            graphics.Dispose();

            debugBmp.Save(_font + "-DEBUG.png", ImageFormat.Png);
#endif

            var initialBitmapData = initialBmp.LockBits(new Rectangle(0, 0, initialBmp.Width, initialBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int minYOffset = int.MaxValue;

            // Retarget each glyph rectangle to get minimum bounding box
            foreach (var glyph in initialGlyphs)
            {
                RetargetGlyphRectangleInwards(initialBitmapData, glyph, true, _config.KerningConfig.AlphaEmptyPixelTolerance);
                minYOffset = Math.Min(minYOffset, glyph.YOffset);
            }
            minYOffset--; //give one pixel of breathing room?

            // Update glyph y offsets
            foreach (var glyph in initialGlyphs)
            {
                glyph.YOffset -= minYOffset;
            }

            // Find the optimal page size for the font
            Size         pagesize = GetOptimalPageSize(initialBmp.Width * _config.SuperSampleLevels, initialBmp.Height * _config.SuperSampleLevels, _config.PageMaxTextureSize);
            QFontGlyph[] glyphs;

            // Generate the final bitmap pages
            List <QBitmap> bitmapPages = GenerateBitmapSheetsAndRepack(initialGlyphs, new[] { initialBitmapData }, pagesize.Width, pagesize.Height, out glyphs, glyphMargin);

            // Clean up
            initialBmp.UnlockBits(initialBitmapData);
            initialBmp.Dispose();

            // Scale and retarget glyphs if needed
            if (_config.SuperSampleLevels != 1)
            {
                ScaleSheetsAndGlyphs(bitmapPages, glyphs, 1.0f / _config.SuperSampleLevels);
                RetargetAllGlyphs(bitmapPages, glyphs, _config.KerningConfig.AlphaEmptyPixelTolerance);
            }

            //create list of texture pages
            var pages = new List <TexturePage>();
            foreach (var page in bitmapPages)
            {
                pages.Add(new TexturePage(page.BitmapData));
            }


            // Build the QFontData
            var fontData = new QFontData
            {
                CharSetMapping = CreateCharGlyphMapping(glyphs),
                Pages          = pages.ToArray()
            };
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();
            fontData.KerningPairs        = KerningCalculator.CalculateKerning(_charSet.ToCharArray(), glyphs, bitmapPages, _config.KerningConfig, _font);
            fontData.NaturallyMonospaced = IsMonospaced(sizes);

            // Save the font texture files if required
            if (saveName != null)
            {
                if (bitmapPages.Count == 1)
                {
                    bitmapPages[0].Bitmap.UnlockBits(bitmapPages[0].BitmapData);
                    bitmapPages[0].Bitmap.Save(saveName + ".png", ImageFormat.Png);
                    bitmapPages[0] = new QBitmap(bitmapPages[0].Bitmap);
                }
                else
                {
                    for (int i = 0; i < bitmapPages.Count; i++)
                    {
                        bitmapPages[i].Bitmap.UnlockBits(bitmapPages[i].BitmapData);
                        bitmapPages[i].Bitmap.Save(saveName + "_sheet_" + i + ".png", ImageFormat.Png);
                        bitmapPages[i] = new QBitmap(bitmapPages[i].Bitmap);
                    }
                }
            }

            // Build the font drop shadow if required
            if (_config.ShadowConfig != null)
            {
                fontData.DropShadowFont = BuildDropShadow(bitmapPages, glyphs, _config.ShadowConfig, _charSet.ToCharArray(), _config.KerningConfig.AlphaEmptyPixelTolerance);
            }

            // Clean up resources
            foreach (var page in bitmapPages)
            {
                page.Free();
            }

            // Check that no glyphs are overlapping
            var intercept = FirstIntercept(fontData.CharSetMapping);
            if (intercept != null)
            {
                throw new Exception("Failed to create glyph set. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This is could be due to an error in the font, or a bug in Graphics.MeasureString().");
            }

            return(fontData);
        }