如何在安卓系统上使用带XMLWorker的iText中的CJK字体



我使用以下设置程序使用iText(商业许可证,iText版本:5.4.5)创建PDF文档:

  • HTML模板是用jmustache生成的,在这个步骤中进行国际化,即文档可以包含欧洲语言,也可以包含日语和中文(也可以是两者的混合,因为一些文本部分可能仍然是英语)

  • 最后的HTML是使用XMLWorker呈现的,如下所示:

    final float marginPt = 28.35f;//1cm == 28.35pt
    final Document document = new Document(PageSize.A4, marginPt, marginPt, marginPt, 0);
    final PdfWriter writer = PdfWriter.getInstance(document, output);
    //we write multiple documents to a ZipOutputStream, so we close the output stream later
    writer.setCloseStream(false);
    document.open();
    final HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
    htmlContext.setImageProvider(new DynamicImageProvider(privateStorageFolder));
    final CSSResolver cssResolver = XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
    final Pipeline<?> pipeline = new CssResolverPipeline(cssResolver,
            new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, writer)));
    final XMLWorker worker = new XMLWorker(pipeline, true);
    final XMLParser p = new XMLParser(worker);
    p.parse(new StringReader(input));
    document.close();
    

对于欧洲字符(拉丁字母、元音变音符、重音符号等),一切都很好。但是对于CJK字符(例如日语),PDF中的结果文本不会显示,也没有提示我安装其他字体的消息。

我尝试将extrajars-2.3-zip中的itext-asian.jar添加到android库中(http://sourceforge.net/projects/itext/files/extrajars/)但这无济于事。

我正在寻找一个解决方案,通过以下方式将CJK文本正确添加到生成的PDF中:

1.)使用PDF CJK功能(即最终用户需要安装CJK字体的阅读器)

2.)在PDF中嵌入一种字体,该字体同时包含拉丁文和拉丁文;CJK字符。

解决方案1将是优选的,但是使用方法2的修复也将是非常值得赞赏的。

解决方案1应该可以使用itext-asian.jar,但在我的设置中它不起作用(出于某种原因,这对Android itext版本不起作用吗?)

对于解决方案2,我需要找到一种在Android中向XMLWorker添加多种字体的方法,因为大多数支持多个脚本的字体都被拆分在不同的ttf文件中(例如google noto字体https://www.google.com/get/noto/)

经过多次的尝试和错误之后,我提出了以下适用于Android和桌面的解决方案:

1.)将itext版本的相应itext-asian.jar添加到类路径中

2.)实现自定义FontFactory,类似于

public class MyFontFactory extends FontFactoryImp {
@Override
public Font getFont(final String fontname, final String encoding, final boolean embedded, final float size, final int style, final BaseColor color, final boolean cached) {
    if ("CJK".equals(fontname)){
        //these parameters were found out via trial-and-error, it is the asian font that looked best for our needs
        //look into the itext-asian.jar for alternatives
        return FontFactory.getFont("HeiseiKakuGo-W5","UniJIS-UCS2-H", BaseFont.NOT_EMBEDDED, size, style, color, cached);           
    } else {
        return super.getFont(fontname, encoding, embedded, size, style, color, cached);
    }
}

3.)将字体工厂添加到您的XMLWorker链中,如下所示:

final MyFontFactory fontFactory = new MyFontFactory();
//this sets the custom font factory for everything *but* the XMLWorker
//(now that's amazing API design -.- )
FontFactory.setFontImp(fontFactory);
//this is the trick to get our fontFactory into the XmlWorker: 
//build the processing pipeline manually and inject the factory along the way
final HtmlPipelineContext htmlContext = new HtmlPipelineContext(new CssAppliersImpl(fontFactory));
final CSSResolver cssResolver = XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
final Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, writer)));
final XMLWorker worker = new XMLWorker(pipeline, true);
final XMLParser p = new XMLParser(worker);
p.parse(new StringReader(input));

现在你可以在HTML/CSS中使用伪字体"CJK",你可以在不嵌入整个字体的情况下获得亚洲字符

* { 
    font-family:CJK; 
    font-size: 8pt;
}

如果你想嵌入一种字体,只需在你的FontFactory中以不同的方式构建你的字体,例如:

return FontFactory.getFont("/system/fonts/DroidSans.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, size, style, color, cached);

当然,你必须确保你有可用的ttf文件,一旦你开始嵌入硬编码的字体文件,你的代码就不再是可移植的了。

最新更新