通过 iText 创建 PDF 文档时,某些 HTML 和 CSS 样式未应用

Posted

技术标签:

【中文标题】通过 iText 创建 PDF 文档时,某些 HTML 和 CSS 样式未应用【英文标题】:Some HTML and CSS styles not applied when creating PDF document by iText 【发布时间】:2018-11-28 15:10:02 【问题描述】:

我在从 html 生成 PDF 时遇到了 iText 问题。我从 Locize 传递“导入信息部分”,其中包含粗体标签和列表项目符号

<li>\n                    
   <b>Toll-free</b> (within Canada and the USA): 
   <b>1.800.xxxxxxx</b>\n                
</li>\n  

pdf 文件在 Confirmation.cs 中生成。下面列出了从 Confirmation.cs 传递到 ImportantInformation.cs 的参数“medSrc”。不知何故,粗体样式和列表项目符号不适用于结果 pdf 文件。

我已经调试了一段时间,但仍然不知道发生了什么。有谁知道我错过了什么?

提前谢谢你!

确认.cs

    ...
    namespace xxx.Pdf.xxx.xxx
    
    public partial class Confirmation
    
        private IApplication application;

        public Confirmation(IApplication application)
        
            this.application = application;
        

        public byte[] Create()
        
            var memoryStream = new MemoryStream();
            var css = Content.Css;

            //Create Document
            PdfDocument pdfDocument = new PdfDocument(new PdfWriter(memoryStream));
            PageSize pageSize = PageSize.LETTER;
            Document document = new Document(pdfDocument, pageSize);

            Header headerHandler = new Header(document);
            PageXofY footerHandler = new PageXofY(pdfDocument);
            document.SetTopMargin(headerHandler.GetTableHeight());

            //Assign event-handlers
            pdfDocument.AddEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
            pdfDocument.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);

           ...
            // ======>Important Information <=======
            var importantInfo = new ImportantInformation();
            Table impInfoTable = importantInfo.CreateTable(
                HtmlUtility.MergeCssWithHtml(css, Content.ImportantInformationEmergencyMedical),
                HtmlUtility.MergeCssWithHtml(css, Content.ImportantInformationTripCancellation));

            document.Add(impInfoTable).Add(new Paragraph("\n"));

            //set column parameters
            float offset = 36;
            float columnWidth = (pageSize.GetWidth() - offset * 2 + 15) / 2;
            float columnHeight = pageSize.GetHeight() - offset * 2;
            float tableWidth = columnWidth - 10;

            //define column area
            Rectangle[] columns = new Rectangle[]
            
                new Rectangle(offset , offset, columnWidth, columnHeight),
                new Rectangle(columnWidth + 30, offset, columnWidth, columnHeight)
            ;
            document.SetRenderer(new ColumnDocumentRenderer(document, columns));

            document.Add(new AreaBreak(AreaBreakType.LAST_PAGE));

            foreach (Applicant applicant in application.Applicants)
            
                ApplicantTable applicantTable = new ApplicantTable();
                Table table = applicantTable.CreateTable(applicant, tableWidth);
                //Table another = applicantTable.CreateTable(application.Applicants[1], tableWidth);

                document.Add(table).Add(new Paragraph("\n").SetFontSize(3));
            

            footerHandler.WriteTotal(pdfDocument);

            document.Close();

            pdfDocument.Close();

            var pdf = memoryStream.ToArray();

            return pdf;
        
    

ImportantInformation.cs

...
namespace xxx.xxx.xxx.Pdf

    public class ImportantInformation
    
    public Table CreateTable(string medSrc, string tciSrc)
    
        float[] colWidth = new float[]  50f, 50f ;
        Table table = new Table(UnitValue.CreatePercentArray(colWidth));
        table.SetWidth(new UnitValue(UnitValue.PERCENT, 100));

        PdfFont avenir = FontFactory.CreateAvenirLightStandardMedium();

        Paragraph title = new Paragraph().Add("**IMPORTANT INFORMATION**").SetFontSize(12).SetFont(avenir).SetBold().SetTextAlignment(TextAlignment.CENTER);
        Cell titleCell = new Cell(1, 2).Add(title).SetBorder(Border.NO_BORDER);
        table.AddCell(titleCell);

        Cell medImportantinfo = new Cell()
            .SetBorder(Border.NO_BORDER)
            .Add(new Paragraph("Paragraph A")
            .SetFirstLineIndent(10f)
            .SetBold()
            .SetFontSize(9)
            .SetFont(avenir));
        Cell tciImportantInfo = new Cell()
            .SetBorder(Border.NO_BORDER)
            .Add(new Paragraph("Paragraph B")
            .SetFirstLineIndent(10f)
            .SetBold()
            .SetFontSize(9)
            .SetFont(avenir));

        IList<IElement> medInfo = HtmlToCellFormat.HtmlToElements(medSrc);

        IList<IElement> tciInfo = HtmlToCellFormat.HtmlToElements(tciSrc);

        foreach (IElement e in medInfo)
        
            medImportantinfo.ElementToCell(e);
        

        foreach (IElement e in tciInfo)
        
            tciImportantInfo.ElementToCell(e);
        

        table.AddCell(medImportantinfo).AddCell(tciImportantInfo);

        return table;
        
    

medSrc:

<html>
<body>\n    
    <ul style=\"text-align: justify; list-style-type: disc; font-family: avenir, Arial, Helvetica, sans-serif; font-size: 10px\">\n        
        <li>\n            In the event of a medical emergency contact:\n            
            <ul style=\"text-align: justify; list-style-type: circle; font-family: avenir, Arial, Helvetica, sans-serif; font-size: 10px\">\n                
                <li>\n                    
                    <b>Toll-free</b> (within Canada and the USA): 
                    <b>1.800xxxxxx</b>\n                
                </li>\n                
                <li>\n                    
                    <b>Collect</b> (from all other locations): 
                    <b>1.xxxxxx</b>\n                
                </li>\n            
            </ul>\n        
        </li>\n        
        ...
    </body>
</html>

更新: 下面是ElementToCell和HtmlToElements函数的定义

public static class HtmlToCellFormat

    public static string baseUri = "/";

    public static void ElementToCell(this Cell cell, IElement e)
    
        var type = e.GetType().ToString();
        if (e.GetType() == typeof(Image))
        

            cell.Add((Image)e);
        
        else if (e.GetType() == typeof(Paragraph) || (e.GetType() == typeof(List)))
        
            cell.Add((IBlockElement)e);
        
    

    public static IList<IElement> HtmlToElements(string content)
    
        ConverterProperties properties = new ConverterProperties();
        properties.SetBaseUri(baseUri);
        FontProvider fontProvider = new DefaultFontProvider(false, false, false);
        FontProgram fontProgram = FontProgramFactory.CreateFont();
        fontProvider.AddFont(fontProgram, "");
        properties.SetFontProvider(fontProvider);
        IList<IElement> elements = HtmlConverter.ConvertToElements(content, properties);
        return elements;
    

【问题讨论】:

变量medImportantinfotciImportantInfo 的类型为Cell,但我在这些类中找不到ElementToCell() 方法。我不是 C# 开发人员,但我在 iText 7 for .NET 中也找不到该方法:github.com/itext/itext7-dotnet/blob/develop/itext/itext.layout/… 该方法是关于什么的?如果我用谷歌搜索,我只能找到对您问题的有效参考:google.com/search?q=iText+ElementToCell+cell Cell 上使用ElementToCell() 方法而不是Add() 方法很奇怪。当然,要使Add() 方法起作用,您可能需要将IElement 强制转换为IBlockElementImage 元素。 @BrunoLowagie 我刚刚添加了您所询问的函数的定义。我们自己定义了 ElementToCell 来处理不同的类型 好的,感谢您的澄清。我会在 Java 中使用 if (e instanceof IBlockElement) 之类的东西,但我不知道 C# 中是否存在。比较 string 的值对我来说看起来很尴尬,但由于我不懂 C#,所以我无法为您提供更多帮助.. @BrunoLowagie 没问题,感谢您的宝贵时间 【参考方案1】:

我通过阅读 iText 的文章解决了这个问题 https://developers.itextpdf.com/content/itext-7-converting-html-pdf-pdfhtml/chapter-6-using-fonts-pdfhtml

简单的改变

FontProvider fontProvider = new DefaultFontProvider(false, false, false); 

FontProvider fontProvider = new DefaultFontProvider(true, true, true);

【讨论】:

以上是关于通过 iText 创建 PDF 文档时,某些 HTML 和 CSS 样式未应用的主要内容,如果未能解决你的问题,请参考以下文章

ITEXT 生成基本的PDF文档

使用 itext 7 在 PDF 中添加新页面

为啥我创建 PDF 文档时没有应用我的字体?

iText pdf完整性检查

如何使用 iText 为我的 (pdf-) 文本添加背景颜色以使用 Java 创建它

itext java pdf到文本创建