C#使用外部字体、嵌入字体到程序资源中(Winform)及字体的版权问题

简介: 应用程序能够使用一个好的字体,是用户界面很重要的一部分,但是很多字体如果系统没有安装,则需要额外引入,这就涉及到极其重要的字体版权问题,及额外字体的使用和安装。最好的方式应该是将字体嵌入到程序中...

引入

我们先看一下按钮显示的字体的例子。如下,新建一个名为EmbedFont的winform项目,给定三个Button,设置基本样式:

button1.FlatStyle = button2.FlatStyle = button3.FlatStyle = FlatStyle.Flat;
button1.FlatAppearance.BorderSize = button2.FlatAppearance.BorderSize = button3.FlatAppearance.BorderSize = 0;
button1.ForeColor = button2.ForeColor = button3.ForeColor = Color.White;

button1.BackColor = Color.MediumPurple;
button2.BackColor = Color.CadetBlue;
button3.BackColor = Color.OrangeRed;

显示如下:

基本效果不错,但是字体是默认的“宋体, 9pt”,总体感觉差点,好看的字体有很多,但是如果系统没有安装也无法使用【需要额外单独安装字体】

下面就简要介绍下字体,以及如何嵌入到Winform的程序资源中,免除需要安装的麻烦。

常见字体及版权

字体版权

注意:很多字体是有版权的,需要付费才能使用,否则直接使用很容易收到版权投诉,最出名的莫过于微软雅黑(Microsoft Yahei),其商业版权归属北大方正。

微软雅黑是美国微软公司委托北京北大方正电子有限公司设计的一款全面支持ClearType技术的字体。字体设计上属于无衬线字体和黑体。

微软雅黑的版权分为两个部分:个人使用为目的的Windows系统的内嵌使用、屏幕输出和打印;以商业发布为目的的微软雅黑版权,由北大方正保留。

关于字体使用侵权的问题,详细介绍可参考 设计师别担心,微软雅黑这样使用不侵权。直接引用系统自带的字体用于显示不属于侵权,但是直接使用或嵌入使用、海报艺术设计上直接使用等,又是商业用途,需要授权。

一些常见的免费字体中,属于明星级别的应该就是思源系列:思源黑体、思源宋体。

此外免费字体还有:

思源柔黑体、思源真黑体、

装甲明朝、源界明朝、花园明朝【明朝系列】

方正黑体、方正书宋、方正仿宋、方正楷体【四种方正免费字体】

源样明体、源流明体、源云明体【源明体系列】

以及站酷系列的很多字体等

推荐参考 48款无版权可商用字体送你,别再用微软雅黑了!那些你日思夜想的无版权字体,我都为你打包好了(超全合集)

而Windows中常见宋体、黑体、楷体、仿宋体等也是有版权的,在计算机软件著作权上需要商业授权,具体可参考 Windows自带的宋体、黑体、楷体、仿宋体等能免费商用吗?

总之使用上还是要注意。

一些查询字体的工具也提供了是否可免费使用的提示,比如

360查字体:https://fonts.safe.360.cn/

常见中文字体对应的英文名称

思源黑体 ---- Source Han Sans CN
思源宋体 ---- Source Han Serif SC

宋体 ---- SimSun
黑体 ---- SimHei
微软雅黑 ---- Microsoft Yahei
微软正黑体 ---- Microsoft JhengHei
楷体 ---- KaiTi
新宋体 ---- NSimSun
仿宋 ---- FangSong
隶书 ---- LiSu
华文行楷 ---- STXingkai

更多参考 css font-family常用的黑体宋体等字体中英文对照表

引用系统已安装字体

下面直接引用系统中的微软雅黑、黑体、隶书、华文行楷等,对比看看和默认的宋体效果:

//// 黑体
//button1.Font = button2.Font = button3.Font = new Font("SimHei", 11f, FontStyle.Regular);

//// 微软雅黑
//button1.Font = button2.Font = button3.Font = new Font("Microsoft Yahei", 11f, FontStyle.Regular);

//// 隶书
//button1.Font = button2.Font = button3.Font = new Font("LiSu", 13f, FontStyle.Regular);

//// 华文行楷
button1.Font = button2.Font = button3.Font = new Font("STXingkai", 13f, FontStyle.Regular);

C#使用外部字体和嵌入字体文件到程序

C#程序使用外部字体文件

上面是直接应用系统的字体,但是有些字体系统并不自带,或没有安装,比如思源系列字体。一个比较好的处理方式是将字体嵌入到程序中,随程序一起被携带使用。

借助私有字体集合类PrivateFontCollection,可以实现引用外部提供的字体,在程序中设定和使用。由于字体文件较大,通常引用一个需要的即可。比如从网上下载的一个思源黑体SourceHanSansCN-Regular.otf就有8M(如果要嵌入多个,真的伤不起...)

复制多个字体文件到生成的程序文件目录中(Debug或Release),同时定义一个字体路径的变量,程序运行时将其添加到PrivateFontCollection对象,后面就可以直接引用了。

PrivateFontCollection pfc = new PrivateFontCollection(); // using System.Drawing.Text;

/// <summary>
/// 添加第三方字体
/// </summary>
void AddPrivateFont()
{
    // 字体路径
    string[] fontNames = { "沐瑶软笔手写体.ttf", "SourceHanSansCN-Regular.otf", "SourceHanSansSC-Heavy.otf" };
    for (int i = 0; i < fontNames.Length; i++)
    {
        pfc.AddFontFile(fontNames[i]);
    }
}

加载并使用字体文件

AddPrivateFont();

// 使用字体文件提供的字体
button1.Font = new Font(pfc.Families[2], 12f);
button2.Font = new Font(pfc.Families[1], 12f);
button3.Font = new Font(pfc.Families[0], 15f);

嵌入字体到程序资源中(使用内存字体)

  1. 通过项目的Resources.resx资源添加字体文件为资源文件,实现字体文件嵌入到程序中。

(或者项目属性->资源)

  1. Resources资源引用的是二进制文件,可以实现直接添加到PrivateFontCollection对象中。
/// <summary>
/// 添加第三方字体
/// </summary>
void AddPrivateFont()
{
    var fontData1 = Properties.Resources.沐瑶软笔手写体;
    var fontData2 = Properties.Resources.SourceHanSansCN_Regular;
    var fontData3 = Properties.Resources.SourceHanSansSC_Heavy;
    unsafe  // 属性设置,生成中 允许不安全代码
    {
        // 将字体添加到PrivateFontCollection
        fixed (byte* pFontData = fontData1)
        {
            pfc.AddMemoryFont((System.IntPtr)pFontData, fontData1.Length);
        }
        fixed (byte* pFontData = fontData2)
        {
            pfc.AddMemoryFont((System.IntPtr)pFontData, fontData2.Length);
        }
        fixed (byte* pFontData = fontData3)
        {
            pfc.AddMemoryFont((System.IntPtr)pFontData, fontData3.Length);
        }
    }
}
  1. 项目属性中允许不安全代码:

  1. 使用 SetCompatibleTextRenderingDefault(true)UseCompatibleTextRendering=true 设置控件启用GDI+渲染使用内存字体(否则字体不生效)
AddPrivateFont();

// 使用内存字体,需要设置 SetCompatibleTextRenderingDefault(true) 或 UseCompatibleTextRendering=true
button1.UseCompatibleTextRendering = button2.UseCompatibleTextRendering = button3.UseCompatibleTextRendering = true;
// 使用字体文件提供的字体
button1.Font = new Font(pfc.Families[2], 12f);
button2.Font = new Font(pfc.Families[1], 12f);
button3.Font = new Font(pfc.Families[0], 15f);
To use the memory font, text on a control must be rendered with GDI+. Use the SetCompatibleTextRenderingDefault method, passing true, to set GDI+ rendering on the application, or on individual controls by setting the control's UseCompatibleTextRendering property to true. Some controls cannot be rendered with GDI+.

效果如下,可以看到,内存字体和直接从字体文件添加的方式有不少区别,有些小瑕疵,尤其是第二个按钮字体,整体偏上,无法正确居中。

嵌入的资源字体文件(资源清单,使用内存字体)

  1. 可以通过直接在项目中添加->现有项,添加字体文件到项目中,然后修改资源文件属性“生成操作”为“嵌入的资源”(BuildActionEnbedded Resource)。

  1. 然后通过Assembly的GetManifestResourceStream(sourceName)方法加载嵌入的资源文件,并添加到PrivateFontCollection
注意:资源必须是包含完整命名空间的名称,否则无法加载到。
/// <summary>
/// 添加第三方字体
/// </summary>
void AddPrivateFont()
{
   var fontName = "沐瑶软笔手写体.ttf";
   // 加载字体
   Assembly assembly = Assembly.GetExecutingAssembly();

   string projectName = assembly.GetName().Name;
   // 加载程序资源
   using (Stream stream = assembly.GetManifestResourceStream($"{projectName}.{fontName}"))
   {
       if (stream == null)
       {
           throw new Exception("资源文件不存在");
       }
       byte[] fontData = new byte[stream.Length];

       stream.Read(fontData, 0, (int)stream.Length);
       stream.Close();

       unsafe  // 属性设置,生成中 允许不安全代码
       {
           // 将字体添加到PrivateFontCollection
           fixed (byte* pFontData = fontData)
           {
               pfc.AddMemoryFont((System.IntPtr)pFontData, fontData.Length);
           }
       }
   }
}
  1. 使用内存字体
button3.UseCompatibleTextRendering = true;
button3.Font = new Font(pfc.Families[0], 15f);

效果:

Graphics(GDI+)直接使用内存字体

直接在控件上应用内存字体,必须启用兼容渲染(Compatible)。而如果直接使用GDI+的Graphics对象绘制文字时,就可以直接使用内存字体。

比如在窗体的Paint事件处理中绘制内存字体的文字:

/// <summary>
/// 窗体的Paint事件方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Paint(object sender, PaintEventArgs e)
{
   Graphics g = e.Graphics;
   Font font = new Font(pfc.Families[0], 20);
   g.DrawString("我是使用内存字体写的文字内容", font, new SolidBrush(Color.PaleVioletRed), 200, 300);
}

Windows中的字体文件及字体安装

Windows中的字体文件位于 C:\Windows\Fonts 中。

而安装字体文件的方法也很简单:

  • 一是直接复制字体文件到系统字体文件夹中
  • 二是右键在菜单中选择“安装”

参考

相关文章
|
2月前
|
缓存 C# Windows
C#程序如何编译成Native代码
【10月更文挑战第15天】在C#中,可以通过.NET Native和第三方工具(如Ngen.exe)将程序编译成Native代码,以提升性能和启动速度。.NET Native适用于UWP应用,而Ngen.exe则通过预编译托管程序集为本地机器代码来加速启动。不过,这些方法也可能增加编译时间和部署复杂度。
136 2
|
3月前
|
SQL API 定位技术
基于C#使用winform技术的游戏平台的实现【C#课程设计】
本文介绍了基于C#使用WinForms技术开发的游戏平台项目,包括项目结构、运行截图、实现功能、部分代码说明、数据库设计和完整代码资源。项目涵盖了登录注册、个人信息修改、游戏商城列表查看、游戏管理、用户信息管理、数据分析等功能。代码示例包括ListView和ImageList的使用、图片上传、图表插件使用和SQL工具类封装,以及高德地图天气API的调用。
基于C#使用winform技术的游戏平台的实现【C#课程设计】
|
2月前
|
设计模式 程序员 C#
C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤
WinForm MDI 模式就像是有超能力一般,让多个子窗体井然有序地排列在一个主窗体之下,既美观又实用。不过,也要小心管理好子窗体们的生命周期哦,否则一不小心就会出现一些意想不到的小bug
167 0
|
2月前
|
API C# Windows
【C#】在winform中如何实现嵌入第三方软件窗体
【C#】在winform中如何实现嵌入第三方软件窗体
113 0
|
2月前
|
XML 存储 安全
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
77 0
|
2月前
|
安全 API C#
C# 如何让程序后台进程不被Windows任务管理器强制结束
C# 如何让程序后台进程不被Windows任务管理器强制结束
66 0
|
2月前
|
API C#
C#实现Winform程序右下角弹窗消息提示
C#实现Winform程序右下角弹窗消息提示
108 0
|
7月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
207 3
|
1月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
32 3
|
3月前
|
API C#
C# 一分钟浅谈:文件系统编程
在软件开发中,文件系统操作至关重要。本文将带你快速掌握C#中文件系统编程的基础知识,涵盖基本概念、常见问题及解决方法。文章详细介绍了`System.IO`命名空间下的关键类库,并通过示例代码展示了路径处理、异常处理、并发访问等技巧,还提供了异步API和流压缩等高级技巧,帮助你写出更健壮的代码。
46 2