Undo/Redo PDF Edits - C++ Sample Code

The Apryse 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 code (provided in Python, C++, C#, Java, Node.js, PHP, Ruby, Go and VB) shows how to use Apryse 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. Learn more about our Server SDK.

1//---------------------------------------------------------------------------------------
2// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
3// Consult legal.txt regarding legal and license information.
4//---------------------------------------------------------------------------------------
5
6#include <PDF/PDFNet.h>
7#include <PDF/PDFDoc.h>
8#include <string>
9#include <iostream>
10#include <PDF/Element.h>
11#include <PDF/ElementBuilder.h>
12#include <PDF/ElementWriter.h>
13#include <PDF/Image.h>
14#include <Common/Matrix2D.h>
15#include "../../LicenseKey/CPP/LicenseKey.h"
16
17using namespace std;
18using namespace pdftron;
19using namespace PDF;
20using namespace SDF;
21using namespace Common;
22
23//---------------------------------------------------------------------------------------
24// The following sample illustrates how to use the UndoRedo API.
25//---------------------------------------------------------------------------------------
26int main(int argc, char *argv[])
27{
28 int ret = 0;
29 try
30 {
31 // The first step in every application using PDFNet is to initialize the
32 // library and set the path to common PDF resources. The library is usually
33 // initialized only once, but calling Initialize() multiple times is also fine.
34 PDFNet::Initialize(LicenseKey);
35
36 // Relative path to the folder containing test files.
37 string input_path = "../../TestFiles/";
38 string output_path = "../../TestFiles/Output/";
39
40 // Open the PDF document.
41 PDFDoc doc((input_path + "newsletter.pdf").c_str());
42
43 UndoManager undo_manager = doc.GetUndoManager();
44
45 // Take a snapshot to which we can undo after making changes.
46 ResultSnapshot snap0 = undo_manager.TakeSnapshot();
47
48 DocSnapshot snap0_state = snap0.CurrentState();
49
50 Page page = doc.PageCreate(); // Start a new page
51
52 ElementBuilder bld; // Used to build new Element objects
53 ElementWriter writer; // Used to write Elements to the page
54 writer.Begin(page); // Begin writing to this page
55
56 // ----------------------------------------------------------
57 // Add JPEG image to the file
58 PDF::Image img = PDF::Image::Create(doc, (input_path + "peppers.jpg").c_str());
59 Element element = bld.CreateImage(img, Matrix2D(200, 0, 0, 250, 50, 500));
60 writer.WritePlacedElement(element);
61
62 writer.End(); // Finish writing to the page
63 doc.PagePushFront(page);
64
65 // Take a snapshot after making changes, so that we can redo later (after undoing first).
66 ResultSnapshot snap1 = undo_manager.TakeSnapshot();
67
68 if (snap1.PreviousState().Equals(snap0_state))
69 {
70 puts("snap1 previous state equals snap0_state; previous state is correct");
71 }
72
73 DocSnapshot snap1_state = snap1.CurrentState();
74
75 doc.Save((output_path + "addimage.pdf").c_str(), SDFDoc::e_incremental, 0);
76
77 if (undo_manager.CanUndo())
78 {
79 ResultSnapshot undo_snap = undo_manager.Undo();
80
81 doc.Save((output_path + "addimage_undone.pdf").c_str(), SDFDoc::e_incremental, 0);
82
83 DocSnapshot undo_snap_state = undo_snap.CurrentState();
84
85 if (undo_snap_state.Equals(snap0_state))
86 {
87 puts("undo_snap_state equals snap0_state; undo was successful");
88 }
89
90 if (undo_manager.CanRedo())
91 {
92 ResultSnapshot redo_snap = undo_manager.Redo();
93
94 doc.Save((output_path + "addimage_redone.pdf").c_str(), SDFDoc::e_incremental, 0);
95
96 if (redo_snap.PreviousState().Equals(undo_snap_state))
97 {
98 puts("redo_snap previous state equals undo_snap_state; previous state is correct");
99 }
100
101 DocSnapshot redo_snap_state = redo_snap.CurrentState();
102
103 if (redo_snap_state.Equals(snap1_state))
104 {
105 puts("Snap1 and redo_snap are equal; redo was successful");
106 }
107 }
108 else
109 {
110 puts("Problem encountered - cannot redo.");
111 ret = 1;
112 }
113 }
114 else
115 {
116 puts("Problem encountered - cannot undo.");
117 ret = 1;
118 }
119 }
120 catch(Common::Exception& e)
121 {
122 cout << e << endl;
123 ret = 1;
124 }
125 catch (...)
126 {
127 cout << "Unknown Exception" << endl;
128 ret = 1;
129 }
130
131 PDFNet::Terminate();
132
133 return ret;
134}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales