Programmatically editing a PDF using Java

Table of contents

    Programmatically editing a PDF using Java
    Summary

    Learn how to use our Java PDF library to programmatically edit PDF documents with comprehensive examples in both Java and Kotlin. This tutorial demonstrates essential PDF editing operations, including page rotation, rearrangement, annotation addition, and importing pages from other documents. Discover how to leverage our DocumentEditor API to create powerful PDF manipulation workflows while maintaining document integrity and performance.

    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 Nutrient 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 Nutrient Java library 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:<%= latest_version(:java) %>'
    }
    repositories {
    maven(url = "https://my.nutrient.io/maven/")
    }
    dependencies {
    implementation("com.pspdfkit:libraries-java:<%= latest_version(:java) %>")
    }

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

    Initializing Nutrient

    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 eocument

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

    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 Nutrient Java PDF library 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 Nutrient Java PDF library?

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

    Can I use Nutrient with Kotlin?

    Yes. Nutrient can be used with both Java and Kotlin.

    What kind of PDF editing can be done with the Nutrient Java PDF library?

    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 Nutrient?

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

    Does Nutrient support chaining operations in the DocumentEditor?

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

    Amit Nayar

    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?