Some test text!


Undo / redo edits to a PDF file using Kotlin

The PDFTron SDK has a low-level facility for undo and redo operations. It is a API that applies to any edits made to a particular document (not just annotations). This sample Kotlin code shows how to use PDFTron SDK to walk back and forth on a fully general, bit-exact list of document states. Saving changes in a mode that is not 'incremental' will wipe out the undo-redo state list; the API will not be able to access old snapshots anymore. See the undoing and redoing guide for more information.

Get StartedSamplesDownload

To run this sample, get started with a free trial of PDFTron SDK.


// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.

import com.pdftron.common.Matrix2D
import com.pdftron.pdf.ElementBuilder
import com.pdftron.pdf.ElementWriter
import com.pdftron.pdf.Image
import com.pdftron.pdf.PDFDoc
import com.pdftron.sdf.ResultSnapshot
import com.pdftron.sdf.SDFDoc
import java.util.*

// The following sample illustrates how to use the UndoRedo API.
class UndoRedoTest : PDFNetSample() {
    init {

    override fun run(outputListener: OutputListener?) {
        mOutputListener = outputListener
        try {
            // The first step in every application using PDFNet is to initialize the
            // library and set the path to common PDF resources. The library is usually
            // initialized only once, but calling Initialize() multiple times is also fine.

            // Open the PDF document.
            val doc = PDFDoc(Utils.getAssetTempFile(PDFNetSample.INPUT_PATH + "newsletter.pdf")!!.absolutePath)

            val undo_manager = doc.undoManager

            // Take a snapshot to which we can undo after making changes.
            val snap0 = undo_manager.takeSnapshot()

            val snap0_state = snap0.currentState()

            val page = doc.pageCreate()    // Start a new page

            val bld = ElementBuilder()        // Used to build new Element objects
            val writer = ElementWriter()        // Used to write Elements to the page
            writer.begin(page)        // Begin writing to this page

            // ----------------------------------------------------------
            // Add JPEG image to the file
            val img = Image.create(doc, Utils.getAssetTempFile(PDFNetSample.INPUT_PATH + "peppers.jpg")!!.absolutePath)
            val element = bld.createImage(img, Matrix2D(200.0, 0.0, 0.0, 250.0, 50.0, 500.0))

            writer.end()    // Finish writing to the page

            // Take a snapshot after making changes, so that we can redo later (after undoing first).
            val snap1 = undo_manager.takeSnapshot()

            if (snap1.previousState().equals(snap0_state)) {
                mOutputListener!!.println("snap1 previous state equals snap0_state; previous state is correct")

            val snap1_state = snap1.currentState()

  "addimage.pdf", mFileList).absolutePath, SDFDoc.SaveMode.INCREMENTAL, null)

            if (undo_manager.canUndo()) {
                val undo_snap: ResultSnapshot
                undo_snap = undo_manager.undo()

      "addimage_undone.pdf", mFileList).absolutePath, SDFDoc.SaveMode.INCREMENTAL, null)

                val undo_snap_state = undo_snap.currentState()

                if (undo_snap_state.equals(snap0_state)) {
                    mOutputListener!!.println("undo_snap_state equals snap0_state; undo was successful")

                if (undo_manager.canRedo()) {
                    val redo_snap = undo_manager.redo()

          "addimage_redone.pdf", mFileList).absolutePath, SDFDoc.SaveMode.INCREMENTAL, null)

                    if (redo_snap.previousState().equals(undo_snap_state)) {
                        mOutputListener!!.println("redo_snap previous state equals undo_snap_state; previous state is correct")

                    val redo_snap_state = redo_snap.currentState()

                    if (redo_snap_state.equals(snap1_state)) {
                        mOutputListener!!.println("Snap1 and redo_snap are equal; redo was successful")
                } else {
                    mOutputListener!!.println("Problem encountered - cannot redo.")
            } else {
                mOutputListener!!.println("Problem encountered - cannot undo.")

            // Calling Terminate when PDFNet is no longer in use is a good practice, but
            // is not required.
        } catch (e: Exception) {

        for (file in mFileList) {

    companion object {

        private var mOutputListener: OutputListener? = null

        private val mFileList = ArrayList<String>()


Free Trial

Get unlimited trial usage of PDFTron SDK to bring accurate, reliable, and fast document processing capabilities to any application or workflow.

Select a platform to get started with your free trial.

Unlimited usage. No email address required.

PDFTron Receives USD$71 Million Growth Investment Led By Silversmith Capital Partners

Learn More