以下代码在许多情况下通过ITextSharp正确地从PDF中提取文本。
using (var pdfReader = new PdfReader(filename))
{
ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
var currentText = PdfTextExtractor.GetTextFromPage(
pdfReader,
1,
strategy);
currentText =
Encoding.UTF8.GetString(Encoding.Convert(
Encoding.Default,
Encoding.UTF8,
Encoding.Default.GetBytes(currentText)));
Console.WriteLine(currentText);
}
但是,对于这个PDF,我得到以下内容而不是文本:" \ u0001 \ u0002 \ u0003 \ u0004 \ u0005 \ u0006 \ a \ b \ t \ a \ u0001 \ U0002 \ U0003 \ U0004 \ u0005 \ u0006 \ U0003"
我尝试了不同的编码甚至是PDFBox,但仍无法正确解码PDF。关于如何解决这个问题的任何想法?
答案 0 :(得分:3)
@Bruno's answer是应该给出的答案,PDF显然没有根据PDF规范的 9.10文本内容提取部分提供允许正确文本提取所需的信息{ {3}} ...
但实际上还有一种有点邪恶的方式从手头的PDF中提取文本!
在以下类的实例中包含一个文本提取策略,将乱码文本替换为正确的文本:
public class RemappingExtractionFilter : ITextExtractionStrategy
{
ITextExtractionStrategy strategy;
System.Reflection.FieldInfo stringField;
public RemappingExtractionFilter(ITextExtractionStrategy strategy)
{
this.strategy = strategy;
this.stringField = typeof(TextRenderInfo).GetField("text", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
}
public void RenderText(TextRenderInfo renderInfo)
{
DocumentFont font =renderInfo.GetFont();
PdfDictionary dict = font.FontDictionary;
PdfDictionary encoding = dict.GetAsDict(PdfName.ENCODING);
PdfArray diffs = encoding.GetAsArray(PdfName.DIFFERENCES);
;
StringBuilder builder = new StringBuilder();
foreach (byte b in renderInfo.PdfString.GetBytes())
{
PdfName name = diffs.GetAsName((char)b);
String s = name.ToString().Substring(2);
int i = Convert.ToInt32(s, 16);
builder.Append((char)i);
}
stringField.SetValue(renderInfo, builder.ToString());
strategy.RenderText(renderInfo);
}
public void BeginTextBlock()
{
strategy.BeginTextBlock();
}
public void EndTextBlock()
{
strategy.EndTextBlock();
}
public void RenderImage(ImageRenderInfo renderInfo)
{
strategy.RenderImage(renderInfo);
}
public String GetResultantText()
{
return strategy.GetResultantText();
}
}
可以像这样使用:
ITextExtractionStrategy strategy = new RemappingExtractionFilter(new LocationTextExtractionStrategy());
string text = PdfTextExtractor.GetTextFromPage(pdfReader, page, strategy);
小心 ,我不得不使用System.Reflection
来访问私人会员。某些环境可能会禁止此操作。
我最初用Java编写了iText代码,因为这是我的主要开发环境。因此,这里是最初的Java版本:
public class RemappingExtractionFilter implements TextExtractionStrategy
{
public RemappingExtractionFilter(TextExtractionStrategy strategy) throws NoSuchFieldException, SecurityException
{
this.strategy = strategy;
this.stringField = TextRenderInfo.class.getDeclaredField("text");
this.stringField.setAccessible(true);
}
@Override
public void renderText(TextRenderInfo renderInfo)
{
DocumentFont font =renderInfo.getFont();
PdfDictionary dict = font.getFontDictionary();
PdfDictionary encoding = dict.getAsDict(PdfName.ENCODING);
PdfArray diffs = encoding.getAsArray(PdfName.DIFFERENCES);
;
StringBuilder builder = new StringBuilder();
for (byte b : renderInfo.getPdfString().getBytes())
{
PdfName name = diffs.getAsName((char)b);
String s = name.toString().substring(2);
int i = Integer.parseUnsignedInt(s, 16);
builder.append((char)i);
}
try
{
stringField.set(renderInfo, builder.toString());
}
catch (IllegalArgumentException | IllegalAccessException e)
{
e.printStackTrace();
}
strategy.renderText(renderInfo);
}
@Override
public void beginTextBlock()
{
strategy.beginTextBlock();
}
@Override
public void endTextBlock()
{
strategy.endTextBlock();
}
@Override
public void renderImage(ImageRenderInfo renderInfo)
{
strategy.renderImage(renderInfo);
}
@Override
public String getResultantText()
{
return strategy.getResultantText();
}
final TextExtractionStrategy strategy;
final Field stringField;
}
可以像这样使用:
String extractRemapped(PdfReader reader, int pageNo) throws IOException, NoSuchFieldException, SecurityException
{
TextExtractionStrategy strategy = new RemappingExtractionFilter(new LocationTextExtractionStrategy());
return PdfTextExtractor.getTextFromPage(reader, pageNo, strategy);
}
(来自RemappingExtractionFilter.java)
首先,这不是所有提取问题的解决方案,仅仅是用于从OP提供的PDF中提取文本。
此方法有效,因为PDF在其字体中使用的名称'编码差异数组可以解释,即使它们不是标准的。这些名称构建为 / G xx ,其中 xx 是此名称所代表的字符的ASCII代码的十六进制表示。
答案 1 :(得分:1)
检查PDF 是否允许正确提取文本的一个很好的测试是在Adobe Reader中打开它并复制和粘贴文本。
例如:我复制了单词ABSTRACT,并将其粘贴在Notepad ++中:
你在Notepad ++中看到了单词ABSTRACT吗?不,您看到%& SOH
'“%GS
。A表示为%,B表示为&,依此类推。
这清楚地表明PDF的内容无法访问:使用的编码(%= A,& = B,...)与人类可以使用的实际字符之间没有映射理解。
简而言之:PDF不允许您提取文本,不使用iText,不使用iTextSharp,不使用PDFBox。您将不得不找到一个OCR工具并OCR整个文档。
有关详细信息,您可能需要观看以下视频: