如何使用 iText 获取使用多种字体呈现的 pdf

Posted

技术标签:

【中文标题】如何使用 iText 获取使用多种字体呈现的 pdf【英文标题】:How to use iText get pdf rendered with multiple fonts 【发布时间】:2020-02-12 07:20:20 【问题描述】:

我正在使用 iText 将包含英文和中文字符的 html 解析为 pdf。我正在使用

  // for pdf rendering
  compile group: 'com.itextpdf', name: 'itextpdf', version: '5.5.13.1'

  // for pdf rendering
  compile group: 'com.itextpdf.tool', name: 'xmlworker', version: '5.5.13.1'

我已经让中文字符解析成为可能,而不是依赖问题

  // for chinese font in pdf rendering
  compile group: 'com.itextpdf', name: 'itext-asian', version: '5.2.0'

和自定义字体提供者

public class StSongProvider extends XMLWorkerFontProvider 

  private static final Logger LOG = LoggerFactory.getLogger(StSongProvider.class);

  public StSongProvider() 
    super(null, null);
  

  @Override
  public Font getFont(final String fontName, String encoding, float size, final int style) 
    BaseFont bfChinese = null;
    try 
      bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
     catch (Exception e) 
      LOG.error("Not found STSong-Light,maybe com.itextpdf.itext-asian dependency problem");
    
    return new Font(bfChinese, size, style);
  

和pdf渲染代码

  public static File html2Pdf(String html, String fileName) 
    try 
      String path = buildPath(fileName);
      // step 1
      Document document = new Document(PageSize.A4);
      document.setMargins(20, 20, 0, 0);
      // step 2
      PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(path));
      // step 3
      document.open();
      // step 4
      InputStream cssInput = null;
      XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)), cssInput, new StSongProvider());
      // step 5
      document.close();
      LOG.info("PDF file:  rendering successfully", path);
      return new File(path);
     catch (IOException ex) 
      // do something
     catch (DocumentException ex) 
      // do something
    
  

但结果 pdf 中的英文字符如果没有合适的字体就不是那么漂亮(所有字符都使用STSong-Light 字体)。我想使用STSong-Light 以中文字符和使用iText 最初支持的一些字体(例如Times-Roman)以英文字符呈现pdf。

我发现 SO thread 可以使用 FontSelector 构建具有多种字体的文档。但是如何使它与pdf创建过程兼容呢? XMLWorkerHelper.getInstance().parseXHtml api 只接受 FontProvider 作为参数。对此有何想法?

【问题讨论】:

【参考方案1】:

解决办法是在自定义字体提供器上做点什么,让它不只返回一种字体,而是返回字体取决于html单元格font-family属性。

public class StSongProvider extends XMLWorkerFontProvider 

  private static final Logger LOG = LoggerFactory.getLogger(StSongProvider.class);

  public StSongProvider() 
    super(null, null);
  

  @Override
  public Font getFont(final String fontName, String encoding, float size, final int style) 
    BaseFont font = null;
    try 
      if (StringUtils.equals(fontName, "STSong-Light")) 
        font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
       else 
        font = BaseFont.createFont(FontFactory.TIMES_ROMAN, FontFactory.defaultEncoding, true);
      
     catch (Exception e) 
      // do something
    
    return new Font(font, size, style);
  


使用上面的字体提供者,并设置html单元格的style="font-family:STSong-Light属性包含中文字符来格式化它们,其他英文字符将用TIMES_ROMAN很好地格式化;

【讨论】:

以上是关于如何使用 iText 获取使用多种字体呈现的 pdf的主要内容,如果未能解决你的问题,请参考以下文章

Java实现HTML代码生成PDF文档

如何使用 iText 获取 Pdf 表单字段的自定义格式脚本?

IText7如何解码字段的默认外观int字体对象及其属性

使用 iText 将字体嵌入 PDF 文件

使用iText 7(C#)创建删除线字体

如何在iText 5中设置字体系列?