You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 21:14:55