Пример #1
0
        private void CopyBitmapToDestinationArea(
            Graphics.Color[] data,
            int dataRowSize,
            Vector2 destinationTopleft,
            FTBitmap ftBitmap
            )
        {
            byte[] buffer = ftBitmap.BufferData;
            int    dataOffset,
                   bufferOffset,
                   pitch = Util.Math.Abs(ftBitmap.Pitch);

            for (int row = 0; row < ftBitmap.Rows; row++)
            {
                dataOffset   = (int)((destinationTopleft.Y + row) * dataRowSize + destinationTopleft.X);
                bufferOffset = row * pitch;

                for (int column = 0; column < ftBitmap.Width; column++, dataOffset++)
                {
                    byte px = buffer[bufferOffset + column];

                    data[dataOffset] = new Graphics.Color(px, px, px, px);
                }
            }
        }
Пример #2
0
 public GlyphBitmap(FTBitmap bitmap)
 {
     Pitch      = bitmap.Pitch;
     Rows       = bitmap.Rows;
     Width      = bitmap.Width;
     PixelMode  = bitmap.PixelMode;
     BufferData = Pitch == 0 ? new byte[0] : bitmap.BufferData;
 }
Пример #3
0
 private static Bitmap CreateBitmap(FTBitmap ftbmp, uint charCode)
 {
     if (ftbmp.Rows > 0 && ftbmp.Width > 0)
     {
         return(FontBitmapConverter.Convert(ftbmp, Color.White, charCode));
     }
     return(null);
 }
Пример #4
0
        /// <summary>
        /// Renders a glyph with a given height, measured as a distance between two text lines in the device pixels.</param>
        /// </summary>
        public Glyph Render(char @char, int height)
        {
            if (lastHeight != height)
            {
                lastHeight = height;
                var pixelSize = (uint)Math.Abs(
                    CalcPixelSize(face, fontHeightResolver?.Invoke(height) ?? height).Round()
                    );
                face.SetPixelSizes(pixelSize, pixelSize);
            }

            var glyphIndex = face.GetCharIndex(@char);

            if (glyphIndex == 0)
            {
                return(null);
            }

            face.LoadGlyph(glyphIndex, LoadFlags.Default, lcdSupported ? LoadTarget.Lcd : LoadTarget.Normal);
            face.Glyph.RenderGlyph(lcdSupported ? RenderMode.Lcd : RenderMode.Normal);
            FTBitmap bitmap = face.Glyph.Bitmap;

            var  verticalOffset = height - face.Glyph.BitmapTop + face.Size.Metrics.Descender.Round();
            var  bearingX       = (float)face.Glyph.Metrics.HorizontalBearingX;
            bool rgbIntensity   = bitmap.PixelMode == PixelMode.Lcd || bitmap.PixelMode == PixelMode.VerticalLcd;
            var  glyph          = new Glyph {
                Pixels         = bitmap.BufferData,
                RgbIntensity   = rgbIntensity,
                Pitch          = bitmap.Pitch,
                Width          = rgbIntensity ? bitmap.Width / 3 : bitmap.Width,
                Height         = bitmap.Rows,
                VerticalOffset = verticalOffset,
                ACWidths       = new Vector2(
                    bearingX,
                    (float)face.Glyph.Metrics.HorizontalAdvance - (float)face.Glyph.Metrics.Width - bearingX
                    ),
            };

            // Iterate through kerning pairs
            foreach (var nextChar in KerningCharacters)
            {
                var nextGlyphIndex = face.GetCharIndex(nextChar);
                var kerning        = (float)face.GetKerning(glyphIndex, nextGlyphIndex, KerningMode.Default).X;
                if (kerning != 0)
                {
                    if (glyph.KerningPairs == null)
                    {
                        glyph.KerningPairs = new List <KerningPair>();
                    }
                    glyph.KerningPairs.Add(new KerningPair {
                        Char = nextChar, Kerning = kerning
                    });
                }
            }
            return(glyph);
        }
Пример #5
0
        public FontTex CreateTexture(char c)
        {
            FontTex ft;

            if (Cache.TryGetValue(c, out ft))
            {
                return(ft);
            }

            uint glyphIndex = FontFace.GetCharIndex(c);

            FontFace.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
            FontFace.Glyph.RenderGlyph(RenderMode.Light);
            FTBitmap ftbmp = FontFace.Glyph.Bitmap;

            int fontW = (int)((float)FontFace.Glyph.Metrics.HorizontalAdvance);
            int fontH = (int)((float)FontFace.Glyph.Metrics.VerticalAdvance);

            if (ftbmp.Width > 0 && ftbmp.Rows > 0)
            {
                ft = FontTex.Create(ftbmp);

                ft.PosX = (int)((float)FontFace.Glyph.Metrics.HorizontalBearingX);
                if (ft.PosX < 0)
                {
                    ft.PosX = 0;
                }
                ;

                float top    = (float)FontFace.Size.Metrics.Ascender;
                float bottom = (float)(FontFace.Glyph.Metrics.Height - FontFace.Glyph.Metrics.HorizontalBearingY);

                int y = (int)(top - (float)FontFace.Glyph.Metrics.HorizontalBearingY);

                ft.PosY = y;

                ft.FontW = Math.Max(fontW, ft.ImgW);
                ft.FontH = (int)(top + bottom);
            }
            else
            {
                ft       = FontTex.CreateSpace((int)FontFace.Glyph.Advance.X, (int)FontFace.Glyph.Advance.Y);
                ft.FontW = fontW;
                ft.FontH = fontH;
            }

            Cache.Add(c, ft);

            //ft.dump_b();
            //Console.WriteLine();

            return(ft);
        }
Пример #6
0
        private static Bitmap FromMono(FTBitmap ftbmp, Color color)
        {
            var data   = new byte[ftbmp.Rows * ftbmp.Width];
            var bitmap = new Bitmap(ftbmp.Width, ftbmp.Rows, PixelFormat.Format32bppArgb);
            var rect   = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
            var data2  = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
            var bytes2 = new byte[Math.Abs(data2.Stride) * data2.Height];

            for (var y = 0; y < ftbmp.Rows; y++)
            {
                for (var x = 0; x < ftbmp.Pitch; x++)
                {
                    var v    = ftbmp.BufferData[y * ftbmp.Pitch + x];
                    var num  = x * 8;
                    var row  = y * ftbmp.Width + x * 8;
                    var bits = 8;
                    if ((ftbmp.Width - num) < 8)
                    {
                        bits = ftbmp.Width - num;
                    }
                    for (var i = 0; i < bits; i++)
                    {
                        var bit = v & (1 << (7 - i));
                        data[row + i] = (byte)bit;
                    }
                }
            }

            for (var y = 0; y < bitmap.Height; y++)
            {
                for (var x = 0; x < bitmap.Width; x++)
                {
                    var v = data[(y * bitmap.Width) + x];
                    if (v != 0)
                    {
                        bytes2[x * 4 + y * data2.Stride + 0] = color.B;
                        bytes2[x * 4 + y * data2.Stride + 1] = color.G;
                        bytes2[x * 4 + y * data2.Stride + 2] = color.R;
                        bytes2[x * 4 + y * data2.Stride + 3] = color.A;
                    }
                }
            }
            Marshal.Copy(bytes2, 0, data2.Scan0, bytes2.Length);
            bitmap.UnlockBits(data2);
            return(bitmap);
        }
Пример #7
0
        private static Bitmap FromGray(FTBitmap ftbmp, Color color)
        {
            Bitmap bmp = new Bitmap(ftbmp.Width, ftbmp.Rows, PixelFormat.Format32bppArgb);

            for (var y = 0; y < bmp.Height; y++)
            {
                for (var x = 0; x < bmp.Width; x++)
                {
                    var d = ftbmp.BufferData[y * bmp.Width + x];
                    if (d != 0)
                    {
                        bmp.SetPixel(x, y, Color.FromArgb(d, color.R, color.G, color.B));
                    }
                }
            }
            return(bmp);
        }
Пример #8
0
        private static Pixmap ToPixmap(FTBitmap bitmap)
        {
            var bufferData = bitmap.BufferData;
            var size       = new Size(bitmap.Width, bitmap.Rows);
            var pixmap     = new Pixmap(PixelFormat.Rgba, size);

            for (int j = 0; j < size.Height; j++)
            {
                for (int i = 0; i < size.Width; i++)
                {
                    int k = (i + bitmap.Width * j) * 4;
                    pixmap.PixelData[k]     = 255;
                    pixmap.PixelData[k + 1] = 255;
                    pixmap.PixelData[k + 2] = 255;
                    pixmap.PixelData[k + 3] = bufferData[i + bitmap.Width * j];
                }
            }
            return(pixmap);
        }
Пример #9
0
        private void RenderIntoColorData(Color[] data, FTBitmap bitmap, Vector2 pos)
        {
            unsafe
            {
                byte *colors = (byte *)bitmap.Buffer;

                for (int y = 0; y < Math.Min(bitmap.Rows, TEXTURE_SIZE); y++)
                {
                    for (int x = 0; x < Math.Min(bitmap.Width, TEXTURE_SIZE); x++)
                    {
                        if ((int)(((y + pos.Y) * TEXTURE_SIZE) + (x + pos.X)) < data.Length)
                        {
                            data[(int)(((y + pos.Y) * TEXTURE_SIZE) + (x + pos.X))] =
                                Color.White * (colors[(y * bitmap.Pitch) + x] / 255f);
                        }
                    }
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Renders a <see cref="FTBitmap"/> to a <see cref="Texture2D"/>.
        /// </summary>
        /// <remarks>
        /// Size of the texture must be equal to or larger than size of the bitmap.
        /// The format of the bitmap must be <see cref="PixelMode.Gray"/>, and the format of the texture must be a 32-bit format
        /// (<see cref="SurfaceFormat.Bgr32"/>, <see cref="SurfaceFormat.Bgra32"/>, or <see cref="SurfaceFormat.Color"/>).
        /// </remarks>
        /// <param name="bitmap">The <see cref="FTBitmap"/> containing character image.</param>
        /// <param name="texture">The <see cref="Texture2D"/> to render to.</param>
        public static void RenderToTexture([NotNull] this FTBitmap bitmap, [NotNull] Texture2D texture)
        {
            Debug.Assert(texture.Width >= bitmap.Width);
            Debug.Assert(texture.Height >= bitmap.Rows);
            Debug.Assert(bitmap.PixelMode == PixelMode.Gray);

            var textureFormat = texture.Format;

            Debug.Assert(textureFormat == SurfaceFormat.Bgr32 | textureFormat == SurfaceFormat.Bgra32 || textureFormat == SurfaceFormat.Color);

            // Are pixel bytes in A-R-G-B order?
            var argb = textureFormat == SurfaceFormat.Color;

            var textureData = new uint[texture.Width * texture.Height];
            var bitmapData  = bitmap.BufferData;

            for (var j = 0; j < bitmap.Rows; j++)
            {
                var bitmapLineStart  = j * bitmap.Pitch;
                var textureLineStart = j * texture.Width;

                for (var i = 0; i < bitmap.Width; i++)
                {
                    var bitmapPixelIndex  = bitmapLineStart + i;
                    var texturePixelIndex = textureLineStart + i;

                    var alpha = (uint)bitmapData[bitmapPixelIndex];
                    var color = alpha;

                    if (argb)
                    {
                        textureData[texturePixelIndex] = color << 16 | color << 8 | color | alpha << 24;
                    }
                    else
                    {
                        textureData[texturePixelIndex] = color << 24 | color << 16 | color << 8 | alpha;
                    }
                }
            }

            texture.SetData(textureData);
        }
Пример #11
0
        Character GetCharacter(char c)
        {
            if (chars.ContainsKey(c))
            {
                return(chars[c]);
            }

            //rendering character
            face.LoadChar(c, LoadFlags.Render, LoadTarget.Light);
            FTBitmap bitmap = face.Glyph.Bitmap;

            //calculating position
            if (x + bitmap.Width > mapSize)
            {
                y += ymax;
                x  = 0;
            }

            if (y + bitmap.Rows > mapSize)
            {
                throw new Exception("out of memory string");
            }

            if (ymax < bitmap.Rows)
            {
                ymax = bitmap.Rows;
            }

            charmap.AddSubImage(bitmap.Buffer, x, y, bitmap.Width, bitmap.Rows);
            Character ch = new Character(new Vector2(x / (float)mapSize, y / (float)mapSize),
                                         new Vector2(bitmap.Width, bitmap.Rows),
                                         new Vector2(face.Glyph.BitmapLeft, face.Glyph.BitmapTop),
                                         face.Glyph.Advance.X.Value);

            chars.Add(c, ch);

            x += bitmap.Width + 1;

            bitmap.Dispose();

            return(ch);
        }
Пример #12
0
        public unsafe GlyphTexture(GL gl, FTBitmap bitmap) : base()
        {
            TextureType = TextureType.Other;

            Size = new GlmSharp.uvec2((uint)bitmap.Width, (uint)bitmap.Rows);

            gl.PixelStore(GLEnum.UnpackAlignment, 1);

            gl.BindTexture(TextureTarget.Texture2D, ID);

            gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)GLEnum.ClampToEdge);
            gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)GLEnum.Linear);
            gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)GLEnum.ClampToEdge);
            gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)GLEnum.Linear);

            fixed(void *i = &bitmap.BufferData[0])
            gl.TexImage2D(TextureTarget.Texture2D, 0, (int)InternalFormat.Red, (uint)bitmap.Width, (uint)bitmap.Rows, 0, PixelFormat.Red, PixelType.UnsignedByte, i);

            gl.PixelStore(GLEnum.UnpackAlignment, 4);
        }
Пример #13
0
        /// <summary>
        ///     Renders the given glyph.
        /// </summary>
        /// <param name="c">The character code (Unicode) of the character to render.</param>
        /// <param name="bitmapLeft">
        ///     The x-Bearing of the glyph on the bitmap (in pixels). The number of pixels from the left border of the image
        ///     to the leftmost pixel of the glyph within the rendered image.
        /// </param>
        /// <param name="bitmapTop">
        ///     The y-Bearing of the glyph on the bitmap (in pixels). The number of pixels from the character's origin
        ///     (base line) of the image to the topmost pixel of the glyph within the rendered image.
        /// </param>
        /// <returns>
        ///     An image data structure containing an image of the given character.
        /// </returns>
        public IImageData RenderGlyph(uint c, out int bitmapLeft, out int bitmapTop)
        {
            _face.LoadChar(c, LoadFlags.Default, LoadTarget.Normal);
            _face.Glyph.RenderGlyph(RenderMode.Normal);

            FTBitmap bmp = _face.Glyph.Bitmap;

            byte[] pixelData = new byte[0]; // empty??
            if (bmp.Width != 0 && bmp.Rows != 0)
            {
                pixelData = new byte[bmp.BufferData.Length];
                Array.Copy(bmp.BufferData, pixelData, bmp.BufferData.Length);
            }

            ImageData ret = new ImageData(pixelData, bmp.Width, bmp.Rows,
                                          new ImagePixelFormat(ColorFormat.Intensity));

            bitmapLeft = _face.Glyph.BitmapLeft;
            bitmapTop  = _face.Glyph.BitmapTop;
            return(ret);
        }
Пример #14
0
        private void CopyBitmap(FTBitmap bitmap, Color4[] pixels, int x, int y)
        {
            if (bitmap.PixelMode != PixelMode.Gray)
            {
                throw new System.Exception("Invalid pixel mode: " + bitmap.PixelMode);
            }
            if (bitmap.Pitch != bitmap.Width)
            {
                throw new System.Exception("Bitmap pitch doesn't match its width");
            }
            var data = bitmap.BufferData;
            var t    = 0;

            for (int i = 0; i < bitmap.Rows; i++)
            {
                int w = (y + i) * TextureSize + x;
                for (int j = 0; j < bitmap.Width; j++)
                {
                    pixels[w++] = new Color4(255, 255, 255, data[t++]);
                }
            }
        }
Пример #15
0
        public static Bitmap Convert(this FTBitmap ftbmp, Color color, uint charCode)
        {
            switch (ftbmp.PixelMode)
            {
            case PixelMode.Mono:
                return(FromMono(ftbmp, color));

            case PixelMode.Gray4:
                throw new NotImplementedException();

            case PixelMode.Gray:
                return(FromGray(ftbmp, color));

            case PixelMode.Lcd:
                throw new NotImplementedException();

            default:
#if NET45
                return(ftbmp.ToGdipBitmap());
#else
                throw new NotImplementedException();
#endif
            }
        }
Пример #16
0
        private int renderCharacter(Face face, char character, int posX, int posY, int atlas, FontInfo info, Graphics graphics)
        {
            uint index = face.GetCharIndex(character);

            face.LoadGlyph(index, LoadFlags.Default, LoadTarget.Normal);
            face.Glyph.RenderGlyph(RenderMode.Normal);

            GlyphMetrics metrics    = face.Glyph.Metrics;
            int          width      = metrics.Width.ToInt32() + metrics.HorizontalBearingX.ToInt32();
            int          xAdvance   = metrics.HorizontalAdvance.ToInt32();
            int          yoffset    = metrics.VerticalAdvance.ToInt32() - metrics.HorizontalBearingY.ToInt32();
            int          charHeight = metrics.Height.ToInt32();

            if (face.Glyph.Bitmap.Width > 0)
            {
                FTBitmap ftbmp = face.Glyph.Bitmap;
                Bitmap   copy  = ftbmp.ToGdipBitmap(Color.White);
                graphics.DrawImageUnscaled(copy, posX + metrics.HorizontalBearingX.ToInt32(), posY);
            }

            info.addCharacter(new CharacterInfo(character, posX, posY, width, charHeight, xAdvance, yoffset, atlas));

            return(width);
        }
Пример #17
0
        /// <summary>
        ///     Renders the given glyph.
        /// </summary>
        /// <param name="c">The character code (Unicode) of the character to render.</param>
        /// <param name="bitmapLeft">
        ///     The x-Bearing of the glyph on the bitmap (in pixels). The number of pixels from the left border of the image
        ///     to the leftmost pixel of the glyph within the rendered image.
        /// </param>
        /// <param name="bitmapTop">
        ///     The y-Bearing of the glyph on the bitmap (in pixels). The number of pixels from the character's origin
        ///     (base line) of the image to the topmost pixel of the glyph within the rendered image.
        /// </param>
        /// <returns>
        ///     An image data structure containing an image of the given character.
        /// </returns>
        public ImageData RenderGlyph(uint c, out int bitmapLeft, out int bitmapTop)
        {
            _face.LoadChar(c, LoadFlags.Default, LoadTarget.Normal);
            _face.Glyph.RenderGlyph(RenderMode.Normal);

            FTBitmap bmp = _face.Glyph.Bitmap;

            ImageData ret = new ImageData
            {
                Height      = bmp.Rows,
                Width       = bmp.Width,
                Stride      = bmp.Width,
                PixelFormat = ImagePixelFormat.Intensity,
            };

            if (!ret.IsEmpty)
            {
                ret.PixelData = new byte[bmp.BufferData.Length];
                Array.Copy(bmp.BufferData, ret.PixelData, bmp.BufferData.Length);
            }
            bitmapLeft = _face.Glyph.BitmapLeft;
            bitmapTop  = _face.Glyph.BitmapTop;
            return(ret);
        }
Пример #18
0
        public Bitmap test_draw(string teststrings)
        {
            //teststrings = teststrings.Replace("\n" , "");
            //teststrings = teststrings.Replace("\r", "");
            Library library = new Library();
            Face    face    = library.NewFace(fontName, 0);


            Bitmap   bmp = new Bitmap((int)Math.Ceiling((double)image_width), (int)Math.Ceiling((double)image_height));
            Graphics g   = Graphics.FromImage(bmp);

            g.Clear(GlobalSettings.cBgColor);
            //g.Clear(Color.Black);
            int x = 0, y = 0;

            for (int i = 0; i < teststrings.ToCharArray().Length; i++)
            {
                string currentChar0 = teststrings.ToCharArray()[i].ToString();
                uint   glyphIndex   = face.GetCharIndex(uchar2code(currentChar0));



                if (this.fontHeight <= 14)
                {
                    face.SetPixelSizes((uint)0, (uint)this.fontHeight);
                    face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                    face.Glyph.RenderGlyph(RenderMode.Normal);
                }
                else
                {
                    face.SetCharSize(0, this.fontHeight, 0, 72);
                    face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd);
                    face.Glyph.RenderGlyph(RenderMode.Lcd);
                }

                //获取字符对齐
                float left, right, top, bottom, FHT;
                int   FHD, kx, ky;

                left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                FHT    = this.fontHeight;
                FHD    = (int)Math.Ceiling(FHT);
                kx     = x + face.Glyph.BitmapLeft;
                ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));

                //选择渲染模式(1倍 or 2倍)
                if (this.grender_mode == "freetype_nearestneighbor")
                {
                    face.SetCharSize(0, this.fontHeight * 2, 0, 72);
                    face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd);
                    face.Glyph.RenderGlyph(RenderMode.Lcd);
                    left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                    right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                    top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                    bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                    FHT    = this.fontHeight;
                    FHD    = (int)Math.Ceiling(FHT);
                    kx     = x + face.Glyph.BitmapLeft;
                    ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));


                    kx = x + face.Glyph.BitmapLeft;
                    ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY));
                    FTBitmap ftbmp = face.Glyph.Bitmap;
                    if (ftbmp.Width == 0)
                    {
                        x += this.tile_width;
                        if (x + this.tile_width > this.image_width)
                        {
                            x  = 0;
                            y += this.tile_height;
                        }
                        continue;
                    }

                    Bitmap tmpBmp = ftbmp.ToGdipBitmap(this.penColor);

                    tmpBmp = kPasteImage(tmpBmp, tile_width * 2, tile_height * 2, (int)face.Glyph.BitmapLeft,
                                         (int)Math.Round(((float)this.fontHeight * 2 - face.Glyph.BitmapTop)));

                    Bitmap cBmp = kResizeImage(tmpBmp, tmpBmp.Width / 2, tmpBmp.Height / 2, System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor);
                    Bitmap nBmp = gray2alpha(cBmp);
                    cBmp.Dispose();

                    g.DrawImageUnscaled(nBmp, x + GlobalSettings.relativePositionX, y + GlobalSettings.relativePositionY);
                    nBmp.Dispose();
                }
                else if (this.grender_mode == "freetype_HighQualityBicubic")
                {
                    face.SetCharSize(0, this.fontHeight * 2, 0, 72);
                    face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                    face.Glyph.RenderGlyph(RenderMode.Normal);
                    left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                    right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                    top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                    bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                    FHT    = this.fontHeight;
                    FHD    = (int)Math.Ceiling(FHT);
                    kx     = x + face.Glyph.BitmapLeft;
                    ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));


                    kx = x + face.Glyph.BitmapLeft;
                    ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY));
                    FTBitmap ftbmp = face.Glyph.Bitmap;
                    if (ftbmp.Width == 0)
                    {
                        x += this.tile_width;
                        if (x + this.tile_width > this.image_width)
                        {
                            x  = 0;
                            y += this.tile_height;
                        }
                        continue;
                    }

                    Bitmap tmpBmp = ftbmp.ToGdipBitmap(this.penColor);

                    tmpBmp = kPasteImage(tmpBmp, tile_width * 2, tile_height * 2, (int)face.Glyph.BitmapLeft,
                                         (int)Math.Round(((float)this.fontHeight * 2 - face.Glyph.BitmapTop)));

                    Bitmap cBmp = kResizeImage(tmpBmp, tmpBmp.Width / 2, tmpBmp.Height / 2, System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic);
                    Bitmap nBmp = gray2alpha(cBmp);
                    cBmp.Dispose();

                    g.DrawImageUnscaled(nBmp, x + GlobalSettings.relativePositionX, y + GlobalSettings.relativePositionY);
                    nBmp.Dispose();
                }
                else if (this.grender_mode == "freetype_drawtwice")
                {
                    face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                    face.Glyph.RenderGlyph(RenderMode.Normal);
                    left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                    right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                    top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                    bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                    FHT    = this.fontHeight;
                    FHD    = (int)Math.Ceiling(FHT);
                    kx     = x + face.Glyph.BitmapLeft;
                    ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));


                    kx = x + face.Glyph.BitmapLeft;
                    ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY));
                    FTBitmap ftbmp = face.Glyph.Bitmap;
                    if (ftbmp.Width == 0)
                    {
                        x += this.tile_width;
                        if (x + this.tile_width > this.image_width)
                        {
                            x  = 0;
                            y += this.tile_height;
                        }
                        continue;
                    }

                    //这是一个临时描边的功能,还没有添加到UI
                    if (GlobalSettings.bUseOutlineEffect == true)
                    {
                        Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor);
                        face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                        face.Glyph.Outline.Embolden(2);
                        face.Glyph.RenderGlyph(RenderMode.Normal);

                        left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                        right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                        top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                        bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                        FHT    = this.fontHeight;
                        FHD    = (int)Math.Ceiling(FHT);
                        kx     = x + face.Glyph.BitmapLeft;
                        ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));

                        kx = x + face.Glyph.BitmapLeft;
                        ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY));
                        FTBitmap ftbmp1 = face.Glyph.Bitmap;
                        Bitmap   sBmp   = ftbmp1.ToGdipBitmap(GlobalSettings.cShadowColor);
                        Bitmap   nBmp   = gray2alpha(cBmp);
                        //Bitmap s2Bmp = gray2alpha(sBmp);

                        g.DrawImageUnscaled(sBmp, kx + GlobalSettings.relativePositionX - 1, ky + GlobalSettings.relativePositionY - 1);//draw twice
                        g.DrawImageUnscaled(nBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY);
                        cBmp.Dispose();
                        nBmp.Dispose();
                        sBmp.Dispose();
                    }
                    else
                    {
                        Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor);
                        face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                        face.Glyph.RenderGlyph(RenderMode.Normal);
                        left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                        right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                        top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                        bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                        FHT    = this.fontHeight;
                        FHD    = (int)Math.Ceiling(FHT);
                        kx     = x + face.Glyph.BitmapLeft;
                        ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));


                        kx = x + face.Glyph.BitmapLeft;
                        ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY));
                        FTBitmap ftbmp1 = face.Glyph.Bitmap;
                        Bitmap   sBmp   = ftbmp1.ToGdipBitmap(this.penColor);
                        Bitmap   nBmp   = gray2alpha(cBmp);
                        sBmp = gray2alpha(sBmp);
                        g.DrawImageUnscaled(sBmp, kx + GlobalSettings.relativePositionX - 1, ky + GlobalSettings.relativePositionY - 1);//draw twice
                        g.DrawImageUnscaled(nBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY);
                        cBmp.Dispose();
                        nBmp.Dispose();
                        sBmp.Dispose();
                    }
                }
                else if (this.grender_mode == "freetype_nosmoothing")
                {
                    face.SetPixelSizes((uint)0, (uint)this.fontHeight);
                    face.LoadGlyph(glyphIndex, LoadFlags.Monochrome, LoadTarget.Mono);
                    face.Glyph.RenderGlyph(RenderMode.Mono);
                    left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                    right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                    top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                    bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                    FHT    = this.fontHeight;
                    FHD    = (int)Math.Ceiling(FHT);
                    kx     = x + face.Glyph.BitmapLeft;
                    ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));

                    kx = x + face.Glyph.BitmapLeft;
                    ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY));
                    FTBitmap ftbmp = face.Glyph.Bitmap;
                    if (ftbmp.Width == 0)
                    {
                        x += this.tile_width;
                        if (x + this.tile_width > this.image_width)
                        {
                            x  = 0;
                            y += this.tile_height;
                        }
                        continue;
                    }
                    Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor);
                    g.DrawImageUnscaled(cBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY);
                    cBmp.Dispose();
                }


                else
                {
                    face.SetCharSize(0, this.fontHeight, 0, 72);
                    if (GlobalSettings.iFontBold > (float)0)
                    {
                        //临时加粗face.Glyph.Outline.Embolden(0.4);值要小于1,不然很丑
                        face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                        face.Glyph.Outline.Embolden(0.4);
                        face.Glyph.RenderGlyph(RenderMode.Normal);
                        left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                        right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                        top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                        bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                        FHT    = this.fontHeight;
                        FHD    = (int)Math.Ceiling(FHT);
                        kx     = x + face.Glyph.BitmapLeft;
                        ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));


                        kx = x + face.Glyph.BitmapLeft;
                        ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY));
                    }



                    FTBitmap ftbmp = face.Glyph.Bitmap;


                    if (ftbmp.Width == 0)
                    {
                        x += this.tile_width;
                        if (x + this.tile_width > this.image_width)
                        {
                            x  = 0;
                            y += this.tile_height;
                        }
                        continue;
                    }
                    if (GlobalSettings.bUseOutlineEffect == true)
                    {
                        Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor);
                        face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                        face.Glyph.Outline.Embolden(2);
                        face.Glyph.RenderGlyph(RenderMode.Normal);
                        left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                        right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                        top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                        bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;
                        FHT    = this.fontHeight;
                        FHD    = (int)Math.Ceiling(FHT);
                        kx     = x + face.Glyph.BitmapLeft;
                        ky     = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop));


                        kx = x + face.Glyph.BitmapLeft;
                        ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY));
                        FTBitmap ftbmp1 = face.Glyph.Bitmap;
                        Bitmap   sBmp   = ftbmp1.ToGdipBitmap(GlobalSettings.cShadowColor);
                        Bitmap   nBmp   = gray2alpha(cBmp);
                        //Bitmap s2Bmp = gray2alpha(sBmp);
                        g.DrawImageUnscaled(sBmp, kx + GlobalSettings.relativePositionX - 1, ky + GlobalSettings.relativePositionY - 1);//draw twice
                        g.DrawImageUnscaled(nBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY);
                        cBmp.Dispose();
                        nBmp.Dispose();
                        sBmp.Dispose();
                    }
                    else
                    {
                        Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor);
                        Bitmap nBmp = gray2alpha(cBmp);
                        cBmp.Dispose();
                        g.DrawImageUnscaled(nBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY);
                        nBmp.Dispose();
                    }
                }


                x += this.tile_width;
                if (x + this.tile_width > this.image_width)
                {
                    x  = 0;
                    y += this.tile_height;
                }
            }
            g.Dispose();
            library.Dispose();
            return(bmp);
        }
Пример #19
0
 /// <summary>
 /// Copies the contents of the <see cref="FTBitmap"/> to a GDI+ <see cref="Bitmap"/>.
 /// </summary>
 /// <returns>A GDI+ <see cref="Bitmap"/> containing this bitmap's data.</returns>
 public static Bitmap ToGdipBitmap(this FTBitmap ftBitmap)
 {
     return(ToGdipBitmap(ftBitmap, Color.Black));
 }
Пример #20
0
        public Table.XYWH[] GetXYWHTable(string fTextStrings)
        {
            Library library = new Library();
            Face    face    = library.NewFace(fontName, 0);

            face.SetCharSize(0, this.fontHeight, 0, 72);


            List <Table.XYWH> tmp     = new List <Table.XYWH>();
            StringReader      fReader = new StringReader(fTextStrings);
            int img_nums;
            int chars_per_page = (image_width / tile_width) * (image_height / tile_height);

            if (fTextStrings.Length < (chars_per_page))
            {
                img_nums = 1;
            }
            else
            {
                img_nums = (fTextStrings.Length / chars_per_page);
                if ((fTextStrings.Length % chars_per_page) > 0)
                {
                    img_nums = (fTextStrings.Length / chars_per_page) + 1;
                }
            }
            for (int i = 0; i < img_nums; i++)
            {
                int    pos = 0;
                string currentString;
                if (i != img_nums - 1)
                {
                    char[] buffer = new char[chars_per_page];
                    fReader.Read(buffer, pos, chars_per_page);
                    currentString = new string(buffer);
                    pos          += currentString.Length;
                }
                else
                {
                    currentString = fReader.ReadToEnd();
                }
                currentString = currentString.Replace("\n", "");
                currentString = currentString.Replace("\r", "");

                int x = 0, y = 0;
                for (int n = 0; n < currentString.ToCharArray().Length; n++)
                {
                    Table.XYWH currentXYWH = new Table.XYWH();
                    currentXYWH.x_pos    = (uint)x;
                    currentXYWH.y_pos    = (uint)y;
                    currentXYWH.page_num = (uint)i + 1;
                    string currentChar0 = currentString.ToCharArray()[n].ToString();
                    uint   char_code    = uchar2code(currentChar0);
                    uint   glyphIndex   = face.GetCharIndex(uchar2code(currentChar0));
                    currentXYWH.charid = char_code; //set charid
                    face.LoadChar((uint)glyphIndex, LoadFlags.Render, LoadTarget.Lcd);
                    face.LoadGlyph((uint)glyphIndex, LoadFlags.Render, LoadTarget.Lcd);
                    face.Glyph.RenderGlyph(RenderMode.Lcd);

                    FTBitmap ftbmp = face.Glyph.Bitmap;
                    if (ftbmp.Width == 0)
                    {
                        currentXYWH.c_width = (uint)tile_width;
                    }
                    else
                    {
                        float advance = (float)face.Glyph.Metrics.HorizontalAdvance;
                        if (advance >= (float)tile_width)
                        {
                            currentXYWH.c_width = (uint)tile_width;
                        }
                        else
                        {
                            currentXYWH.c_width = (uint)face.Glyph.BitmapLeft + (uint)((float)face.Glyph.Metrics.HorizontalBearingX +
                                                                                       (float)GlobalSettings.relativePositionX +
                                                                                       (float)face.Glyph.Metrics.Width);
                        }
                    }
                    //currentXYWH.c_width = (uint)((float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width);//set c_width
                    if (char_code == (uint)32)
                    {
                        currentXYWH.c_width = (uint)tile_width / 2 - 1;
                    }
                    else if ((char_code <= (uint)0x3000) && (char_code >= (uint)0x7e))
                    {
                        currentXYWH.c_width = (uint)tile_width;
                    }

                    else if (char_code >= (uint)8000)
                    {
                        currentXYWH.c_width = (uint)tile_width;
                    }
                    currentXYWH.c_height = (uint)tile_height;
                    tmp.Add(currentXYWH);
                    x += this.tile_width;
                    if (x + this.tile_width > this.image_width)
                    {
                        x  = 0;
                        y += this.tile_height;
                    }

                    ftbmp.Dispose();
                }
            }
            return(tmp.ToArray());
        }
Пример #21
0
        public NISFont DrawT3BFontBitmap(char[] strings)
        {
            NISFont  fnt_data = new NISFont();
            Bitmap   bmp      = new Bitmap(Config.texture_width, Config.texture_height);
            Graphics g        = Graphics.FromImage(bmp);

            g.Clear(Color.FromArgb(0x00000000));
            int     x = 0, y = 0;
            int     tile_w = Config.fontWidth;
            int     tile_h = Config.fontHeight;
            int     relativePositionX = 1;
            int     relativePositionY = -2;
            int     font_height = Config.fontSize;
            Library library = new Library();
            string  facename = Config.ttfName;
            Face    face = library.NewFace(facename, 0);
            float   left, right, top, bottom, FHT;
            int     FHD, kx, ky;

            foreach (char currentChar0 in strings)
            {
                uint charid = uchar2code(currentChar0.ToString());
                face.SetCharSize(0, font_height, 0, 72);
                if (charid < 0x7f)
                {
                    font_height = Config.fontSize - 2;
                    face.SetCharSize(0, font_height, 0, 72);
                }
                else
                {
                    font_height = Config.fontSize;
                }
                face.SetPixelSizes((uint)0, (uint)font_height);

                uint glyphIndex = face.GetCharIndex(charid);

                //Console.WriteLine(glyphIndex);
                face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Lcd);
                face.Glyph.Outline.Embolden(0.5);
                face.Glyph.RenderGlyph(RenderMode.Normal);

                FTBitmap ftbmp  = face.Glyph.Bitmap;
                FTBitmap ftbmp2 = face.Glyph.Bitmap;

                left   = (float)face.Glyph.Metrics.HorizontalBearingX;
                right  = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width;
                top    = (float)face.Glyph.Metrics.HorizontalBearingY;
                bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height;

                FHT = font_height;
                FHD = (int)Math.Ceiling(FHT);
                kx  = x + (int)Math.Round(left);
                ky  = (int)Math.Round((float)y + (float)Math.Ceiling(FHT) - (float)top);


                if (ftbmp.Width == 0 || glyphIndex < 0x20)
                {
                    Face face1 = library.NewFace(Config.baseName, 0);
                    face1.SetCharSize(0, font_height, 0, 72);
                    face1.SetPixelSizes((uint)0, (uint)font_height);
                    glyphIndex = face1.GetCharIndex(charid);
                    face1.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Lcd);
                    face1.Glyph.Outline.Embolden(Fixed26Dot6.FromDouble(0.4));
                    face1.Glyph.RenderGlyph(RenderMode.Normal);

                    left   = (float)face1.Glyph.Metrics.HorizontalBearingX;
                    right  = (float)face1.Glyph.Metrics.HorizontalBearingX + (float)face1.Glyph.Metrics.Width;
                    top    = (float)face1.Glyph.Metrics.HorizontalBearingY;
                    bottom = (float)face1.Glyph.Metrics.HorizontalBearingY + (float)face1.Glyph.Metrics.Height;

                    FHT    = font_height;
                    FHD    = (int)Math.Ceiling(FHT);
                    kx     = x + (int)Math.Round(left);
                    ky     = (int)Math.Round((float)y + (float)Math.Ceiling(FHT) - (float)top);
                    ftbmp  = face1.Glyph.Bitmap;
                    ftbmp2 = face1.Glyph.Bitmap;
                }

                fnt_data.charvalues.Add(new XYWH((int)uchar2code(currentChar0.ToString()),
                                                 x,
                                                 y,
                                                 tile_w,
                                                 tile_h,
                                                 0));

                if (ftbmp2.Width == 0)
                {
                    x += tile_w;
                    if (x + tile_w > Config.texture_width)
                    {
                        x  = 0;
                        y += tile_h;
                    }
                    continue;
                }
                Bitmap cBmp = ftbmp2.ToGdipBitmap(Color.White);
                g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY);
                g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY);
                cBmp.Dispose();



                x += tile_w;
                if (x + tile_w > Config.texture_width)
                {
                    x  = 0;
                    y += tile_h;
                }
            }
            fnt_data.bitmap = bmp;
            return(fnt_data);
        }
Пример #22
0
        private unsafe void CopyFTBitmapToAtlas_LcdRGB(uint *targetPtr, int offsetX, int offsetY, int targetWidth, FTBitmap bmp, int width, int height)
        {
            var bmpPtr = (byte *)bmp.Buffer;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++, targetPtr++, bmpPtr += 3)
                {
                    uint value     = *(uint *)(bmpPtr) >> 8;
                    *    targetPtr = 0xFF000000 | value;
                }
                targetPtr += targetWidth - width;
            }
        }
Пример #23
0
        private unsafe void CopyFTBitmapToAtlas_BGRA(uint *targetPtr, int offsetX, int offsetY, int targetWidth, FTBitmap bmp, int width, int height)
        {
            var bmpPtr = (uint *)bmp.Buffer;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++, targetPtr++, bmpPtr++)
                {
                    uint value = *(uint *)(bmpPtr);
                    //A | R | G | B
                    *targetPtr = (value << 24) | (value >> 24) | (value << 8) & 0xFF0000 | (value >> 8) & 0xFF;
                }
                targetPtr += targetWidth - width;
            }
        }
Пример #24
0
        private unsafe void CopyFTBitmapToAtlas_Gray(uint *targetPtr, int offsetX, int offsetY, int targetWidth, FTBitmap bmp, int width, int height)
        {
            var bmpPtr = (byte *)bmp.Buffer;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++, targetPtr++, bmpPtr++)
                {
                    byte value     = *bmpPtr;
                    *    targetPtr = (uint)(value << 24) | 0xFFFFFFu;
                }
                targetPtr += targetWidth - width;
            }
        }
Пример #25
0
        private unsafe void CopyFTBitmapToAtlas_Gray4(uint *targetPtr, int offsetX, int offsetY, int targetWidth, FTBitmap bmp, int width, int height, int padding)
        {
            //TODO: implement
            var bmpPtr = (byte *)bmp.Buffer;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++, targetPtr++, bmpPtr++)
                {
                    byte value     = *bmpPtr;
                    *    targetPtr = (uint)(value << 24) | 0xFFFFFFu; //value > 0 ? 255<< 24: 0;
                }
                targetPtr += targetWidth - width;
                bmpPtr    += padding;
            }
        }
Пример #26
0
        private unsafe void CopyFTBitmapToAtlas_Mono(uint *targetPtr, int offsetX, int offsetY, int targetWidth, FTBitmap bmp, int width, int height)
        {
            var bmpPtr   = (byte *)bmp.Buffer;
            int subIndex = 0;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++, targetPtr++, subIndex++, bmpPtr++)
                {
                    if ((((*bmpPtr) >> subIndex) & 0x1) != 0)
                    {
                        *targetPtr = 0xFFFFFFFF;
                    }
                    if (subIndex == 8)
                    {
                        subIndex = 0;
                    }
                }
                targetPtr += targetWidth - width;
            }
        }
Пример #27
0
        internal static Bitmap RenderString(Library library, Face face, string text, Color foreColor, Color backColor)
        {
            var   measuredChars = new List <DebugChar>();
            var   renderedChars = new List <DebugChar>();
            float penX = 0, penY = 0;
            float stringWidth      = 0; // the measured width of the string
            float stringHeight     = 0; // the measured height of the string
            float overrun          = 0;
            float underrun         = 0;
            float kern             = 0;
            int   spacingError     = 0;
            bool  trackingUnderrun = true;
            int   rightEdge        = 0; // tracking rendered right side for debugging

            // Bottom and top are both positive for simplicity.
            // Drawing in .Net has 0,0 at the top left corner, with positive X to the right
            // and positive Y downward.
            // Glyph metrics have an origin typically on the left side and at baseline
            // of the visual data, but can draw parts of the glyph in any quadrant, and
            // even move the origin (via kerning).
            float top = 0, bottom = 0;

            // Measure the size of the string before rendering it. We need to do this so
            // we can create the proper size of bitmap (canvas) to draw the characters on.
            for (int i = 0; i < text.Length; i++)
            {
                #region Load character
                char c = text[i];

                // Look up the glyph index for this character.
                uint glyphIndex = face.GetCharIndex(c);

                // Load the glyph into the font's glyph slot. There is usually only one slot in the font.
                face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);

                // Refer to the diagram entitled "Glyph Metrics" at http://www.freetype.org/freetype2/docs/tutorial/step2.html.
                // There is also a glyph diagram included in this example (glyph-dims.svg).
                // The metrics below are for the glyph loaded in the slot.
                float gAdvanceX = (float)face.Glyph.Advance.X; // same as the advance in metrics
                float gBearingX = (float)face.Glyph.Metrics.HorizontalBearingX;
                //float gWidth = face.Glyph.Metrics.Width.ToSingle();
                float gWidth = face.Glyph.Metrics.Width;
                var   rc     = new DebugChar(c, gAdvanceX, gBearingX, gWidth);
                #endregion
                #region Underrun
                // Negative bearing would cause clipping of the first character
                // at the left boundary, if not accounted for.
                // A positive bearing would cause empty space.
                underrun += -(gBearingX);
                if (stringWidth == 0)
                {
                    stringWidth += underrun;
                }
                if (trackingUnderrun)
                {
                    rc.Underrun = underrun;
                }
                if (trackingUnderrun && underrun <= 0)
                {
                    underrun         = 0;
                    trackingUnderrun = false;
                }
                #endregion
                #region Overrun
                // Accumulate overrun, which coould cause clipping at the right side of characters near
                // the end of the string (typically affects fonts with slanted characters)
                if (gBearingX + gWidth > 0 || gAdvanceX > 0)
                {
                    overrun -= Math.Max(gBearingX + gWidth, gAdvanceX);
                    if (overrun <= 0)
                    {
                        overrun = 0;
                    }
                }
                overrun += (float)(gBearingX == 0 && gWidth == 0 ? 0 : gBearingX + gWidth - gAdvanceX);
                // On the last character, apply whatever overrun we have to the overall width.
                // Positive overrun prevents clipping, negative overrun prevents extra space.
                if (i == text.Length - 1)
                {
                    stringWidth += overrun;
                }
                rc.Overrun = overrun; // accumulating (per above)
                #endregion

                #region Top/Bottom
                // If this character goes higher or lower than any previous character, adjust
                // the overall height of the bitmap.
                float glyphTop    = (float)face.Glyph.Metrics.HorizontalBearingY;
                float glyphBottom = (float)(face.Glyph.Metrics.Height - face.Glyph.Metrics.HorizontalBearingY);
                if (glyphTop > top)
                {
                    top = glyphTop;
                }
                if (glyphBottom > bottom)
                {
                    bottom = glyphBottom;
                }
                #endregion

                // Accumulate the distance between the origin of each character (simple width).
                stringWidth += gAdvanceX;
                rc.RightEdge = stringWidth;
                measuredChars.Add(rc);

                #region Kerning (for NEXT character)
                // Calculate kern for the NEXT character (if any)
                // The kern value adjusts the origin of the next character (positive or negative).
                if (face.HasKerning && i < text.Length - 1)
                {
                    char cNext = text[i + 1];
                    kern = (float)face.GetKerning(glyphIndex, face.GetCharIndex(cNext), KerningMode.Default).X;
                    // sanity check for some fonts that have kern way out of whack
                    if (kern > gAdvanceX * 5 || kern < -(gAdvanceX * 5))
                    {
                        kern = 0;
                    }
                    rc.Kern      = kern;
                    stringWidth += kern;
                }

                #endregion
            }

            stringHeight = top + bottom;

            // If any dimension is 0, we can't create a bitmap
            if (stringWidth == 0 || stringHeight == 0)
            {
                return(null);
            }

            // Create a new bitmap that fits the string.
            Bitmap bmp = new Bitmap((int)Math.Ceiling(stringWidth), (int)Math.Ceiling(stringHeight));
            trackingUnderrun = true;
            underrun         = 0;
            overrun          = 0;
            stringWidth      = 0;
            using (var g = Graphics.FromImage(bmp))
            {
                #region Set up graphics
                // HighQuality and GammaCorrected both specify gamma correction be applied (2.2 in sRGB)
                // https://msdn.microsoft.com/en-us/library/windows/desktop/ms534094(v=vs.85).aspx
                g.CompositingQuality = CompositingQuality.HighQuality;
                // HighQuality and AntiAlias both specify antialiasing
                g.SmoothingMode = SmoothingMode.HighQuality;
                // If a background color is specified, blend over it.
                g.CompositingMode = CompositingMode.SourceOver;

                g.Clear(backColor);
                #endregion

                // Draw the string into the bitmap.
                // A lot of this is a repeat of the measuring steps, but this time we have
                // an actual bitmap to work with (both canvas and bitmaps in the glyph slot).
                for (int i = 0; i < text.Length; i++)
                {
                    #region Load character
                    char c = text[i];

                    // Same as when we were measuring, except RenderGlyph() causes the glyph data
                    // to be converted to a bitmap.
                    uint glyphIndex = face.GetCharIndex(c);
                    face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                    face.Glyph.RenderGlyph(RenderMode.Normal);
                    FTBitmap ftbmp = face.Glyph.Bitmap;

                    float gAdvanceX = (float)face.Glyph.Advance.X;
                    float gBearingX = (float)face.Glyph.Metrics.HorizontalBearingX;
                    float gWidth    = (float)face.Glyph.Metrics.Width;

                    var rc = new DebugChar(c, gAdvanceX, gBearingX, gWidth);
                    #endregion
                    #region Underrun
                    // Underrun
                    underrun += -(gBearingX);
                    if (penX == 0)
                    {
                        penX += underrun;
                    }
                    if (trackingUnderrun)
                    {
                        rc.Underrun = underrun;
                    }
                    if (trackingUnderrun && underrun <= 0)
                    {
                        underrun         = 0;
                        trackingUnderrun = false;
                    }
                    #endregion
                    #region Draw glyph
                    // Whitespace characters sometimes have a bitmap of zero size, but a non-zero advance.
                    // We can't draw a 0-size bitmap, but the pen position will still get advanced (below).
                    if ((ftbmp.Width > 0 && ftbmp.Rows > 0))
                    {
                        // Get a bitmap that .Net can draw (GDI+ in this case).
                        Bitmap cBmp = ftbmp.ToGdipBitmap(foreColor);
                        rc.Width    = cBmp.Width;
                        rc.BearingX = face.Glyph.BitmapLeft;
                        int x = (int)Math.Round(penX + face.Glyph.BitmapLeft);
                        int y = (int)Math.Round(penY + top - (float)face.Glyph.Metrics.HorizontalBearingY);
                        //Not using g.DrawImage because some characters come out blurry/clipped. (Is this still true?)
                        g.DrawImageUnscaled(cBmp, x, y);
                        rc.Overrun = face.Glyph.BitmapLeft + cBmp.Width - gAdvanceX;
                        // Check if we are aligned properly on the right edge (for debugging)
                        rightEdge    = Math.Max(rightEdge, x + cBmp.Width);
                        spacingError = bmp.Width - rightEdge;
                    }
                    else
                    {
                        rightEdge    = (int)(penX + gAdvanceX);
                        spacingError = bmp.Width - rightEdge;
                    }
                    #endregion

                    #region Overrun
                    if (gBearingX + gWidth > 0 || gAdvanceX > 0)
                    {
                        overrun -= Math.Max(gBearingX + gWidth, gAdvanceX);
                        if (overrun <= 0)
                        {
                            overrun = 0;
                        }
                    }
                    overrun += (float)(gBearingX == 0 && gWidth == 0 ? 0 : gBearingX + gWidth - gAdvanceX);
                    if (i == text.Length - 1)
                    {
                        penX += overrun;
                    }
                    rc.Overrun = overrun;
                    #endregion

                    // Advance pen positions for drawing the next character.
                    penX += (float)face.Glyph.Advance.X; // same as Metrics.HorizontalAdvance?
                    penY += (float)face.Glyph.Advance.Y;

                    rc.RightEdge = penX;
                    spacingError = bmp.Width - (int)Math.Round(rc.RightEdge);
                    renderedChars.Add(rc);

                    #region Kerning (for NEXT character)
                    // Adjust for kerning between this character and the next.
                    if (face.HasKerning && i < text.Length - 1)
                    {
                        char cNext = text[i + 1];
                        kern = (float)face.GetKerning(glyphIndex, face.GetCharIndex(cNext), KerningMode.Default).X;
                        if (kern > gAdvanceX * 5 || kern < -(gAdvanceX * 5))
                        {
                            kern = 0;
                        }
                        rc.Kern = kern;
                        penX   += (float)kern;
                    }
                    #endregion
                }
            }
            bool printedHeader = false;
            if (spacingError != 0)
            {
                for (int i = 0; i < renderedChars.Count; i++)
                {
                    //if (measuredChars[i].RightEdge != renderedChars[i].RightEdge)
                    //{
                    if (!printedHeader)
                    {
                        DebugChar.PrintHeader();
                    }
                    printedHeader = true;
                    Debug.Print(measuredChars[i].ToString());
                    Debug.Print(renderedChars[i].ToString());
                    //}
                }
                string msg = string.Format("Right edge: {0,3} ({1}) {2}",
                                           spacingError,
                                           spacingError == 0 ? "perfect" : spacingError > 0 ? "space  " : "clipped",
                                           face.FamilyName);
                System.Diagnostics.Debug.Print(msg);
                //throw new ApplicationException(msg);
            }
            return(bmp);
        }
Пример #28
0
        private void Load()
        {
            //SizeMetrics fontSizeMetrics = Face.Size.Metrics;
            //Size glyphSlotSize = new Size(fontSizeMetrics.NominalWidth, fontSizeMetrics.Height.ToSingle());

            /*
             * FontFaceRenderMap renderMap = new FontFaceRenderMap(
             *  face,
             *  glyphSlotSize,
             *  fontSizeMetrics.NominalWidth,
             *  fontSizeMetrics.NominalHeight,
             *  fontSizeMetrics.Height.ToSingle(),
             *  fontSizeMetrics.Ascender.ToSingle(),
             *  fontSizeMetrics.Descender.ToSingle()
             * );
             */

            // adjust signs to respect Raccoon y-origin direction
            LineHeight         = ConvertPxToEm(Face.Size.Metrics.Height.ToSingle(), Size);
            Ascender           = -ConvertPxToEm(Face.Size.Metrics.Ascender.ToSingle(), Size);
            Descender          = Math.Abs(ConvertPxToEm(Face.Size.Metrics.Descender.ToSingle(), Size));
            UnderlinePosition  = Math.Abs(Face.UnderlinePosition / (float)Face.UnitsPerEM);
            UnderlineThickness = Face.UnderlineThickness / (float)Face.UnitsPerEM;

            // prepare texture
            int sideSize        = (int)(Util.Math.Ceiling(System.Math.Sqrt(Face.GlyphCount)) * GlyphSlotSize.Width),
                textureSideSize = Util.Math.CeilingPowerOfTwo(sideSize);

            if (Texture == null)
            {
                Texture = new Graphics.Texture(textureSideSize, textureSideSize);
            }
            else if (Texture.Width != textureSideSize || Texture.Height != textureSideSize)
            {
                Texture.Dispose();
                Texture = new Graphics.Texture(textureSideSize, textureSideSize);
            }

            // prepare texture data copying glyphs bitmaps
            Graphics.Color[] textureData = new Graphics.Color[textureSideSize * textureSideSize];

            Vector2 glyphPosition = Vector2.Zero;

            uint charCode = Face.GetFirstChar(out uint glyphIndex);

            while (glyphIndex != 0)
            {
                Face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                Face.Glyph.RenderGlyph(RenderMode.Normal);

                FTBitmap ftBitmap = Face.Glyph.Bitmap;

                if (ftBitmap != null && ftBitmap.Width > 0 && ftBitmap.Rows > 0)
                {
                    if (ftBitmap.PixelMode != PixelMode.Gray)
                    {
                        throw new System.NotImplementedException("Supported PixelMode formats are: Gray");
                    }

                    // tests if glyph bitmap actually fits on current row
#if TIGHT_PACK_FACE_RENDER_MAP
                    if (glyphPosition.X + ftBitmap.Width >= textureSideSize)
                    {
                        glyphPosition.Y += GlyphSlotSize.Height;
                        glyphPosition.X  = 0;
                    }
#else
                    if (glyphPosition.X + GlyphSlotSize.Width >= textureSideSize)
                    {
                        glyphPosition.Y += GlyphSlotSize.Height;
                        glyphPosition.X  = 0;
                    }
#endif

                    CopyBitmapToDestinationArea(textureData, textureSideSize, glyphPosition, ftBitmap);

                    RegisterGlyph(
                        charCode,
                        new Rectangle(
                            glyphPosition,
                            new Size(ftBitmap.Width, ftBitmap.Rows)
                            ),
                        -ConvertPxToEm(Face.Glyph.Metrics.HorizontalBearingX.ToDouble(), Size),
                        -ConvertPxToEm(Face.Glyph.Metrics.HorizontalBearingY.ToDouble(), Size),
                        ConvertPxToEm(Face.Glyph.Metrics.Width.ToDouble(), Size),
                        ConvertPxToEm(Face.Glyph.Metrics.Height.ToDouble(), Size),
                        ConvertPxToEm(Face.Glyph.Advance.X.ToDouble(), Size),
                        ConvertPxToEm(Face.Glyph.Advance.Y.ToDouble(), Size)
                        );

                    // advance to next glyph area
#if TIGHT_PACK_FACE_RENDER_MAP
                    glyphPosition.X += ftBitmap.Width;
#else
                    glyphPosition.X += GlyphSlotSize.Width;
#endif
                }
                else
                {
                    RegisterGlyph(
                        charCode,
                        Rectangle.Empty,
                        -ConvertPxToEm(Face.Glyph.Metrics.HorizontalBearingX.ToDouble(), Size),
                        -ConvertPxToEm(Face.Glyph.Metrics.HorizontalBearingY.ToDouble(), Size),
                        ConvertPxToEm(Face.Glyph.Metrics.Width.ToDouble(), Size),
                        ConvertPxToEm(Face.Glyph.Metrics.Height.ToDouble(), Size),
                        ConvertPxToEm(Face.Glyph.Advance.X.ToDouble(), Size),
                        ConvertPxToEm(Face.Glyph.Advance.Y.ToDouble(), Size)
                        );
                }

                charCode = Face.GetNextChar(charCode, out glyphIndex);
            }

            // render glyphs
            Texture.SetData(textureData);
        }
Пример #29
0
        public Texture2D RenderString(Face font, string text, Color4 foreColor, Color4 backColor, bool wrapText)
        {
            LineMetrics[] metrics = formatText(font, text, wrapText);

            float maxWidth = 0f, maxHeight = 0f, totalHeight = 0f;

            for (int lineIndex = 0; lineIndex < metrics.Length; lineIndex++)
            {
                LineMetrics lineMetric = metrics[lineIndex];
                maxWidth  = (lineMetric.Width > maxWidth) ? lineMetric.Width : maxWidth;
                maxHeight = (lineMetric.Height > maxHeight) ? lineMetric.Height : maxHeight;

                //Check is to ensure we don't have additional extra space accumulating beneath the texture for large Heights (commas being an example)
                totalHeight += (lineIndex < metrics.Length - 1) ? lineMetric.BaseHeight + LineSpacing : lineMetric.Height;

                metrics[lineIndex] = lineMetric;
            }

            //If any dimension is 0, we can't create a bitmap
            if (maxWidth <= 0 || totalHeight <= 0)
            {
                return(null);
            }

            //Create a new bitmap that fits the string.
            Bitmap bmp = new Bitmap((int)Math.Ceiling(maxWidth), (int)Math.Ceiling(totalHeight));

            using (var g = Graphics.FromImage(bmp))
            {
                #region Rendering Code
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.SmoothingMode      = SmoothingMode.HighQuality;
                g.CompositingMode    = CompositingMode.SourceOver;

                g.Clear((Color)backColor);

                //Draw the string into the bitmap.
                float lineOffset = 0f;
                for (int lineIndex = 0; lineIndex < metrics.Length; lineIndex++)
                {
                    LineMetrics lineMetrics = metrics[lineIndex];

                    //float xOffset = (maxWidth - lineMetrics.Width) / 2f; //Centered
                    float xOffset = 0f;
                    //float xOffset = maxWidth - lineMetrics.Width - 20f;

                    float penX = 0f, penY = 0f;
                    for (int i = 0; i < lineMetrics.Characters.Count; i++)
                    {
                        var  cm = lineMetrics.Characters[i];
                        char c  = cm.Character;

                        uint glyphIndex = font.GetCharIndex(c);
                        font.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                        font.Glyph.RenderGlyph(RenderMode.Normal);
                        FTBitmap ftbmp = font.Glyph.Bitmap;

                        //Underrun
                        if (penX == 0) //First character
                        {
                            penX += -(cm.BearingX);
                        }

                        //We can't draw a 0-size bitmap, but the pen position will still get advanced.
                        if (ftbmp.Width > 0 && ftbmp.Rows > 0)
                        {
                            using (Bitmap cBmp = ftbmp.ToGdipBitmap((Color)foreColor))
                            {
                                int x = (int)Math.Round(penX + cm.BearingX + xOffset);
                                int y = (int)Math.Round(penY + lineMetrics.Top - cm.BearingY + lineOffset);

                                g.DrawImageUnscaled(cBmp, x, y);
                            }
                        }

                        //Advance pen position for the next character
                        penX += cm.AdvanceX + cm.Kern;
                    }

                    lineOffset += lineMetrics.BaseHeight + LineSpacing;
                }
                #endregion
            }

            Texture2D texture = Texture2D.CreateFromBitmap(bmp);
            bmp.Dispose();

            return(texture);
        }
Пример #30
0
        /// <summary>
        /// Copies the contents of the <see cref="FTBitmap"/> to a GDI+ <see cref="Bitmap"/>.
        /// </summary>
        /// <param name="color">The color of the text.</param>
        /// <returns>A GDI+ <see cref="Bitmap"/> containing this bitmap's data with a transparent background.</returns>
        public static Bitmap ToGdipBitmap(this FTBitmap b, Color color)
        {
            if (b.IsDisposed)
            {
                throw new ObjectDisposedException("FTBitmap", "Cannot access a disposed object.");
            }

            if (b.Width == 0 || b.Rows == 0)
            {
                throw new InvalidOperationException("Invalid image size - one or both dimensions are 0.");
            }

            //TODO deal with negative pitch
            switch (b.PixelMode)
            {
            case PixelMode.Mono:
            {
                Bitmap bmp    = new Bitmap(b.Width, b.Rows, PixelFormat.Format1bppIndexed);
                var    locked = bmp.LockBits(new Rectangle(0, 0, b.Width, b.Rows), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);

                for (int i = 0; i < b.Rows; i++)
                {
                    Copy(b.Buffer, i * b.Pitch, locked.Scan0, i * locked.Stride, locked.Stride);
                }

                bmp.UnlockBits(locked);

                ColorPalette palette = bmp.Palette;
                palette.Entries[0] = Color.FromArgb(0, color);
                palette.Entries[1] = Color.FromArgb(255, color);

                bmp.Palette = palette;
                return(bmp);
            }

            case PixelMode.Gray4:
            {
                Bitmap bmp    = new Bitmap(b.Width, b.Rows, PixelFormat.Format4bppIndexed);
                var    locked = bmp.LockBits(new Rectangle(0, 0, b.Width, b.Rows), ImageLockMode.ReadWrite, PixelFormat.Format4bppIndexed);

                for (int i = 0; i < b.Rows; i++)
                {
                    Copy(b.Buffer, i * b.Pitch, locked.Scan0, i * locked.Stride, locked.Stride);
                }

                bmp.UnlockBits(locked);

                ColorPalette palette = bmp.Palette;
                for (int i = 0; i < palette.Entries.Length; i++)
                {
                    float a = (i * 17) / 255f;
                    palette.Entries[i] = Color.FromArgb(i * 17, (int)(color.R * a), (int)(color.G * a), (int)(color.B * a));
                }

                bmp.Palette = palette;
                return(bmp);
            }

            case PixelMode.Gray:
            {
                Bitmap bmp    = new Bitmap(b.Width, b.Rows, PixelFormat.Format8bppIndexed);
                var    locked = bmp.LockBits(new Rectangle(0, 0, b.Width, b.Rows), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

                for (int i = 0; i < b.Rows; i++)
                {
                    Copy(b.Buffer, i * b.Pitch, locked.Scan0, i * locked.Stride, locked.Stride);
                }

                bmp.UnlockBits(locked);

                ColorPalette palette = bmp.Palette;
                for (int i = 0; i < palette.Entries.Length; i++)
                {
                    float a = i / 255f;
                    palette.Entries[i] = Color.FromArgb(i, (int)(color.R * a), (int)(color.G * a), (int)(color.B * a));
                }

                //HACK There's a bug in Mono's libgdiplus requiring the "PaletteHasAlpha" flag to be set for transparency to work properly
                //See https://github.com/Robmaister/SharpFont/issues/62
                if (!hasCheckedForMono)
                {
                    hasCheckedForMono = true;
                    isRunningOnMono   = Type.GetType("Mono.Runtime") != null;
                    if (isRunningOnMono)
                    {
                        monoPaletteFlagsField = typeof(ColorPalette).GetField("flags", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                    }
                }

                if (isRunningOnMono)
                {
                    monoPaletteFlagsField.SetValue(palette, palette.Flags | 1);
                }

                bmp.Palette = palette;
                return(bmp);
            }

            case PixelMode.Lcd:
            {
                //TODO apply color
                int    bmpWidth = b.Width / 3;
                Bitmap bmp      = new Bitmap(bmpWidth, b.Rows, PixelFormat.Format24bppRgb);
                var    locked   = bmp.LockBits(new Rectangle(0, 0, bmpWidth, b.Rows), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                for (int i = 0; i < b.Rows; i++)
                {
                    Copy(b.Buffer, i * b.Pitch, locked.Scan0, i * locked.Stride, locked.Stride);
                }

                bmp.UnlockBits(locked);

                return(bmp);
            }

            /*case PixelMode.VerticalLcd:
             * {
             *      int bmpHeight = b.Rows / 3;
             *      Bitmap bmp = new Bitmap(b.Width, bmpHeight, PixelFormat.Format24bppRgb);
             *      var locked = bmp.LockBits(new Rectangle(0, 0, b.Width, bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
             *      for (int i = 0; i < bmpHeight; i++)
             *              PInvokeHelper.Copy(Buffer, i * b.Pitch, locked.Scan0, i * locked.Stride, b.Width);
             *      bmp.UnlockBits(locked);
             *
             *      return bmp;
             * }*/

            default:
                throw new InvalidOperationException("System.Drawing.Bitmap does not support this pixel mode.");
            }
        }