Blog Post

Programmatically Editing a PDF Using Java

Amit Nayar
Illustration: Programmatically Editing a PDF Using Java

This blog post will show how to edit PDF documents programmatically with both Java and Kotlin. You’ll be rotating and rearranging pages, adding annotations, and importing pages from another document.

Setting Up

This section will outline the steps to take to get set up.

Configuring Dependencies

For this task, you’ll be using our Java PDF library, which is available from the PSPDFKit Maven repository. You can add it as a dependency in the Gradle build system once a project has been created.

Inside your app’s build.gradle file, add both the Maven repository and the PSPDFKit Library for Java dependency. Below, you’ll see how to do it in both the Groovy and Kotlin DSLs:

repositories {
    maven {
        url 'https://my.nutrient.io/maven/'
    }
}

dependencies {
    implementation 'com.pspdfkit:libraries-java:1.6.1'
}
repositories {
    maven(url = "https://my.nutrient.io/maven/")
}

dependencies {
    implementation("com.pspdfkit:libraries-java:1.6.1")
}

For more information about how to integrate PSPDFKit into your project, please refer to our getting started guides.

Initializing PSPDFKit

Once the package is available, you need to initialize it. This can be done either in the free trial version with initializeTrial, or by using initialize if you’ve purchased a license key:

import com.pspdfkit.api.PSPDFKit;
import com.pspdfkit.api.PSPDFKitInitializeException;

public void initializePSPDFKit() throws PSPDFKitInitializeException {
    PSPDFKit.initializeTrial();
    // OR
    PSPDFKit.initialize("<License Key>");
}
import com.pspdfkit.api.PSPDFKit
import com.pspdfkit.api.PSPDFKitInitializeException

@Throws(PSPDFKitInitializeException::class)
fun initializePSPDFKit() : Void {
    PSPDFKit.initializeTrial()
    // OR
    PSPDFKit.initialize("<License Key>")
}

Loading a Document

Our SDK uses data providers to load and save document data. In this example, you’ll load a document into application memory from the file system using a FileDataProvider, and you’ll open it in our core PDF processing library using the PdfDocument class:

package com.my.app;

import com.pspdfkit.api.PSPDFKit;
import com.pspdfkit.api.PSPDFKitInitializeException;
import com.pspdfkit.api.PdfDocument;
import com.pspdfkit.api.providers.FileDataProvider;

import java.io.File;

public class App {
    public static void main(String[] args) throws PSPDFKitInitializeException {
        initializePSPDFKit();
        final File file = new File("path/to/document.pdf");
        final PdfDocument document = PdfDocument.open(new FileDataProvider(file));
    }
}
package com.my.app

import com.pspdfkit.api.PSPDFKit
import com.pspdfkit.api.PSPDFKitInitializeException
import com.pspdfkit.api.PdfDocument
import com.pspdfkit.api.providers.FileDataProvider

import java.io.File

@Throws(PSPDFKitInitializeException::class)
fun main(args: Array<String>) {
    initializePSPDFKit()
    val file = File("path/to/document.pdf")
    val document = PdfDocument.open(FileDataProvider(file))
}

Editing a Document

The DocumentEditor can be used to perform a number of editing operations on the document, process the edits, and output the edited document to a new file. In this example, you’ll use the DocumentEditor to import pages from another document, remove pages, rotate pages, and finally show how the saving mechanism works. Take a look at our Java guides for editing PDFs for the full list of capabilities of our Document Editor.

Importing a Page

Your document is missing a cover page. Luckily, you have another document with the cover page you want to use. With our Java PDF library, you can import this second document and insert the page at the start of your document. To do this, you must import the entire document and then remove the pages you don’t want to keep:

import com.pspdfkit.api.DocumentEditor;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

private DocumentEditor addCoverPage(final PdfDocument document) {
    final DocumentEditor documentEditor = document.createDocumentEditor();
    documentEditor.importDocument(
        0,
        DocumentEditor.IndexPosition.BeforeIndex,
        new FileDataProvider(new File("CoverPage.pdf"))
    );

    // "CoverPage.pdf" has three pages, so you can remove the two you don't need.
    // Note that the page indexes are zero-based. So `1` is the second page.
    final Set<Integer> pages = new HashSet<>(Arrays.asList(1, 2));
    documentEditor.removePages(pages);

    return documentEditor;
}
import com.pspdfkit.api.DocumentEditor

import java.util.Arrays
import java.util.HashSet
import java.util.Set

private fun addCoverPage(document: PdfDocument) =
    document.createDocumentEditor().apply {
        importDocument(
            0,
            DocumentEditor.IndexPosition.BeforeIndex,
            FileDataProvider(File("CoverPage.pdf"))
        )
        // "CoverPage.pdf" has three pages, so you can remove the two you don't need.
        // Note that the page indexes are zero-based. So `1` is the second page.
        removePages(setOf(1, 2))
    }

💡 Tip: As you can see from the code snippet, Document Editor operations can be chained before processing them, so you don’t have to process each operation individually.

Rotating a Page

Let’s say you have an image on the second page of the document that needs to be rotated 90 degrees for it to be shown the correct way. You can chain the rotate operation to the previous editor operations:

import com.pspdfkit.api.basic.Rotation;

// ...

    // The second page needs rotating clockwise by 90 degrees.
    final Set<Integer> rotatePages = new HashSet<>();
    rotatePages.add(1);
    documentEditor.rotatePages(rotatePages, Rotation.Degrees90);

    return documentEditor;
}
import com.pspdfkit.api.basic.Rotation

// ...

    // The second page needs rotating clockwise by 90 degrees.
    documentEditor.rotatePages(setOf(1), Rotation.Degrees90)

    return documentEditor
}

Document Editor Saving

One thing to be aware of when using the Document Editor is that operations must be saved to a data provider, which must then be opened in a new PdfDocument instance if you want to perform additional edits to that document. For this example, you’ll use DocumentEditor#saveDocument() after adding the editor operations. Then, you’ll return a newly opened PdfDocument from the following function to add the annotation in the next section:

/**
 * Applies and saves Document Editor operations to a new document in a temporary location,
 * and then opens and returns the saved document.
 *
 * @param documentEditor Document Editor with the editing operations prepared.
 * @return PdfDocument instance of the edited document.
 */
private PdfDocument saveAndReopenEditedDocument(final DocumentEditor documentEditor) throws IOException {
    final File outputFile = File.createTempFile("tempDocument", ".pdf");

    // You can print out the temporary save location so you can inspect it.
    System.out.println("Temporary file: " + $outputFile.getAbsolutePath());

    documentEditor.saveDocument(new FileDataProvider(outputFile));
    return PdfDocument.open(new FileDataProvider(outputFile));
}
/**
 * Applies and saves Document Editor operations to a new document in a temporary location,
 * and then opens and returns the saved document.
 *
 * @param documentEditor Document Editor with the editing operations prepared.
 * @return PdfDocument instance of the edited document.
 */
@Throws(IOException::class)
private fun saveAndReopenEditedDocument(documentEditor: DocumentEditor): PdfDocument {
    val outputFile = File.createTempFile("tempDocument", ".pdf")

    // You can print out the temporary save location so you can inspect it.
    println("Temporary file: ${outputFile.absolutePath}")

    documentEditor.saveDocument(FileDataProvider(outputFile))
    return PdfDocument.open(FileDataProvider(outputFile))
}

Adding an Annotation

Annotations can be added programmatically using the AnnotationProvider. See our annotation guides for a list of possible annotations. Here, you’ll add a red and blue ellipse on the cover page:

import org.json.JSONObject;

/**
 * Adds an ellipse annotation on the first page of the input document.
 *
 * @param document Document on which to add the annotation.
 */
private void addAnnotation(final PdfDocument document) {
    // Define an annotation in JSON and add it to the first page of the document.
    final JSONObject jsonObject = new JSONObject();

    jsonObject.put("pageIndex", 0);
    jsonObject.put("fillColor", "#FF0000");
    jsonObject.put("strokeColor", "#0000FF");
    jsonObject.put("strokeWidth", 11);
    jsonObject.put("creatorName", "Zaphod");
    jsonObject.put("v", 1);
    jsonObject.put("opacity", 1);
    jsonObject.put("type", "pspdfkit/shape/ellipse");
    jsonObject.put("bbox", new float[]{10, 10, 400, 400});

    document.getAnnotationProvider().addAnnotationJson(jsonObject);
}
import org.json.JSONObject

/**
 * Adds an ellipse annotation on the first page of the input document.
 *
 * @param document Document on which to add the annotation.
 */
private fun addAnnotation(document: PdfDocument) {
    // Define an annotation in JSON and add it to the first page of the document.
    val jsonObject = JSONObject().apply {
        put("pageIndex", 0)
        put("fillColor", "#FF0000")
        put("strokeColor", "#0000FF")
        put("strokeWidth", 11)
        put("creatorName", "Zaphod")
        put("v", 1)
        put("opacity", 1f)
        put("type", "pspdfkit/shape/ellipse")
        put("bbox", floatArrayOf(10f, 10f, 400f, 400f))
    }

    document.annotationProvider.addAnnotationJson(jsonObject)
}

The Whole Program

By combining the above editing operations and annotation addition in their functions, you’ll end up with the following application:

package com.my.app;

import com.pspdfkit.api.*;
import com.pspdfkit.api.basic.Rotation;
import com.pspdfkit.api.providers.FileDataProvider;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class App {
    public static void main(String[] args) throws PSPDFKitInitializeException, IOException {
        initializePSPDFKit();

        final File file = new File("path/to/document.pdf");
        final PdfDocument document = PdfDocument.open(new FileDataProvider(file));

        final DocumentEditor documentEditor = addCoverPage(document);
        final PdfDocument editedDocument = saveAndReopenEditedDocument(documentEditor);
        addAnnotation(editedDocument);

        final File output = new File("path/to/output.pdf");
        editedDocument.saveAs(new FileDataProvider(output), new DocumentSaveOptions.Builder().build());
    }
}

// ... The functions in the above snippets can be defined here.
package com.my.app

import com.pspdfkit.api.DocumentEditor
import com.pspdfkit.api.DocumentSaveOptions
import com.pspdfkit.api.basic.Rotation
import com.pspdfkit.api.PdfDocument
import com.pspdfkit.api.providers.FileDataProvider
import com.pspdfkit.api.PSPDFKit
import com.pspdfkit.api.PSPDFKitInitializeException

import java.io.File
import java.io.IOException
import java.util.HashSet
import org.json.JSONObject

@Throws(PSPDFKitInitializeException::class, IOException::class)
fun main(args: Array<String>) {
    initializePSPDFKit()

    val file = File("path/to/document.pdf")
    var document = PdfDocument.open(FileDataProvider(file))

    val documentEditor = addCoverPage(document)
    var editedDocument = saveAndReopenEditedDocument(documentEditor)
    addAnnotation(editedDocument)

    val output = File("path/to/output.pdf")
    editedDocument.saveAs(FileDataProvider(output), DocumentSaveOptions.Builder().build())
}

// ... The functions in the above snippets can be defined here.

Conclusion

In this post, you saw how easy it is to configure and manipulate PDFs with our Library for Java. You can import pages from other documents, create annotations, add and remove pages, and much more. If you’re looking for an example using C#, you can check out How to Edit a PDF Programmatically with C#.

The PSPDFKit Library for Java offers an easy-to-use yet very powerful API for manipulating PDFs. Check out our Java guides to view the full capabilities of our PDF library. You can also download our Catalog application to get up and running quickly using our readymade examples.

FAQ

How do I install the PSPDFKit Library for Java?

You can add the library as a dependency in your Gradle build file using the provided Maven repository link.

Can I use PSPDFKit with Kotlin?

Yes, PSPDFKit can be used with both Java and Kotlin.

What kind of PDF editing can be done with PSPDFKit for Java?

You can edit PDFs by rotating pages, adding annotations, importing and removing pages, and more.

How do I load a PDF document into memory using PSPDFKit?

You can use the FileDataProvider class to load a PDF document from the file system into memory.

Does PSPDFKit support chaining operations in the DocumentEditor?

Yes, operations like importing, rotating, and removing pages can be chained before processing.

Author
Amit Nayar Android Team Lead

Amit would rather spend his time making pizza, poking campfires, eating cheese and crisps, or climbing trees, but sadly he has to write great software to help save the world from deforestation. It’s a hard life, but someone’s gotta do it.

Explore related topics

Free trial Ready to get started?
Free trial