使用PDFBox 2.x在PDF上放一个按钮

时间:2018-10-14 22:59:50

标签: javascript java button pdfbox acrofields

我希望有人能帮助我解决用PdfBox 2.x创建的PDF上的按钮和文本字段问题。

我试图在页面上放置一个按钮,该按钮使用Javascript函数在文本字段中设置日期。很好。

然后我尝试将Textfield和Button放置在一页以上的文档中,以使Textfield和Button出现在每一页上,但是这样,页面上的Button只将Date写入到单击按钮所在页面上的文本字段。

从那以后,我收到了一个问题,第一页上的按钮对第一页上的文本字段做出了反应,但是第一页是按钮做出反应的唯一页面。

然后,我保存了4个文档,每个文档一页,每个文档工作正常。 但是最后,我将4个文档合并为一个4页的文档,却遇到了与以前相同的问题。

有人可以告诉我,这是什么问题吗?

谢谢 托马斯

这是我的Java代码:

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
import org.apache.pdfbox.pdmodel.interactive.action.PDAnnotationAdditionalActions;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceCharacteristicsDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDPushButton;
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;

public class ScriptButton {

public static void main(String[] args) throws IOException {

    List<PDDocument> aDocList = new ArrayList<PDDocument>();

    String destall = ".\\DS216J\\home\\01Privat\\Script_Button_all.pdf";
    DecimalFormat DFMM = new DecimalFormat("00");

    for (int i = 0; i < 4; i++) {

        PDDocument doc = new PDDocument();
        PDPage page = new PDPage();
        doc.addPage(page);

        COSDictionary acroFormDict = new COSDictionary();
        acroFormDict
                .setBoolean(COSName.getPDFName("NeedAppearances"), true);
        acroFormDict.setItem(COSName.FIELDS, new COSArray());

        PDAcroForm acroForm = new PDAcroForm(doc, acroFormDict);
        doc.getDocumentCatalog().setAcroForm(acroForm);

        PDAnnotationAdditionalActions buttonAction1 = null;
        PDActionJavaScript javascript = null;
        PDActionJavaScript tfJs = null;

        String iStr = DFMM.format(i);
        String dest = ".\\DS216J\\home\\01Privat\\Script_Button_" + iStr
                + ".pdf";

        PDFont font = PDType1Font.HELVETICA;
        PDResources resources = new PDResources();
        resources.put(COSName.getPDFName("Helvetica"), font);
        acroForm.setDefaultResources(resources);

        PDAppearanceStream pdAppearanceStream = new PDAppearanceStream(doc);
        pdAppearanceStream.setResources(resources);

        PDTextField textField = new PDTextField(acroForm);
        textField.setPartialName("SampleField-" + iStr);

        String defaultAppearance = "/Helv 24 Tf 0 0 0 rg";
        textField.setDefaultAppearance(defaultAppearance);

        textField.setMultiline(true);
        textField.setValue("Click to get Date");

        acroForm.getFields().add(textField);

        PDAnnotationWidget fieldwidget = textField.getWidgets().get(0);
        PDRectangle rect = new PDRectangle(50, 600, 300, 70);
        fieldwidget.setRectangle(rect);
        fieldwidget.setPage(page);

        PDAppearanceCharacteristicsDictionary fieldAppearance = new PDAppearanceCharacteristicsDictionary(
                new COSDictionary());
        fieldAppearance.setBorderColour(new PDColor(
                new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE));
        fieldAppearance.setBackground(new PDColor(new float[] { 1, 1, 1 },
                PDDeviceRGB.INSTANCE));
        fieldwidget.setAppearanceCharacteristics(fieldAppearance);

        fieldwidget.setPrinted(true);

        page.getAnnotations().add(fieldwidget);

        COSDictionary cosDict1 = new COSDictionary();
        COSArray buttonRect1 = new COSArray();
        buttonRect1.add(new COSFloat(50));
        buttonRect1.add(new COSFloat(575));
        buttonRect1.add(new COSFloat(150));
        buttonRect1.add(new COSFloat(550));

        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("Datum anzeigen"));
        cosDict1.setItem(COSName.DA,
                new COSString("/F0 6 Tf 0 g 1 1 1 rg "));

        PDPushButton button1 = new PDPushButton(acroForm);
        javascript = new PDActionJavaScript("function date" + iStr
                + "() {var fld" + iStr + " = this.getField('SampleField-"
                + iStr + "'); fld" + iStr
                + ".value = util.printd('dd mmmm yyyy',new Date());}");

        doc.getDocumentCatalog().setOpenAction(javascript);

        tfJs = new PDActionJavaScript("date" + iStr + "();");
        buttonAction1 = new PDAnnotationAdditionalActions();

        buttonAction1.setU(tfJs);
        button1.getWidgets().get(0).setActions(buttonAction1);

        button1.getCOSObject().addAll(cosDict1);
        acroForm.getFields().add(button1);

        PDAnnotationWidget buttonWidget1 = button1.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("Felder löschen");

        buttonWidget1.setAppearanceCharacteristics(buttonFieldAppearance);
        page.getAnnotations().add(buttonWidget1);

        File file = new File(dest);
        file.getParentFile().mkdirs();

        doc.save(dest);
        doc.close();

        aDocList.add(doc);
    }

    PDDocument aDocWithallPages = new PDDocument();
    PDFMergerUtility PDFmerger = new PDFMergerUtility();

    PDFmerger.setDestinationFileName(destall);

    int i = 0;
    for (Iterator<PDDocument> iterator = aDocList.iterator(); iterator
            .hasNext();) {
        iterator.next();

        String iStr = DFMM.format(i);
        File newFile = new File(".\\DS216J\\home\\01Privat\\Script_Button_"
                + iStr + ".pdf");
        PDFmerger.addSource(newFile);

        i = i + 1;
    }

    PDFmerger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());

    aDocWithallPages.close();

}

}

1 个答案:

答案 0 :(得分:0)

第二个解决方案(合并)将无法工作,因为PDFBox无法更改JS代码。我尝试重新创建的第一个解决方案(您未显示),恕我直言,一个问题是OpenAction中只有一个date函数。您需要JavaScript名称树中的每个函数(您可能甚至不需要在字段中全部输入即可工作,但我没有对此进行测试):

output_list

2018年10月20日更新: 我在代码中做了另外两个更改: 1)public static void main(String[] args) throws IOException { String dest = "SO52807807.pdf"; Map<String, PDActionJavaScript> map = new HashMap<>(); DecimalFormat DFMM = new DecimalFormat("00"); try (PDDocument doc = new PDDocument()) { PDDocumentNameDictionary documentNameDictionary = new PDDocumentNameDictionary(doc.getDocumentCatalog()); PDJavascriptNameTreeNode javascriptNameTreeNode = new PDJavascriptNameTreeNode(); documentNameDictionary.setJavascript(javascriptNameTreeNode); COSDictionary acroFormDict = new COSDictionary(); acroFormDict .setBoolean(COSName.getPDFName("NeedAppearances"), true); acroFormDict.setItem(COSName.FIELDS, new COSArray()); PDAcroForm acroForm = new PDAcroForm(doc, acroFormDict); doc.getDocumentCatalog().setAcroForm(acroForm); for (int i = 0; i < 4; i++) { PDPage page = new PDPage(); doc.addPage(page); PDAnnotationAdditionalActions buttonAction1 = null; PDActionJavaScript javascript = null; PDActionJavaScript tfJs = null; String iStr = DFMM.format(i); PDFont font = PDType1Font.HELVETICA; PDResources resources = new PDResources(); resources.put(COSName.getPDFName("Helv"), font); acroForm.setDefaultResources(resources); PDAppearanceStream pdAppearanceStream = new PDAppearanceStream(doc); pdAppearanceStream.setResources(resources); PDTextField textField = new PDTextField(acroForm); textField.setPartialName("SampleField-" + iStr); String defaultAppearance = "/Helv 24 Tf 0 0 0 rg"; textField.setDefaultAppearance(defaultAppearance); textField.setMultiline(true); acroForm.getFields().add(textField); PDAnnotationWidget fieldwidget = textField.getWidgets().get(0); PDRectangle rect = new PDRectangle(50, 600, 300, 70); fieldwidget.setRectangle(rect); fieldwidget.setPage(page); textField.setValue("Click to get Date"); PDAppearanceCharacteristicsDictionary fieldAppearance = new PDAppearanceCharacteristicsDictionary( new COSDictionary()); fieldAppearance.setBorderColour(new PDColor( new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE)); fieldAppearance.setBackground(new PDColor(new float[] { 1, 1, 1 }, PDDeviceRGB.INSTANCE)); fieldwidget.setAppearanceCharacteristics(fieldAppearance); fieldwidget.setPrinted(true); page.getAnnotations().add(fieldwidget); COSDictionary cosDict1 = new COSDictionary(); COSArray buttonRect1 = new COSArray(); buttonRect1.add(new COSFloat(50)); buttonRect1.add(new COSFloat(575)); buttonRect1.add(new COSFloat(150)); buttonRect1.add(new COSFloat(550)); 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("Datum anzeigen")); cosDict1.setItem(COSName.DA, new COSString("/F0 6 Tf 0 g 1 1 1 rg ")); PDPushButton button1 = new PDPushButton(acroForm); javascript = new PDActionJavaScript("function date" + iStr + "() {var fld" + iStr + " = this.getField('SampleField-" + iStr + "'); fld" + iStr + ".value = util.printd('dd mmmm yyyy',new Date());}"); //doc.getDocumentCatalog().setOpenAction(javascript); map.put("date" + iStr, javascript); tfJs = new PDActionJavaScript("date" + iStr + "();"); buttonAction1 = new PDAnnotationAdditionalActions(); buttonAction1.setU(tfJs); button1.getWidgets().get(0).setActions(buttonAction1); button1.getCOSObject().addAll(cosDict1); acroForm.getFields().add(button1); PDAnnotationWidget buttonWidget1 = button1.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("Felder löschen"); buttonWidget1.setAppearanceCharacteristics(buttonFieldAppearance); page.getAnnotations().add(buttonWidget1); } javascriptNameTreeNode.setNames(map); doc.getDocumentCatalog().setNames(documentNameDictionary); File file = new File(dest); file.getParentFile().mkdirs(); doc.save(dest); } } 中的字体名称必须与默认资源(“ Helv”)中的字体名称相同。 2)必须在分配小部件之后而不是之前设置字段的值。 (如果您考虑的话,这很有意义-小部件是关于视觉的。)如果不这样做,则在与非Adobe查看器一起显示时会带来麻烦。

更新:25.5.2019: 恕我直言,该代码有点笨拙,因为不必设置大多数字典元素。在this answer中可以找到创建按钮的更好版本。