使用 PDFBox 将计算脚本添加到 pdf 表单字段

Add calculation script to pdf form fields with PDFBox

也许有人可以帮我解决这个问题。我有一个 java 应用程序,它使用 flying-saucer-pdf 从 HTML 模板生成 PDF 文件。由于不支持 JavaScript,我打算在使用 PDFBox 创建 PDF 后添加我的 JavaScript。

我想添加 Java脚本以从字段 A 中读取值,根据该值计算新的总和并将其写入另一个字段 B。每次计算输入字段 A 发生变化。

但我的问题是,我不知道如何将我的 Java脚本添加到现有的 PDF 文件中。我在计算脚本下找到了这个 example online on how to add JavaScript, but it only shows how to register an Action to the opening event of the PDF. This doesn't help since I want to add calculations as described in the Acrobat JS Developer Guide

我想我必须以某种方式修改文档 PDAcroForm。甚至还有一个 getScriptingHandler()-Method,这看起来很有希望,但在我的文档中是空的。到目前为止,我添加 Java 脚本的代码如下所示:

try (var document = PDDocument.load(pdfFile)) {
  var documentDocumentCatalog = document.getDocumentCatalog();
  var documentAcroForm = documentDocumentCatalog.getAcroForm();
  var javascriptString = FileUtils.readFileToString(
                           javascriptFile, 
                           StandardCharsets.UTF_8,
                         );
  var javascript = new PDActionJavaScript(javascriptString);
  documentAcroForm.getScriptingHandler().calculate(javascript, "99");
} catch (IOException e) {
  e.printStackTrace();
}

>>更新<<

感谢您的投入,我已经成功实现了计算新值的目标。我的 Java 代码现在看起来像这样:

try (var document = PDDocument.load(pdfFile)) {
  var catalog = document.getDocumentCatalog();
  var acroForm = catalog.getAcroForm();

  var fieldActions = new PDFormFieldAdditionalActions();
  var javascriptString = FileUtils.readFileToString(javascriptFile, StandardCharsets.UTF_8);
  var actionJavaScript = new PDActionJavaScript(javascriptString);
  actionJavaScript.setAction(javascriptString);
  fieldActions.setC(actionJavaScript);

  var field = (PDTextField) acroForm.getField("fieldA");
  field.setActions(fieldActions);
  var coArray = new COSArray();
  coArray.add(field);
  acroForm.getCOSObject().setItem(COSName.CO, coArray);

  document.save(pdfFile);
} catch (IOException e) {
  e.printStackTrace();
}

我的Java脚本代码如下所示:

calculateValue("fieldA", "fieldB");

function calculateValue(sourceFieldName, targetFieldName) {
    this.getField(sourceFieldName).value = Math.floor(this.getField(targetFieldName).value / 2 - 5)
}

这有效,虽然我偶然发现了一些奇怪的行为,也许我只是误解了更改事件。使用此代码,即使我只将“fieldA”添加到重新计算顺序,似乎任何字段中的任何更改都会触发事件。我真正想要实现的是,只有特定字段的更改才会触发另一个特定字段的重新计算。这就是重新计算的方式吗?

>>更新2<<

没关系,我只是犯了一个错误,并在每次重新计算事件时更新了两个字段...在调整我的 Java脚本后,现在一切正常。

还有一个问题,如何向文档全局添加一个 Java脚本函数,然后在现场事件中调用它?

感谢您的帮助!

在 PDF 级别,它看起来像这样:

//The text field
10 0 obj
<</AA<</C 12 0 R>>/AP<</N 100 0 R>>/F 4/FT/Tx/Ff 2/MK<</BC[0.0 0.0 0.0]>>/P 23 0 R/Rect[339.288 570.374 443.231 589.985]/Subtype/Widget/T(Textfield10)/Type/Annot/V(7)>>
endobj

//The JS function which writes the result of 'Textfield1'+'Textfield3' into Textfield10
12 0 obj
<</JS(AFSimple_Calculate\("SUM", new Array \("Textfield1", "Textfield3"\)\);)/S/JavaScript>>
endobj

14 0 obj
<</CO[10 0 R]/DA(/Helv 0 Tf 0 g )/Fields[10 0 R 16 0 R 18 0 R] ...>>

如您所见,附加操作 (AA) 属性是要使用的关键。在网络上或 上有几个关于如何做到这一点的答案。它看起来像这样:

PDFormFieldAdditionalActions pdFormFieldAdditionalActions = new PDFormFieldAdditionalActions();
PDActionJavaScript jsSumAction = new PDActionJavaScript();
jsSumAction .setAction("AFSimple_Calculate\("SUM", new Array \("Textfield1", "Textfield3"\)\);");
pdFormFieldAdditionalActions.setC((PDAction) jsSumAction);

请注意,此处使用的 JS 语法是 *dobe JS 语法 - 因此它可能不适用于其他查看器。但这就是 PDF 中 JS 脚本的问题,也是 PDF/A...

中禁止它的原因之一