【问题标题】:How do I Embed a font with my C# application? (using Visual Studio 2005)如何在我的 C# 应用程序中嵌入字体? (使用 Visual Studio 2005)
【发布时间】:2010-10-18 03:26:18
【问题描述】:

在我正在开发的应用程序中嵌入 truetype 字体的最佳方式是什么?基本上我想确保在另一台机器上安装时我的应用程序可以使用特定的字体。我有 *.ttf 字体文件,只需要一种嵌入方式或在应用程序运行时自动安装它。

我需要在安装过程中设置安装程序来安装字体还是可以在应用程序运行时动态加载字体?事实上,两者都很高兴知道。

应用程序正在使用 .NET 2.0 在 C# 中开发。

【问题讨论】:

    标签: c# fonts


    【解决方案1】:

    看起来比这更容易;您可以将字体作为资源嵌入到您的应用中,并在应用的 Properties 命名空间中将其作为强类型属性进行访问。但是给定的链接应该是一个很好的起点。


    对于禁用 VB 的用户:

    Add the font as a resource in your application. 调用资源 MyFontLol。您可以从 Properties.Resources.MyFontLol 访问此资源(作为字节数组)。

    我没有测试以下,但它似乎是可行的:

    public void LoadMyFontLolKThx()
    {
        // get our font and wrap it in a memory stream
        byte[] myFont = Properties.Resources.MyFontLol;
        using (var ms = new MemoryStream(myFont))
        {
            // used to store our font and make it available in our app
            PrivateFontCollection pfc = new PrivateFontCollection();
            // The next call requires a pointer to our memory font
            // I'm doing it this way; not sure what best practice is
            GCHandle handle = GCHandle.Alloc(ms, GCHandleType.Pinned);
            // If Length > int.MaxValue this will throw
            checked
            {
                pfc.AddMemoryFont(
                    handle.AddrOfPinnedObject(), (int)ms.Length); 
            }
            var font = new Font(pfc.Families[0],12);
    
            // use your font here
        }
    }
    

    最后一点。 PFC 将字体存储为 GDI+ 字体。这些与某些表单控件不兼容。来自文档:

    要使用记忆字体, 控件必须使用 GDI+ 呈现。 使用 SetCompatibleTextRenderingDefault 方法,传递 true,设置 GDI+ 在应用程序上呈现,或在 通过设置单独的控制 控制UseCompatibleTextRendering 属性为真。有些控件不能 用 GDI+ 渲染。

    【讨论】:

    • 我的。字体。哈哈。 那个是你能想到的最好的名字吗?
    • 我可以挖方法名LolKThx
    • 当我尝试这个时,将 MemoryStream 传递给 GCHandle.Alloc 肯定存在问题 - 不是原始类型对象是异常的要点。 耸耸肩
    • @Will:问题,当我转到第一个链接时,我收到了恶意网页警告。 “因为它告诉我”是链接的文字。这是误报吗?
    • @JohnCarpenter 它倒了。我只是要把它拿出来。喜欢“The Thing”,顺便说一句。
    【解决方案2】:

    这个blog post 应该可以帮到你。

    基本上,您将字体添加为嵌入式资源,然后将其加载到PrivateFontCollection 对象中。

    【讨论】:

    • 当我尝试使用我使用这种技术创建的字体绘制一些文本时,有时会抛出异常,除非我保留对 PrivateFontCollection 的引用。我想我有我的字体,为什么我还需要收藏?我假设字体使用来自它的信息并且它被垃圾收集或其他东西。
    【解决方案3】:

    这是 Will 的答案,翻译成 C#(未经测试):

    PrivateFontCollection pfc = new PrivateFontCollection();
    
    using (Stream fontStream = GetType().Assembly.GetManifestResourceStream("Alphd___.ttf"))
    {
        if (null == fontStream)
        {
            return;
        }
    
        int fontStreamLength = (int) fontStream.Length;
    
        IntPtr data = Marshal.AllocCoTaskMem(fontStreamLength);
    
        byte[] fontData = new byte[fontStreamLength];
        fontStream.Read(fontData, 0, fontStreamLength);
    
        Marshal.Copy(fontData, 0, data, fontStreamLength);
    
        pfc.AddMemoryFont(data, fontStreamLength);
    
        Marshal.FreeCoTaskMem(data);
    }
    

    连同他们的 Paint() 方法:

    protected void Form1_Paint(object sender, PaintEventArgs e)
    {
        bool bold = false;
        bool italic = false;
    
        e.Graphics.PageUnit = GraphicsUnit.Point;
    
        using (SolidBrush b = new SolidBrush(Color.Black))
        {
            int y = 5;
    
            foreach (FontFamily fontFamily in pfc.Families)
            {
                if (fontFamily.IsStyleAvailable(FontStyle.Regular))
                {
                    using (Font font = new Font(fontFamily, 32, FontStyle.Regular))
                    {
                        e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                    }
                    y += 40;
                }
                if (fontFamily.IsStyleAvailable(FontStyle.Bold))
                {
                    bold = true;
                    using (Font font = new Font(fontFamily, 32, FontStyle.Bold))
                    {
                        e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                    }
                    y += 40;
                }
                if (fontFamily.IsStyleAvailable(FontStyle.Italic))
                {
                    italic = true;
                    using (Font font = new Font(fontFamily, 32, FontStyle.Italic))
                    {
                        e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                    }
                    y += 40;
                }
    
                if(bold && italic)
                {
                    using(Font font = new Font(fontFamily, 32, FontStyle.Bold | FontStyle.Italic))
                    {
                        e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                    }
                    y += 40;
                }
    
                using (Font font = new Font(fontFamily, 32, FontStyle.Underline))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                    y += 40;
                }
    
                using (Font font = new Font(fontFamily, 32, FontStyle.Strikeout))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
            }
        }
    }
    

    【讨论】:

    • 是的,@coffee_machine。我确信它被 b 在 using 块中声明并且可以被删除的事实所涵盖。
    • 实际上你是在 for 循环中处理它。这仅适用于第一次迭代。
    • 好收获。这就是我直接翻译别人的代码所得到的。谢谢,@coffee_machine!
    • @ajukraine:这基本上是别人在 VB 中已删除的答案的翻译。我不确定我从哪里得到元帅分配的东西,所以我还不能回答你,但给我一点,我会看看我能挖出什么。
    • @J-Roel:希望我能记得这样我才能告诉你。目前已经有将近 4 年没有使用 C#了。
    【解决方案4】:

    这可能不是最好的方法,但你不能在资源中包含字体,然后将其复制到 windows 目录上的字体文件夹吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多