C# 访问AcroFields的速度较慢(iTextSharp)
我正在使用iTextSharp从PDF中提取SignatureName。 我在访问大尺寸和多页PDF(约40MB和约5000页)的AcroFiels时遇到问题(速度过慢) 下面是我的代码片段:C# 访问AcroFields的速度较慢(iTextSharp),c#,itextsharp,acrofields,C#,Itextsharp,Acrofields,我正在使用iTextSharp从PDF中提取SignatureName。 我在访问大尺寸和多页PDF(约40MB和约5000页)的AcroFiels时遇到问题(速度过慢) 下面是我的代码片段: using iTextSharp.text.pdf; private static List<byte[]> GetSignsFromPDF(string filePath) { var result = new List<byte[]>(); var rando
using iTextSharp.text.pdf;
private static List<byte[]> GetSignsFromPDF(string filePath)
{
var result = new List<byte[]>();
var randomAccessFileOrArray = new RandomAccessFileOrArray(filePath);
var reader = new PdfReader(randomAccessFileOrArray, null);
var fields = reader.AcroFields;
if (fields == null)
{
return result;
}
var signatureNames = fields.GetSignatureNames();
signatureNames.Sort();
foreach (string name in signatureNames)
{
var sigDict = fields.GetSignatureDictionary(name);
var contents = sigDict.GetAsString(PdfName.CONTENTS);
if (contents != null)
{
result.Add(contents.GetOriginalBytes());
}
}
return result;
}
使用iTextSharp.text.pdf;
私有静态列表GetSignsFromPDF(字符串文件路径)
{
var result=新列表();
var randomAccessFileOrArray=新的randomAccessFileOrArray(文件路径);
var reader=new PdfReader(randomAccessFileOrArray,null);
变量字段=reader.AcroFields;
如果(字段==null)
{
返回结果;
}
var signatureNames=fields.GetSignatureNames();
signatureNames.Sort();
foreach(SignatureName中的字符串名称)
{
var sigDict=fields.GetSignatureDictionary(名称);
var contents=sigDict.GetAsString(PdfName.contents);
如果(内容!=null)
{
Add(contents.GetOriginalBytes());
}
}
返回结果;
}
有一种更智能/更快的方式访问AcroFields,还是我应该等待它
非常感谢。在评论中,猜测速度过慢是由于在
AcroFields
实例中初始化字段集合时,iText(Sharp)不仅检查目录中引用的字段->AcroForm->字段而且(实际上最重要)从所有文档页面的注释中
幸运的是,这个初始化没有在AcroFields
构造函数中发生,因此我们可以在不检查所有页面的情况下注入检索到的字段集合
以下方法是内部AcroFields
方法Fill
(负责延迟初始化)的副本,删除了页面遍历,并通过反射启用了对隐藏成员的访问。它可用于测试推测
void fill(PdfReader reader, AcroFields acroFields)
{
IDictionary<string, AcroFields.Item> fields = new LinkedDictionary<string, AcroFields.Item>();
PdfDictionary top = (PdfDictionary)PdfReader.GetPdfObjectRelease(reader.Catalog.Get(PdfName.ACROFORM));
if (top == null)
return;
PdfBoolean needappearances = top.GetAsBoolean(PdfName.NEEDAPPEARANCES);
if (needappearances == null || !needappearances.BooleanValue)
acroFields.GenerateAppearances = true;
else
acroFields.GenerateAppearances = false;
PdfArray arrfds = (PdfArray)PdfReader.GetPdfObjectRelease(top.Get(PdfName.FIELDS));
if (arrfds == null || arrfds.Size == 0)
return;
System.Reflection.FieldInfo valuesField = typeof(AcroFields.Item).GetField("values", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
System.Reflection.FieldInfo widgetsField = typeof(AcroFields.Item).GetField("widgets", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
System.Reflection.FieldInfo widgetRefsField = typeof(AcroFields.Item).GetField("widget_refs", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
System.Reflection.FieldInfo mergedField = typeof(AcroFields.Item).GetField("merged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
System.Reflection.FieldInfo pageField = typeof(AcroFields.Item).GetField("page", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
System.Reflection.FieldInfo tabOrderField = typeof(AcroFields.Item).GetField("tabOrder", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
for (int j = 0; j < arrfds.Size; ++j)
{
PdfDictionary annot = arrfds.GetAsDict(j);
if (annot == null)
{
PdfReader.ReleaseLastXrefPartial(arrfds.GetAsIndirectObject(j));
continue;
}
if (!PdfName.WIDGET.Equals(annot.GetAsName(PdfName.SUBTYPE)))
{
PdfReader.ReleaseLastXrefPartial(arrfds.GetAsIndirectObject(j));
continue;
}
PdfArray kids = (PdfArray)PdfReader.GetPdfObjectRelease(annot.Get(PdfName.KIDS));
if (kids != null)
continue;
PdfDictionary dic = new PdfDictionary();
dic.Merge(annot);
PdfString t = annot.GetAsString(PdfName.T);
if (t == null)
continue;
String name = t.ToUnicodeString();
if (fields.ContainsKey(name))
continue;
AcroFields.Item item = new AcroFields.Item();
fields[name] = item;
((List<PdfDictionary>)valuesField.GetValue(item)).Add(dic); // item.AddValue(dic);
((List<PdfDictionary>)widgetsField.GetValue(item)).Add(dic); // item.AddWidget(dic);
((List<PdfIndirectReference>)widgetRefsField.GetValue(item)).Add(arrfds.GetAsIndirectObject(j)); //item.AddWidgetRef(arrfds.GetAsIndirectObject(j)); // must be a reference
((List<PdfDictionary>)mergedField.GetValue(item)).Add(dic); // item.AddMerged(dic);
((List<int>)pageField.GetValue(item)).Add((int)-1); // item.AddPage(-1);
((List<int>)tabOrderField.GetValue(item)).Add((int)-1); // item.AddTabOrder(-1);
}
System.Reflection.FieldInfo fieldsField = typeof(AcroFields).GetField("fields", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
fieldsField.SetValue(acroFields, fields);
}
如果使用这种方法大大减少了时间(同时提供了所需的字段),则该推测得到证实
查看代码,您会发现它没有正确地遍历字段结构:字段可能按层次排列,但代码只考虑第一级元素。不过,它应该足以对上述推测进行第一次测试。请解释您所说的过度缓慢的确切含义。如果可能,请共享一个link到样本PDF进行分析。对于过慢,我指的是在生产机器上调试和发布时的等待时间大约为20-60分钟。我试图找到一个PDF,我可以在这里共享,因为唯一有问题的PDF包含合理的客户数据。好的,这是过慢。:)我还没有在iText(Sharp)上经历过如此缓慢的操作。因此,这些PDF很可能确实有一些特殊之处。好的,我想我找到了一个更详尽的测试用例。我生成了一个1852页、11.1Mb大小的随机文本PDF。我试图访问此网站的AcroFields,它需要iTextSharp查找AcroFields浏览所有页面-它确实。。。出于兼容性原因。过去有一些PDF表单创建产品,它们没有将所有字段添加到AcroForm表单字段树中,而只是将它们的外观作为文档页面的注释引用。
using (PdfReader reader = new PdfReader(file))
{
AcroFields acroFields = reader.AcroFields;
fill(reader, acroFields);
...