2015-09-22 59 views
2

我正在使用MigraDoc在我的ASP.NET5 MVC6 Web應用程序中生成PDF,該應用程序已部署到Azure雲。我使用的是1.50版本的beta-2,但我也嘗試使用v1.50 beta-1和v1.32。用於嵌入字體的PDFsharp/MigraDoc字體解析器:System.ArgumentException:字體'Ubuntu'無法找到

我已經在應用程序在本地運行時生成PDF。但是,當應用程序在雲服務器上運行時,由於無法訪問任何字體,導致生成PDF時遇到了很大的麻煩。 Following the PDFsharp docs,我試圖通過在我的代碼中嵌入字體來創建「私人字體」。

我對使用PDFsharp直接

public static MyResolver FontResolver = new MyResolver(); 
    public void RenderPdf(CreateDocumentViewModel viewModel) 
    { 
     GlobalFontSettings.FontResolver = FontResolver; 
     //... 
     XFont font = new XFont("times-roman", 12, XFontStyle.Regular); 
     //This font is then used in DrawString. 
    } 

不過,我現在想利用MigraDoc,這樣我就不必做所有的排版自己的雲計算成功生成PDF文件。

我遵循ThomasHövel的博客here (this is the new one for beta-2的優秀指南,儘管我之前也曾遵循過his earlier post for beta-1)。他的項目在當地是完全適合我的。

我實現了用於我的Web App項目的示例。這是正是相同,只是main托馬斯的代碼是在我的控制器的方法是點擊一個按鈕運行:

字體Resolver類:

public class DemoFontResolver : IFontResolver 
{ 
    public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic) 
    { 
     // Ignore case of font names. 
     var name = familyName.ToLower(); 

     // Deal with the fonts we know. 
     switch (name) 
     { 
      case "ubuntu": 
       if (isBold) 
       { 
        if (isItalic) 
         return new FontResolverInfo("Ubuntu#bi"); 
        return new FontResolverInfo("Ubuntu#b"); 
       } 
       if (isItalic) 
        return new FontResolverInfo("Ubuntu#i"); 
       return new FontResolverInfo("Ubuntu#"); 

      case "janitor": 
       return new FontResolverInfo("Janitor#"); 
     } 

     // We pass all other font requests to the default handler. 
     // When running on a web server without sufficient permission, you can return a default font at this stage. 
     return PlatformFontResolver.ResolveTypeface(familyName, isBold, isItalic); 
    } 

    /// <summary> 
    /// Return the font data for the fonts. 
    /// </summary> 
    public byte[] GetFont(string faceName) 
    { 
     switch (faceName) 
     { 
      case "Janitor#": 
       return DemoFontHelper.Janitor; 

      case "Ubuntu#": 
       return DemoFontHelper.Ubuntu; 

      case "Ubuntu#b": 
       return DemoFontHelper.UbuntuBold; 

      case "Ubuntu#i": 
       return DemoFontHelper.UbuntuItalic; 

      case "Ubuntu#bi": 
       return DemoFontHelper.UbuntuBoldItalic; 
     } 

     return GetFont(faceName); 
    } 
} 

/// <summary> 
/// Helper class that reads font data from embedded resources. 
/// </summary> 
public static class DemoFontHelper 
{ 
    public static byte[] Janitor 
    { 
     get { return LoadFontData("RealEstateDocumentGenerator.fonts.janitor.Janitor.ttf"); } 
    } 

    // Tip: I used JetBrains dotPeek to find the names of the resources (just look how dots in folder names are encoded). 
    // Make sure the fonts have compile type "Embedded Resource". Names are case-sensitive. 
    public static byte[] Ubuntu 
    { 
     get { return LoadFontData("RealEstateDocumentGenerator.fonts.ubuntufontfamily0._80.Ubuntu-B.ttf"); } 
    } 

    public static byte[] UbuntuBold 
    { 
     get { return LoadFontData("RealEstateDocumentGenerator.fonts.ubuntufontfamily0._80.Ubuntu-B.ttf"); } 
    } 

    public static byte[] UbuntuItalic 
    { 
     get { return LoadFontData("RealEstateDocumentGenerator.fonts.ubuntufontfamily0._80.Ubuntu-RI.ttf"); } 
    } 

    public static byte[] UbuntuBoldItalic 
    { 
     get { return LoadFontData("RealEstateDocumentGenerator.fonts.ubuntufontfamily0._80.Ubuntu-BI.ttf"); } 
    } 

    /// <summary> 
    /// Returns the specified font from an embedded resource. 
    /// </summary> 
    static byte[] LoadFontData(string name) 
    { 
     var assembly = Assembly.GetExecutingAssembly(); 

     using (Stream stream = assembly.GetManifestResourceStream(name)) 
     { 
      if (stream == null) 
       throw new ArgumentException("No resource with name " + name); 

      int count = (int)stream.Length; 
      byte[] data = new byte[count]; 
      stream.Read(data, 0, count); 
      return data; 
     } 
    } 
} 

Home控制器:

public class HomeController : Controller 
{ 
    [HttpPost] 
    public ActionResult CreateDocument() 
    { 
     DemoProjectMain(); 
     return View(); 
    } 

    public void DemoProjectMain() 
    { 
     // That's all it takes to register your own fontresolver 
     GlobalFontSettings.FontResolver = new DemoFontResolver(); 

     // And now the slightly modified MigraDoc Hello World sample. 

     // Create a MigraDoc document 
     Document document = DemoCreateDocument(); 
     document.UseCmykColor = true; 

     // Create a renderer for the MigraDoc document. 
     PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(unicode); 

     WriteDocument(document, pdfRenderer); 
    } 

    public void WriteDocument(Document document, PdfDocumentRenderer renderer) 
    { 

     renderer.Document = document; 
     renderer.RenderDocument(); 

     // Send PDF to browser 
     MemoryStream stream = new MemoryStream(); 
     renderer.PdfDocument.Save(stream, false); 
     Response.Clear(); 
     Response.ContentType = "application/pdf"; 
     Response.AddHeader("content-length", stream.Length.ToString()); 
     Response.BinaryWrite(stream.ToArray()); 
     Response.Flush(); 
     stream.Close(); 
     Response.End(); 
    } 

    /// <summary> 
    /// Creates an absolutely minimalistic document. 
    /// </summary> 
    static Document DemoCreateDocument() 
    { 
     // Create a new MigraDoc document 
     Document document = new Document(); 

     DemoSetupStyles(document); 

     // Add a section to the document 
     Section section = document.AddSection(); 

     // Add a paragraph to the section 
     Paragraph paragraph = section.AddParagraph(); 

     paragraph.Format.Font.Color = Color.FromCmyk(100, 30, 20, 50); 

     // Add some text to the paragraph 
     paragraph.AddFormattedText("Hello, World!", TextFormat.Bold); 

     section.AddParagraph("Hello, World!"); 

     // Demonstration for Heading styles. 
     paragraph = section.AddParagraph("Hello, World! (Heading 1)"); 
     paragraph.Style = StyleNames.Heading1; 

     paragraph = section.AddParagraph("Hello, World! (Heading 2)"); 
     paragraph.Style = StyleNames.Heading2; 

     paragraph = section.AddParagraph("Hello, World! (Heading 3)"); 
     paragraph.Style = StyleNames.Heading3; 

     paragraph = section.AddParagraph("Hello, World! (Heading 4)"); 
     paragraph.Style = StyleNames.Heading4; 

     paragraph = section.AddParagraph(); 

     paragraph.Format.Font.Color = Color.FromCmyk(100, 30, 20, 50); 

     // Add some text to the paragraph 
     paragraph.AddFormattedText("Hello, World!", TextFormat.Bold); 

     section.AddParagraph("Hello, World!"); 

     return document; 
    } 

    private static void DemoSetupStyles(Document document) 
    { 
     // Default font for all styles. 
     var style = document.Styles[StyleNames.Normal]; 
     style.Font.Name = "Ubuntu"; 

     // Overwrite font for headings 1 & 2. 
     style = document.Styles[StyleNames.Heading1]; 
     style.Font.Name = "Janitor"; 
     style.Font.Size = 32; 

     // Heading 2 inherits font from Heading 1. 
     style = document.Styles[StyleNames.Heading2]; 
     style.Font.Size = 28; 

     // Set normal font for Heading 3. 
     style = document.Styles[StyleNames.Heading3]; 
     style.Font.Name = "Ubuntu"; 
     style.Font.Size = 24; 

     style = document.Styles[StyleNames.Heading4]; 
     style.Font.Size = 20; 
    } 
} 

當我運行該應用程序並單擊觸發演示代碼的按鈕時,出現錯誤「Font '找不到'在renderer.RenderDocument()發生。 如何獲取字體解析器以查找/識別字體,以便我可以使用MigraDoc在ASP.NET MVC應用程序上生成PDF文件?

完整的錯誤消息和堆棧跟蹤如下:

Server Error in '/' Application.

Font 'Ubuntu' cannot be found.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentException: Font 'Ubuntu' cannot be found.

Source Error:

Line 305: 
Line 306:   renderer.Document = document; 
Line 307:   renderer.RenderDocument(); 
Line 308: 
Line 309:   // Send PDF to browser 

Source File: C:\Users\User\Documents\Visual Studio 2015\Projects\DocumentGenerator\DocumentGenerator\Controllers\HomeController.cs Line: 307

Stack Trace:

[ArgumentException: Font 'Ubuntu' cannot be found.]

System.Drawing.FontFamily.CreateFontFamily(String name, FontCollection fontCollection) +1123173 
System.Drawing.FontFamily..ctor(String name) +11 
PdfSharp.Drawing.XFontFamily..ctor(String name) +92 
MigraDoc.Rendering.FontHandler.GetDescent(XFont font) +129 
MigraDoc.Rendering.ParagraphRenderer.CalcVerticalInfo(XFont font) +154 
MigraDoc.Rendering.ParagraphRenderer.InitFormat(Area area, FormatInfo previousFormatInfo) +392 
MigraDoc.Rendering.ParagraphRenderer.Format(Area area, FormatInfo previousFormatInfo) +62 
MigraDoc.Rendering.TopDownFormatter.FormatOnAreas(XGraphics gfx, Boolean topLevel) +738 
MigraDoc.Rendering.FormattedDocument.Format(XGraphics gfx) +647 
MigraDoc.Rendering.DocumentRenderer.PrepareDocument() +269 
MigraDoc.Rendering.PdfDocumentRenderer.PrepareDocumentRenderer(Boolean prepareCompletely) +119 
MigraDoc.Rendering.PdfDocumentRenderer.PrepareRenderPages() +19 
MigraDoc.Rendering.PdfDocumentRenderer.RenderDocument() +13 
DocumentGenerator.Controllers.HomeController.WriteDocument(Document document, PdfDocumentRenderer renderer) in C:\Users\User\Documents\Visual Studio 2015\Projects\DocumentGenerator\DocumentGenerator\Controllers\HomeController.cs:307 
DocumentGenerator.Controllers.HomeController.DemoProjectMain() in C:\Users\User\Documents\Visual Studio 2015\Projects\DocumentGenerator\DocumentGenerator\Controllers\HomeController.cs:165 
DocumentGenerator.Controllers.HomeController.CreateDocument(CreateDocumentViewModel model, String command) in C:\Users\User\Documents\Visual Studio 015\Projects\DocumentGenerator\DocumentGenerator\Controllers\HomeController.cs:56 
lambda_method(Closure , ControllerBase , Object[]) +146 
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +14 
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +157 
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27 
System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +22 
System.Web.Mvc.Async.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) +29 
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +32 
System.Web.Mvc.Async.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d() +50 
System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +225 
System.Web.Mvc.Async.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult) +10 
System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +10 
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +34 
System.Web.Mvc.Async.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() +26 
System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +100 
System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +10 
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +27 
System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +13 
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +29 
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49 
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +36 
System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller) +12 
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +22 
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49 
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +26 
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10 
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +21 
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +29 
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49 
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +28 
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9 
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9723757 
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155 

Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.6.79.0

+0

錯誤發生在第307行'renderer.RenderDocument();'中。您顯示的HomeController源代碼包含'pdfRenderer.RenderDocument();'行。也許你正在運行的代碼不是你想運行的代碼 - 至少它不是你在這裏展示的代碼。很難找到錯誤。 –

+0

嗨@ThomasH - 你說的對,我很抱歉。實際上,我將添加到示例中的代碼移到了一個單獨的'WriteDocument'方法中,以更清楚地將其隔離。我已經更新了顯示此代碼的代碼,您可以希望看到現在在該方法中的「Line 307:renderer.RenderDocument();」的位置。 – Ivan

回答

3

您使用MigraDoc的GDI版本。錯誤消息來自GDI +。

我的示例代碼已經過WPF構建測試。請嘗試在您的服務器上構建WPF。

AFAIK您仍然必須使用帶有GDI構建的XPrivateFontCollection。如果你想堅持服務器上的GDI構建,請刪除IFontResolver並使用XPrivateFontCollection。

+0

謝謝Thomas!我會嘗試WPF構建,儘管我選擇了GDI,因爲根據http://www.pdfsharp.net/NuGetPackage_PDFsharp-MigraDoc-wpf。ashx GDI應該在ASP.NET應用程序中使用。如果我不能使用它,我會考慮使用'XPrivateFontCollection'。我會讓你知道今晚的情況。 – Ivan

+0

我們將檢查字體解析器爲什麼不能用於GDI構建。但切換到WPF通常是「無痛」,值得一試。如果有效,那將是一個快速而簡單的解決方案。 –

+0

PDFsharpTeam和@ThomasH,感謝你的直接支持,你說的對,這是一個快速簡單的解決方案!我將WPF構建包的GDI構建包與FontResolver交換完美!您可能需要更改鏈接的文檔,以推薦WPF構建ASP.NET而不是GDI構建。再次感謝!! – Ivan