【问题标题】:iText + HTMLWorker - How to change default font?iText + HTMLWorker - 如何更改默认字体?
【发布时间】:2011-06-23 13:07:59
【问题描述】:

我必须从 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();
    }
}

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

我测试了许多与 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);

【问题讨论】:

标签: java html character-encoding itext


【解决方案1】:

您可以将样式表添加到 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;
    }

【讨论】:

    【解决方案2】:

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

    我遇到了一些土耳其字符没有打印在 PDF 文档中的问题,因此我在 PDF 中包含了字体包,例如 this

    【讨论】:

      【解决方案3】:

      它不会更改默认字体,只会更改您将应用的标签。

      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/"));
      

      示例:

      【讨论】:

        【解决方案4】:

        在你的样式标签中,或许你可以使用 CSS3 来改变字体:

        <style>
        @font-face {
        font-family: myFont;
        src: url(Filename);
        }
        </style>
        

        不确定这是不是您要问的。

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

            想法 #1

            一个答案立刻浮现在脑海:更改 iText。具体来说,Font.getCalculatedBaseFont,第 644 行。

            String fontName = BaseFont.HELVETICA;
            

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

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

            除非字体是“Base 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);
            

            这让我觉得技术上最合理的想法。它是为刚刚发布的 5.0.6 版 iText 编写的。以前的版本通过 setInterfaceProps() 设置字体提供程序。在这一点上,“提供者”更像是一个名称更改。我怀疑在 5.1 中将不再是这种情况。

            PS:FontFactoryImp 有两个您可能也会感兴趣的公共成员:defaultEncodingdefaultEmbedding。您应该能够将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 首先应该做的)。

            【讨论】:

            • 我试图使用 Your Idea#1 让它工作,但没有令人满意的结果。
            • 我已将 Arial TTF 转换为 AFM,复制到资源,然后更改 BaseFont.HELVETICA 以使其指向 Arial。最后,我得到了 PDF,但出现错误“Arial MT 字体包含错误的 /BBox。”和 #$#$% 而不是波兰语字符。唯一的优点是输出文档中的 Arial :)
            • 我发现了这个:好的。你的字体不好。字体是复杂的结构,您的特定字体没有所有必需的内部条目。 “BBox”代表边界框,是一个数字数组,描述了包含字体中所有字符的最小框。在 PC 系统上,PostScript Type 1 字体应包含在扩展名为“pfb”或“pfa”的文件中。它会附带一个“pfm”文件,但这并不是字体的严格部分。
            • 所以,你没有做错任何事。您的代码有效,并且 PDF 看起来很棒。这是一个坏/损坏的字体。与提供字体的人交谈,或寻找不同的字体供应商。
            • 您是否尝试注册字体提供商?这看起来是正确的做法。
            猜你喜欢
            • 2018-03-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-09-14
            • 1970-01-01
            • 2023-02-03
            • 2014-09-27
            • 1970-01-01
            相关资源
            最近更新 更多