Ejemplo n.º 1
0
        public void Pack_AdjustedGlyphs_All()
        {
            // Arrange
            var glyphs = new List <Bitmap>();

            glyphs.Add(new Bitmap(5, 5));
            glyphs[0].SetPixel(2, 1, Color.White);
            glyphs[0].SetPixel(2, 2, Color.White);
            glyphs[0].SetPixel(2, 3, Color.White);
            glyphs[0].SetPixel(1, 2, Color.White);
            glyphs[0].SetPixel(3, 2, Color.White);
            glyphs.Add(new Bitmap(5, 5));
            glyphs[1].SetPixel(2, 2, Color.White);
            glyphs[1].SetPixel(2, 1, Color.White);
            glyphs[1].SetPixel(3, 2, Color.White);
            glyphs.Add(new Bitmap(2, 2));
            glyphs[2].SetPixel(0, 0, Color.White);
            glyphs[2].SetPixel(1, 0, Color.White);
            var adjustedGlyphs = FontMeasurement.MeasureWhiteSpace(glyphs);
            var binPacker      = new BinPacker(new Size(5, 3));

            // Act
            var boxes = binPacker.Pack(adjustedGlyphs).ToArray();

            // Assert
            boxes.Length.Should().Be(3);
            boxes[0].position.Should().Be(Point.Empty);
            boxes[1].position.Should().Be(new Point(3, 0));
            boxes[2].position.Should().Be(new Point(3, 2));
        }
Ejemplo n.º 2
0
        public void Pack_AdjustedGlyphs_Space()
        {
            // Arrange
            var glyphs = new List <Bitmap>();

            glyphs.Add(new Bitmap(5, 5));
            var adjustedGlyphs = FontMeasurement.MeasureWhiteSpace(glyphs);
            var binPacker      = new BinPacker(new Size(6, 6));

            // Act
            var boxes = binPacker.Pack(adjustedGlyphs).ToArray();

            // Assert
            boxes.Length.Should().Be(1);
            boxes[0].position.Should().Be(new Point(1, 1));
        }
Ejemplo n.º 3
0
        public void Measure_WhiteSpace_Works()
        {
            // Arrange
            var glyphs = new List <Bitmap>();

            glyphs.Add(new Bitmap(5, 5));
            glyphs[0].SetPixel(2, 2, Color.White);
            glyphs.Add(new Bitmap(5, 5));
            glyphs[1].SetPixel(2, 2, Color.White);
            glyphs[1].SetPixel(2, 1, Color.White);

            // Act
            var adjustedGlyphs = FontMeasurement.MeasureWhiteSpace(glyphs).ToArray();

            // Assert
            adjustedGlyphs.Length.Should().Be(2);
            adjustedGlyphs[0].WhiteSpaceAdjustment.GlyphSize.Should().Be(new Size(1, 1));
            adjustedGlyphs[1].WhiteSpaceAdjustment.GlyphSize.Should().Be(new Size(1, 2));
            adjustedGlyphs[0].WhiteSpaceAdjustment.GlyphPosition.Should().Be(new Point(2, 2));
            adjustedGlyphs[1].WhiteSpaceAdjustment.GlyphPosition.Should().Be(new Point(2, 1));
        }
Ejemplo n.º 4
0
        public (Stream fontStream, Image fontImage) Save(List <CharacterInfo> characterInfos, Size imageSize)
        {
            // Generating font textures
            var adjustedGlyphs = FontMeasurement.MeasureWhiteSpace(characterInfos.Select(x => (Bitmap)x.Glyph)).ToList();

            // Adjust image size for at least the biggest letter
            var height = Math.Max(adjustedGlyphs.Max(x => x.WhiteSpaceAdjustment.GlyphSize.Height), imageSize.Height);
            var width  = Math.Max(adjustedGlyphs.Max(x => x.WhiteSpaceAdjustment.GlyphSize.Width), imageSize.Width);

            imageSize = new Size(width, height);

            var generator    = new FontTextureGenerator(imageSize, 0);
            var textureInfos = generator.GenerateFontTextures(adjustedGlyphs, 3).ToList();

            // Join important lists
            var joinedCharacters = characterInfos.OrderBy(x => x.CodePoint).Join(adjustedGlyphs, c => c.Glyph, ag => ag.Glyph,
                                                                                 (c, ag) => new { character = c, adjustedGlyph = ag })
                                   .Select(cag => new
            {
                cag.character,
                cag.adjustedGlyph,
                textureIndex    = textureInfos.FindIndex(x => x.Glyphs.Any(y => y.Item1 == cag.adjustedGlyph.Glyph)),
                texturePosition = textureInfos.SelectMany(x => x.Glyphs).FirstOrDefault(x => x.Item1 == cag.adjustedGlyph.Glyph).Item2
            });

            // Create character information
            var charMaps      = new List <(AdjustedGlyph, XfCharMap)>(adjustedGlyphs.Count);
            var charSizeInfos = new List <XfCharSizeInfo>();

            foreach (var joinedCharacter in joinedCharacters)
            {
                if (joinedCharacter.textureIndex == -1)
                {
                    continue;
                }

                var charSizeInfo = new XfCharSizeInfo
                {
                    offsetX     = (sbyte)joinedCharacter.adjustedGlyph.WhiteSpaceAdjustment.GlyphPosition.X,
                    offsetY     = (sbyte)joinedCharacter.adjustedGlyph.WhiteSpaceAdjustment.GlyphPosition.Y,
                    glyphWidth  = (byte)joinedCharacter.adjustedGlyph.WhiteSpaceAdjustment.GlyphSize.Width,
                    glyphHeight = (byte)joinedCharacter.adjustedGlyph.WhiteSpaceAdjustment.GlyphSize.Height
                };
                if (!charSizeInfos.Contains(charSizeInfo))
                {
                    charSizeInfos.Add(charSizeInfo);
                }

                // Only used for Time Travelers
                var codePoint = ConvertChar(joinedCharacter.character.CodePoint);
                //var codePoint = joinedCharacter.character.CodePoint;

                var charInformation = new XfCharInformation
                {
                    charSizeInfoIndex = charSizeInfos.IndexOf(charSizeInfo),
                    charWidth         = char.IsWhiteSpace((char)codePoint) ?
                                        joinedCharacter.character.CharacterSize.Width :
                                        joinedCharacter.character.CharacterSize.Width - charSizeInfo.offsetX
                };

                charMaps.Add((joinedCharacter.adjustedGlyph, new XfCharMap
                {
                    codePoint = (ushort)codePoint,
                    charInformation = charInformation,
                    imageInformation = new XfImageInformation
                    {
                        colorChannel = joinedCharacter.textureIndex,
                        imageOffsetX = joinedCharacter.texturePosition.X,
                        imageOffsetY = joinedCharacter.texturePosition.Y
                    }
                }));

                if (codePoint != joinedCharacter.character.CodePoint)
                {
                    charInformation = new XfCharInformation
                    {
                        charSizeInfoIndex = charSizeInfos.IndexOf(charSizeInfo),
                        charWidth         = char.IsWhiteSpace((char)joinedCharacter.character.CodePoint)
                            ? joinedCharacter.character.CharacterSize.Width
                            : joinedCharacter.character.CharacterSize.Width - charSizeInfo.offsetX
                    };

                    charMaps.Add((joinedCharacter.adjustedGlyph, new XfCharMap
                    {
                        codePoint = (ushort)joinedCharacter.character.CodePoint,
                        charInformation = charInformation,
                        imageInformation = new XfImageInformation
                        {
                            colorChannel = joinedCharacter.textureIndex,
                            imageOffsetX = joinedCharacter.texturePosition.X,
                            imageOffsetY = joinedCharacter.texturePosition.Y
                        }
                    }));
                }
            }

            // Set escape characters
            var escapeIndex = charMaps.FindIndex(x => x.Item2.codePoint == '?');

            Header.largeEscapeCharacter = escapeIndex < 0 ? (short)0 : (short)escapeIndex;
            Header.smallEscapeCharacter = 0;

            // Minimize top value and line height
            Header.largeCharHeight = (short)charSizeInfos.Max(x => x.glyphHeight + x.offsetY);
            Header.smallCharHeight = 0;

            // Draw textures
            var img = new Bitmap(imageSize.Width, imageSize.Height);
            var gfx = Graphics.FromImage(img);

            for (var i = 0; i < textureInfos.Count; i++)
            {
                var destPoints = new[]
                {
                    new PointF(0, 0),
                    new PointF(textureInfos[i].FontTexture.Width, 0),
                    new PointF(0, textureInfos[i].FontTexture.Height)
                };
                var rect = new RectangleF(0, 0, textureInfos[i].FontTexture.Width, textureInfos[i].FontTexture.Height);
                var attr = new ImageAttributes();
                attr.SetColorMatrix(_inverseColorMatrices[i]);
                gfx.DrawImage(textureInfos[i].FontTexture, destPoints, rect, GraphicsUnit.Pixel, attr);
            }

            // Save fnt.bin
            var savedFntBin = new MemoryStream();

            using (var bw = new BinaryWriterX(savedFntBin, true))
            {
                //Table0
                bw.BaseStream.Position = 0x28;
                Header.charSizeCount   = (short)charSizeInfos.Count;
                WriteMultipleCompressed(bw, charSizeInfos, _t0Comp);
                bw.WriteAlignment(4);

                //Table1
                Header.largeCharOffset = (short)(bw.BaseStream.Position >> 2);
                Header.largeCharCount  = (short)charMaps.Count;
                WriteMultipleCompressed(bw, charMaps.OrderBy(x => x.Item2.codePoint).Select(x => x.Item2).ToArray(), _t1Comp);
                bw.WriteAlignment(4);

                //Table2
                Header.smallCharOffset = (short)(bw.BaseStream.Position >> 2);
                Header.smallCharCount  = 0;
                WriteMultipleCompressed(bw, Array.Empty <XfCharMap>(), _t2Comp);
                bw.WriteAlignment(4);

                //Header
                bw.BaseStream.Position = 0;
                bw.WriteType(Header);
            }

            return(savedFntBin, img);
        }