PDF Bookmarks and Outlines - Add/Edit/Read - C++ Sample Code

Requirements
View Demo

Sample code to use Apryse SDK for programmatically reading and editing existing outline items, and for creating new PDF bookmarks using the high-level API. Sample code provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby and VB.

Implementation steps

To manipulate bookmarks and outlines with Apryse Server SDK:

Step 1: Follow get started with Server SDK in your preferred language or framework
Step 2: Add the sample code provided in this guide

To use this feature in production, your license key will need the Page Manipulation Package. Trial keys already include all packages.

Learn more about our Server SDK and PDF Editing & Manipulation Library.

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 <iostream>
9#include <assert.h>
10#include "../../LicenseKey/CPP/LicenseKey.h"
11
12using namespace std;
13using namespace pdftron;
14using namespace SDF;
15using namespace PDF;
16
17//-----------------------------------------------------------------------------------------
18// The sample code illustrates how to read and edit existing outline items and create
19// new bookmarks using the high-level API.
20//-----------------------------------------------------------------------------------------
21
22void PrintIndent(Bookmark item)
23{
24 int ident = item.GetIndent() - 1;
25 for (int i=0; i<ident; ++i) cout << " ";
26}
27
28// Prints out the outline tree to the standard output
29void PrintOutlineTree(Bookmark item)
30{
31 for (; item.IsValid(); item=item.GetNext())
32 {
33 PrintIndent(item);
34 cout << (item.IsOpen() ? "- " : "+ ") << item.GetTitle() << " ACTION -> ";
35
36 // Print Action
37 Action action = item.GetAction();
38 if (action.IsValid()) {
39 if (action.GetType() == Action::e_GoTo) {
40 Destination dest = action.GetDest();
41 if (dest.IsValid()) {
42 Page page = dest.GetPage();
43 cout << "GoTo Page #" << page.GetIndex() << endl;
44 }
45 }
46 else {
47 cout << "Not a 'GoTo' action" << endl;
48 }
49 } else {
50 cout << "NULL" << endl;
51 }
52
53 if (item.HasChildren()) // Recursively print children sub-trees
54 {
55 PrintOutlineTree(item.GetFirstChild());
56 }
57 }
58}
59
60int main(int argc, char *argv[])
61{
62 int ret = 0;
63 PDFNet::Initialize(LicenseKey);
64
65 // Relative path to the folder containing test files.
66 string input_path = "../../TestFiles/";
67 string output_path = "../../TestFiles/Output/";
68
69 // The following example illustrates how to create and edit the outline tree
70 // using high-level Bookmark methods.
71 try
72 {
73 PDFDoc doc((input_path + "numbered.pdf").c_str());
74 doc.InitSecurityHandler();
75
76 // Lets first create the root bookmark items.
77 Bookmark red = Bookmark::Create(doc, "Red");
78 Bookmark green = Bookmark::Create(doc, "Green");
79 Bookmark blue = Bookmark::Create(doc, "Blue");
80
81 doc.AddRootBookmark(red);
82 doc.AddRootBookmark(green);
83 doc.AddRootBookmark(blue);
84
85 // You can also add new root bookmarks using Bookmark.AddNext("...")
86 blue.AddNext("foo");
87 blue.AddNext("bar");
88
89 // We can now associate new bookmarks with page destinations:
90
91 // The following example creates an 'explicit' destination (see
92 // section '8.2.1 Destinations' in PDF Reference for more details)
93 Destination red_dest = Destination::CreateFit(doc.GetPageIterator().Current());
94 red.SetAction(Action::CreateGoto(red_dest));
95
96 // Create an explicit destination to the first green page in the document
97 green.SetAction(Action::CreateGoto(
98 Destination::CreateFit(doc.GetPage(10)) ));
99
100 // The following example creates a 'named' destination (see
101 // section '8.2.1 Destinations' in PDF Reference for more details)
102 // Named destinations have certain advantages over explicit destinations.
103 const char* key = "blue1";
104 Action blue_action = Action::CreateGoto((UChar*) key, UInt32(strlen(key)),
105 Destination::CreateFit(doc.GetPage(19)) );
106
107 blue.SetAction(blue_action);
108
109 // We can now add children Bookmarks
110 Bookmark sub_red1 = red.AddChild("Red - Page 1");
111 sub_red1.SetAction(Action::CreateGoto(Destination::CreateFit(doc.GetPage(1))));
112 Bookmark sub_red2 = red.AddChild("Red - Page 2");
113 sub_red2.SetAction(Action::CreateGoto(Destination::CreateFit(doc.GetPage(2))));
114 Bookmark sub_red3 = red.AddChild("Red - Page 3");
115 sub_red3.SetAction(Action::CreateGoto(Destination::CreateFit(doc.GetPage(3))));
116 Bookmark sub_red4 = sub_red3.AddChild("Red - Page 4");
117 sub_red4.SetAction(Action::CreateGoto(Destination::CreateFit(doc.GetPage(4))));
118 Bookmark sub_red5 = sub_red3.AddChild("Red - Page 5");
119 sub_red5.SetAction(Action::CreateGoto(Destination::CreateFit(doc.GetPage(5))));
120 Bookmark sub_red6 = sub_red3.AddChild("Red - Page 6");
121 sub_red6.SetAction(Action::CreateGoto(Destination::CreateFit(doc.GetPage(6))));
122
123 // Example of how to find and delete a bookmark by title text.
124 Bookmark foo = doc.GetFirstBookmark().Find("foo");
125 if (foo.IsValid())
126 {
127 foo.Delete();
128 }
129 else
130 {
131 assert(false);
132 }
133
134 Bookmark bar = doc.GetFirstBookmark().Find("bar");
135 if (bar.IsValid())
136 {
137 bar.Delete();
138 }
139 else
140 {
141 assert(false);
142 }
143
144 // Adding color to Bookmarks. Color and other formatting can help readers
145 // get around more easily in large PDF documents.
146 red.SetColor(1, 0, 0);
147 green.SetColor(0, 1, 0);
148 green.SetFlags(2); // set bold font
149 blue.SetColor(0, 0, 1);
150 blue.SetFlags(3); // set bold and italic
151
152 doc.Save((output_path + "bookmark.pdf").c_str(), 0, 0);
153 cout << "Done. Result saved in bookmark.pdf" << endl;
154 }
155 catch(Common::Exception& e)
156 {
157 cout << e << endl;
158 ret = 1;
159 }
160 catch(...)
161 {
162 cout << "Unknown Exception" << endl;
163 ret = 1;
164 }
165
166
167 // The following example illustrates how to traverse the outline tree using
168 // Bookmark navigation methods: Bookmark.GetNext(), Bookmark.GetPrev(),
169 // Bookmark.GetFirstChild () and Bookmark.GetLastChild ().
170 try
171 {
172 // Open the document that was saved in the previous code sample
173 PDFDoc doc((output_path + "bookmark.pdf").c_str());
174 doc.InitSecurityHandler();
175
176 Bookmark root = doc.GetFirstBookmark();
177 PrintOutlineTree(root);
178
179 cout << "Done." << endl;
180 }
181 catch(Common::Exception& e)
182 {
183 cout << e << endl;
184 ret = 1;
185 }
186 catch(...)
187 {
188 cout << "Unknown Exception" << endl;
189 ret = 1;
190 }
191
192 // The following example illustrates how to create a Bookmark to a page
193 // in a remote document. A remote go-to action is similar to an ordinary
194 // go-to action, but jumps to a destination in another PDF file instead
195 // of the current file. See Section 8.5.3 'Remote Go-To Actions' in PDF
196 // Reference Manual for details.
197 try
198 {
199 // Open the document that was saved in the previous code sample
200 PDFDoc doc((output_path + "bookmark.pdf").c_str());
201 doc.InitSecurityHandler();
202
203 // Create file specification (the file referred to by the remote bookmark)
204 Obj file_spec = doc.CreateIndirectDict();
205 file_spec.PutName("Type", "Filespec");
206 file_spec.PutString("F", "bookmark.pdf");
207 FileSpec spec(file_spec);
208 Action goto_remote = Action::CreateGotoRemote(spec, 5, true);
209
210 Bookmark remoteBookmark1 = Bookmark::Create(doc, "REMOTE BOOKMARK 1");
211 remoteBookmark1.SetAction(goto_remote);
212 doc.AddRootBookmark(remoteBookmark1);
213
214 // Create another remote bookmark, but this time using the low-level SDF/Cos API.
215 // Create a remote action
216 Bookmark remoteBookmark2 = Bookmark::Create(doc, "REMOTE BOOKMARK 2");
217 doc.AddRootBookmark(remoteBookmark2);
218
219 Obj gotoR = remoteBookmark2.GetSDFObj().PutDict("A");
220 {
221 gotoR.PutName("S","GoToR"); // Set action type
222 gotoR.PutBool("NewWindow", true);
223
224 // Set the file specification
225 gotoR.Put("F", file_spec);
226
227 // jump to the first page. Note that pages are indexed from 0.
228 Obj dest = gotoR.PutArray("D"); // Set the destination
229 dest.PushBackNumber(9);
230 dest.PushBackName("Fit");
231 }
232
233 doc.Save((output_path + "bookmark_remote.pdf").c_str(), SDFDoc::e_linearized, 0);
234
235 cout << "Done. Result saved in bookmark_remote.pdf" << endl;
236 }
237 catch(Common::Exception& e)
238 {
239 cout << e << endl;
240 ret = 1;
241 }
242 catch(...)
243 {
244 cout << "Unknown Exception" << endl;
245 ret = 1;
246 }
247
248 PDFNet::Terminate();
249 return ret;
250}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales