如何解决PDFBox提取文本时的无Unicode映射编码错误?
解决PDFBox提取Adobe压缩PDF文本为空的GBK字体映射问题
问题原因
报错org.apache.pdfbox.pdmodel.font.PDType0Font [422] | | No Unicode mapping for CID+63 (63) in font BFLONM+SimSun,Bold-GBK-EUC-H的核心原因是:Adobe压缩PDF时对BFLONM+SimSun,Bold-GBK-EUC-H字体做了精简处理,仅保留了GBK编码的字形数据,未嵌入完整的CID到Unicode映射表,导致PDFBox无法将字体的CID字符转换为可识别的Unicode文本。
解决方案
1. 自定义PDFTextStripper补全GBK映射
扩展PDFTextStripper类,重写getUnicode方法,在遇到无映射的CID时,手动通过GBK编码转换为Unicode字符:
import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.text.PDFTextStripper; import java.io.IOException; import java.io.UnsupportedEncodingException; public class GBKCompatibleTextStripper extends PDFTextStripper { public GBKCompatibleTextStripper() throws IOException { super(); } @Override protected String getUnicode(PDType0Font font, int cid) throws IOException { try { // 先尝试默认映射 return super.getUnicode(font, cid); } catch (IllegalArgumentException e) { // 针对带GBK标识的字体,尝试GBK编码转换 if (font.getName().contains("GBK-EUC-H")) { // 将CID转换为GBK双字节编码(需确认CID与GBK码位的对应关系,此处为通用逻辑) byte[] gbkBytes = {(byte) ((cid >> 8) & 0xFF), (byte) (cid & 0xFF)}; try { return new String(gbkBytes, "GBK"); } catch (UnsupportedEncodingException ex) { return "?"; } } // 非GBK字体抛出原异常 throw e; } } }
使用时替换原PDFTextStripper:
PDDocument doc = PDDocument.load(new File("your.pdf")); GBKCompatibleTextStripper stripper = new GBKCompatibleTextStripper(); String text = stripper.getText(doc); doc.close();
2. 预处理PDF修复字体映射
通过工具重新生成PDF,强制嵌入完整的字体映射信息:
- Adobe Acrobat:打开PDF后选择「另存为其他」→「优化PDF」,在字体设置中勾选「嵌入所有字体」并取消「子集化字体」,保存后即可修复映射。
- Ghostscript命令行:执行以下命令重新生成PDF:
gs -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -dEmbedAllFonts=true -dSubsetFonts=false -o fixed.pdf input.pdf
3. 替换有问题的GBK字体
使用PDFBox将缺失映射的字体替换为系统中带完整Unicode映射的SimSun Bold字体:
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.cos.COSName; import java.io.File; import java.io.IOException; public class FontReplacer { public static void main(String[] args) throws IOException { PDDocument document = PDDocument.load(new File("input.pdf")); for (PDPage page : document.getPages()) { PDResources resources = page.getResources(); for (COSName fontName : resources.getFontNames()) { PDFont font = resources.getFont(fontName); if (font.getName().contains("BFLONM+SimSun,Bold-GBK-EUC-H")) { // 加载系统中的SimSun Bold字体文件(需替换为实际路径) PDType0Font newFont = PDType0Font.load(document, new File("C:/Windows/Fonts/simsunb.ttf")); resources.put(fontName, newFont); } } } document.save("fixed.pdf"); document.close(); } }
验证方法
处理完成后,重新用PDFTextStripper提取文本,检查输出内容是否正常,同时查看日志是否仍存在"No Unicode mapping"类错误。
内容的提问来源于stack exchange,提问作者yiCarlos
相关产品推荐
相关产品推荐

