Build, Write and Embed Elements in PDF - C++ Sample Code

Sample code to use Apryse SDK's page writing API to generate new pages, embed fonts & images, and copy graphical elements from one page to another. 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 <SDF/Obj.h>
7#include <PDF/PDFNet.h>
8#include <PDF/PDFDoc.h>
9#include <PDF/ElementBuilder.h>
10#include <PDF/ElementWriter.h>
11#include <PDF/ElementReader.h>
12
13#include <Filters/MappedFile.h>
14#include <Filters/FilterReader.h>
15
16#include <SDF/SDFDoc.h>
17#include <iostream>
18#include "../../LicenseKey/CPP/LicenseKey.h"
19
20using namespace std;
21using namespace pdftron;
22using namespace SDF;
23using namespace PDF;
24using namespace Filters;
25
26int main(int argc, char *argv[])
27{
28 int ret = 0;
29 PDFNet::Initialize(LicenseKey);
30
31 // Relative path to the folder containing test files.
32 string input_path = "../../TestFiles/";
33 string output_path = "../../TestFiles/Output/";
34
35 try
36 {
37 PDFDoc doc;
38
39 ElementBuilder eb; // ElementBuilder is used to build new Element objects
40 ElementWriter writer; // ElementWriter is used to write Elements to the page
41
42 Element element;
43 GState gstate;
44
45 // Start a new page ------------------------------------
46 Page page = doc.PageCreate(Rect(0, 0, 612, 794));
47
48 writer.Begin(page); // begin writing to the page
49
50 // Create an Image that can be reused in the document or on the same page.
51 Image img = Image::Create(doc, (input_path + "peppers.jpg").c_str());
52
53 element = eb.CreateImage(img, Common::Matrix2D(img.GetImageWidth()/2, -145, 20, img.GetImageHeight()/2, 200, 150));
54 writer.WritePlacedElement(element);
55
56 gstate = element.GetGState(); // use the same image (just change its matrix)
57 gstate.SetTransform(200, 0, 0, 300, 50, 450);
58 writer.WritePlacedElement(element);
59
60 // use the same image again (just change its matrix).
61 writer.WritePlacedElement(eb.CreateImage(img, 300, 600, 200, -150));
62
63 writer.End(); // save changes to the current page
64 doc.PagePushBack(page);
65
66 // Start a new page ------------------------------------
67 // Construct and draw a path object using different styles
68 page = doc.PageCreate(Rect(0, 0, 612, 794));
69
70 writer.Begin(page); // begin writing to this page
71 eb.Reset(); // Reset the GState to default
72
73 eb.PathBegin(); // start constructing the path
74 eb.MoveTo(306, 396);
75 eb.CurveTo(681, 771, 399.75, 864.75, 306, 771);
76 eb.CurveTo(212.25, 864.75, -69, 771, 306, 396);
77 eb.ClosePath();
78 element = eb.PathEnd(); // the path is now finished
79 element.SetPathFill(true); // the path should be filled
80
81 // Set the path color space and color
82 gstate = element.GetGState();
83 gstate.SetFillColorSpace(ColorSpace::CreateDeviceCMYK());
84 gstate.SetFillColor(ColorPt(1, 0, 0, 0)); // cyan
85 gstate.SetTransform(0.5, 0, 0, 0.5, -20, 300);
86 writer.WritePlacedElement(element);
87
88 // Draw the same path using a different stroke color
89 element.SetPathStroke(true); // this path is should be filled and stroked
90 gstate.SetFillColor(ColorPt(0, 0, 1, 0)); // yellow
91 gstate.SetStrokeColorSpace(ColorSpace::CreateDeviceRGB());
92 gstate.SetStrokeColor(ColorPt(1, 0, 0)); // red
93 gstate.SetTransform(0.5, 0, 0, 0.5, 280, 300);
94 gstate.SetLineWidth(20);
95 writer.WritePlacedElement(element);
96
97 // Draw the same path with with a given dash pattern
98 element.SetPathFill(false); // this path is should be only stroked
99 gstate.SetStrokeColor(ColorPt(0, 0, 1)); // blue
100 gstate.SetTransform(0.5, 0, 0, 0.5, 280, 0);
101 vector<double> dash_pattern;
102 dash_pattern.push_back(30);
103 gstate.SetDashPattern(dash_pattern, 0);
104 writer.WritePlacedElement(element);
105
106 // Use the path as a clipping path
107 writer.WriteElement(eb.CreateGroupBegin()); // Save the graphics state
108 // Start constructing the new path (the old path was lost when we created
109 // a new Element using CreateGroupBegin()).
110 eb.PathBegin();
111 eb.MoveTo(306, 396);
112 eb.CurveTo(681, 771, 399.75, 864.75, 306, 771);
113 eb.CurveTo(212.25, 864.75, -69, 771, 306, 396);
114 eb.ClosePath();
115 element = eb.PathEnd(); // path is now constructed
116 element.SetPathClip(true); // this path is a clipping path
117 element.SetPathStroke(true); // this path should be filled and stroked
118 gstate = element.GetGState();
119 gstate.SetTransform(0.5, 0, 0, 0.5, -20, 0);
120
121 writer.WriteElement(element);
122
123 writer.WriteElement(eb.CreateImage(img, 100, 300, 400, 600));
124
125 writer.WriteElement(eb.CreateGroupEnd()); // Restore the graphics state
126
127 writer.End(); // save changes to the current page
128 doc.PagePushBack(page);
129
130
131 // Start a new page ------------------------------------
132 page = doc.PageCreate(Rect(0, 0, 612, 794));
133
134 writer.Begin(page); // begin writing to this page
135 eb.Reset(); // Reset the GState to default
136
137 // Begin writing a block of text
138 element = eb.CreateTextBegin(Font::Create(doc, Font::e_times_roman), 12);
139 writer.WriteElement(element);
140
141 element = eb.CreateTextRun("Hello World!");
142 element.SetTextMatrix(10, 0, 0, 10, 0, 600);
143 element.GetGState().SetLeading(15); // Set the spacing between lines
144 writer.WriteElement(element);
145
146 writer.WriteElement(eb.CreateTextNewLine()); // New line
147
148 element = eb.CreateTextRun("Hello World!");
149 gstate = element.GetGState();
150 gstate.SetTextRenderMode(GState::e_stroke_text);
151 gstate.SetCharSpacing(-1.25);
152 gstate.SetWordSpacing(-1.25);
153 writer.WriteElement(element);
154
155 writer.WriteElement(eb.CreateTextNewLine()); // New line
156
157 element = eb.CreateTextRun("Hello World!");
158 gstate = element.GetGState();
159 gstate.SetCharSpacing(0);
160 gstate.SetWordSpacing(0);
161 gstate.SetLineWidth(3);
162 gstate.SetTextRenderMode(GState::e_fill_stroke_text);
163 gstate.SetStrokeColorSpace(ColorSpace::CreateDeviceRGB());
164 gstate.SetStrokeColor(ColorPt(1, 0, 0)); // red
165 gstate.SetFillColorSpace(ColorSpace::CreateDeviceCMYK());
166 gstate.SetFillColor(ColorPt(1, 0, 0, 0)); // cyan
167 writer.WriteElement(element);
168
169
170 writer.WriteElement(eb.CreateTextNewLine()); // New line
171
172 // Set text as a clipping path to the image.
173 element = eb.CreateTextRun("Hello World!");
174 gstate = element.GetGState();
175 gstate.SetTextRenderMode(GState::e_clip_text);
176 writer.WriteElement(element);
177
178 // Finish the block of text
179 writer.WriteElement(eb.CreateTextEnd());
180
181 // Draw an image that will be clipped by the above text
182 writer.WriteElement(eb.CreateImage(img, 10, 100, 1300, 720));
183
184 writer.End(); // save changes to the current page
185 doc.PagePushBack(page);
186
187 // Start a new page ------------------------------------
188 //
189 // The example illustrates how to embed the external font in a PDF document.
190 // The example also shows how ElementReader can be used to copy and modify
191 // Elements between pages.
192
193 ElementReader reader;
194
195 // Start reading Elements from the last page. We will copy all Elements to
196 // a new page but will modify the font associated with text.
197 reader.Begin(doc.GetPage(doc.GetPageCount()));
198
199 page = doc.PageCreate(Rect(0, 0, 1300, 794));
200
201 writer.Begin(page); // begin writing to this page
202 eb.Reset(); // Reset the GState to default
203
204 // Embed an external font in the document.
205 Font font = Font::CreateTrueTypeFont(doc, (input_path + "font.ttf").c_str());
206
207 while ((element = reader.Next())==true) // Read page contents
208 {
209 if (element.GetType() == Element::e_text)
210 {
211 element.GetGState().SetFont(font, 12);
212 }
213
214 writer.WriteElement(element);
215 }
216
217 reader.End();
218 writer.End(); // save changes to the current page
219
220 doc.PagePushBack(page);
221
222
223 // Start a new page ------------------------------------
224 //
225 // The example illustrates how to embed the external font in a PDF document.
226 // The example also shows how ElementReader can be used to copy and modify
227 // Elements between pages.
228
229 // Start reading Elements from the last page. We will copy all Elements to
230 // a new page but will modify the font associated with text.
231 reader.Begin(doc.GetPage(doc.GetPageCount()));
232
233 page = doc.PageCreate(Rect(0, 0, 1300, 794));
234
235 writer.Begin(page); // begin writing to this page
236 eb.Reset(); // Reset the GState to default
237
238 // Embed an external font in the document.
239 Font font2 = Font::CreateType1Font(doc, (input_path + "Misc-Fixed.pfa").c_str());
240
241 while ((element = reader.Next())) // Read page contents
242 {
243 if (element.GetType() == Element::e_text)
244 {
245 element.GetGState().SetFont(font2, 12);
246 }
247
248 writer.WriteElement(element);
249 }
250
251 reader.End();
252 writer.End(); // save changes to the current page
253 doc.PagePushBack(page);
254
255
256 // Start a new page ------------------------------------
257 page = doc.PageCreate();
258 writer.Begin(page); // begin writing to this page
259 eb.Reset(); // Reset the GState to default
260
261 // Begin writing a block of text
262 element = eb.CreateTextBegin(Font::Create(doc, Font::e_times_roman), 12);
263 element.SetTextMatrix(1.5, 0, 0, 1.5, 50, 600);
264 element.GetGState().SetLeading(15); // Set the spacing between lines
265 writer.WriteElement(element);
266
267 const char* para = "A PDF text object consists of operators that can show "
268 "text strings, move the text position, and set text state and certain "
269 "other parameters. In addition, there are three parameters that are "
270 "defined only within a text object and do not persist from one text "
271 "object to the next: Tm, the text matrix, Tlm, the text line matrix, "
272 "Trm, the text rendering matrix, actually just an intermediate result "
273 "that combines the effects of text state parameters, the text matrix "
274 "(Tm), and the current transformation matrix";
275
276 const char* para_end = para + strlen(para);
277 const char* text_run = para;
278 const char* text_run_end;
279
280 double para_width = 300; // paragraph width is 300 units
281 double cur_width = 0;
282
283 while (text_run < para_end)
284 {
285 text_run_end = strchr(text_run, ' ');
286 if (!text_run_end) text_run_end = para_end;
287
288 element = eb.CreateTextRun(text_run, UInt32(text_run_end-text_run+1));
289 if (cur_width + element.GetTextLength() < para_width)
290 {
291 writer.WriteElement(element);
292 cur_width += element.GetTextLength();
293 }
294 else
295 {
296 writer.WriteElement(eb.CreateTextNewLine()); // New line
297 element = eb.CreateTextRun(text_run, UInt32(text_run_end-text_run+1));
298 cur_width = element.GetTextLength();
299 writer.WriteElement(element);
300 }
301
302 text_run = text_run_end+1;
303 }
304
305 // -----------------------------------------------------------------------
306 // The following code snippet illustrates how to adjust spacing between
307 // characters (text runs).
308 element = eb.CreateTextNewLine();
309 writer.WriteElement(element); // Skip 2 lines
310 writer.WriteElement(element);
311
312 writer.WriteElement(eb.CreateTextRun("An example of space adjustments between inter-characters:"));
313 writer.WriteElement(eb.CreateTextNewLine());
314
315 // Write string "AWAY" without space adjustments between characters.
316 element = eb.CreateTextRun("AWAY");
317 writer.WriteElement(element);
318
319 writer.WriteElement(eb.CreateTextNewLine());
320
321 // Write string "AWAY" with space adjustments between characters.
322 element = eb.CreateTextRun("A");
323 writer.WriteElement(element);
324
325 element = eb.CreateTextRun("W");
326 element.SetPosAdjustment(140);
327 writer.WriteElement(element);
328
329 element = eb.CreateTextRun("A");
330 element.SetPosAdjustment(140);
331 writer.WriteElement(element);
332
333 element = eb.CreateTextRun("Y again");
334 element.SetPosAdjustment(115);
335 writer.WriteElement(element);
336
337 // Draw the same strings using direct content output...
338 writer.Flush(); // flush pending Element writing operations.
339
340 // You can also write page content directly to the content stream using
341 // ElementWriter.WriteString(...) and ElementWriter.WriteBuffer(...) methods.
342 // Note that if you are planning to use these functions you need to be familiar
343 // with PDF page content operators (see Appendix A in PDF Reference Manual).
344 // Because it is easy to make mistakes during direct output we recommend that
345 // you use ElementBuilder and Element interface instead.
346
347 writer.WriteString("T* T* "); // Skip 2 lines
348 writer.WriteString("(Direct output to PDF page content stream:) Tj T* ");
349 writer.WriteString("(AWAY) Tj T* ");
350 writer.WriteString("[(A)140(W)140(A)115(Y again)] TJ ");
351
352 // Finish the block of text
353 writer.WriteElement(eb.CreateTextEnd());
354
355 writer.End(); // save changes to the current page
356 doc.PagePushBack(page);
357
358 // Start a new page ------------------------------------
359
360 // Image Masks
361 //
362 // In the opaque imaging model, images mark all areas they occupy on the page as
363 // if with opaque paint. All portions of the image, whether black, white, gray,
364 // or color, completely obscure any marks that may previously have existed in the
365 // same place on the page.
366 // In the graphic arts industry and page layout applications, however, it is common
367 // to crop or 'mask out' the background of an image and then place the masked image
368 // on a different background, allowing the existing background to show through the
369 // masked areas. This sample illustrates how to use image masks.
370
371 page = doc.PageCreate();
372 writer.Begin(page); // begin writing to the page
373
374 // Create the Image Mask
375 MappedFile imgf(input_path + "imagemask.dat");
376 FilterReader mask_read(imgf);
377
378 ColorSpace device_gray = ColorSpace::CreateDeviceGray();
379 Image mask = Image::Create(doc, mask_read, 64, 64, 1, device_gray, Image::e_ascii_hex);
380
381 mask.GetSDFObj().PutBool("ImageMask", true);
382
383 element = eb.CreateRect(0, 0, 612, 794);
384 element.SetPathStroke(false);
385 element.SetPathFill(true);
386 element.GetGState().SetFillColorSpace(device_gray);
387 element.GetGState().SetFillColor(ColorPt(0.8));
388 writer.WritePlacedElement(element);
389
390 element = eb.CreateImage(mask, Common::Matrix2D(200, 0, 0, -200, 40, 680));
391 element.GetGState().SetFillColor(ColorPt(0.1));
392 writer.WritePlacedElement(element);
393
394 element.GetGState().SetFillColorSpace(ColorSpace::CreateDeviceRGB());
395 element.GetGState().SetFillColor(ColorPt(1, 0, 0));
396 element = eb.CreateImage(mask, Common::Matrix2D(200, 0, 0, -200, 320, 680));
397 writer.WritePlacedElement(element);
398
399 element.GetGState().SetFillColor(ColorPt(0, 1, 0));
400 element = eb.CreateImage(mask, Common::Matrix2D(200, 0, 0, -200, 40, 380));
401 writer.WritePlacedElement(element);
402
403 {
404 // This sample illustrates Explicit Masking.
405 Image img = Image::Create(doc, (input_path + "peppers.jpg").c_str());
406
407 // mask is the explicit mask for the primary (base) image
408 img.SetMask(mask);
409
410 element = eb.CreateImage(img, Common::Matrix2D(200, 0, 0, -200, 320, 380));
411 writer.WritePlacedElement(element);
412 }
413
414 writer.End(); // save changes to the current page
415 doc.PagePushBack(page);
416
417 // Transparency sample ----------------------------------
418
419 // Start a new page -------------------------------------
420 page = doc.PageCreate();
421 writer.Begin(page); // begin writing to this page
422 eb.Reset(); // Reset the GState to default
423
424 // Write some transparent text at the bottom of the page.
425 element = eb.CreateTextBegin(Font::Create(doc, Font::e_times_roman), 100);
426
427 // Set the text knockout attribute. Text knockout must be set outside of
428 // the text group.
429 gstate = element.GetGState();
430 gstate.SetTextKnockout(false);
431 gstate.SetBlendMode(GState::e_bl_difference);
432 writer.WriteElement(element);
433
434 element = eb.CreateTextRun("Transparency");
435 element.SetTextMatrix(1, 0, 0, 1, 30, 30);
436 gstate = element.GetGState();
437 gstate.SetFillColorSpace(ColorSpace::CreateDeviceCMYK());
438 gstate.SetFillColor(ColorPt(1, 0, 0, 0));
439
440 gstate.SetFillOpacity(0.5);
441 writer.WriteElement(element);
442
443 // Write the same text on top the old; shifted by 3 points
444 element.SetTextMatrix(1, 0, 0, 1, 33, 33);
445 gstate.SetFillColor(ColorPt(0, 1, 0, 0));
446 gstate.SetFillOpacity(0.5);
447
448 writer.WriteElement(element);
449 writer.WriteElement(eb.CreateTextEnd());
450
451 // Draw three overlapping transparent circles.
452 eb.PathBegin(); // start constructing the path
453 eb.MoveTo(459.223, 505.646);
454 eb.CurveTo(459.223, 415.841, 389.85, 343.04, 304.273, 343.04);
455 eb.CurveTo(218.697, 343.04, 149.324, 415.841, 149.324, 505.646);
456 eb.CurveTo(149.324, 595.45, 218.697, 668.25, 304.273, 668.25);
457 eb.CurveTo(389.85, 668.25, 459.223, 595.45, 459.223, 505.646);
458 element = eb.PathEnd();
459 element.SetPathFill(true);
460
461 gstate = element.GetGState();
462 gstate.SetFillColorSpace(ColorSpace::CreateDeviceRGB());
463 gstate.SetFillColor(ColorPt(0, 0, 1)); // Blue Circle
464
465 gstate.SetBlendMode(GState::e_bl_normal);
466 gstate.SetFillOpacity(0.5);
467 writer.WriteElement(element);
468
469 // Translate relative to the Blue Circle
470 gstate.SetTransform(1, 0, 0, 1, 113, -185);
471 gstate.SetFillColor(ColorPt(0, 1, 0)); // Green Circle
472 gstate.SetFillOpacity(0.5);
473 writer.WriteElement(element);
474
475 // Translate relative to the Green Circle
476 gstate.SetTransform(1, 0, 0, 1, -220, 0);
477 gstate.SetFillColor(ColorPt(1, 0, 0)); // Red Circle
478 gstate.SetFillOpacity(0.5);
479 writer.WriteElement(element);
480
481 writer.End(); // save changes to the current page
482 doc.PagePushBack(page);
483
484 // End page ------------------------------------
485
486 doc.Save((output_path + "element_builder.pdf").c_str(), SDFDoc::e_remove_unused, NULL);
487 // doc.Save((output_path + "element_builder.pdf").c_str(), Doc::e_linearized, NULL);
488 cout << "Done. Result saved in element_builder.pdf..." << endl;
489 }
490 catch(Common::Exception& e)
491 {
492 cout << e << endl;
493 ret = 1;
494 }
495 catch(...)
496 {
497 cout << "Unknown Exception" << endl;
498 ret = 1;
499 }
500
501 PDFNet::Terminate();
502 return ret;
503}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales