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

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.

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