PDFsharp / MigraDoc嵌入字体的字体解析器:System.ArgumentException: 找不到字体“Ubuntu”。

6
我正在使用MigraDoc在我的ASP.NET5 MVC6 Web应用程序中生成PDF,该应用程序部署在Azure云上。我使用的是版本1.50 beta-2,但我也尝试过使用v1.50 beta-1和v1.32。
当应用程序在本地运行时,我成功地生成了PDF。然而,由于无法访问任何字体,当应用程序在云服务器上运行时,我一直在努力生成PDF,遇到了很大的问题。按照PDFsharp文档的说明,我尝试通过将字体嵌入到我的代码中来创建“私有字体”。
我成功地使用PDFsharp直接在云上生成了PDF。
    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,这样我就不必自己进行所有的排版工作了。
我按照Thomas Hövel博客上的优秀指南(这是beta-2的新指南)进行了操作,尽管我之前也曾经遵循他为beta-1所写的早期文章。他的项目对我来说完全正常,在本地运行良好。
我实现了示例以在我的Web App项目中使用。它与Thomas的代码完全相同,只是main是我的控制器中的一个方法,在按钮单击时运行: 字体解析器类:
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;
        }
    }
}

主页控制器:

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;
    }
}

当我运行应用程序并点击触发演示代码的按钮时,出现错误“无法找到字体'Ubuntu'”,该错误发生在renderer.RenderDocument()。如何使字体解析器能够找到/识别字体,以便我可以在我的ASP.NET MVC应用程序上使用MigraDoc生成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


错误发生在第307行 renderer.RenderDocument();。您展示的HomeController源代码包含了这一行 pdfRenderer.RenderDocument();。也许您运行的代码不是您想要运行的代码 - 至少它不是您在这里展示的代码。这使得定位错误变得困难。 - I liked the old Stack Overflow
嗨@ThomasH - 你是对的,我很抱歉。实际上,我将添加到示例中的代码片段移动到了一个单独的“WriteDocument”方法中,以更清晰地隔离它。我已更新了显示此内容的代码,您现在可以看到“Line 307: renderer.RenderDocument();”在该方法中的位置了。 - 08Dc91wk
1个回答

4
您正在使用MigraDoc的GDI构建版本。错误消息来自GDI+。
我的示例代码已经使用WPF构建进行了测试。请在您的服务器上尝试使用WPF构建。
据我所知,您仍然需要在GDI版本中使用XPrivateFontCollection。如果您想在服务器上继续使用GDI版本,请删除IFontResolver并使用XPrivateFontCollection。

谢谢Thomas!我会尝试WPF版本,但是我之前选择GDI是因为根据 http://www.pdfsharp.net/NuGetPackage_PDFsharp-MigraDoc-wpf.ashx 的说明,GDI 应该在 ASP.NET 应用程序中使用。如果无法运行,我会考虑使用 XPrivateFontCollection。今晚我会告诉你结果。 - 08Dc91wk
我们将检查为什么字体解析器与GDI构建不兼容。但是切换到WPF通常是“无痛的”,值得一试。如果可以解决问题,那将是一个快速且简单的解决方案。 - I liked the old Stack Overflow
1
PDFsharpTeam和@ThomasH,感谢您们的直接支持,您们是正确的,这是一个快速简单的解决方案!我将GDI构建包替换为WPF构建包,FontResolver完美地工作了!您可能需要更改我链接到的文档,建议ASP.NET使用WPF构建而不是GDI构建。再次感谢!! - 08Dc91wk
我花了很多很多的时间来尝试让这个工作起来,并且从GDI转到WPF让我一下子排除了问题...谢谢。 - David Ward

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接