iText + HTMLWorker - 如何更改默认字体?

11

我需要从HTML源代码创建一个PDF文件。目前,我遇到了一个有关输出文件中特殊(波兰)字符的问题,准确来说是它们缺失的问题。

HTML源代码:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<table width="100%" border="0.5" align="center" cellpadding="0" style="border-collapse:collapse; border:1px solid black; font-family:Arial, Helvetica, sans-serif; font-size:16px">
  <tr>
    <td align="center" ><b>Test: ąęłóćńśŁÓŃĆŻŹąśżźłęó</b></td>
  </tr>
</table>

Java源代码:

Document document = new Document(PageSize.A4, 38, 38, 50, 38);  
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("iTextExample.pdf"));  
document.open();  
HTMLWorker htmlWorker = new HTMLWorker(document);  
htmlWorker.parse(new StringReader(readFileAsString("index.html")));  
document.close();


public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) {
            throw new IOException("File " + filePath + " too large, was " + len + " bytes.");
        }
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}

我的问题是:如何将整个PDF文件的默认字体(Helvetica)更改为例如Arial Bold?

我尝试了许多与StyleSheet相关的示例,但它们都没有起作用。我必须更改默认字体,因为没有波兰字符 - 这就是我希望能够解决的方法。

编辑:

class defaultFontProvider extends FontFactoryImp {

    private String _default;

    public defaultFontProvider(String def) {
        _default = def;
    }

    public Font getFont(String fontName, String encoding, boolean embedded, float size, int style, BaseColor color, boolean cached) {
        if (fontName == null || size == 0) {
            fontName = _default;
        }

        return super.getFont(fontName, encoding, embedded, size, style, color, cached);
    }
}

上述代码嵌入了arial.ttf,这没问题,但我如何将其设置为整个文档的默认字体(而不是Helvetica)。

然后...

Map<String,Object> providers = new HashMap<String, Object>();

defaultFontProvider dfp = new defaultFontProvider("arial.ttf");

providers.put(HTMLWorker.FONT_PROVIDER, dfp);

HTMLWorker htmlWorker = new HTMLWorker(document);
htmlWorker.setProviders(providers);

我们可不可以使用iText从HTML和CSS文件创建PDF/A-2文档时做到这一点? - S_S
@Sumit 看看这个例子:https://developers.itextpdf.com/examples/archiving-and-accessibility-itext5/pdfa-2 - monczek
这个例子不是从HTML和CSS文件创建的,我在使用XMLWorker时遇到了困难,你能看一下我的问题吗?https://stackoverflow.com/q/52736441/3169868 - S_S
6个回答

3

想法 #1

有一个答案立刻浮现在脑海中:改变iText。具体来说,是Font.getCalculatedBaseFont函数,第644行。

String fontName = BaseFont.HELVETICA;

实际上,我认为这不会起作用,除非您还改变字体创建的方式...第712行

cfont = BaseFont.createFont(fontName, encoding, false);

除非字体是“基本14”之一,否则您必须提供字体文件的路径而不是简单的字体名称。

另一个选项:XSLT

转换输入,使您可以将字体定义添加到包含文本的任何节点的样式中。

最后:注册fontProvider

您可以在FontFactoryImp之上运行,并将空字符串简单地映射到您选择的字体。

class DefaultFontProvider extends FontFactoryImp {
  private String default;
  public DefaultFontProvider(String def) {
    default = def;
  }

  // I believe this is the correct override, but there are quite a few others.
  public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color, boolean cached) {
    if (fontName == null || fontName.size() == 0) {
      fontName = default;
    }
    return super.getFont(fontName, encoding, embedded, size, style, color, cached);
  }
}


Map<String,Object> providers = new HashMap<String, Object)();
providers.put(HTMLWorker.FONT_PROVIDER, new DefaultFontProvider("Arial Bold"));

myHTMLWorker.setProviders(providers);

这个想法在技术上似乎是最可靠的。它是为iText新发布的5.0.6版本编写的。以前的版本通过 "setInterfaceProps()" 设置字体提供程序。"Providers" 在这一点上更多是一个名称变更而已。我猜在5.1中不再是这种情况。
附注: "FontFactoryImp" 还有两个公共成员,您可能也感兴趣: "defaultEncoding" 和 "defaultEmbedding"。您应该能够调整 "defaultEncoding" 以获得更适合波兰语的内容。我建议使用 "Identity-H" (又名 "BaseFont.IDENTITY_H"),但这会强制所有字体都嵌入子集,从而忽略 "defaultEmbedding",使您的文件比不嵌入字体时要大一些。
两个可能的问题:
1. 明确请求 "Helvetica"。 为确保,我建议将 "System.out.println(("Requested font: " + fontName);" 放入您的 getFont 函数的开头。这将让您看到所有字体调用,并确保您已正确替换所有字体。如果是这种情况,您可以测试并将其替换为 "_default"。
2. 您的 fontFactory 可能找不到 "Arial Bold" 的任何内容,因此回退到默认值 (再次是 Helvetica)。 我认为您需要调用 "dfp.registerDirectories()"。这将在几个不同的操作系统上查找所有字体,并允许您通过字体名称引用它们,而不是通过路径(这是 FontFactoryImp 首先要做的事情)。

我试图使用您的idea#1让它工作,但是没有令人满意的结果。 - monczek
我已将Arial TTF转换为AFM,复制到资源中,然后更改BaseFont.HELVETICA以使其指向Arial。最后,我得到了PDF文件,但出现错误“字体Arial MT包含错误/BBox”,并且波兰字符显示为#$#$%。唯一的好处是输出文档中有Arial :) - monczek
我发现了这个:好的。你有一个糟糕的字体。字体是复杂的结构,而你的特定字体没有所有必需的内部条目。 "BBox" 代表边界框,它是一个数字数组,描述了包含字体中所有字符的最小框。在 PC 系统上,PostScript Type 1 字体应该包含在带有 ".pfb" 或 ".pfa" 扩展名的文件中。它将附带一个 "pfm" 文件,但那不是字体的组成部分。 - monczek
我已经尝试了DefaultFontProvider,看起来很有前途,但它仍然没有按预期工作。输出的PDF文件嵌入了所需的字体,但还是有Helvetica字体,文档也没有使用提供的TTF字体。有什么想法吗?我认为我们已经接近成功了... :) - monczek
你能添加你的字体提供者代码吗?还是我理解错了? - Mark Storer
显示剩余2条评论

2
它不会改变默认字体,而只会改变您应用的标签。
E.g. <Body>

在HTML标签中添加样式属性
<tag style="font-family: Arial Unicode MS, FreeSans; font-size:16px; font-weight: normal; >Здраво दी फोंट डाउनलोड Ravi Parekh! </tag>

注意:系统应在XMLWorkerFontProvider中找到ARIALUNI。
XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(html.getBytes(Charset.forName("UTF-8"))), null,Charset.forName("UTF-8"), new XMLWorkerFontProvider("/fonts/"));

示例:样本PDF


1
在您的样式标签中,也许可以使用CSS3来更改字体:
<style>
@font-face {
font-family: myFont;
src: url(Filename);
}
</style>

“不确定这是否是您要问的内容。”

0

如果您想在 PDF 中使用不同的字体,则需要包含字体包。

我曾经遇到过一个问题,即某些土耳其字符无法打印在 PDF 文档中,因此我在 PDF 中包含了字体包,如 this


0
你可以将样式表添加到HTML解析器中。这应该可以解决字体和变音符号的问题,但是在选择字体时必须要做出明智的选择。
           HttpContext.Current.Response.ContentType = "application / pdf";
            HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=" + HttpUtility.UrlPathEncode(name));
            HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            StringWriter sw = new StringWriter();
            HtmlTextWriter hw = new HtmlTextWriter(sw);
            Page.RenderControl(hw);
           
            StringReader sr = new StringReader(sw.ToString());
            Document pdfDoc = new Document(header.Length > 7 ? header.Length > 14 ? header.Length > 21 ? PageSize.A3.Rotate() : PageSize.A3 : PageSize.A4.Rotate() : PageSize.A4, 10f, 10f, 10f, 0f);
            HTMLWorker htmlparser = new HTMLWorker(pdfDoc);
            string sylfaenpath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\sylfaen.ttf";
            FontFactory.Register(sylfaenpath, "sylfaen");

            htmlparser.SetStyleSheet(GenerateStyleSheet());

            PdfWriter.GetInstance(pdfDoc, HttpContext.Current.Response.OutputStream);
            
            pdfDoc.Open();
            htmlparser.Parse(sr);
            pdfDoc.Close();
            HttpContext.Current.Response.Write(pdfDoc);
            HttpContext.Current.ApplicationInstance.CompleteRequest();


    private static StyleSheet GenerateStyleSheet()
    {
        StyleSheet css = new StyleSheet();

        css.LoadTagStyle("body", "face", "sylfaen");
        css.LoadTagStyle("body", "encoding", "Identity-H");
        css.LoadTagStyle("body", "size", "13pt");
        
        css.LoadTagStyle("h1", "size", "30pt");
        css.LoadTagStyle("h1", "style", "line-height:30pt;font-weight:bold;");
        css.LoadTagStyle("h2", "size", "22pt");
        css.LoadTagStyle("h2", "style", "line-height:30pt;font-weight:bold;margin-top:5pt;margin-bottom:12pt;");
        css.LoadTagStyle("h3", "size", "15pt");
        css.LoadTagStyle("h3", "style", "line-height:25pt;font-weight:bold;margin-top:1pt;margin-bottom:15pt;");
        css.LoadTagStyle("h4", "size", "13pt");
        css.LoadTagStyle("h4", "style", "line-height:23pt;margin-top:1pt;margin-bottom:15pt;");
        css.LoadTagStyle("hr", "width", "100%");
        css.LoadTagStyle("a", "style", "text-decoration:underline;");
        return css;
    }

-1

protected void pdfButton_Click(object sender, EventArgs e) { List showCourses = new List(); CourseManager aCourseManager = new CourseManager(); int departmentId = Convert.ToInt16(departmentDropDownList.Text); int semesterId = Convert.ToInt16(semesterDropDownList.Text); showCourses = aCourseManager.GetScheduleCoursesByDepartmentIdAndSemester(departmentId, semesterId);

保护的 void pdfButton_Click(object sender, EventArgs e) { List showCourses = new List(); CourseManager aCourseManager = new CourseManager(); int departmentId = Convert.ToInt16(departmentDropDownList.Text); int semesterId = Convert.ToInt16(semesterDropDownList.Text); showCourses = aCourseManager.GetScheduleCoursesByDepartmentIdAndSemester(departmentId, semesterId);

        Document doc = new Document(iTextSharp.text.PageSize.LETTER, 10, 10, 42, 35);
        string pdfFilePath = Server.MapPath("CoursePdf.pdf");
        PdfWriter wri = PdfWriter.GetInstance(doc, new FileStream(pdfFilePath, FileMode.Create));
        doc.Open(); //Open Document to write
        iTextSharp.text.Font font8 = FontFactory.GetFont("ARIAL", 7);
        string heading = " \t\t                                          Course Schedule Details for Department: " +
                                departmentDropDownList.SelectedItem;
        Paragraph reportHeading = new Paragraph(heading);
        if (showCourses != null)
        {
            PdfPTable PdfTable = new PdfPTable(6);
            PdfPCell PdfPCell = null;
            PdfPCell = new PdfPCell(new Phrase(new Chunk("Course Code", font8)));
            PdfTable.AddCell(PdfPCell);
            PdfPCell = new PdfPCell(new Phrase(new Chunk("Course Name", font8)));
            PdfTable.AddCell(PdfPCell);
            PdfPCell = new PdfPCell(new Phrase(new Chunk("Semester Name", font8)));
            PdfTable.AddCell(PdfPCell);
            PdfPCell = new PdfPCell(new Phrase(new Chunk("Course Credit", font8)));
            PdfTable.AddCell(PdfPCell);
            PdfPCell = new PdfPCell(new Phrase(new Chunk("Assign To", font8)));
            PdfTable.AddCell(PdfPCell);
            PdfPCell = new PdfPCell(new Phrase(new Chunk("Schedule", font8)));
            PdfTable.AddCell(PdfPCell);

            foreach (ShowCourse aCourse in showCourses)
            {
                PdfPCell = new PdfPCell(new Phrase(new Chunk(aCourse.courseCode, font8)));
                PdfTable.AddCell(PdfPCell);
                PdfPCell = new PdfPCell(new Phrase(new Chunk(aCourse.courseName, font8)));
                PdfTable.AddCell(PdfPCell);
                PdfPCell = new PdfPCell(new Phrase(new Chunk(aCourse.semesterName, font8)));
                PdfTable.AddCell(PdfPCell);
                PdfPCell = new PdfPCell(new Phrase(new Chunk((aCourse.credit).ToString(), font8)));
                PdfTable.AddCell(PdfPCell);
                PdfPCell = new PdfPCell(new Phrase(new Chunk(aCourse.teacherName , font8)));
                PdfTable.AddCell(PdfPCell);
                PdfPCell = new PdfPCell(new Phrase(new Chunk(aCourse.schedule, font8)));
                PdfTable.AddCell(PdfPCell);
            }
            PdfTable.SpacingBefore = 15f; // Give some space after the text or it m
            doc.Add(reportHeading); // add paragraph to the document
            doc.Add(PdfTable); // add pdf table to the document
            doc.Close();
            // string pdfPath = Server.MapPath("~/SomePDFFile.pdf");
            WebClient client = new WebClient();
            Byte[] buffer = client.DownloadData(pdfFilePath);
            Response.ContentType = "application/pdf";
            Response.AddHeader("content-length", buffer.Length.ToString());
            Response.BinaryWrite(buffer);
        }

    }

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