WPF解析Fnt字体

偶遇需要再 WPF中加载Fnt字体,此做。。。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Helper.JilyImage;

namespace Helper.JilyData
{

    public class FntInfo
    {

        public FileInfo FntFileInfo { get; set; }

        /// <summary> 字体名称 </summary>
        public string Name { get; set; }

        /// <summary> 大小为32像素 </summary>
        public int Size { get; set; }

        /// <summary> 加粗 </summary>
        public bool Bold { get; set; }

        /// <summary> 斜体 </summary>
        public bool Italic { get; set; }

        /// <summary> 编码字符集,没有填写值即使用默认 </summary>
        public string Charset { get; set; }

        /// <summary> 使用Unicode </summary>
        public bool Unicode { get; set; }

        /// <summary> 纵向缩放百分比 </summary>
        public double StretchH { get; set; }

        /// <summary> 开启平滑 </summary>
        public bool Smooth { get; set; }

        /// <summary> 开启抗锯齿 </summary>
        public bool Aa { get; set; }

        /// <summary> 内边距,文字与边框的空隙 </summary>
        public FntPadding Padding { get; set; }

        /// <summary> 外边距,就是相临边缘的距离 </summary>
        public FntPadding Spacing { get; set; }

        public FntCommon Common { get; set; }

        /// <summary> 此种字体共用到图数 </summary>
        public List<FntPage> Pages { get; set; }

        public List<FntChar> Chars { get; set; }

        public List<FntKerning> Kernings { get; set; }

        public Rect Bounds { get; private set; }

        private FntInfo()
        {
            this.Common = new FntCommon();
            this.Pages = new List<FntPage>();
            this.Chars = new List<FntChar>();
            this.Kernings = new List<FntKerning>();
        }

        public FntInfo(string fntpath, Encoding encoding = null)
            : this()
        {
            this.FntFileInfo = new FileInfo(fntpath);
            if (this.FntFileInfo.Exists)
            {
                var fntlines = File.ReadAllLines(this.FntFileInfo.FullName, encoding ?? Encoding.Default);
                foreach (var item in fntlines)
                {
                    if (item.StartsWith("info"))
                    {
                        DecodeInfo(item);
                    }
                    else if (item.StartsWith("common"))
                    {
                        DecodeCommon(item);
                    }
                    else if (item.StartsWith("page"))
                    {
                        DecodePage(item);
                    }
                    else if (item.StartsWith("char") && !item.StartsWith("chars"))
                    {
                        DecodeChar(item);
                    }
                    else if (item.StartsWith("kerning") && !item.StartsWith("kernings"))
                    {
                        DecodeKerning(item);
                    }
                }
            }
        }

        private void DecodeInfo(string str)
        {
            this.Name = GetValueAfterTittle(str, "face=\"", ‘"‘);
            this.Size = int.Parse(GetValueAfterTittle(str, "size="));
            this.Bold = int.Parse(GetValueAfterTittle(str, "bold=")) != 0;
            this.Italic = int.Parse(GetValueAfterTittle(str, "italic=")) != 0;
            this.Charset = GetValueAfterTittle(str, "charset=\"", ‘"‘);
            this.Unicode = int.Parse(GetValueAfterTittle(str, "unicode=")) != 0;
            this.StretchH = int.Parse(GetValueAfterTittle(str, "stretchH="));
            this.Smooth = int.Parse(GetValueAfterTittle(str, "smooth=")) != 0;
            this.Aa = int.Parse(GetValueAfterTittle(str, "aa=")) != 0;
            this.Padding = new FntPadding(GetValueAfterTittle(str, "padding="));
            this.Spacing = new FntPadding(GetValueAfterTittle(str, "spacing="));
        }

        private void DecodeCommon(string str)
        {
            this.Common.LineHeight = int.Parse(GetValueAfterTittle(str, "lineHeight="));
            this.Common.Base = int.Parse(GetValueAfterTittle(str, "base="));
            this.Common.ScaleW = int.Parse(GetValueAfterTittle(str, "scaleW="));
            this.Common.ScaleH = int.Parse(GetValueAfterTittle(str, "scaleH="));
            this.Common.Packed = int.Parse(GetValueAfterTittle(str, "lineHeight=")) != 0;
        }

        private void DecodePage(string str)
        {
            var page = new FntPage();
            page.Id = int.Parse(GetValueAfterTittle(str, "id="));
            page.FilePath = GetValueAfterTittle(str, "file=\"", ‘"‘);
            page.RealPath = this.FntFileInfo.DirectoryName + "\\" + page.FilePath;
            this.Pages.Add(page);
        }

        private void DecodeChar(string str)
        {
            var fntchar = new FntChar();
            fntchar.Id = int.Parse(GetValueAfterTittle(str, "id="));
            fntchar.X = int.Parse(GetValueAfterTittle(str, "x="));
            fntchar.Y = int.Parse(GetValueAfterTittle(str, "y="));
            fntchar.Width = int.Parse(GetValueAfterTittle(str, "width="));
            fntchar.Height = int.Parse(GetValueAfterTittle(str, "height="));
            fntchar.Xoffset = int.Parse(GetValueAfterTittle(str, "xoffset="));
            fntchar.Yoffset = int.Parse(GetValueAfterTittle(str, "yoffset="));
            fntchar.Xadvance = int.Parse(GetValueAfterTittle(str, "xadvance="));
            fntchar.Page = int.Parse(GetValueAfterTittle(str, "page="));
            fntchar.Chnl = int.Parse(GetValueAfterTittle(str, "chnl="));

            fntchar.InitData(this);

            this.Chars.Add(fntchar);
        }

        private void DecodeKerning(string str)
        {
            var kerning = new FntKerning();
            kerning.First = int.Parse(GetValueAfterTittle(str, "first="));
            kerning.Second = int.Parse(GetValueAfterTittle(str, "second="));
            kerning.Amount = int.Parse(GetValueAfterTittle(str, "amount="));
            this.Kernings.Add(kerning);
        }

        public ImageSource GetStrImage(string text)
        {
            //1 移除不在范围内的字符
            List<char> chars = new List<char>();
            foreach (var item in text)
            {
                if (this.Chars.FirstOrDefault(fc => fc.Id == (int)item) != null)
                {
                    chars.Add(item);
                }
            }

            int viewwidth = 1;
            int viewheight = 1;
            int count = chars.Count - 1;
            for (int i = 0; i <= count; i++)
            {
                char item = chars[i];
                var c = this.Chars.FirstOrDefault(fc => fc.Id == (int)item);
                if (c != null)
                {
                    //设置宽高,用最大高度
                    viewheight = (c.Height + c.Yoffset) > viewheight ? (c.Height + c.Yoffset) : viewheight;
                    viewwidth += (c.Xadvance);

                    if (i != 0)
                    {
                        var kerning = this.Kernings.FirstOrDefault(k => k.First == (int)item && k.Second == (int)chars[i - 1]);
                        if (kerning != null)
                        {
                            //补齐长度,在存在偏移的时候,偏移量也计算在总长度
                            viewwidth += kerning.Amount;
                        }
                    }
                }
            }

            int currentxoffset = 0;
            var img = new Bitmap(viewwidth, viewheight);
            using (var g = Graphics.FromImage(img))
            {
                for (int i = 0; i <= count; i++)
                {
                    char item = chars[i];
                    var c = this.Chars.FirstOrDefault(fc => fc.Id == (int)item);
                    if (c != null)
                    {
                        var xposition = currentxoffset + c.Xoffset;
                        int yposition = c.Yoffset;

                        if (i != 0)
                        {
                            //前后两个字符进行偏移
                            var kerning = this.Kernings.FirstOrDefault(k => k.First == (int)item && k.Second == (int)chars[i - 1]);
                            if (kerning != null)
                            {
                                //确定位置,和前一个相比,加上需要偏移的位置
                                xposition += kerning.Amount;
                            }
                        }
                        //当显示文字为空格 char 32 时不需要绘制
                        if (c.Data != null)
                        {
                            g.DrawImage(c.Data, xposition, yposition, c.Width, c.Height);
                        }
                        //叠加当前绘制过的长度
                        currentxoffset += (c.Xadvance);
                    }
                }
            }

            Bounds = new Rect(0, 0, viewwidth, viewheight);

            return img.ConvertImageSource();
        }

        private string GetValueAfterTittle(string s, string tittle, char endwith = ‘ ‘)
        {
            //补齐一个空格,用来判断最后的字符
            var str = s + " ";
            if (!string.IsNullOrWhiteSpace(str))
            {
                int firstindex = str.IndexOf(tittle) + tittle.Length;
                int lastindex = str.IndexOf(endwith, firstindex);
                if (firstindex != -1 && lastindex != -1)
                {
                    return new string(str.Skip(firstindex).Take(lastindex - firstindex).ToArray());
                }
            }
            return "";
        }

    }

    public class FntCommon
    {
        /// <summary> 行高,如果遇到换行符时,绘制字的位置坐标的Y值在换行后增加的像素值 </summary>
        public int LineHeight { get; set; }

        /// <summary> 字的基本大小 </summary>
        public int Base { get; set; }

        /// <summary> 图片宽 </summary>
        public int ScaleW { get; set; }

        /// <summary>
        /// 图片高
        /// </summary>
        public int ScaleH { get; set; }

        //没搞明白什么用
        //alphaChnl = int.Parse(GetValueAfterTittle(str, "alphaChnl="));
        //redChnl = int.Parse(GetValueAfterTittle(str, "redChnl="));
        //greenChnl = int.Parse(GetValueAfterTittle(str, "greenChnl="));
        //blueChnl = int.Parse(GetValueAfterTittle(str, "blueChnl="));

        /// <summary> 图片压缩 </summary>
        public bool Packed { get; set; }

        public FntCommon()
        {

        }
    }

    public class FntPage
    {
        /// <summary> 当前页数 </summary>
        public int Id { get; set; }

        /// <summary> 图片相对fnt文件的路径 </summary>
        public string FilePath { get; set; }

        private string realPath;
        public string RealPath
        {
            get { return realPath; }
            set
            {
                realPath = value;
                FntImage = BitmapHelper.GetBitmap(realPath);
            }
        }

        public Bitmap FntImage { get; private set; }

    }

    public class FntChar
    {

        /// <summary> 文字的 ID </summary>
        public int Id { get; set; }

        /// <summary> 所在图片的X </summary>
        public int X { get; set; }
        /// <summary> 所在图片的Y </summary>
        public int Y { get; set; }

        /// <summary> 宽 </summary>
        public int Width { get; set; }
        /// <summary> 高 </summary>
        public int Height { get; set; }

        /// <summary> 像素偏移X </summary>
        public int Xoffset { get; set; }
        /// <summary> 像素偏移Y </summary>
        public int Yoffset { get; set; }

        /// <summary> 绘制完后相应位置的x往后移 ... 像素再画下一个字 </summary>
        public int Xadvance { get; set; }

        /// <summary> 所在图片页 </summary>
        public int Page { get; set; }

        /// <summary> 未知 </summary>
        public int Chnl { get; set; }

        public Bitmap Data { get; private set; }

        static int count = 0;
        public void InitData(FntInfo fntinfo)
        {
            count++;
            var page = fntinfo.Pages.FirstOrDefault(i => i.Id == this.Page);

            if (page != null)
            {
                var rect = new Rectangle(this.X, this.Y, this.Width, this.Height);
                if (Rectangle.Empty != rect && !(this.Width == 0 && this.Height == 0))
                {
                    this.Data = page.FntImage.Clone(rect, page.FntImage.PixelFormat);
                }
            }
        }

        public override string ToString()
        {
            return ((char)this.Id).ToString();
        }
    }

    public class FntKerning
    {
        /// <summary> 位移的前字符 </summary>
        public int First { get; set; }

        /// <summary> 位移的后字符 </summary>
        public int Second { get; set; }

        /// <summary> X右移位置,正为右 </summary>
        public int Amount { get; set; }

    }

    public struct FntPadding
    {
        public int V1 { get; set; }
        public int V2 { get; set; }
        public int V3 { get; set; }
        public int V4 { get; set; }

        public FntPadding(int v1, int v2, int v3, int v4)
            : this()
        {
            this.V1 = v1;
            this.V2 = v2;
            this.V3 = v3;
            this.V4 = v4;
        }

        public FntPadding(string value)
            : this()
        {
            var values = value.Split(‘,‘);
            if (values.Length == 2)
            {
                this.V1 = int.Parse(values[0]);
                this.V2 = int.Parse(values[0]);
                this.V3 = int.Parse(values[1]);
                this.V4 = int.Parse(values[1]);
            }
            else if (value.Length == 4)
            {
                this.V1 = int.Parse(values[0]);
                this.V2 = int.Parse(values[1]);
                this.V3 = int.Parse(values[2]);
                this.V4 = int.Parse(values[3]);
            }
        }
    }
}

时间: 2025-01-05 23:30:55

WPF解析Fnt字体的相关文章

WPF解析TTF 字体

偶遇需要自己解析 TTF 字体并显示,此做... using System; using System.Collections.Generic; using System.Drawing.Text; using System.IO; using System.Linq; using System.Runtime.Serialization; using System.Text; using System.Windows; using System.Windows.Media; using Sys

为WPF程序添加字体

很多时候我们开发的程序可能会在多个版本的Windows上运行,比如XP.Win7.Win8. 为了程序美观,现在很多公司会使用WPF作为程序的界面设计. 跨版本的操作的操作系统往往有一些字体上的问题,比如Win7和Win8有微软雅黑字体,而XP上没有(虽然微软已经明确不在维护XP,但往往还是有很多一部分使用者会使用相当长一段时间,比如医疗机构.企事业单位),还有的一种情况就是为了程序效果的需要而使用一些特殊的字体. WPF程序只要下面几个步骤就可以为程序自带字体,而不需要放到系统目录的Fonts

Fnt字体格式详解

cocos2d里的数字和符号基本都会用到fnt字体, 从直观的使用来说, fnt就是讲我们熟悉和0123和图片绑定起来, 在使用0123时, 直接用图片代替, 当然这个图片不可能是矢量图, 所以在游戏中就要尽量避免对fnt字体的缩放操作, 因为对mac下fnt生成软件实在是用得不爽, 于是想写一个TexturePacker的插件, 自己实现fnt格式导出, 其中fnt文件的内容详解如下, 备忘: 第一行是对字体的介绍. info face="华康海报体W12(P)" size=32 b

cocosstdio之字体之文本和FNT字体

FNT字体和文本字体的作用是:导入字体资源可以使用字体资源便可以使用其资源内的字体来在程序中使用 不同的是FNT字体资源内容比较少,所以个人猜想可以在特定情况下使用: 两种字体资源对比: 赋值过程对比:

WPF中的字体改善

原文:WPF中的字体改善 WPF4对字体渲染做了很大的改善,增加了TextOptions属性,该属性可以设置TextFormattingMode,TextRenderingMode,TextHintingMode 1.TextFormattingMode 它提供了两种设置: · Ideal  —— WPF4之前的模式 · Display —— 新的模式,可以使字体显示更清晰 (一般将TextFormattingMode设置为Display,可以提高字体显示的清晰度) 2.TextRenderin

WPF中应用字体图标

原文:WPF中应用字体图标 一.什么是字体图标 我们在进行GDI(图形界面)编程的过程中图标是不可少的.近些年随着网络的繁荣和移动应用的繁荣,矢量图的应用越来越火. 矢量图是一种用数学方法描述的.由一系列点和线组成的图,因此相比位图文件比较小,并且还和分辨率无关.字体图标就是将这种图只作为文件(常见的.ttf,即TrueType Font),并通过一些表示代码引用. 二.字体图标文件的获得 1.下载一些公共的图标如:Awesome,阿里巴巴. 这些网站中有的可以直接下载.ttf(或其他字体图标格

wpf使用truetype字体ttf

查了半天都是语焉不详,这篇算是稍微详细点的:http://www.cnblogs.com/junhengml/p/6878933.html 要先查找到字体的字库名称,才能使用: <Window.Resources> <Style TargetType="TextBlock"> <Setter Property="Width" Value="46"/> <Setter Property="Heig

WPF解析Word为图片

偶遇需要解析Word为单张图,此做 http://git.oschina.net/jiailiuyan/OfficeDecoder using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Text; using System.IO; using System.Linq; using System.Reflection; using System.Text; using S

在WPF中使用字体图标

ICO字体实现步骤 一.到Font-Awesome官方网站下载字体压缩包        二.下载到的压缩包,解压后获得图标字体文件        三.然后把字体文件夹拷贝到项目中,目录为(/fonts/字体文件)        四.对文件右键,设置“复制到输出目录”为“如果较新则复制”        五.编写代码    <Style x:Key="FontAwesome" >        <Setter Property="TextElement.Font