总之
该异常的原因是 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 实现包装在一个抑制这些异常的实现中来防止这种错误情况停止文本提取。
例如使用这个帮助类
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 规范明确要求平衡且正确嵌套的标记内容运算符。