Добавление кнопки с функцией SubmitForm с PDFBOX в Java - PullRequest
1 голос
/ 29 октября 2019

* Обновление : мне удалось заставить его работать. Я настроил небольшой виртуальный сервер только для того, чтобы ловить, если кнопка отправки что-то делает, и кажется, что она работает. Хотя по какой-то причине кнопка не видна, когда я открываю PDF с помощью Adobe Reader, но она есть и работает. В браузере это показывает нормально. Я обновил код с помощью теперь работающего кода.

У меня есть несколько PDF-файлов с заполняемыми полями формы. Теперь я хочу автоматически добавить кнопку в PDF-файлы, которая при нажатии должна представить новые и заполненные PDF-файлы. Когда это работает, он будет работать на сервере, но сейчас мне просто нужна кнопка отправки.

Эта функция уже существует в Adobe Acrobat Pro DC («Добавить кнопку отправки», https://helpx.adobe.com/acrobat/using/setting-action-buttons-pdf-forms.html).But Мне нужно сделать это с большим количеством PDF-файлов, поэтому я хочу автоматизировать ее, и янужно было бы купить дорогую лицензию. Лучший из возможных способов, который я мог бы найти, - это использовать библиотеку Java PDFBOX (https://pdfbox.apache.org/index.html).). Но я застрял с добавлением действия для кнопки.

Это мой Код, вместо того, чтобы импортировать PDF, вы можете просто создать новый, пустой. Важной является кнопка отправки:

public static void main(String[] args)
  {
    try
    {
      PDDocument pdf = PDDocument.load(inputFile);
      PDAcroForm acro = pdf.getDocumentCatalog().getAcroForm();

      COSDictionary cosDict1 = new COSDictionary();
      COSArray buttonRect1 = new COSArray();
      buttonRect1.add(new COSFloat(35)); // x1
      buttonRect1.add(new COSFloat(10)); // y1
      buttonRect1.add(new COSFloat(105)); // x2
      buttonRect1.add(new COSFloat(30)); // y2

      cosDict1.setItem(COSName.RECT, buttonRect1);
      cosDict1.setItem(COSName.FT, COSName.getPDFName("Btn")); // Field
      // Type
      cosDict1.setItem(COSName.TYPE, COSName.ANNOT);
      cosDict1.setItem(COSName.SUBTYPE, COSName.getPDFName("Widget"));
      cosDict1.setItem(COSName.T, new COSString("submit"));
      cosDict1.setItem(COSName.DA, new COSString("/F0 6 Tf 0 g 1 1 1 rg "));

      PDPushButton button = new PDPushButton(acro);

      button.getCOSObject().addAll(cosDict1);
      acro.getFields().add(button);

      PDAnnotationWidget widget = button.getWidgets().get(0);

      PDAppearanceCharacteristicsDictionary buttonFieldAppearance = new 
      PDAppearanceCharacteristicsDictionary(
        new COSDictionary());
      COSArray borderColorArray = new COSArray();
      borderColorArray.add(new COSFloat((float)(141f / 255f)));
      borderColorArray.add(new COSFloat((float)(179f / 255f)));
      borderColorArray.add(new COSFloat((float)(226f / 255f)));
      PDColor blue = new PDColor(borderColorArray, PDDeviceRGB.INSTANCE);
      buttonFieldAppearance.setBorderColour(blue);
      buttonFieldAppearance.setBackground(blue);
      buttonFieldAppearance.setNormalCaption("Submit");
      widget.setAppearanceCharacteristics(buttonFieldAppearance);

      pdf.save(outputFile);
      pdf.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
      System.err.println(e.getLocalizedMessage());
    }
  }

Даже после прочтения частей API PDFBOX (https://pdfbox.apache.org/docs/2.0.13/javadocs/) Я до сих пор не понимаю, как я должен это делать. Я пытался реверс-инжиниринг формы PDF с рабочей кнопкой отправки, которую я создал с помощью тестовой версии Adobe Acrobat Pro DC. Это сделало ее немного понятнее, но я все ещене полностью понимаю. Я заметил, что он что-то делает с COSDictonarys, поэтому я добавил следующий код, который обрабатывает действие кнопки:

      PDActionSubmitForm submitForm = new PDActionSubmitForm();
      widget.setAction(submitForm);

      COSDictionary cosDic = new COSDictionary();
      COSDictionary cosURIDic = new COSDictionary();
      cosURIDic.setItem(COSName.F, new COSString("http://localhost:80/cgi- 
      bin/myscript#FDF"));
      cosURIDic.setItem(COSName.FILESPEC, COSName.URI);
       cosDic.setItem(COSName.F, cosURIDic);
      cosDic.setItem(COSName.S, COSName.getPDFName("SubmitForm"));
      COSDictionary buttonCOSDic = new COSDictionary(cosDic);

      widget.getAction().getCOSObject().addAll(buttonCOSDic);

      pdf.getPage(0).getAnnotations().add(widget);
      button.getWidgets().add(widget);

И это то, что я используюd, чтобы попытаться выполнить обратный инжиниринг того, что делает Adobe Acrobat Pro DC:

public static void main(String[] args)
  {
    try
    {
      PDDocument pdf = PDDocument.load(inputFile);
      PDAcroForm acro = pdf.getDocumentCatalog().getAcroForm();

      List<PDField> acroFields = acro.getFields();
      for (PDField pdField : acroFields)
      {
        if (pdField.getFullyQualifiedName().toLowerCase().contains("submit"))
        {
          try
          {
            System.out.println("FieldType: " + pdField.getFieldType());
            // System.out.println("Actions: " + pdField.getActions().toString()); //NullPointer
            System.out.println("Widgets: " + pdField.getWidgets().toString());
            List<PDAnnotationWidget> listWidgets = pdField.getWidgets();
            for (PDAnnotationWidget pdAnnotationWidget : listWidgets)
            {
              System.out.println("PDAction: " + pdAnnotationWidget.getAction());
              System.out
                .println("PDActionCOSObject: " + pdAnnotationWidget.getAction().getCOSObject());
            }
          }
          catch (Exception e)
          {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.err.println(e.getLocalizedMessage());
          }
        }
      }
      System.out.println("end");
    }
    catch (IOException e)
    {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

, который печатает:

FieldType: Btn
Widgets: [org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget@156643d4]
PDAction: org.apache.pdfbox.pdmodel.interactive.action.PDActionSubmitForm@200a570f
PDActionCOSObject: COSDictionary{COSName{F}:COSDictionary{COSName{F}:COSString{http://localhost:80/cgi-bin/myscript#FDF};COSName{FS}:COSName{URL};};COSName{S}:COSName{SubmitForm};}

Поэтому я буду продолжать пытаться найти решение, но, возможно, некоторые из вас ужезнать ответ и может помочь мне. Надеюсь, я включил все, что тебе может понадобиться, чтобы помочь мне.

...