Hot questions for Using PDFBox in javascript

Top Java Programmings / PDFBox / javascript

Question:

I'm new to PDFBox, I have a requirement to send the PDF to the printer when it is opened. We are using PDFBox api to generate the PDFs. I have used the below code to try setting the action on open but nothing worked. Please help. I have used different javascript like window.print(); this.print(); print();

    PDDocument doc = new PDDocument();
    PDActionJavaScript javascript=new PDActionJavaScript("app.print();");
    doc.getDocumentCatalog().setOpenAction(javascript);

Answer:

You can do this without JS:

    PDActionNamed action = new PDActionNamed();
    action.setN("Print");
    doc.getDocumentCatalog().setOpenAction(action);

Question:

My goal is to extract and process any JavasSript code that a PDF document might contain. By opening a PDF in editor I can see objects like this:

    402 0 obj
<</S/JavaScript/JS(\n\r\n   /* Set day 25 */\r\n    FormRouter_SetCurrentDate\("25"\);\r)>>
endobj

I am trying to use Apache PDFBox to accomplish this but so far with no luck.

This line returns an empty list:

 jsObj = doc.getObjectsByType(COSName.JAVA_SCRIPT);

Can anyone can give me some direction?


Answer:

This tool is based on the PrintFields example in PDFBox. It will show the Javascript fields in forms. I wrote it last year for a guy who had problems with relationship between AcroForm fields (some fields were enabled / disabled depending on the values of other fields). There are still other places where there can be Javascript.

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package pdfboxpageimageextraction;

import java.io.File;
import java.io.IOException;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDNonTerminalField;
import org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField;

/**
 * This example will take a PDF document and print all the fields from the file.
 *
 * @author Ben Litchfield
 *
 */
public class PrintJavaScriptFields
{

    /**
     * This will print all the fields from the document.
     *
     * @param pdfDocument The PDF to get the fields from.
     *
     * @throws IOException If there is an error getting the fields.
     */
    public void printFields(PDDocument pdfDocument) throws IOException
    {
        PDDocumentCatalog docCatalog = pdfDocument.getDocumentCatalog();
        PDAcroForm acroForm = docCatalog.getAcroForm();
        List<PDField> fields = acroForm.getFields();

        //System.out.println(fields.size() + " top-level fields were found on the form");
        for (PDField field : fields)
        {
            processField(field, "|--", field.getPartialName());
        }
    }

    private void processField(PDField field, String sLevel, String sParent) throws IOException
    {
        String partialName = field.getPartialName();

        if (field instanceof PDTerminalField)
        {
            PDTerminalField termField = (PDTerminalField) field;
            PDFormFieldAdditionalActions fieldActions = field.getActions();
            if (fieldActions != null)
            {
                System.out.println(field.getFullyQualifiedName() + ": " + fieldActions.getClass().getSimpleName() + " js field actionS:\n" + fieldActions.getCOSObject());
                printPossibleJS(fieldActions.getK());
                printPossibleJS(fieldActions.getC());
                printPossibleJS(fieldActions.getF());
                printPossibleJS(fieldActions.getV());
            }
            for (PDAnnotationWidget widgetAction : termField.getWidgets())
            {
                PDAction action = widgetAction.getAction();
                if (action instanceof PDActionJavaScript)
                {
                    System.out.println(field.getFullyQualifiedName() + ": " + action.getClass().getSimpleName() + " js widget action:\n" + action.getCOSObject());
                    printPossibleJS(action);
                }
            }
        }

        if (field instanceof PDNonTerminalField)
        {
            if (!sParent.equals(field.getPartialName()))
            {
                if (partialName != null)
                {
                    sParent = sParent + "." + partialName;
                }
            }
            //System.out.println(sLevel + sParent);

            for (PDField child : ((PDNonTerminalField) field).getChildren())
            {
                processField(child, "|  " + sLevel, sParent);
            }
        }
        else
        {
            String fieldValue = field.getValueAsString();
            StringBuilder outputString = new StringBuilder(sLevel);
            outputString.append(sParent);
            if (partialName != null)
            {
                outputString.append(".").append(partialName);
            }
            outputString.append(" = ").append(fieldValue);
            outputString.append(", type=").append(field.getClass().getName());
            //System.out.println(outputString);
        }
    }

    private void printPossibleJS(PDAction kAction)
    {
        if (kAction instanceof PDActionJavaScript)
        {
            PDActionJavaScript jsAction = (PDActionJavaScript) kAction;
            String jsString = jsAction.getAction();
            if (!jsString.contains("\n"))
            {
                // avoid display problems with netbeans
                jsString = jsString.replaceAll("\r", "\n").replaceAll("\n\n", "\n");
            }
            System.out.println(jsString);
            System.out.println();
        }
    }

    /**
     * This will read a PDF file and print out the form elements. <br />
     * see usage() for commandline
     *
     * @param args command line arguments
     *
     * @throws IOException If there is an error importing the FDF document.
     */
    public static void main(String[] args) throws IOException
    {
        PDDocument pdf = null;
        try
        {
            pdf = PDDocument.load(new File("XXXX", "YYYYY.pdf"));
            PrintJavaScriptFields exporter = new PrintJavaScriptFields();
            exporter.printFields(pdf);
        }
        finally
        {
            if (pdf != null)
            {
                pdf.close();
            }
        }
    }

} 

As a bonus, here's code to show all COSString objects:

public class ShowAllCOSStrings
{
    static Set<COSString> strings = new HashSet<COSString>();

    static void crawl(COSBase base)
    {
        if (base instanceof COSString)
        {
            strings.add((COSString)base);
            return;
        }
        if (base instanceof COSDictionary)
        {
            COSDictionary dict = (COSDictionary) base;
            for (COSName key : dict.keySet())
            {
                crawl(dict.getDictionaryObject(key));
            }
            return;
        }
        if (base instanceof COSArray)
        {
            COSArray ar = (COSArray) base;

            for (COSBase item : ar)
            {
                crawl(item);
            }
            return;
        }
        if (base instanceof COSNull || 
                base instanceof COSObject || 
                base instanceof COSName || 
                base instanceof COSNumber || 
                base instanceof COSBoolean || 
                base == null)
        {
            return;
        }
        System.out.println("huh? " + base);
    }

    public static void main(String[] args) throws IOException
    {
        PDDocument doc = PDDocument.load(new File("XXX","YYY.pdf"));

        for (COSObject obj : doc.getDocument().getObjects())
        {
            COSBase base = obj.getObject();
            //System.out.println(obj + ": " + base);
            crawl(base);
        }
        System.out.println(strings.size() + " strings:");
        for (COSString s : strings)
        {
            String str = s.getString();
            if (!str.contains("\n"))
            {
                // avoid display problems with netbeans
                str = str.replaceAll("\r", "\n").replaceAll("\n\n", "\n");
            }
            System.out.println(str);
        }
        doc.close();
    }
}

However Javascript can also be in a stream. See in the PDF spec "Additional entries specific to a rendition action", the JS entry:

A text string or stream containing a JavaScript script that shall be executed when the action is triggered.

You can change the code above to catch COSStream objects too; COSStream is extended from COSDictionary.

Question:

In PDFBOX, I want to insert some images as form fields which can be stored in an acroform. Later for some value changes in specific PDTextBox field by user, I want to invoke Javascript function to show/hide above image fields. Also confirm whether there is a support in javascript to make image field hide/show (i.e., If I am able to give name to such image filed then i think it is possible).

Is there functionality available in PDFBOX 1.8.10 to achieve this goal? If yes, please provide reference code/document.

Thanks for help in advanced.


Answer:

I have fixed above issue to treat an image as the field.

I have taken PDPushButton field and set image in it, so that I can show/hide an image through java script too.

Look at below sample code:

package sample.pdfbox.example;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;

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.exceptions.COSVisitorException;
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.common.PDStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDPixelMap;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDPushButton;

public class MyPushButton2 
{
    public static void main(String arg[])  throws IOException, COSVisitorException
    {
        PDDocument document = new PDDocument();
        PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
        document.addPage(page);

        PDFont font = PDType1Font.HELVETICA;
        PDResources res = new PDResources();
        String fontName = res.addFont(font);
        String da = "/Helv 0 Tf 0 g";

        COSDictionary acroFormDict = new COSDictionary(); 
        acroFormDict.setItem(COSName.FIELDS, new COSArray());
        acroFormDict.setItem(COSName.DA, new COSString(da));

        PDAcroForm acroForm =  new PDAcroForm(document, acroFormDict);
        acroForm.setDefaultResources(res);
        document.getDocumentCatalog().setAcroForm(acroForm);


        float x = 10f;
        float y = page.getMediaBox().getHeight();  
        float yOffset = 15f;
        float yCurrent = y - yOffset;  

     // Create appearance stream for local image
        COSArray rectStream = new COSArray();
        rectStream.add(new COSFloat(0));
        rectStream.add(new COSFloat(0));
        rectStream.add(new COSFloat(25));
        rectStream.add(new COSFloat(25));

        final PDRectangle boundingBox = new PDRectangle(rectStream);
        InputStream imageStream = MyPushButton2.class.getResourceAsStream("/Penguins.jpg");
        BufferedImage bImage = ImageIO.read(imageStream);
        PDXObjectImage image = new PDPixelMap(document,bImage);

        PDResources holderFormResources = new PDResources();
        PDStream holderFormStream = new PDStream(document);
        PDXObjectForm holderForm = new PDXObjectForm(holderFormStream);
        holderForm.setResources(holderFormResources);
        holderForm.setBBox(boundingBox);
        holderForm.setFormType(1);

        PDAppearanceDictionary appearance = new PDAppearanceDictionary();
        appearance.getCOSObject().setDirect(true);
        PDAppearanceStream appearanceStream = new PDAppearanceStream(holderForm.getCOSStream());
        appearance.setNormalAppearance(appearanceStream);

        PDResources innerFormResources = new PDResources();
        PDStream innerFormStream = new PDStream(document);
        PDXObjectForm innerForm = new PDXObjectForm(innerFormStream);
        innerForm.setResources(innerFormResources);
        innerForm.setBBox(boundingBox);
        innerForm.setFormType(1);

        String innerFormName = holderFormResources.addXObject(innerForm, "FRM");

        PDResources imageFormResources = new PDResources();
        PDStream imageFormStream = new PDStream(document);

        PDXObjectForm imageForm = new PDXObjectForm(imageFormStream);
        imageForm.setResources(imageFormResources);
        imageForm.setBBox(boundingBox);
        imageForm.setFormType(1);

        String imageFormName = innerFormResources.addXObject(imageForm, "n");
        String imageName = imageFormResources.addXObject(image, "img");

        String holderFormComment = "q 1 0 0 1 0 0 cm /" + innerFormName + " Do Q \n";
        String innerFormComment = "q q 5 0 0 5 0 0 cm /" + imageFormName + " Do Q\n";
        String imgFormComment = "q 5 0 0 5 0 0 cm /" + imageName + " Do Q\n";

        appendRawCommands(holderFormStream.createOutputStream(), holderFormComment);
        appendRawCommands(innerFormStream.createOutputStream(), innerFormComment);
        appendRawCommands(imageFormStream.createOutputStream(), imgFormComment);

        // Create Pushbutton containing status image
        COSDictionary cosDict = new COSDictionary();
        COSArray rect = new COSArray();
        rect.add(new COSFloat(100));
        rect.add(new COSFloat(500));
        rect.add(new COSFloat(300));
        rect.add(new COSFloat(700));

        cosDict.setItem(COSName.RECT, rect);
        cosDict.setItem(COSName.FT, COSName.getPDFName("Btn")); // Field Type
        cosDict.setItem(COSName.TYPE, COSName.ANNOT);
        cosDict.setItem(COSName.SUBTYPE, COSName.getPDFName("Widget"));
        cosDict.setItem(COSName.T, new COSString("ImageField1"));
        cosDict.setInt(COSName.F, 4);
        cosDict.setInt(COSName.FF, 65536);

        PDPushButton button = new PDPushButton(document.getDocumentCatalog().getAcroForm(), cosDict);
        button.setReadonly(true);

        button.getWidget().setAppearance(appearance);
        page.getAnnotations().add(button.getWidget());                          
        acroForm.getFields().add(button); // Added this line for Tilman's comment

        yCurrent = yCurrent - 20 - yOffset;

        File file = new File("C:\\pdf\\ImageButton.pdf");
        System.out.println("Sample file saved at : " + file.getAbsolutePath());
        document.save(file);
        document.close();
    }

    public static void appendRawCommands(OutputStream os, String commands) throws IOException {
        os.write(commands.getBytes("ISO-8859-1"));
        os.close();
    }

}

Hope this solution helps!!

Question:

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

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

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.

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?

Thanks Thomas

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

}

}


Answer:

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

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.

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.

Question:

My use case is to have a button like so on a pdf page (really to add them to existing pages but for now I just want to see it work on anything).

----------
-  Back  -
----------

And what it does is just closes the current pdf page. The idea is to have multiple tabs opened and each tab is a pdf and then when you hit the "Back" button it closes the current pdf which will then focus back to the previous pdf. This is what I have been trying to use so far.

        // Create a new empty document
        try {
            PDDocument document = new PDDocument();

            // Create a new blank page and add it to the document
            PDPage blankPage = new PDPage();
            document.addPage( blankPage );

            PDBorderStyleDictionary borderULine = new PDBorderStyleDictionary();
            borderULine.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
            PDColor green = new PDColor(new float[] { 0, 1, 0 }, PDDeviceRGB.INSTANCE);
//            PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);

//            textWidth = (font.getStringWidth("Click Here") / 1000) * 18;
            PDAnnotationLink txtLink = new PDAnnotationLink();
            txtLink.setBorderStyle(borderULine);

            // add an action
//            PDActionURI action = new PDActionURI();
//            action.setURI("www.google.com");
            PDActionJavaScript action = new PDActionJavaScript("this.closeDoc()");
            txtLink.setAction(action);
            txtLink.setContents("HI");
            txtLink.setColor(green);

            PDRectangle position = new PDRectangle();
            position.setLowerLeftX(10);
            position.setLowerLeftY(20);
            position.setUpperRightX(100);
            position.setUpperRightY(40);
            txtLink.setRectangle(position);
            txtLink.setInvisible(false);
            blankPage.getAnnotations().add(txtLink);

            // Save the newly created document
            document.save("C:\\Users\\jsmith\\Desktop\\demo\\BlankPage.pdf");
            document.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

And I cant seem to see anything on the pdf page (its just all white), I did get the following code at at least be able to go to a new page instead of the javascript but it was still invisible. I just was able to hover over the bottom left and notice i could click on a link.

            PDActionURI action = new PDActionURI();
            action.setURI("www.google.com");

Answer:

Improved answer as discussed in the comments of the OPs own answer, and it also includes the answer from the follow-up question.

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

COSDictionary acroFormDict = new COSDictionary();
PDAcroForm acroForm = new PDAcroForm(doc, acroFormDict);
doc.getDocumentCatalog().setAcroForm(acroForm);
acroForm.setFields(new ArrayList<>());

PDPushButton button = new PDPushButton(acroForm);
button.setPartialName("Btn1");

PDActionJavaScript actionJavaScript = new PDActionJavaScript("this.closeDoc();");
PDAnnotationAdditionalActions additionalActions = new PDAnnotationAdditionalActions();
additionalActions.setU(actionJavaScript);

// widget
PDAnnotationWidget widget = button.getWidgets().get(0);
widget.setActions(additionalActions);
widget.setRectangle(new PDRectangle(100, 700, 100, 50));

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

// Create appearance
PDAppearanceDictionary appearanceDictionary = new PDAppearanceDictionary();
PDAppearanceStream appearanceStream = new PDAppearanceStream(doc);
appearanceStream.setResources(new PDResources());
try (PDPageContentStream cs = new PDPageContentStream(doc, appearanceStream))
{
    PDRectangle bbox = new PDRectangle(widget.getRectangle().getWidth(), widget.getRectangle().getHeight());
    appearanceStream.setBBox(bbox);
    cs.setNonStrokingColor(0, 0, 0); // black
    cs.addRect(bbox.getLowerLeftX() + 0.5f, bbox.getLowerLeftY() + 0.5f, bbox.getWidth() - 1, bbox.getHeight() - 1);
    cs.stroke();

    // put some useful text
    cs.setFont(PDType1Font.HELVETICA, 20);
    cs.beginText();
    cs.newLineAtOffset(20, 20);
    cs.showText("Close");
    cs.endText();
}
appearanceDictionary.setNormalAppearance(appearanceStream);
widget.setAppearance(appearanceDictionary);

page.getAnnotations().add(widget);

acroForm.getFields().add(button);

doc.save("..../Button.pdf");
doc.close();