Можно ли изменить имена полей формы PDF? - PullRequest
8 голосов
/ 26 февраля 2010

Вот ситуация. У меня есть PDF с автоматически сгенерированными именами полей в формате PDF. Проблема в том, что эти имена не очень удобны для пользователя. Они выглядят примерно так: topmostSubform [0] .Page1 [0] .Website_Address [0]

Я хочу иметь возможность изменить их так, чтобы они были чем-то вроде WebsiteAddress. У меня есть доступ к ABCPDF, и у меня есть опыт работы с iTextSharp, но я пытался использовать эти API для этого (доступ к полям формы и попытка переименовать), но не похоже, что это возможно.

Есть ли у кого-нибудь опыт попыток сделать это через какой-то API (желательно с открытым исходным кодом). Код также .Net также.

Ответы [ 8 ]

10 голосов
/ 27 февраля 2010

Хорошая новость: вы можете изменить имена полей в iTextSharp.

Вы не можете редактировать PDF, хотя. Вы читаете в существующем PDF, обновляете имена полей в памяти, а затем записываете свой исправленный PDF. Чтобы изменить имя поля, вызовите метод AcroFields.RenameField.

Вот фрагмент:

PdfReader reader = new PdfReader(PDF_PATH);
using (FileStream fs = new FileStream("Test Out.pdf", FileMode.Create)) {
    PdfStamper stamper = new PdfStamper(reader, fs);
    AcroFields fields = stamper.AcroFields;
    fields.RenameField("oldFieldName", "newFieldName");
    stamper.Close();
}

Теперь плохая новость: похоже, существуют ограничения на символы, которые вы можете использовать в переименованных полях.

Я протестировал приведенный выше фрагмент с именем вашего примера поля, и он не сработал. Удалить периоды, хотя и это работает. Я не уверен, что есть обходной путь, но это может быть проблемой для вас,

6 голосов
/ 13 ноября 2012

У меня была проблема вчера и после того, как я попробовал ответы на форуме и других, но ничего не сделал. Мой код выглядел так:

// Open up the file and read the fields on it.
var pdfReader = new PdfReader(PATH_TO_PDF);
var fs = new FileStream(pdfFilename, FileMode.Create, FileAccess.ReadWrite)
var stamper = new PdfStamper(pdfReader, fs);
var pdfFields = stamper.AcroFields;

//I thought this next line of code I commented out will do it
//pdfFields.RenameField("currentFieldName", "newFieldName");

// It did for some fields, but returned false for others.
// Then I looked at the AcroFields.RenameField method in itextSharp source and noticed some restrictions. You may want to do the same.
//  So I replaced that line  pdfFields.RenameField(currentFieldName, newFieldName); with these 5 lines

AcroFields.Item item = pdfFields.Fields[currentFieldName];
PdfString ss = new PdfString(newFieldName, PdfObject.TEXT_UNICODE);
item.WriteToAll(PdfName.T, ss, AcroFields.Item.WRITE_VALUE | AcroFields.Item.WRITE_MERGED);
item.MarkUsed(pdfFields, AcroFields.Item.WRITE_VALUE);
pdfFields.Fields[newFieldName] = item;

И это сделало работу

6 голосов
/ 27 мая 2010

Полное имя поля AcroForm явно не хранится в поле. На самом деле он получен из иерархии полей, где слева представлен список предков, разделенных точками.

Простое переименование поля из 'topmostSubform [0] .Page1 [0] .Website_Address [0]' в 'WebsiteAddress', следовательно, вряд ли даст правильный результат.

Вы найдете раздел 8.6.2 «Словари полей» справочника в формате PDF, в котором подробно объясняется, как работает именование полей; -)

По сути, каждое поле в AcroForm определяется словарем, который может содержать определенные необязательные записи, относящиеся к имени поля.

  • Ключ '/ T' указывает частичное имя. В вашем вопросе 'topmostSubform [0]', 'Page1 [0]' и Website_Address [0] представляют частичные имена.

  • Ключ '/ TU' указывает альтернативное «удобное для пользователя» имя для полей, которое можно использовать вместо фактического имени поля для идентификации полей в пользовательском интерфейсе.

Вместо переименования рассматриваемого поля подумайте о добавлении записи / TU!

В приведенном ниже примере ABCpdf используется для перебора всех полей в AcroForm и вставки альтернативного имени в поле на основе его частичного имени.

VBScript:

Set theDoc = CreateObject("ABCpdf7.Doc")
theDoc.Read "myForm.pdf"

Dim theFieldIDs, theList
theFieldIDs = theDoc.GetInfo(theDoc.Root, "Field IDs")
theList = Split(theFieldIDs, ",")

For Each fieldID In theList
    thePartialName = theDoc.GetInfo(fieldID, "/T:text")
    theDoc.SetInfo fieldID, "/TU:text", thePartialName
Next

theDoc.Save "output.pdf"
theDoc.Clear

Изменение "/TU:text" на "/T:text" установит частичное имя поля.

Примеры написанных на C # и VB.NET используемых функций можно найти здесь: Doc.GetInfo , Doc.SetInfo . См. Также документацию по путям к объектам .

3 голосов
/ 10 апреля 2013

Может быть, вы можете рассмотреть это:

  • iText не бесплатен, в пропиетарной среде программного обеспечения (2.1.7 it / s последняя «бесплатная» версия).
  • AbcPDF тоже не бесплатный.

Я должен сказать, что у нас есть лицензия AbcPDF, и мы также используем iText 2.1.7 в наших проектах на Java ... поэтому я могу сказать, что согласен с предыдущими ответами, НО вы не можете использовать / покупать эти продукты , вы можете попробовать заменить имя в чистый PDF-код (как обычный текстовый файл), следуя спецификации PDF:

Пример поля подписи:

35 0 obj
<<
/AP <<
/N 37 0 R
>>
/DA (/TimesRoman 0 Tf 0 g)
/F 4
/FT /Sig
/P 29 0 R
/Rect [ 86 426 266 501 ]
/Subtype /Widget
/T (FIELD_MODIF)
/Type /Annot
/V 36 0 R
>>
endobj

Где "FIELD_MODIF" - это место, где ставится НОВОЕ имя.

2 голосов
/ 23 октября 2013

Хотя вы не можете переименовывать поля с помощью JavaScript, вы можете добавить новые поля и удалить существующие поля. Вы также можете вырезать и вставлять между документами. Итак ...

Один . Разработайте сценарий переименования, например ::10000

    var doc = app.activeDocs[0];
    var fnames = new Array();
    for ( var i = 0; i < doc.numFields - 1; i++) {      
        fnames[i] = doc.getNthFieldName(i);
    }
    for (var i = 0; i < doc.numFields - 1; i++){        
        var f = doc.getField(fnames[i] + ".0");
        var nfn = fnames[i].replace("1","2");
        var rb = doc.addField(nfn,"radiobutton",0,f.rect)
        for ( var j = 1; j < 9; j++){//Add the other 8
            f = doc.getField(fnames[i] + "." + j);
            doc.addField(nfn,"radiobutton",0,f.rect)
        }
        rb.setExportValues([1,2,3,4,5,6,7,8,9]);
        rb.borderStyle = f.borderStyle;
        rb.strokeColor = f.strokeColor;
        rb.fillColor = f.fillColor;
        doc.removeField(fnames[i]);
        console.println(fnames[i] + " to " + nfn);
    }

Примечания:
Переименование полей может изменить порядок полей для getNthFieldName, поэтому сначала получите их.
Группа радиокнопок - это одно поле (getField ("Groupname")), чтобы получить n-е в той же группе, используйте getField ("Groupname.n"), они нужны для прямоугольника положения. Свойства, которые применяются ко всем, могут быть установлены enmase.
Параметры addField: имя поля, тип поля, страница, прямоугольник положения)
В примере 9 радиокнопок в каждой группе

Два . Вырежьте и вставьте поля, которые вы хотите переименовать, в пустой PDF-файл (я предположил одну страницу выше). Запустите скрипт. Вырежьте и вставьте обратно.

Вам может потребоваться изменить app.activeDocs [0] на app.activeDocs [1] или заменить «doc» на «this», если оба документа открыты при запуске сценария

1 голос
/ 20 января 2018

лучший способ - сохранить поля прямоугольника, а затем создать новое поле с желаемым именем и сохраненной прямоугольной позицией, новое поле будет в той же позиции, что и старое поле, та да :) вот код:

Sub CreateNewField()
 Create = "var f = this.getField('" & oldFieldName & "'); var rect = f.rect; 
 this.addField('" & newFieldName & "','text',0,rect);"
 FormFields.ExecuteThisJavascript Create
 DeleteField 'sub to delete old field
End Sub
0 голосов
/ 28 мая 2013

Вот пример Java, найденный в книге "iText в действии"

Это взято из их примера исходного кода для книги и очень помогло мне с этой же проблемой. part2.chapter06.ConcatenateForms2

public static void main(String[] args)
    throws IOException, DocumentException {
    // Create a PdfCopyFields object
    PdfCopyFields copy
        = new PdfCopyFields(new FileOutputStream(RESULT));
    // add a document
    PdfReader reader1 = new PdfReader(renameFieldsIn(DATASHEET, 1));
    copy.addDocument(reader1);
    // add a document
    PdfReader reader2 = new PdfReader(renameFieldsIn(DATASHEET, 2));
    copy.addDocument(reader2);
    // Close the PdfCopyFields object
    copy.close();
    reader1.close();
    reader2.close();
}


private static byte[] renameFieldsIn(String datasheet, int i)
    throws IOException, DocumentException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // Create the stamper
    PdfStamper stamper = new PdfStamper(new PdfReader(datasheet), baos);
    // Get the fields
    AcroFields form = stamper.getAcroFields();
    // Loop over the fields
    Set<String> keys = new HashSet<String>(form.getFields().keySet());
    for (String key : keys) {
        // rename the fields
        form.renameField(key, String.format("%s_%d", key, i));
    }
    // close the stamper
    stamper.close();
    return baos.toByteArray();
}
0 голосов
/ 27 февраля 2010

Да, возможно переименовать поля формы. У меня нет опыта работы с API исходного кода, который поможет вам в этом, но мои компании PDF SDK могут помочь вам в этом, и после небольшого поиска выясняется, что iText действительно позволит вам переименовать поля формы .

...