Using a BMP image as font in Monogame

三世轮回 提交于 2019-12-10 21:36:59

问题


Is there a way to load a custom font using a BMP image..

I have seen a solution online by Microsoft providing this, but i keep on getting content-load exception when trying to run this solution.

It seems like this used to work with XNA but might not be the case anymore with Monogame.

I want my own custom font, since this font won't be pre-installed on the computer of the client.

I already looked at XNB files from SpriteFont Converter, and that is not the solution i wish to aim for.

Any help will be appreciated, thanks


回答1:


After a Long while load of research, I ended up on finding a solution online. Here is a link to the tutorial : http://www.craftworkgames.com/blog/tutorial-bmfont-rendering-with-monogame/

This methods require you to download a software called bmFont : http://www.angelcode.com/products/bmfont/

With this software, you will receive an output of your Font as 2 files :

  1. .fnt file, used for the pattern in the texture
  2. .png file, which is the actual characters.

In order to make those files work with your monoproject (could work also with XNA i suppose), you need to add this class to your project (Note : You will need to change the namespace) :

// ---- AngelCode BmFont XML serializer ----------------------
// ---- By DeadlyDan @ deadlydan@gmail.com -------------------
// ---- There's no license restrictions, use as you will. ----
// ---- Credits to http://www.angelcode.com/ -----------------

using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Dashboard
{
    public class BmFont {

        String fontFilePath;
        FontFile fontFile;
        Texture2D fontTexture;
        FontRenderer _fontRenderer;

        public BmFont(String fontTexture, String png, ContentManager c) {
            fontFilePath = Path.Combine(c.RootDirectory, fontTexture);
            fontFile = FontLoader.Load(fontFilePath);
            this.fontTexture = c.Load<Texture2D>(png);
            _fontRenderer = new FontRenderer(fontFile, this.fontTexture);
        }

        public void draw(String message, Vector2 pos, SpriteBatch _spriteBatch) {
            _fontRenderer.DrawText(_spriteBatch, (int)pos.X, (int)pos.Y, message);
        }

    }


    public class FontRenderer
    {

        public static FontFile Load(Stream stream)
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(FontFile));
            FontFile file = (FontFile) deserializer.Deserialize(stream);
            return file;
        }

        public FontRenderer (FontFile fontFile, Texture2D fontTexture)
        {
            _fontFile = fontFile;
            _texture = fontTexture;
            _characterMap = new Dictionary<char, FontChar>();

            foreach(var fontCharacter in _fontFile.Chars)
            {
                char c = (char)fontCharacter.ID;
                _characterMap.Add(c, fontCharacter);
            }
        }

        private Dictionary<char, FontChar> _characterMap;
        private FontFile _fontFile;
        private Texture2D _texture;
        public void DrawText(SpriteBatch spriteBatch, int x, int y, string text)
        {
            int dx = x;
            int dy = y;
            foreach(char c in text)
            {
                FontChar fc;
                if(_characterMap.TryGetValue(c, out fc))
                {
                    var sourceRectangle = new Rectangle(fc.X, fc.Y, fc.Width, fc.Height);
                    var position = new Vector2(dx + fc.XOffset, dy + fc.YOffset);

                    spriteBatch.Draw(_texture, position, sourceRectangle, Color.White);
                    dx += fc.XAdvance;
                }
            }
        }
    }


    [Serializable]
    [XmlRoot ( "font" )]
    public class FontFile
    {
        [XmlElement ( "info" )]
        public FontInfo Info
        {
            get;
            set;
        }

        [XmlElement ( "common" )]
        public FontCommon Common
        {
            get;
            set;
        }

        [XmlArray ( "pages" )]
        [XmlArrayItem ( "page" )]
        public List<FontPage> Pages
        {
            get;
            set;
        }

        [XmlArray ( "chars" )]
        [XmlArrayItem ( "char" )]
        public List<FontChar> Chars
        {
            get;
            set;
        }

        [XmlArray ( "kernings" )]
        [XmlArrayItem ( "kerning" )]
        public List<FontKerning> Kernings
        {
            get;
            set;
        }
    }

    [Serializable]
    public class FontInfo
    {
        [XmlAttribute ( "face" )]
        public String Face
        {
            get;
            set;
        }

        [XmlAttribute ( "size" )]
        public Int32 Size
        {
            get;
            set;
        }

        [XmlAttribute ( "bold" )]
        public Int32 Bold
        {
            get;
            set;
        }

        [XmlAttribute ( "italic" )]
        public Int32 Italic
        {
            get;
            set;
        }

        [XmlAttribute ( "charset" )]
        public String CharSet
        {
            get;
            set;
        }

        [XmlAttribute ( "unicode" )]
        public Int32 Unicode
        {
            get;
            set;
        }

        [XmlAttribute ( "stretchH" )]
        public Int32 StretchHeight
        {
            get;
            set;
        }

        [XmlAttribute ( "smooth" )]
        public Int32 Smooth
        {
            get;
            set;
        }

        [XmlAttribute ( "aa" )]
        public Int32 SuperSampling
        {
            get;
            set;
        }

        private Rectangle _Padding;
        [XmlAttribute ( "padding" )]
        public String Padding
        {
            get
            {
                return _Padding.X + "," + _Padding.Y + "," + _Padding.Width + "," + _Padding.Height;
            }
            set
            {
                String[] padding = value.Split ( ',' );
                _Padding = new Rectangle ( Convert.ToInt32 ( padding[0] ), Convert.ToInt32 ( padding[1] ), Convert.ToInt32 ( padding[2] ), Convert.ToInt32 ( padding[3] ) );
            }
        }

        private Point _Spacing;
        [XmlAttribute ( "spacing" )]
        public String Spacing
        {
            get
            {
                return _Spacing.X + "," + _Spacing.Y;
            }
            set
            {
                String[] spacing = value.Split ( ',' );
                _Spacing = new Point ( Convert.ToInt32 ( spacing[0] ), Convert.ToInt32 ( spacing[1] ) );
            }
        }

        [XmlAttribute ( "outline" )]
        public Int32 OutLine
        {
            get;
            set;
        }
    }

    [Serializable]
    public class FontCommon
    {
        [XmlAttribute ( "lineHeight" )]
        public Int32 LineHeight
        {
            get;
            set;
        }

        [XmlAttribute ( "base" )]
        public Int32 Base
        {
            get;
            set;
        }

        [XmlAttribute ( "scaleW" )]
        public Int32 ScaleW
        {
            get;
            set;
        }

        [XmlAttribute ( "scaleH" )]
        public Int32 ScaleH
        {
            get;
            set;
        }

        [XmlAttribute ( "pages" )]
        public Int32 Pages
        {
            get;
            set;
        }

        [XmlAttribute ( "packed" )]
        public Int32 Packed
        {
            get;
            set;
        }

        [XmlAttribute ( "alphaChnl" )]
        public Int32 AlphaChannel
        {
            get;
            set;
        }

        [XmlAttribute ( "redChnl" )]
        public Int32 RedChannel
        {
            get;
            set;
        }

        [XmlAttribute ( "greenChnl" )]
        public Int32 GreenChannel
        {
            get;
            set;
        }

        [XmlAttribute ( "blueChnl" )]
        public Int32 BlueChannel
        {
            get;
            set;
        }
    }

    [Serializable]
    public class FontPage
    {
        [XmlAttribute ( "id" )]
        public Int32 ID
        {
            get;
            set;
        }

        [XmlAttribute ( "file" )]
        public String File
        {
            get;
            set;
        }
    }

    [Serializable]
    public class FontChar
    {
        [XmlAttribute ( "id" )]
        public Int32 ID
        {
            get;
            set;
        }

        [XmlAttribute ( "x" )]
        public Int32 X
        {
            get;
            set;
        }

        [XmlAttribute ( "y" )]
        public Int32 Y
        {
            get;
            set;
        }

        [XmlAttribute ( "width" )]
        public Int32 Width
        {
            get;
            set;
        }

        [XmlAttribute ( "height" )]
        public Int32 Height
        {
            get;
            set;
        }

        [XmlAttribute ( "xoffset" )]
        public Int32 XOffset
        {
            get;
            set;
        }

        [XmlAttribute ( "yoffset" )]
        public Int32 YOffset
        {
            get;
            set;
        }

        [XmlAttribute ( "xadvance" )]
        public Int32 XAdvance
        {
            get;
            set;
        }

        [XmlAttribute ( "page" )]
        public Int32 Page
        {
            get;
            set;
        }

        [XmlAttribute ( "chnl" )]
        public Int32 Channel
        {
            get;
            set;
        }
    }

    [Serializable]
    public class FontKerning
    {
        [XmlAttribute ( "first" )]
        public Int32 First
        {
            get;
            set;
        }

        [XmlAttribute ( "second" )]
        public Int32 Second
        {
            get;
            set;
        }

        [XmlAttribute ( "amount" )]
        public Int32 Amount
        {
            get;
            set;
        }
    }

    public class FontLoader
    {
        public static FontFile Load ( String filename )
        {
            XmlSerializer deserializer = new XmlSerializer ( typeof ( FontFile ) );
            TextReader textReader = new StreamReader ( filename );
            FontFile file = ( FontFile ) deserializer.Deserialize ( textReader );
            textReader.Close ( );
            return file;
        }
    }
}

I have slightly modified this class in order to implement it in a Object Oriented way. Here is how you make use of this class with your Custom font in your main Game.cs file.

For this example, i have the files time_0.png and time.fnt produced by the software BmFonts. They are the result of the font Avenir Next Condensed that I wanted to use.

public class Game1 : Game
{
    // Graphic variables used for the game to work
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    BmFont fontTime;



    public Game1 ()
    {
        graphics = new GraphicsDeviceManager (this);
        Content.RootDirectory = "Content";              
        graphics.IsFullScreen = true;       
    }

    protected override void LoadContent ()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch (GraphicsDevice);
        fontTime = new BmFont ("time.fnt", "time_0.png", this.Content);
    }

    protected override void Draw (GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear (Color.CornflowerBlue);



        spriteBatch.Begin();
            fontTime.draw (DateTime.Now.ToString("HH mm"), new Vector2 (100, 50)), spriteBatch);
        spriteBatch.End();
        base.Draw (gameTime);
    }



}

There you go. Now you should be all fine, see it working for yourself. The hard part will be playing around with your font size, since you'll need to generate a file for each font size you want.

Although, this techniques offer you to possibility to directly embbed a font without requiering the end user to have it on his computer installed (Which used to crash).

Enjoy, Kevin



来源:https://stackoverflow.com/questions/29453118/using-a-bmp-image-as-font-in-monogame

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!