如何在iText XMLWorker中摆脱Helvetica?

我们使用iText从Java代码生成PDF文件,这在大多数情况下都能很好地工作。 几天前,我们开始生成PDF / A而不是普通的PDF文件,需要嵌入所有字体。 iText Document主要是自定义PdfPTable和其他类的构建,我们直接控制字体。 所有使用的字体都是通过以下代码加载的TTF文件创建的 – 这很好用:

  private BaseFont load(String path) { try { URL fontResource = PrintSettings.class.getResource(path); if (fontResource == null) { return null; } String fontPath = fontResource.toExternalForm(); BaseFont baseFont = BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); baseFont.setSubset(true); return baseFont; } catch (DocumentException ex) { Logger.getLogger(PrintSettings.class).warn("..."); } catch (IOException ex) { Logger.getLogger(PrintSettings.class).warn("..."); } return FontFactory.getFont(PrintSettings.FONT, "UTF-8", true, 8f, Font.NORMAL, PrintSettings.COLOR_TEXT).getBaseFont(); } 

现在我们在PDF中使用一种特定的内容类型,它是从HTML代码生成的。 我们使用XMLWorker来处理该部分。 只要我们没有嵌入字体,这工作得很好。 但是使用PDF / A我们需要嵌入所有字体,现在我们正在努力解决未知的Helvetica使用来源。

我们试图通过使用我们自己的FontProvider类来解决这个问题:

 public class PrintFontProvider extends FontFactoryImp { @Override public Font getFont(String fontName, String encoding, boolean embedded, float size, int style, BaseColor color, boolean cached) { // LiberationSans – http://de.wikipedia.org/wiki/Liberation_(Schriftart) – http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web if (style == Font.NORMAL) return new Font(this.load("fonts/Liberation/LiberationSans-Regular.ttf"), size, Font.NORMAL, color); if (style == Font.BOLD) return new Font(this.load("fonts/Liberation/LiberationSans-Bold.ttf"), size, Font.NORMAL, color); if (style == Font.BOLDITALIC) return new Font(this.load("fonts/Liberation/LiberationSans-BoldItalic.ttf"), size, Font.NORMAL, color); if (style == Font.ITALIC) return new Font(this.load("fonts/Liberation/LiberationSans-Italic.ttf"), size, Font.NORMAL, color); return new Font(this.load("fonts/Liberation/LiberationSans-Regular.ttf"), size, style, color); } private BaseFont load(String path) { ... } } 

它使用以下代码与XMLWorker连接:

 HtmlPipelineContext html = new HtmlPipelineContext(null); html.setTagFactory(Tags.getHtmlTagProcessorFactory()); CSSResolver css = XMLWorkerHelper.getInstance().getDefaultCssResolver(true); // We need to control the FontProdiver! html.setCssAppliers(new CssAppliersImpl(new PrintFontProvider())); Pipeline pipeline = new CssResolverPipeline(css, new HtmlPipeline(html, new PdfWriterPipeline(this.document, writer))); XMLWorker worker = new XMLWorker(pipeline, true); XMLParser p = new XMLParser(worker); p.parse(new ByteArrayInputStream(StringUtils.iTextHTML(string).getBytes())); 

大多数简单的HTML元素以这种方式工作……但有一些似乎忽略了FontProvider并继续使用Helvetica ,它不会嵌入到PDF / A中(我们没有那种字体)。 例如

  1. ...

使用它。

 Caused by: com.itextpdf.text.pdf.PdfXConformanceException: All the fonts must be embedded. This one isn't: Helvetica at com.itextpdf.text.pdf.internal.PdfXConformanceImp.checkPDFXConformance(PdfXConformanceImp.java:225) at com.itextpdf.text.pdf.PdfWriter.addSimple(PdfWriter.java:2192) at com.itextpdf.text.pdf.PdfContentByte.setFontAndSize(PdfContentByte.java:1444) at com.itextpdf.text.pdf.PdfDocument.writeLineToContent(PdfDocument.java:1463) at com.itextpdf.text.pdf.ColumnText.go(ColumnText.java:968) at com.itextpdf.text.pdf.ColumnText.go(ColumnText.java:841) at com.itextpdf.text.pdf.ColumnText.showTextAligned(ColumnText.java:1189) at com.itextpdf.text.pdf.ColumnText.showTextAligned(ColumnText.java:1208) at com.itextpdf.text.pdf.PdfDocument.flushLines(PdfDocument.java:1193) at com.itextpdf.text.pdf.PdfDocument.newPage(PdfDocument.java:830) at com.itextpdf.text.Document.newPage(Document.java:367) 

我现在已经没有想法如何摆脱Helvetica ……现在试图解决这个问题8个多小时……还有更多想法吗?

我已经深入挖掘并从ListItem上的OrderedUnorderedList移动到List

 /** * Adds an Element to the List. * * @param o the element to add. * @return true if adding the object succeeded * @since 5.0.1 (signature changed to use Element) */ @Override public boolean add(final Element o) { if (o instanceof ListItem) { ListItem item = (ListItem) o; if (this.numbered || this.lettered) { Chunk chunk = new Chunk(this.preSymbol, this.symbol.getFont()); chunk.setAttributes(this.symbol.getAttributes()); int index = this.first + this.list.size(); if ( this.lettered ) chunk.append(RomanAlphabetFactory.getString(index, this.lowercase)); else chunk.append(String.valueOf(index)); chunk.append(this.postSymbol); item.setListSymbol(chunk); } else { item.setListSymbol(this.symbol); } item.setIndentationLeft(this.symbolIndent, this.autoindent); item.setIndentationRight(0); return this.list.add(item); } else if (o instanceof List) { List nested = (List) o; nested.setIndentationLeft(nested.getIndentationLeft() + this.symbolIndent); this.first--; return this.list.add(nested); } return false; } 

此代码引用this.symbol.getFont() ,它在类初始化时设置为undefined …

 public class List implements TextElementArray, Indentable { [...] /** This is the listsymbol of a list that is not numbered. */ protected Chunk symbol = new Chunk("- "); 

我只是使用另一个Chunk构造函数,它采用了我的Font并且瞧… 解决了 。 编号列表不再使用Helvetica,而是使用我自己的字体,它可以正确嵌入。

这花了我很多年! 另一种方法可能是为

    实现自己的TagProcessor,但我们没有时间再这样做了。 我将为此提交一份错误报告……我们会看到它是否得到了更加灵活的修复。