В комментариях гипотеза пришла, что чрезмерная медлительность связано с тем, что IText (Sharp) во время инициализации коллекции поля в AcroFields
инстанции не только проверяет поля ссылки в Каталог ->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);
...
При использовании этого метода сокращает время значительно (в то же время при подаче желаемых полей), то гипотеза подтверждена.
Глядя на код одного признает, что это не правильно ходить структуру поля: Поля могут быть организованы иерархически, но код учитывает только первые элементы уровня. Однако этого достаточно для первого теста гипотезы, упомянутой выше.
Пожалуйста, объясните, что именно вы имеете в виду * чрезмерная медлительность *. И если возможно, поделитесь ссылкой на образец PDF для анализа. – mkl
Для _очередной slowness_ я имею в виду около ** 20-60 минут ** времени ожидания как отладки в VS как в выпуске на производственной машине. Я пытаюсь найти PDF-файл, который я могу использовать здесь, потому что единственный, у кого есть проблемы, содержит разумные данные клиента. – alessandrotoro
Хорошо, это ** является ** чрезмерной медлительностью. :) Я еще не испытал такую медлительность с iText (Sharp). Таким образом, вполне вероятно, что что-то особенное в этих pdf-файлах. – mkl