C# IText赢得';无法正确读取PDF区域
我正在使用C# IText赢得';无法正确读取PDF区域,c#,pdf,itext,C#,Pdf,Itext,我正在使用LocationTextExtractionStrategy与自定义iTextractionStrategy类结合来阅读PDF。有了这段代码,我可以毫无问题地根据coords读取文档部分 现在我得到了一个类似于其他文档的PDF,但如果我尝试阅读它,我会得到如下文本: 2 D 80 D 8 1 M 13M2 R V / 8 3B 3 3 710 022/F//0 R8 8 1 0 / 3 这是我正在使用的代码: private static string
LocationTextExtractionStrategy
与自定义iTextractionStrategy
类结合来阅读PDF。有了这段代码,我可以毫无问题地根据coords读取文档部分
现在我得到了一个类似于其他文档的PDF,但如果我尝试阅读它,我会得到如下文本:
2 D 80 D 8 1 M 13M2 R V / 8 3B 3 3 710 022/F//0 R8 8 1 0 / 3
这是我正在使用的代码:
private static string ReadFilePart(string fileName,int pageNumber, int fromLeft, int fromBottom, int width, int height)
{
var rect = new System.util.RectangleJ(fromLeft, fromBottom, width, height);
var pdfReader = new PdfReader(fileName);
var filters = new RenderFilter[1];
filters[0] = new RegionTextRenderFilter(rect);
var strategy = new FilteredTextRenderListener(new LocationTextExtractionStrategy(), filters);
var pageText = PdfTextExtractor.GetTextFromPage(pdfReader, pageNumber, new LimitedTextStrategy(strategy));
pdfReader.Close();
return pageText;
}
private class LimitedTextStrategy : ITextExtractionStrategy
{
public readonly ITextExtractionStrategy textextractionstrategy;
public LimitedTextStrategy(ITextExtractionStrategy strategy)
{
textextractionstrategy = strategy;
}
public void RenderText(TextRenderInfo renderInfo)
{
foreach (TextRenderInfo info in renderInfo.GetCharacterRenderInfos())
{
textextractionstrategy.RenderText(info);
}
}
public string GetResultantText()
{
return textextractionstrategy.GetResultantText();
}
public void BeginTextBlock()
{
textextractionstrategy.BeginTextBlock();
}
public void EndTextBlock()
{
textextractionstrategy.EndTextBlock();
}
public void RenderImage(ImageRenderInfo renderInfo)
{
textextractionstrategy.RenderImage(renderInfo);
}
}
由于敏感数据,我无法共享PDF文件
更新
如果我用SimpleTextExtractionStrategy
更改LocationTextExtractionStrategy
,它将识别不带奇怪字符的整行(PDF结构?)
更新2
我现在可以共享该文件了!有问题的页面为2°和3°
更新3
为我指出了正确的方向,我修复了将FistChar
、LastChar
和Widths
添加到所有缺少默认值属性的字体中的问题
private static PdfReader FontFix(PdfReader pdfReader)
{
for (var p = 1; p <= pdfReader.NumberOfPages; p++)
{
var dic = pdfReader.GetPageN(p);
var resources = dic.GetAsDict(PdfName.RESOURCES);
var fonts = resources?.GetAsDict(PdfName.FONT);
if (fonts == null) continue;
foreach (var key in fonts.Keys)
{
var font = fonts.GetAsDict(key);
var firstChar = font.Get(PdfName.FIRSTCHAR);
if(firstChar==null)
font.Put(PdfName.FIRSTCHAR, new PdfNumber(0));
var lastChar = font.Get(PdfName.LASTCHAR);
if (lastChar == null)
font.Put(PdfName.LASTCHAR, new PdfNumber(255));
var widths= font.GetAsArray(PdfName.WIDTHS);
if (widths == null)
{
var array=new int[256];
array=Enumerable.Repeat(600, 256).ToArray();
font.Put(PdfName.WIDTHS, new PdfArray(array));
}
}
}
return pdfReader;
}
private static PdfReader FontFix(PdfReader PdfReader)
{
对于(var p=1;p)PDF中的错误
此问题的原因是PDF包含一个不完整的字体字典。PDF中的大多数字体字典都是完整的,但有一个例外,对象28中的字典用于共享资源中的fontFo0,用于“填充”第二页和第三页上的字段:
<<
/Name /Fo0
/Subtype /TrueType
/BaseFont /CourierNew
/Type /Font
/Encoding /WinAnsiEncoding
>>
将renderInfo
(描述较长的字符串)拆分为多个TextRenderInfo
实例(每个实例描述一个glyph)。如果renderInfo
的字体是关键的Fo0,则所有这些TextRenderInfo
实例都具有相同的位置,因为iTextSharp假定glyph宽度为0
…使用LocationTextExtractionsStrategy
然后,这些TextRenderInfo
实例被过滤并转发到LocationTextExtractionStrategy
,后者随后按位置对它们进行排序。由于位置重合,并且所使用的排序算法不会将具有相同位置的元素保持在其原始顺序,因此这种排序会有效地将它们洗牌。最终,y你得到的所有对应的字符都是一个混乱的顺序
…使用simpletextraction策略
在这种情况下,这些TextRenderInfo
实例将被过滤并转发到simpletextractionstrategy
,该策略不会对它们进行排序,而是将各自对应的字符添加到结果字符串中。如果在内容流中,文本显示操作以读取顺序进行,则结果策略返回的结果也符合正确的阅读顺序
为什么Adobe Reader以正确的顺序显示文本?
如果遇到损坏的PDF,不同的程序可以尝试不同的策略来应对这种情况
本案中的Adobe Reader最有可能在操作系统中搜索CourierNew TrueType字体程序,并使用其中的宽度信息。这很可能是该破坏字体结构的创建者所希望的。如果您无法共享pdf,并且您的策略对所有其他pdf(而不仅仅是此pdf)都适用,那么,恐怕要帮你的忙几乎是不可能的。如果你是一个有支持合同的iText客户,那么如果你愿意,我们可以签署一份保密协议,但是我们已经默认将客户的文件视为机密文件。如果我试着在Illustrator中导入PDF并使用默认选项保存它,它会起作用。我认为问题在于lem与文件的创建方式有关。我添加了一个“已损坏”文件和一个解决方案,其中包含我用于读取PDF文件的代码。您认为我是否可以使用iText检查页面字体字典,并在不完整时用默认字体定义替换字体定义?是的,您可以。只需检索Fo0字体资源即可(文件的所有页面都共享)并添加缺少的条目,特别是FirstChar、LastChar和Widths。我能找到一个示例或文档来实现这一点吗?我会尝试写一些东西。可能需要一两天的时间,但是.600是有意义的,我刚刚用CourierNew创建了一个文档并将其导出为PDF,在导出过程中,宽度都是600。考虑到winansioncoding应该不需要小于32的FirstChar。不过,这很可能也没有什么坏处。
public void RenderText(TextRenderInfo renderInfo)
{
foreach (TextRenderInfo info in renderInfo.GetCharacterRenderInfos())
{
textextractionstrategy.RenderText(info);
}
}