问题
pdfbox 转换PDF为IMAGE时由于不存在相关字体导致输出的图片中文字不显示
处理
- 查看控制台提示信息
org.apache.pdfbox.pdmodel.font.PDCIDFontType0 - Using fallback HYZhongHei-197 for CID-keyed font STSong-Light
- 检查本地系统, 发现无
STSong-Light
字体, 但是有类似的STSong
, 考虑替换 - 通过日志确定提示代码位置, 向上查找
font
的读取位置FontMappers.instance().getCIDFont
, 具体实现由FontMapperImpl
提供- 先查找
otf
, 没有再查找ttf
, 最后再通过相关属性查找类似的字体
- 先查找
FontMapperImpl
无法被继承导致无法重写getCIDFont
方法, 通过查看FontMappers.instance()
, 发现内部的instance
可以重新设置- 编写一个
MyFontMapperImpl
, 在内部持有原来的FontMapperImpl
, 同时在getCIDFont
中添加代码, 将查找不到的STSong-Light
直接替换为STSong
, 其余方法调用FontMapperImpl
的实现 - 在调用
renderImageWithDPI
前, 通过FontMappers.set(new MyFontMapperImpl());
设置
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.24</version>
</dependency>
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.font.FontMappers;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class PDFToImage2 {
public static void main(String[] args) throws IOException, FontFormatException {
String dir = "/split-pdf-to-image/";
String filename = "Report.pdf";
// 加载PDF文档
PDDocument document = PDDocument.load(new File(dir + filename));
// 创建PDF渲染器
PDFRenderer pdfRenderer = new PDFRenderer(document);
// 设置自己的fontmapper
FontMappers.set(new MyFontMapperImpl());
// 转换第一页
BufferedImage image = pdfRenderer.renderImageWithDPI(0, 300, ImageType.RGB);
document.close();
System.out.println("转换完成");
ImageIO.write(image, "JPEG", new File(dir + filename + ".jpg"));
}
}
import org.apache.fontbox.FontBoxFont;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.pdfbox.pdmodel.font.*;
public class MyFontMapperImpl implements FontMapper {
FontMapper df = FontMappers.instance();
MyFontMapperImpl(){}
@Override
public FontMapping<TrueTypeFont> getTrueTypeFont(String baseFont, PDFontDescriptor fontDescriptor) {
return df.getTrueTypeFont(baseFont, fontDescriptor);
}
@Override
public FontMapping<FontBoxFont> getFontBoxFont(String baseFont, PDFontDescriptor fontDescriptor) {
return df.getFontBoxFont(baseFont, fontDescriptor);
}
@Override
public CIDFontMapping getCIDFont(String baseFont, PDFontDescriptor fontDescriptor, PDCIDSystemInfo cidSystemInfo) {
if("STSong-Light".equals(baseFont)){
System.out.println("替换 STSong-Light 为 STSong");
baseFont = "STSong";
}
return df.getCIDFont(baseFont, fontDescriptor, cidSystemInfo);
}
}
其他
- 参考: 通过重写类实现加载外部字体
- 其他方式: 在项目中覆盖FontMapperImpl类达到在getCIDFont添加自定义代码