1

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

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

  • 最终的 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.) 将字体嵌入到包含拉丁文和 CJK 字符的 PDF 中。

解决方案 1 更可取,但使用方法 2 的修复也将不胜感激。

解决方案 1 应该适用于 itext-asian.jar,但它不在我的设置中(由于某种原因,它不适用于 Android itext 版本吗?)

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

4

1 回答 1

4

经过大量的反复试验,我想出了以下适用于 Android 和桌面的解决方案:

1.) 将适合itext-asian.jar您的 itext 版本添加到您的类路径中

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 文件,一旦你开始嵌入硬编码的字体文件,你的代码就不再那么便携了。

于 2014-11-03T14:57:23.767 回答