2016-04-07 87 views
2

我在我的資源中嵌入了一個.ttf字體文件(「Amatic Bold」,具體而言),我使用下面的代碼獲取字體。 我試過代碼FOM這個帖子:How do I Embed a font with my C# application? (using Visual Studio 2005)C#中嵌入的資源字體無法正常工作

這是我實現:

static public Font GetCustomFont (byte[] fontData, float size, FontStyle style) 
    { 
     if (_fontCollection == null) _fontCollection = new PrivateFontCollection(); 
     IntPtr fontPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(fontData.Length); 
     System.Runtime.InteropServices.Marshal.Copy(fontData, 0, fontPtr, fontData.Length); 
     _fontCollection.AddMemoryFont(fontPtr, fontData.Length); 
     System.Runtime.InteropServices.Marshal.FreeCoTaskMem(fontPtr); 
     return new Font(_fontCollection.Families[0], size, style); 
    } 

進出口使用它這樣:

Font font = GetCustomFont(Properties.MainResources.Amatic_Bold, 25, System.Drawing.FontStyle.Bold);  

字體應該是這樣的: enter image description here

問題是字體正在加載但使用時不能正確顯示;它看起來像是一個「Arial」或其他標準字體,而不是它應該是的。 如果我在Windows中安裝的字體,它的工作原理(我想是顯而易見的......)

我搜索了現有的答案,但could'nt找到我確切的問題...

任何幫助將不勝感激。 在此先感謝。

+1

這個可怕的bug代碼就像病毒一樣,它非常難以擺脫。您正在被字體保存,它是一種OpenType字體。僅適用於WPF或Direct2D應用程序。字體映射器找到可以在Winforms應用程序中工作的替代品。 –

+0

謝謝,@HansPassant。使用字體而不必安裝它有什麼好的選擇嗎? –

+1

當您安裝字體時它實際上工作嗎?然後修復此代碼中的錯誤。您不能調用Marshal.FreeCoTaskMem(),直到不再使用字體並調用._fontCollection.Dispose()方法爲止_fontCollection.Families [0]總是返回第一個字體,而不是最後一個加載的字體。 –

回答

1

那麼......我想我明白了!

我會解釋我所「發現」(它是否能明顯與否):

  • 第一:Application.SetCompatibleTextRenderingDefault必須設置爲在被渲染內存的字體控制。 (也Control.UseCompatibleTextRendering可以使用) 是微軟文檔中完全規定,但我已經錯過了:-(

  • 二:!PrivateFontCollection.Families返回添加字體的數組,但..驚喜它是按字母順序排序 無重要的是你添加字體的順序或者你使用的方法(AddMemoryFont/AddFontFile),你會得到它按字母順序! 所以,如果你添加多個字體,然後試圖獲得你添加的最後一個字體,你可能會得到錯誤的。

  • 第三:我也試過FreeCoTaskMem()在集合中添加字體或在表單關閉時執行此操作。兩者都爲我工作! 我不知道這個的確切含義......

這是我的最終代碼:

//This list is used to properly dispose PrivateFontCollection after usage 
    static private List<PrivateFontCollection> _fontCollections; 

    [STAThread] 
    private static void Main(string[] args) 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(true); //Mandatory in order to have Memory fonts rendered in the controls. 

     //Dispose all used PrivateFontCollections when exiting 
     Application.ApplicationExit += delegate { 
      if (_fontCollections != null) { 
       foreach (var fc in _fontCollections) if (fc != null) fc.Dispose(); 
       _fontCollections = null; 
      } 
     }; 

     Application.Run(new frmMain()); 
    } 

    void frmMain_Load(object sender, EventArgs e) 
    { 
     Font font1 = GetCustomFont(Properties.Resources.Amatic_Bold, 25, FontStyle.Bold); 
     //or... 
     Font font1 = GetCustomFont("Amatic-Bold.ttf", 25, FontStyle.Bold); 

     labelTestFont1.Font = font1; 

     Font font2 = GetCustomFont(Properties.Resources.<font_resource>, 25, FontStyle.Bold); 
     //or... 
     Font font2 = GetCustomFont("<font_filename>", 25, FontStyle.Bold); 

     labelTestFont2.Font = font2; 

     //... 

    } 
    static public Font GetCustomFont (byte[] fontData, float size, FontStyle style) 
    { 
     if (_fontCollections == null) _fontCollections = new List<PrivateFontCollection>(); 
     PrivateFontCollection fontCol = new PrivateFontCollection(); 
     IntPtr fontPtr = Marshal.AllocCoTaskMem(fontData.Length); 
     Marshal.Copy(fontData, 0, fontPtr, fontData.Length); 
     fontCol.AddMemoryFont(fontPtr, fontData.Length); 
     Marshal.FreeCoTaskMem(fontPtr);  //<-- It works! 
     _fontCollections.Add (fontCol); 
     return new Font(fontCol.Families[0], size, style); 
    } 


    static public Font GetCustomFont (string fontFile, float size, FontStyle style) 
    { 
     if (_fontCollections == null) _fontCollections = new List<PrivateFontCollection>(); 
     PrivateFontCollection fontCol = new PrivateFontCollection(); 
     fontCol.AddFontFile (fontFile); 
     _fontCollections.Add (fontCol); 
     return new Font(fontCol.Families[0], size, style); 
    } 

正如你所看到的,我已經決定爲每個字體的獨家PrivateFontCollection,然後將其存儲到一個列表上的應用程序的最終處置結束。

這是在3個不同的PC(都與Windows 7,32和64位)和3個不同的.ttf字體測試。

結果的一個例子:

enter image description here

我不知道我的做法是不夠好,但我相信它可能是有用的人!

一個細節: 不像我所期待的,AddMemoryFont慢則AddFontFile(21ms對15毫秒)

再次感謝所有評論!

0

問題可能是因爲在使用字體文件時需要指定fontfamily確切字體,編譯器切換到默認字體。 您可以通過以下兩種方法獲得您缺少的基本想法。

var fontFile = new FontFamily("pack://application:,,,/Resources/#YourFont"); 
var typeface = new Typeface(new FontFamily(new Uri("pack://application:,,,/"), "/Resources/#YourFont"), FontStyles.Normal, FontWeights.Regular, FontStretches.Normal); 
var cultureinfo = new CultureInfo("en-us"); 
var ft = new FormattedText("YourText", cultureinfo, FlowDirection.LeftToRight, 
    typeface, 28, Brushes.White) 
dc.DrawText(ft, new Point(0,0)); 

通過使用資源路徑在客戶端系統上安裝字體。

PrivateFontCollection yourfont = new PrivateFontCollection(); 
yourfont.AddFontFile("Your font Path"); 
label1.Font = new Font(yourfont.Families[0], 16, FontStyle.Regular); 
+0

謝謝,@Jerin,我會試一試。 –

相關問題