使用PDFBox 2.x在PDF上放置一个按钮 [英] Put a Button on PDF with PDFBox 2.x

查看:208
本文介绍了使用PDFBox 2.x在PDF上放置一个按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I hope somebody can help me with my Problem with Buttons and Textfields on a PDF created with PdfBox 2.x.

我试图在我的页面上放置一个按钮,它使用Javascript函数在Textfield中设置Date。这很好。

I tried to put a Button on my Page, which sets a Date in a Textfield with a Javascript function. That works fine.

然后我尝试将Textfield和Button放在一个包含多个页面的Document中,这样Textfield和Button就出现在每一页上,但是这样,页面上的按钮只将日期写入了按钮所在页面上的文本字段,我点击了。

I then tried to put the Textfield and the Button in a Document with more than one page, so that the Textfield and the Button appears on every Page, but in that way, that the Button on the page writes the Date only to the Textfield on the Page where the Button is, I clicked on.

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

From that on I receive the Problem, that the Button on Page one reacted to the Textfield on Page one, but Page one is the only Page where the Button reacts.

然后我保存了4份文件每页一页,每篇文档都运行良好。
但最后我将4份文件合并为4页,我收到的问题与以前相同。

Then I saved 4 Documents with one Page Each, Each Document worked fine. But when at the end I merged the 4 Documents to one with 4 Pages, i received the same problem than before.

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

Can Somebody tell me, what the problem is here?

谢谢
Thomas

Thanks Thomas

这是我的Java代码:

Here is my Java-Code:

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();

}

}

推荐答案

第二种解决方案(合并)不起作用,因为PDFBox无法更改JS代码。第一个解决方案(你没有显示)我试图重新创建,一个问题恕我直言,在OpenAction中只有一个日期函数。你需要JavaScript名称树中的每个函数(你甚至可以在没有所有字段但我没有测试的情况下工作):

The second solution (merging) won't work because PDFBox can't change the JS code. The first solution (which you don't show) I tried to recreate, one problem IMHO is that there is only 1 date function which is in OpenAction. You need each function in the JavaScript name tree (you might even work without by having all in the field but I didn't test that):

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);
    }
}

更新20.10.2018:
我做的代码中的另外两项更改:
1) defaultAppearance 中的字体名称必须与默认资源(Helv)中的字体名称相同。
2)必须在分配窗口小部件之后设置字段的值,而不是之前。 (如果你考虑它是有意义的 - 小部件是关于视觉的)。当用非Adobe观众显示时,不这样做可能意味着麻烦。

Update 20.10.2018: I made two more changes in the code: 1) the font name in the defaultAppearance must be the same font name as in the default resources ("Helv"). 2) the value of the field must be set AFTER the widget is assigned, not before. (makes sense if you think about it - the widget is about the visual).. Not doing that could mean trouble when displaying with non Adobe viewers.

更新:25.5。 2019:
恕我直言,代码有点笨重,因为大多数字典元素不必设置。可以在此答案中找到创建按钮的更好版本。 。

Update: 25.5.2019: IMHO the code is a bit clunky because most dictionary elements don't have to be set. A better version to create a button can be found in this answer.

这篇关于使用PDFBox 2.x在PDF上放置一个按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆