Fonts iText:从PdfAChecker引发的误导性异常消息?

Fonts iText:从PdfAChecker引发的误导性异常消息?,fonts,itext,Fonts,Itext,一段时间以来,我一直在尝试将HTML编写成PDF/a兼容的PDF。 我正在使用以下库: itext-pdfa-5.5.12 itextpdf-5.5.12 xmlworker-5.5.12 以下错误似乎经常出现: Exception in thread "main" com.itextpdf.text.pdf.PdfAConformanceException: All the fonts must be embedded. This one isn't: Helvetica 在某些情况下,

一段时间以来,我一直在尝试将HTML编写成PDF/a兼容的PDF。 我正在使用以下库:

  • itext-pdfa-5.5.12
  • itextpdf-5.5.12
  • xmlworker-5.5.12
以下错误似乎经常出现:

Exception in thread "main" com.itextpdf.text.pdf.PdfAConformanceException: All the fonts must be embedded. This one isn't: Helvetica
在某些情况下,这一信息似乎具有误导性。我的代码非常类似于关键行在代码中注释

  • 当评论时,我得到一个关于缺少Helvetica字体的异常
  • 未注释时,程序将毫无例外地执行
在生成的PDF文件中,我可以看到单个嵌入式字体(ArialMT)。我发现异常消息非常奇怪,但我无法理解为什么只使用Arial时会出现Helvetica。这是一个问题(bug)还是我遗漏了什么

public class BugFontExceptionDemo {
    public static void main(String[] args) {
        StringBuffer buf = new StringBuffer();
        buf.append("<body>");
        buf.append("<h1 style=\"font-family:arial\">Text in arial</h1>");
        buf.append("</body>");

        OutputStream file = null;
        Document document = null;
        PdfAWriter writer = null;
        try {
            file = new FileOutputStream(
                    new File("C:\\Users\\Emilien\\PROJECTS_FILES\\PROJECT_EXPORT_TEST\\PDF_A_HTML_WORKING.pdf"));
            document = new Document();
            writer = PdfAWriter.getInstance(document, file, PdfAConformanceLevel.PDF_A_1B);
            document.addTitle("Test document");
            writer.createXmpMetadata();
            document.open();

            ICC_Profile icc = ICC_Profile.getInstance(new FileInputStream(
                    "C:\\Users\\Emilien\\PROJECTS_FILES\\PROJECT_EXPORT_TEST\\sRGB_CS_profile.icm"));
            writer.setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc);

            CSSResolver cssResolver = new StyleAttrCSSResolver();
            CssFile cssFile = XMLWorkerHelper.getCSS(new FileInputStream("./css/style.css"));
            cssResolver.addCss(cssFile);

            MyFontProvider fontProvider = new MyFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
//          fontProvider.register("./fonts/arial.ttf");

            CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
            HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
            htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());

            PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
            HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
            CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);

            XMLWorker worker = new XMLWorker(css, true);
            XMLParser p = new XMLParser(worker);

            Reader reader = new StringReader(buf.toString());
            p.parse(reader);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (document != null && document.isOpen())
                document.close();
            try {
                if (file != null)
                    file.close();
            } catch (IOException e) {
            }
            if (writer != null && !writer.isCloseStream())
                writer.close();
        }
    }
}


public static class MyFontProvider extends XMLWorkerFontProvider {

        public MyFontProvider(String path) {
            super(path);
        }

        @Override
        public Font getFont(final String fontname, String encoding, float size, final int style) {
            System.out.println("registered: " + isRegistered(fontname) + " fontname: " + fontname + " encoding: "
                    + encoding + " size: " + size + " style: " + style);
            Font font = super.getFont(fontname, encoding, size, style);
            return font;
        }

        @Override
        public Font getFont(String fontname, String encoding, boolean embedded, float size, int style,
                BaseColor color) {
            System.out.println("registered: " + isRegistered(fontname) + " fontname: " + fontname + " encoding: "
                    + encoding + " embedded : " + embedded + " size: " + size + " style: " + style + " BaseColor: "
                    + color);
            Font font = super.getFont(fontname, encoding, embedded, size, style, color);
            return font;
        }
    }
公共类BugFontExceptionDemo{
公共静态void main(字符串[]args){
StringBuffer buf=新的StringBuffer();
buf.追加(“”);
buf.追加(“arial文本”);
buf.追加(“”);
OutputStream文件=null;
单据=空;
PdfAWriter=null;
试一试{
file=newfileoutputstream(
新文件(“C:\\Users\\Emilien\\PROJECTS\u FILES\\PROJECT\u EXPORT\u TEST\\PDF\u A\u HTML\u WORKING.PDF”);
文件=新文件();
writer=PdfAWriter.getInstance(文档、文件、PdfAConformanceLevel.PDF_A_1B);
文件。添加标题(“测试文件”);
writer.createXmpMetadata();
document.open();
ICC\u Profile ICC=ICC\u Profile.getInstance(新文件输入流(
“C:\\Users\\Emilien\\PROJECTS\u FILES\\PROJECT\u EXPORT\u TEST\\sRGB\u CS\u profile.icm”);
writer.setOutputinates(“自定义”、“自定义”、“自定义”http://www.color.org“,“sRGB IEC61966-2.1”,国际商会);
CSSResolver CSSResolver=新样式AttrCSSResolver();
CssFile CssFile=xmlworkerhelp.getCSS(新文件输入流(“./css/style.css”);
cssResolver.addCss(cssFile);
MyFontProvider fontProvider=新的MyFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
//fontProvider.register(“./fonts/arial.ttf”);
CssAppliers CssAppliers=新的CssAppliersImpl(fontProvider);
HtmlPipelineContext htmlContext=新的HtmlPipelineContext(cssAppliers);
setTagFactory(Tags.getHtmlTagProcessorFactory());
PdfWriterPipeline pdf=新的PdfWriterPipeline(文档、编写器);
HtmlPipeline html=新的HtmlPipeline(htmlContext,pdf);
CssResolverPipeline css=新的CssResolverPipeline(cssResolver,html);
XMLWorker=newxmlworker(css,true);
XMLParser p=新的XMLParser(worker);
Reader Reader=新的StringReader(buf.toString());
p、 解析(读取器);
}捕获(例外e){
e、 printStackTrace();
}最后{
if(document!=null&&document.isOpen())
document.close();
试一试{
如果(文件!=null)
file.close();
}捕获(IOE异常){
}
if(writer!=null&&!writer.isCloseStream())
writer.close();
}
}
}
公共静态类MyFontProvider扩展了XMLWorkerFontProvider{
公共MyFontProvider(字符串路径){
超级(路径);
}
@凌驾
公共字体getFont(最终字符串字体名称、字符串编码、浮点大小、最终整数样式){
System.out.println(“已注册:”+isRegistered(fontname)+“fontname:”+fontname+“编码:”
+编码+“大小:”+大小+“样式:”+样式);
Font Font=super.getFont(字体名称、编码、大小、样式);
返回字体;
}
@凌驾
公共字体getFont(字符串fontname、字符串编码、布尔嵌入、浮点大小、int样式、,
基色(颜色){
System.out.println(“已注册:”+isRegistered(fontname)+“fontname:”+fontname+“编码:”
+编码+“嵌入:”+嵌入+“大小:”+大小+“样式:”+样式+“基色:”
+颜色);
Font Font=super.getFont(字体名称、编码、嵌入、大小、样式、颜色);
返回字体;
}
}

使用
DONTLOOKFORFONTS
参数注册您的
MyFontProvider
;因此,它将不知道任何字体(除了“内置”标准14字体)开始

如果您不手动注册任何字体,这将保持不变。这正是你的情况,焦点线被评论

因此,当HTML处理过程中请求使用Arial时,将使用标准14字体的替换,在本例中为Helvetica。但iText并没有提供这些“内置”字体,只有PDF浏览器才需要,iText只知道它的一些指标。因此,iText不能也不会嵌入字体程序,而只是引用它,这将导致底层PDF/A检查代码的错误消息


然后你想知道

当请求字体但不可用时,是否可以要求
XMLWorker
引发异常,而不是用Helvetica悄悄地替换字体

当然,正如你自己发现的那样

我只需在
XMLWorkerFontProvider
中检查注册即可。如果字体没有注册,我抛出一个异常


您可以使用
DONTLOOKFORFONTS
注册您的
MyFontProvider
;因此,它将不知道任何字体(除了可能的“内置”标准14字体)开始。如果您不手动注册任何字体,这将保持不变。因此,当HTML处理过程中请求使用Arial时,将使用标准14字体的替换,在本例中为Helvetica。但这些“内置”字体并没有内置在iText、PDF和hav中