2015-12-30 70 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); 
    ... 

如果使用這種方法減少了時間相當(而在同一時間提供所需的字段),則猜想被證實。


看代碼一個認識,它不正常行走的外地結構:字段可分層排列,但是代碼只考慮第一級的元素。儘管如此,對上述猜想的第一次測試應該足夠了。