【问题标题】:iTextSharp HTML to PDF conversion - unable to change fontiTextSharp HTML 到 PDF 的转换 - 无法更改字体
【发布时间】:2016-03-28 13:11:12
【问题描述】:

我正在用 ASP.NET MVC5 应用程序中的 HTML 使用 iTextSharp (5.5.7.0) 创建一些 PDF 文档,但我无法更改字体。我已经尝试了几乎所有可以在 SO 或其他资源中找到的东西。

生成PDF的代码如下:

    public Byte[] GetRecordsPdf(RecordsViewModel model)
    {
        var viewPath = "~/Template/RecordTemplate.cshtml";
        var renderedReport = RenderViewToString(viewPath, model);

        FontFactory.RegisterDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Fonts));

        using (var ms = new MemoryStream())
        {
            using (var doc = new Document())
            {
                doc.SetPageSize(PageSize.A4.Rotate());

                using (var writer = PdfWriter.GetInstance(doc, ms))
                {
                    doc.Open();

                    using (var html = new MemoryStream(Encoding.Default.GetBytes(renderedReport)))
                    {
                        XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, html, Encoding.Default);
                    }

                    doc.Close();
                }
            }

            var bytes = ms.ToArray();
            return bytes;
        }
    }

实际的 HTML 包含在 renderReport 字符串变量中(我有强类型的 .cshtml 文件,我使用 MVC Razor 引擎渲染该文件,然后以字符串形式返回 HTML)。

我尝试注册一些特定的字体,但没有帮助。我也尝试在我的机器上注册所有字体(如上例所示),但这也没有帮助。字体已加载我在调试模式下检查过。

CSS 像这样嵌入在 HTML 文件中(在标题、样式标签中):

    body {
        font-size: 7px;
        font-family: Comic Sans MS;
    }

(为了测试,我决定使用 Comic Sans,因为我可以轻松识别它,实际上我对 Arial Unicode MS 更感兴趣)。

而且我实际上可以使用 CSS 中的 font-family 属性更改字体,但只能使用 iTextSharp 默认预加载的字体 - Times New Roman、Arial、Courier 和其他一些字体(Helvetica我认为)。 当我将其更改为 - Comic Sans 或其他未预加载的 iTextSharp 时,会使用默认字体(我会说 Arial)呈现。

我需要更改字体的原因是因为我的渲染 HTML (ČĆŠĐŽčćšđž) 中有一些克罗地亚语字符,这些字符在 PDF 中丢失,目前我认为主要原因是 - 字体。

我错过了什么?

【问题讨论】:

    标签: html asp.net-mvc pdf fonts itextsharp


    【解决方案1】:

    要完成这项工作的几件事。

    首先,XMLWorkerHelper 默认不使用FontFactory,您需要使用ParseXHtml() 的重载之一,它采用IFontProvider。这两个重载都要求您为 CSS 文件指定 Stream,但如果您的 CSS 位于 HTML 文件中,则可以只传递 null。幸运的是,FontFactory 有一个静态属性,您可以使用它来实现这一点,称为FontFactory.FontImp

    //                                                                                 **This guy**
    XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHTML, null, Encoding.UTF8, FontFactory.FontImp);
    

    其次,我知道您说过您出于绝望而尝试注册整个字体目录,但这可能是一个相当昂贵的电话。如果可以,请始终尝试仅注册所需的字体。虽然是可选的,但我也强烈建议您明确定义字体的别名,因为字体可以有多个名称,而且它们并不总是我们想的那样。

    FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "comic.ttf"), "Comic Sans MS");
    

    第三,这可能不会影响到您,但是 HTML 中不存在的任何标签,即使它们在逻辑上是隐含的,也不会从 CSS 中应用样式。换种说法听起来很奇怪,如果你的 HTML 只是 <p>Hello</p> 而你的 CSS 是 body{font-size: 7px;},字体大小将不会被应用,因为你的 HTML 缺少 <body> 标签。

    第四,这是可选的,但通常更容易分别指定 HTML 和 CSS,我将在下面的示例中这样做。

    您的代码已经完成了 95%,因此只需进行一些调整,它应该可以工作。我只是解析原始 HTML 和 CSS 而不是视图,但您可以根据需要进行修改。请记住(我想你知道这一点)iTextSharp 不能处理 ASP.Net,只能处理 HTML,所以你需要确保你的 ASP.Net 到 HTML 的转换过程是健全的。

    //Sample HTML and CSS
    var html = @"<body><p>Sva ljudska bića rađaju se slobodna i jednaka u dostojanstvu i pravima. Ona su obdarena razumom i sviješću i trebaju jedna prema drugima postupati u duhu bratstva.</p></body>";
    var css = "body{font-size: 7px; font-family: Comic Sans MS;}";
    
    //Register a single font
    FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "comic.ttf"), "Comic Sans MS");
    
    //Placeholder variable for later
    Byte[] bytes;
    
    using (var ms = new MemoryStream()) {
        using (var doc = new Document()) {
            doc.SetPageSize(PageSize.A4.Rotate());
    
            using (var writer = PdfWriter.GetInstance(doc, ms)) {
                doc.Open();
    
                //Get a stream of our HTML
                using (var msHTML = new MemoryStream(Encoding.UTF8.GetBytes(html))) {
    
                    //Get a stream of our CSS
                    using (var msCSS = new MemoryStream(Encoding.UTF8.GetBytes(css))) {
    
                        XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHTML, msCSS, Encoding.UTF8, FontFactory.FontImp);
                    }
                }
    
                doc.Close();
            }
        }
    
        bytes = ms.ToArray();
    }
    

    【讨论】:

    • 谢谢回答。由于这确实改变了我在 pdf 中的字体,因此可以接受答案。我完全不知道 XmlWorker 默认不使用 FontFactory。但似乎我对克罗地亚字符的看法完全错误——这与字体无关。目前似乎默认 FontFactory 正在使用 CP1252 编码加载所有字体(如果没有记错的话),我应该使用 Identity_H。任何想法如何做到这一点?
    • 附带说明,我建议不要将PdfWriter 放入using 指令中。如果没有发生错误,编写器会被doc.Close 隐式关闭,如果发生错误,PdfWriter 会在Document之前被处理,这可能会在后者出现时导致其他错误处置,而这些额外的错误隐藏了原来的错误。
    • @Franko 您现在可能已经想通了,但是如果您创建一个新的 XMLWorkerFontProvider 即var fontImp = new iTextSharp.tool.xml.XMLWorkerFontProvider("your_font_directory"); fontImp.DefaultEncoding = "Identity-H";,然后使用fontImp 而不是FontFactory.FontImp,则可以将编码更改为 Identity_H。跨度>
    猜你喜欢
    • 1970-01-01
    • 2015-05-09
    • 1970-01-01
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 2022-03-07
    • 2013-08-01
    相关资源
    最近更新 更多