Изменить порядок AcroFields в существующих PDF с помощью iText?
У меня есть PDF с текстовыми полями формы в один слой поверх другого. Когда я заполняю поля через iText и сглаживаю форму, поле формы, которое я создал поверх другого поля формы, теперь находится внизу.
Например, у меня есть текстовое поле с именем "number_field", которое находится под вторым текстовым полем с именем "name_field". Когда я устанавливаю значение для этих полей через iText (то есть, 10 для number_field и "John" для name_field), число_field теперь находится над name_field.
Как изменить порядок на странице этих полей с помощью iText? Является ли это возможным?
Ссылка на пример PDF: https://freecompany.sharefile.com/d-s84f6d63e7d04fe79
1 ответ
Я сделал следующий билет в трекере проблем в iText Group:
Проблема вызвана тем, что iText считывает элементы поля в
HashMap
следовательно, нет никакого способа предсказать, в каком порядке они будут сплющены. Обычно это не проблема. Я не думаю, что эта проблема возникает в том случае, если вы не выравниваете PDF, потому что в этом случае внешний вид сохраняется в аннотациях виджета, и программа просмотра PDF должна решить, какое поле покрывает другое в случае перекрывающихся полей,Однако если поля формы перекрываются, вы не можете предсказать, какое поле будет покрыто при выравнивании.
Предположим, что мы будем использовать
TreeMap
вместоHashMap
это решит проблему? Не совсем, потому чтоComparator
мы будем использовать? Иногда порядок табуляции определяется, но не всегда. Если это не определено, должны ли мы упорядочить поля в том порядке, в котором они появляются в/Fields
массив? Или имеет смысл упорядочить их по порядку аннотаций виджетов в/Annots
массив? Другой вариант - заказать их в зависимости от их положения на странице. Короче говоря, это не решение, которое должен принять iText.Однако, если кто-то хотел бы решить эту проблему, мы могли бы создать
Comparator
переменная-член дляPdfStamperImp
, Если такойComparator
предоставляется (мы могли бы даже предоставить некоторые реализации), тогда процесс выравнивания будет выполняться в порядке, определенномComparator
,
Этот билет получил очень низкий приоритет (я предполагаю, что вы не являетесь клиентом одной из компаний iText Software), но при написании этого билета у меня была другая идея.
Я уже ссылался на подчеркивающую часть текста, используя iTextSharp в комментариях. В этом случае вы получите все позиции на местах (используя getFieldPositions()
метод) и нарисуйте все содержимое в правильном порядке, используя ColumnText
, У этого подхода есть несколько недостатков: чтобы шрифт, размер шрифта и цвет шрифта были правильными, вам необходимо изучить поля. Это требует некоторого программирования.
Сейчас я публикую это как ответ, потому что у меня есть гораздо лучшая альтернатива: заполните форму в два прохода! Это показано в примере FillFormFieldOrder. Заполняем форму src
в результате чего сплющенная форма dest
как это:
public void manipulatePdf(String src, String dest) throws DocumentException, IOException {
go2(go1(src), dest);
}
Как видите, мы выполняем go1()
Метод первый:
public byte[] go1(String src) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, baos);
AcroFields form = stamper.getAcroFields();
form.setField("sunday_1", "1");
form.setField("sunday_2", "2");
form.setField("sunday_3", "3");
form.setField("sunday_4", "4");
form.setField("sunday_5", "5");
form.setField("sunday_6", "6");
stamper.setFormFlattening(true);
stamper.partialFormFlattening("sunday_1");
stamper.partialFormFlattening("sunday_2");
stamper.partialFormFlattening("sunday_3");
stamper.partialFormFlattening("sunday_4");
stamper.partialFormFlattening("sunday_5");
stamper.partialFormFlattening("sunday_6");
stamper.close();
reader.close();
return baos.toByteArray();
}
Это заполняет все sunday_x
поля и использует частичное выравнивание формы, чтобы сгладить только эти поля. go1()
метод занимает src
в качестве параметра и возвращает byte[]
будет частично сплющенная форма.
byte[]
будет использоваться в качестве параметра для go2()
метод, который требует dest
как его второй параметр. Теперь мы собираемся заполнить sunday_x_notes
поля:
public void go2(byte[] src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
AcroFields form = stamper.getAcroFields();
form.setField("sunday_1_notes", "It's Sunday today, let's go to the sea");
form.setField("sunday_2_notes", "It's Sunday today, let's go to the park");
form.setField("sunday_3_notes", "It's Sunday today, let's go to the beach");
form.setField("sunday_4_notes", "It's Sunday today, let's go to the woods");
form.setField("sunday_5_notes", "It's Sunday today, let's go to the lake");
form.setField("sunday_6_notes", "It's Sunday today, let's go to the river");
stamper.setFormFlattening(true);
stamper.close();
reader.close();
}
Как видите, теперь мы сглаживаем все поля. Результат выглядит так:
Теперь вам больше не нужно беспокоиться о порядке полей, а не в /Fields
массив, а не в /Annots
массив. Поля заполняются в том порядке, в котором вы хотите. Примечания теперь охватывают даты, а не наоборот.