来自Resources的addFontFile

时间:2013-04-11 12:40:55

标签: c# winforms visual-studio

我使用以下代码添加了自定义字体:

PrivateFontCollection pfc = new PrivateFontCollection();
pfc.AddFontFile("C:\\Path To\\YourFont.ttf");
label1.Font = new System.Drawing.Font(pfc.Families[0], 16, FontStyle.Regular);

我在资源中添加了字体文件。如何从资源中添加addFontFile

5 个答案:

答案 0 :(得分:10)

private static void AddFontFromResource(PrivateFontCollection privateFontCollection, string fontResourceName)
{
    var fontBytes = GetFontResourceBytes(typeof (App).Assembly, fontResourceName);
    var fontData = Marshal.AllocCoTaskMem(fontBytes.Length);
    Marshal.Copy(fontBytes, 0, fontData, fontBytes.Length);
    privateFontCollection.AddMemoryFont(fontData, fontBytes.Length);
    // Marshal.FreeCoTaskMem(fontData);  Nasty bug alert, read the comment
}

private static byte[] GetFontResourceBytes(Assembly assembly, string fontResourceName)
{
    var resourceStream = assembly.GetManifestResourceStream(fontResourceName);
    if (resourceStream == null)
        throw new Exception(string.Format("Unable to find font '{0}' in embedded resources.", fontResourceName));
    var fontBytes = new byte[resourceStream.Length];
    resourceStream.Read(fontBytes, 0, (int)resourceStream.Length);
    resourceStream.Close();
    return fontBytes;
}

答案 1 :(得分:7)

如果您在资源中包含了字体

尝试此功能

private void addfontfrommemory()
{
 Stream fontStream = this.GetType().Assembly.GetManifestResourceStream("yourfont.ttf");

      byte[] fontdata = new byte[fontStream.Length];
      fontStream.Read(fontdata,0,(int)fontStream.Length);
      fontStream.Close();
      unsafe
      {
        fixed(byte * pFontData = fontdata)
        {
          pfc.AddMemoryFont((System.IntPtr)pFontData,fontdata.Length);
        }
      }
    }

<强>被修改

如何从汇编中加载资源:(YourNamespace.file.ttf)

Stream fontStream = Assembly.GetExecutingAssembly()
 .GetManifestResourceStream("WindowsFormsApplication1.SBADR.TTF");

我的解决方案资源管理器:

enter image description here

答案 2 :(得分:3)

这就是我这样做的方式。

首先获取Font.ttf文件并使用Visual Studio,将文件拖放到根文件夹或资源文件夹中。

在解决方案资源管理器中,右键单击该文件,然后单击属性。选择Build Action = Content。这将在Project Properties&gt;下的Application Files中显示该文件。发布&gt;应用文件。您将看到现在可以选择文件(默认情况下会自动包含该文件)。

ClickOnce现在将文件复制到StartupPath

要使用它,请按照以下示例进行操作:

PrivateFontCollection pfc = new PrivateFontCollection();

pfc.AddFontFile(Path.Combine(Application.StartupPath, "font_name.ttf"));

textBox1.Font = new Font(pfc.Families[0], 18, FontStyle.Regular);

答案 3 :(得分:3)

警告:如果您珍惜自己的理智,并且可以通过从文件中加载该字体来避免这种情况,那么不要将它们打包为资源。我现在告诉您:它不值得。 1

答案

[DllImport("gdi32.dll")]
private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts);
private static PrivateFontCollection pfc = new PrivateFontCollection();
private static uint cFonts = 0;
private static void AddFont(byte[] fontdata)
{ 
    int fontLength;  System.IntPtr dataPointer;

    //We are going to need a pointer to the font data, so we are generating it here
    dataPointer = Marshal.AllocCoTaskMem(fontdata.Length);
            

    //Copying the fontdata into the memory designated by the pointer
    Marshal.Copy(fontdata, 0, dataPointer, (int)fontdata.Length);

    // Register the font with the system.
    AddFontMemResourceEx(dataPointer, (uint)fontdata.Length, IntPtr.Zero, ref cFonts);

    //Keep track of how many fonts we've added.
    cFonts += 1;

    //Finally, we can actually add the font to our collection
    pfc.AddMemoryFont(dataPointer, (int)fontdata.Length);
}

好的,这里有很多要解压的内容,但是对于那些寻求复制/粘贴的人来说,如果没有下面的代码行,您将度过一个糟糕的时光。它必须在创建第一个表单之前和加载第一个字体之前运行: 2

Application.SetCompatibleTextRenderingDefault(true);

您可以通过简单地调用上述函数来使用此代码,如下所示:

AddFont(Properties.Resources.Roboto_Light);

现在,如果您对此有疑问,则需要处理 AddFontMemResourceEx函数,因为确实很难正确使用它。基本上,此功能的作用是跟踪内存中的字体。看来pfc.AddMemoryFont实际上并没有增加cFonts,这导致它无声地无法正确加载第一个字体之后的每种字体。每次添加唯一字体系列时,此计数器必须增加一个。已经添加的字体系列的斜体和粗体不算作新的家族,因此cFonts不应为此增加。

理论上,AddFontMemResourceEx的返回值是一个指针,该指针引用当前存储在内存中的字体数量的位置。似乎也无法获得实际数字,这就是为什么我通过递增cFonts.来手动保持跟踪的原因如果您无法正确递增cFonts,则此方法将无提示地失败。唯一的失败方法就是查看字体是否正确加载。

摘要

这个答案很长。这是我发现唯一可行的方法,但是您需要跳过这么多圈来从资源中添加字体这一事实是荒谬的。我不明白为什么AddFromMemory函数如此中断,我有信心我必须做错了什么或读错了什么,但是仅此而已。这是很多工作,即使是现在,对于字体的粗体和斜体变体,它也不是最稳定的解决方案。如果您能解释这里发生的事情以及为什么这么奇怪,我很想听听。目前,这是我唯一知道的方式。

脚语

1:此外,它将破坏WindowsFormsDesigner。在WindowsFormsDesigner环境中无法将compatibleTextRenderingDefault设置为true,因此您将不断收到错误,并且文本无法正确呈现。我通过将字体加载放入try {} catch {}中来解决此问题,然后仅尝试从我自己的硬盘驱动器上的硬编码路径加载字体。由于从文件加载不需要这些麻烦,因此它就像一个超级按钮。

2:这绝对是荒谬的。理论上,SetCompatibleTextRenderingDefault()设置控件使用的默认文本呈现技术。它确定他们是应使用旧版文本呈现技术还是使用较新的文本呈现技术。由于(至少就我而言)字体是在生成第一个控件之前就已加载的,所以我绝对不知道为什么这会影响任何事情。而且我知道这不是旧字体还是其他字体,因为如果我从文件(大概包含相同的数据)中加载它们,则此设置无关紧要。毫无意义。

答案 4 :(得分:0)

这会将字体加载到私有字体集合中,并避免使用上面的示例看到的任何对象引用和内存运行时错误。

出于性能原因,我们只想加载一次字体,并在调用之间保持对字体的引用以进行多次绘图操作。诀窍是,如果您保留对已创建的PrivateFontCollection对象的引用,则确保Font不会超出范围。

添加一些静态(共享)变量

Private Shared _sharedFont As Font
Private Shared _sharedFontCollection As Text.PrivateFontCollection
Private Shared _sharedFontSize As Integer

然后声明这些函数

Private Function LoadSharedFont(ByVal fontName As String, ByVal size As Integer, ByVal style As FontStyle) As Font
    'Check if font name or size has changed, then clear cache
    If size <> _sharedFontSize Then _sharedFont = Nothing

    If _sharedFont Is Nothing Then

        'Make this shared so this variable doesnt go out of scope and is garbage collected
        _sharedFontCollection = New Text.PrivateFontCollection()
        _sharedFont = LoadFont(fontName, size, style)
        _sharedFontSize = size
    End If

    Return _sharedFont
End Function

Private Function LoadFont(ByVal fontName As String, ByVal size As Integer, ByVal style As FontStyle) As Font
    Dim executingAssembly As System.Reflection.Assembly = Reflection.Assembly.GetCallingAssembly()
    Dim myNamespace As String = executingAssembly.GetName().Name.ToString()

    Try
        Using fontstream = executingAssembly.GetManifestResourceStream(myNamespace + "." + fontName)
            Dim fontBytes(CInt(fontstream.Length)) As Byte
            fontstream.Read(fontBytes, 0, CInt(fontstream.Length))

            Dim fontData As System.IntPtr = Marshal.AllocCoTaskMem(fontBytes.Length)
            Marshal.Copy(fontBytes, 0, fontData, fontBytes.Length)
            _sharedFontCollection.AddMemoryFont(fontData, fontBytes.Length)
            Marshal.FreeCoTaskMem(fontData)
        End Using

        Return New Font(_sharedFontCollection.Families(0), size, style)

    Catch ex As Exception
        'An unexpected error has occurred so return a default Font just in case.
        Return New Drawing.Font("Arial", size, FontStyle.Regular)
    End Try

End Function

使用如下:

Dim font = LoadSharedFont("OpenSans-CondBold.ttf", 12, FontStyle.Bold)