从使用 ItextSharp 或 PDFSharp 创建的拼合 PDF 中提取文本
Extract Text from Flattenned PDF created with ItextSharp Or PDFSharp
我想从我拥有的使用 ItextSharp 的特定模板创建的许多 PDF 中检索一些数据。
那些 PDF 被拼合了
FormFlattening = true;
我尝试了很多在互联网上找到的不同方法,并且 none 奏效了。我收到一条错误消息:
System.InvalidOperationException: 'Stack empty.'
总是当我尝试提取时,通常在以下行,无论策略如何:
string thePage = PdfTextExtractor.GetTextFromPage(reader, i, strategy);
我也尝试了 pdfSharp,但没有成功,也没有关于提取的真实文档。
我还尝试了两个使用 IKVM 的库,但它们无法在我的项目上工作。
编辑 1:我当前的解决方法是使用 Xpdf 中的 pdftotext.exe,将其作为进程调用,然后读取 txt 文件。这有点慢。
我使用的是商业产品,没有任何问题。 Adobe Acrobat 无法提取任何内容。
许多底层表单文本是图像,我也没有提取它,但它可能与耦合的 OCR 引擎一起使用。我假设您只想要文本内容而不是图像 OCR。如果它是 OCR 并提取到 Unicode 文档,那就没问题了。
简而言之
出现该异常的原因是 PDF 中存在错误。一些扁平化到内容中的外观流包含两个结束标记内容操作,用于单个开始标记内容操作。在关联的 IContentOperator
实施中,第二个 EMC 导致异常。通过将该实现包装在抑制这些异常的实现中,您可以提取文本。
错误
一些扁平化到内容中的外观流包含针对单个开始标记内容操作的两个结束标记内容操作。
例如以前的外观流扁平化为 Xobject Xi8 形式,如下所示:
/Tx BMC
q
1.00 1.00 130.91 29.51 re
W
n
0.00 g
BT
/ArialMT 14.00 Tf
2 10.90 Td
15.62 TL
(\b\tüü\b) Tj
ET
Q
EMC
EMC
与 EMC 操作关联的 IContentOperator
实施只是执行
markedContentStack.Pop();
如果第二个 EMC 为空 markedContentStack
,则会导致 InvalidOperationException
.
解决方法
您可以通过将 EMC IContentOperator
实现包装在抑制这些异常的实现中来防止这种错误情况停止文本提取。
例如使用这个助手 class
public class InvalidOperationExceptionIgnoringWrapper : IContentOperator
{
public void Invoke(PdfContentStreamProcessor processor, PdfLiteral oper, List<PdfObject> operands)
{
try
{
WrappedOperator.Invoke(processor, oper, operands);
}
catch (InvalidOperationException e)
{
Console.Error.WriteLine("Caught InvalidOperationException {0} for {1}", e.Message, oper);
}
}
public IContentOperator WrappedOperator { get; set; }
}
如下:
var pdfReader = new PdfReader(@"SamplePDF.pdf");
int pageNumber = 1;
PdfDictionary pageDic = pdfReader.GetPageN(pageNumber);
PdfDictionary resourcesDic = pageDic.GetAsDict(PdfName.RESOURCES);
ITextExtractionStrategy renderListener = new SimpleTextExtractionStrategy();
PdfContentStreamProcessor processor = new PdfContentStreamProcessor(renderListener);
InvalidOperationExceptionIgnoringWrapper wrapper = new InvalidOperationExceptionIgnoringWrapper();
IContentOperator original = processor.RegisterContentOperator("EMC", wrapper);
wrapper.WrappedOperator = original;
processor.ProcessContent(ContentByteUtils.GetContentBytesForPage(pdfReader, pageNumber), resourcesDic);
var pageText = renderListener.GetResultantText();
现在文本提取时抑制了四个 InvalidOperationExceptions。
这实际上不是最终的修复或解决方案,只是解决方法,因为实际错误在 PDF 中,这些内容流是无效的,因为 PDF 规范明确要求平衡和正确嵌套的标记内容运算符。
我想从我拥有的使用 ItextSharp 的特定模板创建的许多 PDF 中检索一些数据。
那些 PDF 被拼合了
FormFlattening = true;
我尝试了很多在互联网上找到的不同方法,并且 none 奏效了。我收到一条错误消息:
System.InvalidOperationException: 'Stack empty.'
总是当我尝试提取时,通常在以下行,无论策略如何:
string thePage = PdfTextExtractor.GetTextFromPage(reader, i, strategy);
我也尝试了 pdfSharp,但没有成功,也没有关于提取的真实文档。 我还尝试了两个使用 IKVM 的库,但它们无法在我的项目上工作。
编辑 1:我当前的解决方法是使用 Xpdf 中的 pdftotext.exe,将其作为进程调用,然后读取 txt 文件。这有点慢。
我使用的是商业产品,没有任何问题。 Adobe Acrobat 无法提取任何内容。 许多底层表单文本是图像,我也没有提取它,但它可能与耦合的 OCR 引擎一起使用。我假设您只想要文本内容而不是图像 OCR。如果它是 OCR 并提取到 Unicode 文档,那就没问题了。
简而言之
出现该异常的原因是 PDF 中存在错误。一些扁平化到内容中的外观流包含两个结束标记内容操作,用于单个开始标记内容操作。在关联的 IContentOperator
实施中,第二个 EMC 导致异常。通过将该实现包装在抑制这些异常的实现中,您可以提取文本。
错误
一些扁平化到内容中的外观流包含针对单个开始标记内容操作的两个结束标记内容操作。
例如以前的外观流扁平化为 Xobject Xi8 形式,如下所示:
/Tx BMC
q
1.00 1.00 130.91 29.51 re
W
n
0.00 g
BT
/ArialMT 14.00 Tf
2 10.90 Td
15.62 TL
(\b\tüü\b) Tj
ET
Q
EMC
EMC
与 EMC 操作关联的 IContentOperator
实施只是执行
markedContentStack.Pop();
如果第二个 EMC 为空 markedContentStack
,则会导致 InvalidOperationException
.
解决方法
您可以通过将 EMC IContentOperator
实现包装在抑制这些异常的实现中来防止这种错误情况停止文本提取。
例如使用这个助手 class
public class InvalidOperationExceptionIgnoringWrapper : IContentOperator
{
public void Invoke(PdfContentStreamProcessor processor, PdfLiteral oper, List<PdfObject> operands)
{
try
{
WrappedOperator.Invoke(processor, oper, operands);
}
catch (InvalidOperationException e)
{
Console.Error.WriteLine("Caught InvalidOperationException {0} for {1}", e.Message, oper);
}
}
public IContentOperator WrappedOperator { get; set; }
}
如下:
var pdfReader = new PdfReader(@"SamplePDF.pdf");
int pageNumber = 1;
PdfDictionary pageDic = pdfReader.GetPageN(pageNumber);
PdfDictionary resourcesDic = pageDic.GetAsDict(PdfName.RESOURCES);
ITextExtractionStrategy renderListener = new SimpleTextExtractionStrategy();
PdfContentStreamProcessor processor = new PdfContentStreamProcessor(renderListener);
InvalidOperationExceptionIgnoringWrapper wrapper = new InvalidOperationExceptionIgnoringWrapper();
IContentOperator original = processor.RegisterContentOperator("EMC", wrapper);
wrapper.WrappedOperator = original;
processor.ProcessContent(ContentByteUtils.GetContentBytesForPage(pdfReader, pageNumber), resourcesDic);
var pageText = renderListener.GetResultantText();
现在文本提取时抑制了四个 InvalidOperationExceptions。
这实际上不是最终的修复或解决方案,只是解决方法,因为实际错误在 PDF 中,这些内容流是无效的,因为 PDF 规范明确要求平衡和正确嵌套的标记内容运算符。