使用iText HtmlConverter转HTML到PDF时表格caption元素报错问题
问题描述
使用HtmlConverter.convertToElements将HTML转换为元素并添加到PDF时,其余HTML元素均正常渲染,但表格内直接嵌套的<caption>元素会触发字体解析错误:
java.lang.IllegalStateException: FontProvider and FontSet are empty.
Cannot resolve font family name (see ElementPropertyContainer#setFontFamily)
without initialized FontProvider (see RootElement#setFontProvider).
报错发生在com.itextpdf.layout.renderer.TextRenderer.resolveFonts方法,此时FontProvider无字体。即使给<caption>显式定义字体样式也无效,其他元素(h3、p、div、th、td)使用相同字体配置可正常渲染;若通过display: none;隐藏<caption>,所有元素均可正常生成PDF。环境为Linux、Java、itext7-core 7.2.3、html2pdf 4.0.3。
临时解决办法
1. 预处理HTML替换caption标签
直接将<caption>替换为<div>或<p>,并手动添加表格标题的样式,避开iText对caption的特殊处理逻辑:
<table> <div style="text-align:center; margin:8px 0; font-weight:bold;">Some text</div> ... TRs with TDs here ... </table>
若需批量处理,可在Java中用字符串替换:
String processedHtml = htmlContent .replace("<caption>", "<div class='table-caption'>") .replace("</caption>", "</div>");
同时定义对应的CSS样式:
.table-caption { text-align: center; margin: 0.5em 0; font-weight: bold; }
2. 自定义TagWorker处理caption元素
继承默认TagWorker,重写caption的处理逻辑,强制为其设置字体:
public class CustomCaptionTagWorker extends TagWorker { public CustomCaptionTagWorker(IElementNode element, ProcessorContext context) { super(element, context); } @Override public void processEnd(IElementNode element, ProcessorContext context) { super.processEnd(element, context); if (getElementResult() instanceof Paragraph) { Paragraph captionPara = (Paragraph) getElementResult(); // 直接指定字体,或从全局FontProvider获取 captionPara.setFontFamily("Arial") .setFontSize(12) .setBold(); } } }
将自定义TagWorker注册到ConverterProperties:
ConverterProperties properties = new ConverterProperties(); properties.setTagWorkerFactory(new DefaultTagWorkerFactory() { @Override public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) { if ("caption".equals(tag.name())) { return new CustomCaptionTagWorker(tag, context); } return super.getCustomTagWorker(tag, context); } }); List<IElement> elements = HtmlConverter.convertToElements(htmlContent, properties);
3. 全局设置FontProvider
确保在添加元素到PDF前,给Document明确设置全局FontProvider:
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest)); Document doc = new Document(pdfDoc); // 加载系统字体或自定义字体 FontProvider fontProvider = new DefaultFontProvider(true, true, true); doc.setFontProvider(fontProvider); // 转换并添加元素 List<IElement> elements = HtmlConverter.convertToElements(htmlContent); for (IElement element : elements) { doc.add(element); } doc.close();
全局FontProvider会被所有元素共享,可覆盖caption元素的字体解析问题。
内容的提问来源于stack exchange,提问作者nikos

