在評論猜想想出了過度緩慢是由於這樣的事實:在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);
...
如果使用這種方法減少了時間相當(而在同一時間提供所需的字段),則猜想被證實。
看代碼一個認識,它不正常行走的外地結構:字段可分層排列,但是代碼只考慮第一級的元素。儘管如此,對上述猜想的第一次測試應該足夠了。
來源
2016-01-04 23:11:21
mkl
請解釋您的意思是*過度緩慢*。如果可能的話,分享一個樣本PDF鏈接進行分析。 – mkl
對於_excessive slowness_我的意思是大約** 20-60分鐘**的等待時間都在調試VS在生產機器上發佈。我試圖找到一個我可以在這裏分享的PDF,因爲唯一有問題的包含明智的客戶數據。 – alessandrotoro
好的,**是**過度緩慢。 :)我還沒有經歷過iText(夏普)的這種緩慢。因此,這些pdf很可能確實有些特別之處。 – mkl