2015-12-30 67 views
2

我正在使用iTextSharp从PDF中提取SignatureNames。 我遇到了问题(过慢)访问大尺寸和许多页面PDF(〜40MB和〜5000页)的AcroFiels。缓慢访问AcroFields(iTextSharp)

这里我的代码片段:

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; 
} 

有访问AcroFields或者我应该等待iTextSharp的东西更聪明/更快的方法?

非常感谢。

+1

请解释您的意思是*过度缓慢*。如果可能的话,分享一个样本PDF链接进行分析。 – mkl

+0

对于_excessive slowness_我的意思是大约** 20-60分钟**的等待时间都在调试VS在生产机器上发布。我试图找到一个我可以在这里分享的PDF,因为唯一有问题的包含明智的客户数据。 – alessandrotoro

+0

好的,**是**过度缓慢。 :)我还没有经历过iText(夏普)的这种缓慢。因此,这些pdf很可能确实有些特别之处。 – mkl

回答

1

在评论猜想想出了过度缓慢是由于这样的事实:在AcroFields实例字段集合初始化期间的iText(夏普)不仅检查在目录中引用的领域 - >AcroForm - >字段,但也(实际上最重要的)从ANNOTS的所有文档页面。

幸运的是,这个初始化并不在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); 
} 

应当呼吁AcroFields实例尽早,例如:

using (PdfReader reader = new PdfReader(file)) 
{ 
    AcroFields acroFields = reader.AcroFields; 
    fill(reader, acroFields); 
    ... 

如果使用这种方法减少了时间相当(而在同一时间提供所需的字段),则猜想被证实。


看代码一个认识,它不正常行走的外地结构:字段可分层排列,但是代码只考虑第一级的元素。尽管如此,对上述猜想的第一次测试应该足够了。