使用iText7 8.0.4提取PDF文本仅返回问号的问题求助
解决iText7提取PDF文本显示问号的问题
问题现象
使用iText7 8.0.4提取PDF文本时,输出内容全为问号:
???????? ?????????? ? ???????????????????????? ??????????????????? ???????? ???????????????????????????? ???????????????????????? ???????????????????????????? ?????????????? ????????????????????? ???????????? ???????????????????? ?????????? ????? ?????????? ????????????????????? ??????????????????????????????????? ????????????? ?????????? ????????????????? ?????????????????????????????????? ??????? ???????????????? ???????????????? ...
但在Adobe Acrobat和Chrome浏览器中可正常复制该PDF的文本,且PDF仅使用Verdana字体。
原测试代码
MemoryStream pdfStream = ... pdfStream.Position = 0; var strategy = new LocationTextExtractionStrategy(); var reader = new PdfReader(pdfStream); using var pdfDocument = new PdfDocument(reader); for (int i = 1; i <= pdfDocument.GetNumberOfPages(); ++i) { var page = pdfDocument.GetPage(i); var text = PdfTextExtractor.GetTextFromPage(page, strategy); }
适配旧版代码时的错误
尝试将旧版iText解决方案迁移到iText7时,出现以下编译错误:
CS0246 找不到类型或命名空间名称“PdfStamper” CS1061 “PdfReader”不包含“GetPageResources”的定义,也找不到可接受第一个参数为“PdfReader”类型的扩展方法“GetPageResources” CS1061 “PdfDictionary”不包含“GetAsDict”的定义,也找不到可接受第一个参数为“PdfDictionary”类型的扩展方法“GetAsDict” CS0117 “PdfName”不包含“FONT”的定义
解决方案
问题根源是PDF中的Verdana字体缺少正确的ToUnicode映射表,导致iText7无法将字体编码转换为Unicode字符。可以通过自定义文本提取策略,手动指定编码映射来解决:
1. 自定义文本提取策略
创建继承自LocationTextExtractionStrategy的自定义策略,处理无Unicode映射的字体:
using iText.Kernel.Font; using iText.Kernel.Pdf.Canvas.Parser; using iText.Kernel.Pdf.Canvas.Parser.Data; using iText.Kernel.Pdf.Canvas.Parser.Listener; using System.Linq; public class CustomUnicodeTextStrategy : LocationTextExtractionStrategy { protected override void RenderText(TextRenderInfo renderInfo) { var font = renderInfo.GetFont(); if (font != null && !font.HasUnicode()) { // 使用Windows-1252编码(Verdana常用编码)映射字符 var encoding = PdfEncodings.WINANSI; var textBytes = font.ConvertToBytes(renderInfo.GetText()); var unicodeChars = textBytes.Select(b => (char)encoding.GetUnicode(b)).ToArray(); var correctedText = new string(unicodeChars); // 创建修正后的TextRenderInfo对象 var correctedRenderInfo = new TextRenderInfo( correctedText, renderInfo.GetGraphicsState(), renderInfo.GetBaseline(), renderInfo.GetAscentLine(), renderInfo.GetDescentLine(), renderInfo.GetWordSpacing(), renderInfo.GetCharacterSpacing(), renderInfo.GetHorizontalScaling(), renderInfo.GetFontSize(), renderInfo.GetFont(), renderInfo.GetRise(), renderInfo.GetTextMatrix(), renderInfo.GetStartPoint(), renderInfo.GetEndPoint(), renderInfo.GetWidth() ); base.RenderText(correctedRenderInfo); } else { base.RenderText(renderInfo); } } }
2. 使用自定义策略提取文本
修改原代码,使用自定义策略替代默认的LocationTextExtractionStrategy,同时注册系统字体目录确保iText能找到Verdana字体:
MemoryStream pdfStream = ... pdfStream.Position = 0; // 注册系统字体目录,让iText能访问本地Verdana字体 FontProgramFactory.RegisterSystemDirectories(); var reader = new PdfReader(pdfStream); using var pdfDocument = new PdfDocument(reader); // 使用自定义文本提取策略 var strategy = new CustomUnicodeTextStrategy(); for (int i = 1; i <= pdfDocument.GetNumberOfPages(); ++i) { var page = pdfDocument.GetPage(i); var text = PdfTextExtractor.GetTextFromPage(page, strategy); // 处理提取到的正确文本 }
说明
- 注册系统字体目录是为了让iText能加载本地的Verdana字体,确保字符映射的准确性。
- 若PDF使用其他编码,可将
PdfEncodings.WINANSI替换为对应编码(如PdfEncodings.UTF8)。
内容的提问来源于stack exchange,提问作者Andrus
相关产品推荐
相关产品推荐

