Sample Obj-C 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. Learn more about our iOS 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#import <OBJC/PDFNetOBJC.h>
7#import <Foundation/Foundation.h>
8
9int main(int argc, char *argv[])
10{
11 @autoreleasepool {
12 int ret = 0;
13 [PTPDFNet Initialize: 0];
14
15 @try
16 {
17 PTPDFDoc *doc = [[PTPDFDoc alloc] init];
18
19 PTElementBuilder *eb = [[PTElementBuilder alloc] init]; // ElementBuilder is used to build new Element objects
20 PTElementWriter *writer = [[PTElementWriter alloc] init]; // ElementWriter is used to write Elements to the page
21
22 PTElement *element;
23 PTGState *gstate;
24
25 // Start a new page ------------------------------------
26 PTPage *page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 612 y2: 794]];
27
28 [writer WriterBeginWithPage: page placement: e_ptoverlay page_coord_sys: YES compress: YES resources: NULL]; // begin writing to the page
29
30 // Create an Image that can be reused in the document or on the same page.
31 PTImage *img = [PTImage Create: [doc GetSDFDoc] filename: @"../../TestFiles/peppers.jpg"];
32
33 element = [eb CreateImageWithMatrix:img mtx: [[PTMatrix2D alloc] initWithA: [img GetImageWidth]/2 b: -145 c: 20 d: [img GetImageHeight]/2 h: 200 v: 150]];
34 [writer WritePlacedElement: element];
35
36 gstate = [element GetGState]; // use the same image (just change its matrix)
37 [gstate SetTransform: 200 b: 0 c: 0 d: 300 h: 50 v: 450];
38 [writer WritePlacedElement: element];
39
40 // use the same image again (just change its matrix).
41 [writer WritePlacedElement: [eb CreateImageWithCornerAndScale: img x: 300 y: 600 hscale: 200 vscale: -150]];
42
43 [writer End]; // save changes to the current page
44 [doc PagePushBack: page];
45
46 // Start a new page ------------------------------------
47 // Construct and draw a path object using different styles
48 page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 612 y2: 794]];
49
50 [writer WriterBeginWithPage: page placement: e_ptoverlay page_coord_sys: YES compress: YES resources: NULL]; // begin writing to the page
51 [eb Reset: [[PTGState alloc] init]]; // Reset the GState to default
52
53 [eb PathBegin]; // start constructing the path
54 [eb MoveTo: 306 y: 396];
55 [eb CurveTo: 681 cy1: 771 cx2: 399.75 cy2: 864.75 x2: 306 y2: 771];
56 [eb CurveTo: 212.25 cy1: 864.75 cx2: -69 cy2: 771 x2: 306 y2: 396];
57 [eb ClosePath];
58 element = [eb PathEnd]; // the path is now finished
59 [element SetPathFill: YES]; // the path should be filled
60
61 // Set the path color space and color
62 gstate = [element GetGState];
63 [gstate SetFillColorSpace: [PTColorSpace CreateDeviceCMYK]];
64 [gstate SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w: 0]]; // cyan
65 [gstate SetTransform: 0.5 b: 0 c: 0 d: 0.5 h: -20 v: 300];
66 [writer WritePlacedElement: element];
67
68 // Draw the same path using a different stroke color
69 [element SetPathStroke: YES]; // this path is should be filled and stroked
70 [gstate SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0 y: 0 z: 1 w: 0]]; // yellow
71 [gstate SetStrokeColorSpace: [PTColorSpace CreateDeviceRGB]];
72 [gstate SetStrokeColorWithColorPt: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w: 0]]; // red
73 [gstate SetTransform: 0.5 b: 0 c: 0 d: 0.5 h: 280 v: 300];
74 [gstate SetLineWidth: 20];
75 [writer WritePlacedElement: element];
76
77 // Draw the same path with with a given dash pattern
78 [element SetPathFill: NO]; // this path is should be only stroked
79 [gstate SetStrokeColorWithColorPt: [[PTColorPt alloc] initWithX: 0 y: 0 z: 1 w: 0]]; // blue
80 [gstate SetTransform: 0.5 b: 0 c: 0 d: 0.5 h: 280 v: 0];
81 NSMutableArray *dash_pattern = [[NSMutableArray alloc] init];
82 [dash_pattern addObject: @30.0];
83 [gstate SetDashPattern: dash_pattern phase: 0];
84 [writer WritePlacedElement: element];
85
86 // Use the path as a clipping path
87 [writer WriteElement: [eb CreateGroupBegin]]; // Save the graphics state
88 // Start constructing the new path (the old path was lost when we created
89 // a new Element using CreateGroupBegin()).
90 [eb PathBegin];
91 [eb MoveTo: 306 y: 396];
92 [eb CurveTo: 681 cy1: 771 cx2: 399.75 cy2: 864.75 x2: 306 y2: 771];
93 [eb CurveTo: 212.25 cy1: 864.75 cx2: -69 cy2: 771 x2: 306 y2: 396];
94 [eb ClosePath];
95 element = [eb PathEnd]; // path is now constructed
96 [element SetPathClip: YES]; // this path is a clipping path
97 [element SetPathStroke: YES]; // this path should be filled and stroked
98 gstate = [element GetGState];
99 [gstate SetTransform: 0.5 b: 0 c: 0 d: 0.5 h: -20 v: 0];
100
101 [writer WriteElement: element];
102
103 [writer WriteElement: [eb CreateImageWithCornerAndScale: img x: 100 y: 300 hscale: 400 vscale: 600]];
104
105 [writer WriteElement: [eb CreateGroupEnd]]; // Restore the graphics state
106
107 [writer End]; // save changes to the current page
108 [doc PagePushBack: page];
109
110
111 // Start a new page ------------------------------------
112 page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 612 y2: 794]];
113
114 [writer WriterBeginWithPage: page placement: e_ptoverlay page_coord_sys: YES compress: YES resources: NULL]; // begin writing to this page
115 [eb Reset: [[PTGState alloc] init]]; // Reset the GState to default
116
117 // Begin writing a block of text
118 element = [eb CreateTextBeginWithFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_roman embed: NO] font_sz: 12];
119 [writer WriteElement: element];
120
121 element = [eb CreateTextRun: @"Hello World!"];
122 [element SetTextMatrix: 10 b: 0 c: 0 d: 10 h: 0 v: 600];
123 [[element GetGState] SetLeading: 15]; // Set the spacing between lines
124 [writer WriteElement: element];
125
126 [writer WriteElement: [eb CreateTextNewLine]]; // New line
127
128 element = [eb CreateTextRun: @"Hello World!"];
129 gstate = [element GetGState];
130 [gstate SetTextRenderMode: e_ptstroke_text];
131 [gstate SetCharSpacing: -1.25];
132 [gstate SetWordSpacing: -1.25];
133 [writer WriteElement: element];
134
135 [writer WriteElement: [eb CreateTextNewLine]]; // New line
136
137 element = [eb CreateTextRun: @"Hello World!"];
138 gstate = [element GetGState];
139 [gstate SetCharSpacing: 0];
140 [gstate SetWordSpacing: 0];
141 [gstate SetLineWidth: 3];
142 [gstate SetTextRenderMode: e_ptfill_stroke_text];
143 [gstate SetStrokeColorSpace: [PTColorSpace CreateDeviceRGB]];
144 [gstate SetStrokeColorWithColorPt: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w: 0]]; // red
145 [gstate SetFillColorSpace: [PTColorSpace CreateDeviceCMYK]];
146 [gstate SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w: 0]];; // cyan
147 [writer WriteElement: element];
148
149
150 [writer WriteElement: [eb CreateTextNewLine]]; // New line
151
152 // Set text as a clipping path to the image.
153 element = [eb CreateTextRun: @"Hello World!"];
154 gstate = [element GetGState];
155 [gstate SetTextRenderMode: e_ptclip_text];
156 [writer WriteElement: element];
157
158 // Finish the block of text
159 [writer WriteElement: [eb CreateTextEnd]];
160
161 // Draw an image that will be clipped by the above text
162 [writer WriteElement: [eb CreateImageWithCornerAndScale: img x: 10 y: 100 hscale: 1300 vscale: 720]];
163
164 [writer End]; // save changes to the current page
165 [doc PagePushBack: page];
166
167 // Start a new page ------------------------------------
168 //
169 // The example illustrates how to embed the external font in a PDF document.
170 // The example also shows how ElementReader can be used to copy and modify
171 // Elements between pages.
172
173 PTElementReader *reader = [[PTElementReader alloc] init];
174
175 // Start reading Elements from the last page. We will copy all Elements to
176 // a new page but will modify the font associated with text.
177 [reader Begin: [doc GetPage: [doc GetPageCount]]];
178
179 page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 1300 y2: 794]];
180
181 [writer WriterBeginWithPage: page placement: e_ptoverlay page_coord_sys: YES compress: YES resources: NULL]; // begin writing to this page
182 [eb Reset: [[PTGState alloc] init]]; // Reset the GState to default
183
184 // Embed an external font in the document.
185 PTFont *font = [PTFont CreateTrueTypeFont: [doc GetSDFDoc] font_path: @"../../TestFiles/font.ttf" embed: YES subset: YES];
186
187 while ((element = [reader Next]) != NULL) // Read page contents
188 {
189 if ([element GetType] == e_pttext)
190 {
191 [[element GetGState] SetFont: font font_sz: 12];
192 }
193
194 [writer WriteElement: element];
195 }
196
197 [reader End];
198 [writer End]; // save changes to the current page
199
200 [doc PagePushBack: page];
201
202
203 // Start a new page ------------------------------------
204 //
205 // The example illustrates how to embed the external font in a PDF document.
206 // The example also shows how ElementReader can be used to copy and modify
207 // Elements between pages.
208
209 // Start reading Elements from the last page. We will copy all Elements to
210 // a new page but will modify the font associated with text.
211 [reader Begin: [doc GetPage: [doc GetPageCount]]];
212
213 page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 1300 y2: 794]];
214
215 [writer WriterBeginWithPage: page placement: e_ptoverlay page_coord_sys: YES compress: YES resources: NULL]; // begin writing to this page
216 [eb Reset: [[PTGState alloc] init]]; // Reset the GState to default
217
218 // Embed an external font in the document.
219 PTFont *font2 = [PTFont CreateType1Font: [doc GetSDFDoc] font_path: @"../../TestFiles/Misc-Fixed.pfa" embed: YES];
220
221 while ((element = [reader Next]) != NULL) // Read page contents
222 {
223 if ([element GetType] == e_pttext)
224 {
225 [[element GetGState] SetFont: font2 font_sz: 12];
226 }
227
228 [writer WriteElement: element];
229 }
230
231 [reader End];
232 [writer End]; // save changes to the current page
233 [doc PagePushBack: page];
234
235
236 // Start a new page ------------------------------------
237 page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 612 y2: 792]];
238
239 [writer WriterBeginWithPage: page placement: e_ptoverlay page_coord_sys: YES compress: YES resources: NULL]; // begin writing to this page
240 [eb Reset: [[PTGState alloc] init]]; // Reset the GState to default
241
242 // Begin writing a block of text
243 element = [eb CreateTextBeginWithFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_roman embed: NO] font_sz: 12];
244 [element SetTextMatrix: 1.5 b: 0 c: 0 d: 1.5 h: 50 v: 600];
245 [[element GetGState] SetLeading: 15]; // Set the spacing between lines
246 [writer WriteElement: element];
247
248 NSString* para = @"A PDF text object consists of operators that can show "
249 "text strings, move the text position, and set text state and certain "
250 "other parameters. In addition, there are three parameters that are "
251 "defined only within a text object and do not persist from one text "
252 "object to the next: Tm, the text matrix, Tlm, the text line matrix, "
253 "Trm, the text rendering matrix, actually just an intermediate result "
254 "that combines the effects of text state parameters, the text matrix "
255 "(Tm), and the current transformation matrix";
256
257 double para_end = para.length;
258 double text_run = 0;
259
260 double para_width = 300; // paragraph width is 300 units
261 double cur_width = 0;
262
263 while (text_run < para_end)
264 {
265 double text_run_end = [para rangeOfString: @" " options: NSLiteralSearch range: NSMakeRange(text_run, para.length-text_run)].location;
266
267 if (text_run_end == NSNotFound) text_run_end = para_end - 1;
268
269 NSString *str = [para substringWithRange: NSMakeRange(text_run, text_run_end-text_run+1)];
270 element = [eb CreateTextRun: str];
271 if (cur_width + [element GetTextLength] < para_width)
272 {
273 [writer WriteElement: element];
274 cur_width = cur_width + [element GetTextLength];
275 }
276 else
277 {
278 [writer WriteElement: [eb CreateTextNewLine]]; // New line
279 element = [eb CreateTextRun: str];
280 cur_width = [element GetTextLength];
281 [writer WriteElement: element];
282 }
283
284 text_run = text_run_end+1;
285 }
286
287 // -----------------------------------------------------------------------
288 // The following code snippet illustrates how to adjust spacing between
289 // characters (text runs).
290 element = [eb CreateTextNewLine];
291 [writer WriteElement: element]; // Skip 2 lines
292 [writer WriteElement: element];
293
294 [writer WriteElement: [eb CreateTextRun: @"An example of space adjustments between inter-characters:"]];
295 [writer WriteElement: [eb CreateTextNewLine]];
296
297 // Write string "AWAY" without space adjustments between characters.
298 element = [eb CreateTextRun: @"AWAY"];
299 [writer WriteElement: element];
300
301 [writer WriteElement: [eb CreateTextNewLine]];
302
303 // Write string "AWAY" with space adjustments between characters.
304 element = [eb CreateTextRun: @"A"];
305 [writer WriteElement: element];
306
307 element = [eb CreateTextRun: @"W"];
308 [element SetPosAdjustment: 140];
309 [writer WriteElement: element];
310
311 element = [eb CreateTextRun: @"A"];
312 [element SetPosAdjustment: 140];
313 [writer WriteElement: element];
314
315 element = [eb CreateTextRun: @"Y again"];
316 [element SetPosAdjustment: 115];
317 [writer WriteElement: element];
318
319 // Draw the same strings using direct content output...
320 [writer Flush]; // flush pending Element writing operations.
321
322 // You can also write page content directly to the content stream using
323 // ElementWriter.WriteString(...) and ElementWriter.WriteBuffer(...) methods.
324 // Note that if you are planning to use these functions you need to be familiar
325 // with PDF page content operators (see Appendix A in PDF Reference Manual).
326 // Because it is easy to make mistakes during direct output we recommend that
327 // you use ElementBuilder and Element interface instead.
328
329 [writer WriteString: @"T* T* "]; // Skip 2 lines
330 [writer WriteString: @"(Direct output to PDF page content stream:) Tj T* "];
331 [writer WriteString: @"(AWAY) Tj T* "];
332 [writer WriteString: @"[(A)140(W)140(A)115(Y again)] TJ "];
333 // Finish the block of text
334 [writer WriteElement: [eb CreateTextEnd]];
335
336 [writer End]; // save changes to the current page
337 [doc PagePushBack: page];
338
339 // Start a new page ------------------------------------
340
341 // Image Masks
342 //
343 // In the opaque imaging model, images mark all areas they occupy on the page as
344 // if with opaque paint. All portions of the image, whether black, white, gray,
345 // or color, completely obscure any marks that may previously have existed in the
346 // same place on the page.
347 // In the graphic arts industry and page layout applications, however, it is common
348 // to crop or 'mask out' the background of an image and then place the masked image
349 // on a different background, allowing the existing background to show through the
350 // masked areas. This sample illustrates how to use image masks.
351
352 page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 612 y2: 792]];
353 [writer WriterBeginWithPage: page placement: e_ptoverlay page_coord_sys: YES compress: YES resources: NULL]; // begin writing to this page
354
355 // Create the Image Mask
356 PTMappedFile *imgf = [[PTMappedFile alloc] initWithFilename: @"../../TestFiles/imagemask.dat"];
357 PTFilterReader *mask_read = [[PTFilterReader alloc] initWithFilter: imgf];
358
359 PTColorSpace *device_gray = [PTColorSpace CreateDeviceGray];
360 PTImage *mask = [PTImage CreateWithStreamAndFormat: [doc GetSDFDoc] image_data: mask_read width: 64 height: 64 bpc: 1 color_space: device_gray input_format: e_ptascii_hex];
361
362 [[mask GetSDFObj] PutBool: @"ImageMask" value: YES];
363
364 element = [eb CreateRect: 0 y: 0 width: 612 height: 794];
365 [element SetPathStroke: NO];
366 [element SetPathFill: YES];
367 [[element GetGState] SetFillColorSpace: device_gray];
368 [[element GetGState] SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0.8 y: 0 z: 0 w:0]];
369 [writer WritePlacedElement: element];
370
371 element = [eb CreateImageWithMatrix: mask mtx: [[PTMatrix2D alloc] initWithA: 200 b: 0 c: 0 d: -200 h: 40 v: 680]];
372 [[element GetGState] SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0.1 y: 0 z: 0 w:0]];
373 [writer WritePlacedElement: element];
374
375 [[element GetGState] SetFillColorSpace: [PTColorSpace CreateDeviceRGB]];
376 [[element GetGState] SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w:0]];
377 element = [eb CreateImageWithMatrix: mask mtx: [[PTMatrix2D alloc] initWithA: 200 b: 0 c: 0 d: -200 h: 320 v: 680]];
378 [writer WritePlacedElement: element];
379
380 [[element GetGState] SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0 y: 1 z: 0 w:0]];
381 element = [eb CreateImageWithMatrix: mask mtx: [[PTMatrix2D alloc] initWithA: 200 b: 0 c: 0 d: -200 h: 40 v: 380]];
382 [writer WritePlacedElement: element];
383
384 {
385 // This sample illustrates Explicit Masking.
386 PTImage *img = [PTImage CreateWithFile: [doc GetSDFDoc] filename: @"../../TestFiles/peppers.jpg" encoder_hints: [[PTObj alloc] init]];
387
388 // mask is the explicit mask for the primary (base) image
389 [img SetMaskWithImage: mask];
390
391 element = [eb CreateImageWithMatrix: img mtx: [[PTMatrix2D alloc] initWithA: 200 b: 0 c: 0 d: -200 h: 320 v: 380]];
392 [writer WritePlacedElement: element];
393 }
394
395 [writer End]; // save changes to the current page
396 [doc PagePushBack: page];
397
398 // Transparency sample ----------------------------------
399
400 // Start a new page -------------------------------------
401 page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 612 y2: 792]];
402 [writer WriterBeginWithPage: page placement: e_ptoverlay page_coord_sys: YES compress: YES resources: NULL]; // begin writing to this page
403 [eb Reset: [[PTGState alloc] init]]; // Reset the GState to default
404
405 // Write some transparent text at the bottom of the page.
406 element = [eb CreateTextBeginWithFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_roman embed: NO] font_sz: 100];
407
408 // Set the text knockout attribute. Text knockout must be set outside of
409 // the text group.
410 gstate = [element GetGState];
411 [gstate SetTextKnockout: NO];
412 [gstate SetBlendMode: e_ptbl_difference];
413 [writer WriteElement: element];
414
415 element = [eb CreateTextRun: @"Transparency"];
416 [element SetTextMatrix: 1 b: 0 c: 0 d: 1 h: 30 v: 30];
417 gstate = [element GetGState];
418 [gstate SetFillColorSpace: [PTColorSpace CreateDeviceCMYK]];
419 [gstate SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w:0]];
420
421 [gstate SetFillOpacity: 0.5];
422 [writer WriteElement: element];
423
424 // Write the same text on top the old; shifted by 3 points
425 [element SetTextMatrix: 1 b: 0 c: 0 d: 1 h: 33 v: 33];
426 [gstate SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0 y: 1 z: 0 w:0]];
427 [gstate SetFillOpacity: 0.5];
428
429 [writer WriteElement: element];
430 [writer WriteElement: [eb CreateTextEnd]];
431
432 // Draw three overlapping transparent circles.
433 [eb PathBegin]; // start constructing the path
434 [eb MoveTo: 459.223 y: 505.646];
435 [eb CurveTo: 459.223 cy1: 415.841 cx2: 389.85 cy2: 343.04 x2: 304.273 y2: 343.04];
436 [eb CurveTo: 218.697 cy1: 343.04 cx2: 149.324 cy2: 415.841 x2: 149.324 y2: 505.646];
437 [eb CurveTo: 149.324 cy1: 595.45 cx2: 218.697 cy2: 668.25 x2: 304.273 y2: 668.25];
438 [eb CurveTo: 389.85 cy1: 668.25 cx2: 459.223 cy2: 595.45 x2: 459.223 y2: 505.646];
439 element = [eb PathEnd];
440 [element SetPathFill: YES];
441
442 gstate = [element GetGState];
443 [gstate SetFillColorSpace: [PTColorSpace CreateDeviceRGB]];
444 [gstate SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0 y: 0 z: 1 w:0]]; // Blue Circle
445
446 [gstate SetBlendMode: e_ptbl_normal];
447 [gstate SetFillOpacity: 0.5];
448 [writer WriteElement: element];
449
450 // Translate relative to the Blue Circle
451 [gstate SetTransform: 1 b: 0 c: 0 d: 1 h: 113 v: -185];
452 [gstate SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0 y: 1 z: 0 w:0]]; // Green Circle
453 [gstate SetFillOpacity: 0.5];
454 [writer WriteElement: element];
455
456 // Translate relative to the Green Circle
457 [gstate SetTransform: 1 b: 0 c: 0 d: 1 h: -220 v: 0];
458 [gstate SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w:0]]; // Red Circle
459 [gstate SetFillOpacity: 0.5];
460 [writer WriteElement: element];
461
462 [writer End]; // save changes to the current page
463 [doc PagePushBack: page];
464
465 // End page ------------------------------------
466
467 [doc SaveToFile: @"../../TestFiles/Output/element_builder.pdf" flags: e_ptremove_unused];
468 // doc.Save((output_path + "element_builder.pdf").c_str(), Doc::e_ptlinearized, NULL);
469 NSLog(@"Done. Result saved in element_builder.pdf...");
470 }
471 @catch(NSException *e)
472 {
473 NSLog(@"%@", e.reason);
474 ret = 1;
475 }
476 [PTPDFNet Terminate: 0];
477 return ret;
478 }
479}
1//---------------------------------------------------------------------------------------
2// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
3// Consult legal.txt regarding legal and license information.
4//---------------------------------------------------------------------------------------
5
6import PDFNet
7import Foundation
8
9func runElementBuilderTest() -> Int {
10 return autoreleasepool {
11 var ret: Int = 0
12
13
14 do {
15 try PTPDFNet.catchException {
16 let doc: PTPDFDoc = PTPDFDoc()
17
18 let eb: PTElementBuilder = PTElementBuilder() // ElementBuilder is used to build new Element objects
19 let writer: PTElementWriter = PTElementWriter() // ElementWriter is used to write Elements to the page
20
21 var element: PTElement
22 var gstate: PTGState
23
24 // Start a new page ------------------------------------
25 var page: PTPage? = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 794))
26
27 writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to the page
28
29 // Create an Image that can be reused in the document or on the same page.
30 let img: PTImage = PTImage.create(doc.getSDFDoc(), filename: Bundle.main.path(forResource: "peppers", ofType: "jpg"))
31
32 element = eb.createImage(withMatrix: img, mtx: PTMatrix2D(a: Double(img.getWidth() / 2), b: -145, c: 20, d: Double(img.getHeight() / 2), h: 200, v: 150))
33 writer.writePlacedElement(element)
34
35 gstate = element.getGState() // use the same image (just change its matrix)
36 gstate.setTransform(200, b: 0, c: 0, d: 300, h: 50, v: 450)
37 writer.writePlacedElement(element)
38
39 // use the same image again (just change its matrix).
40 writer.writePlacedElement(eb.createImage(withCornerAndScale: img, x: 300, y: 600, hscale: 200, vscale: -150))
41
42 writer.end() // save changes to the current page
43 doc.pagePushBack(page)
44
45 // Start a new page ------------------------------------
46 // Construct and draw a path object using different styles
47 page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 794))
48
49 writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to the page
50 eb.reset(PTGState()) // Reset the GState to default
51
52 eb.pathBegin() // start constructing the path
53 eb.move(to: 306, y: 396)
54 eb.curve(to: 681, cy1: 771, cx2: 399.75, cy2: 864.75, x2: 306, y2: 771)
55 eb.curve(to: 212.25, cy1: 864.75, cx2: -69, cy2: 771, x2: 306, y2: 396)
56 eb.closePath()
57 element = eb.pathEnd() // the path is now finished
58 element.setPathFill(true) // the path should be filled
59
60 // Set the path color space and color
61 gstate = element.getGState()
62 gstate.setFill(PTColorSpace.createDeviceCMYK())
63 gstate.setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // cyan
64 gstate.setTransform(0.5, b: 0, c: 0, d: 0.5, h: -20, v: 300)
65 writer.writePlacedElement(element)
66
67 // Draw the same path using a different stroke color
68 element.setPathStroke(true) // this path is should be filled and stroked
69 gstate.setFillColor(with: PTColorPt(x: 0, y: 0, z: 1, w: 0)) // yellow
70 gstate.setStroke(PTColorSpace.createDeviceRGB())
71 gstate.setStrokeColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // red
72 gstate.setTransform(0.5, b: 0, c: 0, d: 0.5, h: 280, v: 300)
73 gstate.setLineWidth(20)
74 writer.writePlacedElement(element)
75
76 // Draw the same path with with a given dash pattern
77 element.setPathFill(false) // this path is should be only stroked
78 gstate.setStrokeColor(with: PTColorPt(x: 0, y: 0, z: 1, w: 0)) // blue
79 gstate.setTransform(0.5, b: 0, c: 0, d: 0.5, h: 280, v: 0)
80 let dash_pattern = NSMutableArray(capacity: 1)
81 dash_pattern.add(30.0)
82 gstate.setDashPattern(dash_pattern, phase: 0)
83 writer.writePlacedElement(element)
84
85 // Use the path as a clipping path
86 writer.write(eb.createGroupBegin())
87 // Save the graphics state
88 // Start constructing the new path (the old path was lost when we created
89 // a new Element using CreateGroupBegin()).
90 eb.pathBegin()
91 eb.move(to: 306, y: 396)
92 eb.curve(to: 681, cy1: 771, cx2: 399.75, cy2: 864.75, x2: 306, y2: 771)
93 eb.curve(to: 212.25, cy1: 864.75, cx2: -69, cy2: 771, x2: 306, y2: 396)
94 eb.closePath()
95 element = eb.pathEnd() // path is now constructed
96 element.setPathClip(true) // this path is a clipping path
97 element.setPathStroke(true) // this path should be filled and stroked
98 gstate = element.getGState()
99 gstate.setTransform(0.5, b: 0, c: 0, d: 0.5, h: -20, v: 0)
100
101 writer.write(element)
102
103 writer.write(eb.createImage(withCornerAndScale: img, x: 100, y: 300, hscale: 400, vscale: 600))
104
105 writer.write(eb.createGroupEnd()) // Restore the graphics state
106
107 writer.end() // save changes to the current page
108 doc.pagePushBack(page)
109
110 // Start a new page ------------------------------------
111 page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 794))
112
113 writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
114 eb.reset(PTGState()) // Reset the GState to default
115
116 // Begin writing a block of text
117 element = eb.createTextBegin(with: PTFont.create(doc.getSDFDoc(), type: e_pttimes_roman, embed: false), font_sz: 12)
118 writer.write(element)
119
120 element = eb.createTextRun("Hello World!")
121 element.setTextMatrix(10, b: 0, c: 0, d: 10, h: 0, v: 600)
122 element.getGState().setLeading(15) // Set the spacing between lines
123 writer.write(element)
124
125 writer.write(eb.createTextNewLine()) // New line
126
127 element = eb.createTextRun("Hello World!")
128 gstate = element.getGState()
129 gstate.setTextRenderMode(e_ptstroke_text)
130 gstate.setCharSpacing(-1.25)
131 gstate.setWordSpacing(-1.25)
132 writer.write(element)
133
134 writer.write(eb.createTextNewLine()) // New line
135
136 element = eb.createTextRun("Hello World!")
137 gstate = element.getGState()
138 gstate.setCharSpacing(0)
139 gstate.setWordSpacing(0)
140 gstate.setLineWidth(3)
141 gstate.setTextRenderMode(e_ptfill_stroke_text)
142 gstate.setStroke(PTColorSpace.createDeviceRGB())
143 gstate.setStrokeColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // red
144 gstate.setFill(PTColorSpace.createDeviceCMYK())
145 gstate.setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // cyan
146 writer.write(element)
147
148 writer.write(eb.createTextNewLine()) // New line
149
150 // Set text as a clipping path to the image.
151 element = eb.createTextRun("Hello World!")
152 gstate = element.getGState()
153 gstate.setTextRenderMode(e_ptclip_text)
154 writer.write(element)
155
156 // Finish the block of text
157 writer.write(eb.createTextEnd())
158
159 // Draw an image that will be clipped by the above text
160 writer.write(eb.createImage(withCornerAndScale: img, x: 10, y: 100, hscale: 1300, vscale: 720))
161
162 writer.end() // save changes to the current page
163 doc.pagePushBack(page)
164
165 // Start a new page ------------------------------------
166 //
167 // The example illustrates how to embed the external font in a PDF document.
168 // The example also shows how ElementReader can be used to copy and modify
169 // Elements between pages.
170
171 let reader: PTElementReader = PTElementReader()
172
173 // Start reading Elements from the last page. We will copy all Elements to
174 // a new page but will modify the font associated with text.
175 reader.begin(doc.getPage(UInt32(doc.getPageCount())))
176
177 page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 1300, y2: 794))
178
179 writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
180 eb.reset(PTGState()) // Reset the GState to default
181
182 // Embed an external font in the document.
183 let font = PTFont.createTrueTypeFont(doc.getSDFDoc(), font_path: Bundle.main.path(forResource: "font", ofType: "ttf"), embed: true, subset: true)
184
185 while let element = reader.next() {
186 if element.getType().rawValue == e_pttext.rawValue {
187 element.getGState().setFont(font, font_sz: 12)
188 }
189 writer.write(element)
190 }
191
192 reader.end()
193 writer.end() // save changes to the current page
194
195 doc.pagePushBack(page)
196
197 // Start a new page ------------------------------------
198 //
199 // The example illustrates how to embed the external font in a PDF document.
200 // The example also shows how ElementReader can be used to copy and modify
201 // Elements between pages.
202
203 // Start reading Elements from the last page. We will copy all Elements to
204 // a new page but will modify the font associated with text.
205 reader.begin(doc.getPage(UInt32(doc.getPageCount())))
206
207 page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 1300, y2: 794))
208
209 writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
210 eb.reset(PTGState()) // Reset the GState to default
211
212 // Embed an external font in the document.
213 let font2 = PTFont.createType1Font(doc.getSDFDoc(), font_path: Bundle.main.path(forResource: "Misc-Fixed", ofType: "pfa"), embed: true)
214
215 while let element = reader.next() {
216 if element.getType().rawValue == e_pttext.rawValue {
217 element.getGState().setFont(font2, font_sz: 12)
218 }
219 writer.write(element)
220 }
221
222 reader.end()
223 writer.end() // save changes to the current page
224 doc.pagePushBack(page)
225
226 // Start a new page ------------------------------------
227 page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 792))
228
229 writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
230 eb.reset(PTGState()) // Reset the GState to default
231
232 // Begin writing a block of text
233 element = eb.createTextBegin(with: PTFont.create(doc.getSDFDoc(), type: e_pttimes_roman, embed: false), font_sz: 12)
234 element.setTextMatrix(1.5, b: 0, c: 0, d: 1.5, h: 50, v: 600)
235 element.getGState().setLeading(15) // Set the spacing between lines
236 writer.write(element)
237
238 let para = """
239 A PDF text object consists of operators that can show \
240 text strings, move the text position, and set text state and certain \
241 other parameters. In addition, there are three parameters that are \
242 defined only within a text object and do not persist from one text \
243 object to the next: Tm, the text matrix, Tlm, the text line matrix, \
244 Trm, the text rendering matrix, actually just an intermediate result \
245 that combines the effects of text state parameters, the text matrix \
246 (Tm), and the current transformation matrix
247 """
248
249 let para_end = para.count
250 var text_run = 0
251
252 let para_width: Double = 300 // paragraph width is 300 units
253 var cur_width: Double = 0
254
255 while text_run < para_end {
256 var text_run_end: Int = (para as NSString).range(of: " ", options: .literal, range: NSRange(location: text_run, length: para.count - text_run)).location
257
258 if text_run_end == NSNotFound {
259 text_run_end = para_end - 1
260 }
261 let str: String = (para as NSString).substring(with: NSRange(location: text_run, length: text_run_end - text_run + 1))
262 element = eb.createTextRun(str)
263 if cur_width + element.getTextLength() < para_width {
264 writer.write(element)
265 cur_width = cur_width + element.getTextLength()
266 }
267 else {
268 writer.write(eb.createTextNewLine()) // New line
269 element = eb.createTextRun(str)
270 cur_width = element.getTextLength()
271 writer.write(element)
272 }
273
274 text_run = text_run_end + 1
275 }
276
277 // -----------------------------------------------------------------------
278 // The following code snippet illustrates how to adjust spacing between
279 // characters (text runs).
280 element = eb.createTextNewLine()
281 writer.write(element) // Skip 2 lines
282 writer.write(element)
283
284 writer.write(eb.createTextRun("An example of space adjustments between inter-characters:"))
285 writer.write(eb.createTextNewLine())
286
287 // Write string "AWAY" without space adjustments between characters.
288 element = eb.createTextRun("AWAY")
289 writer.write(element)
290
291 writer.write(eb.createTextNewLine())
292
293 // Write string "AWAY" with space adjustments between characters.
294 element = eb.createTextRun("A")
295 writer.write(element)
296
297 element = eb.createTextRun("W")
298 element.setPosAdjustment(140)
299 writer.write(element)
300
301 element = eb.createTextRun("A")
302 element.setPosAdjustment(140)
303 writer.write(element)
304
305 element = eb.createTextRun("Y again")
306 element.setPosAdjustment(115)
307 writer.write(element)
308
309 // Draw the same strings using direct content output...
310 writer.flush() // flush pending Element writing operations.
311
312 // You can also write page content directly to the content stream using
313 // ElementWriter.WriteString(...) and ElementWriter.WriteBuffer(...) methods.
314 // Note that if you are planning to use these functions you need to be familiar
315 // with PDF page content operators (see Appendix A in PDF Reference Manual).
316 // Because it is easy to make mistakes during direct output we recommend that
317 // you use ElementBuilder and Element interface instead.
318
319 writer.write("T* T* ") // Skip 2 lines
320 writer.write("(Direct output to PDF page content stream:) Tj T* ")
321 writer.write("(AWAY) Tj T* ")
322 writer.write("[(A)140(W)140(A)115(Y again)] TJ ")
323 // Finish the block of text
324 writer.write(eb.createTextEnd())
325
326 writer.end() // save changes to the current page
327 doc.pagePushBack(page)
328
329 // Start a new page ------------------------------------
330
331 // Image Masks
332 //
333 // In the opaque imaging model, images mark all areas they occupy on the page as
334 // if with opaque paint. All portions of the image, whether black, white, gray,
335 // or color, completely obscure any marks that may previously have existed in the
336 // same place on the page.
337 // In the graphic arts industry and page layout applications, however, it is common
338 // to crop or 'mask out' the background of an image and then place the masked image
339 // on a different background, allowing the existing background to show through the
340 // masked areas. This sample illustrates how to use image masks.
341
342 page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 792))
343 writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
344
345 // Create the Image Mask
346 let imgf = PTMappedFile(filename: Bundle.main.path(forResource: "imagemask", ofType: "dat"))
347 let mask_read = PTFilterReader(filter: imgf)
348
349 let device_gray = PTColorSpace.createDeviceGray()
350 let mask: PTImage = PTImage.create(withStreamAndFormat: doc.getSDFDoc(), image_data: mask_read, width: 64, height: 64, bpc: 1, color_space: device_gray, input_format: e_ptascii_hex)
351
352 mask.getSDFObj().putBool("ImageMask", value: true)
353 element = eb.createRect(0, y: 0, width: 612, height: 794)
354
355 element.setPathStroke(false)
356 element.setPathFill(true)
357 element.getGState().setFill(device_gray)
358 element.getGState().setFillColor(with: PTColorPt(x: 0.8, y: 0, z: 0, w: 0))
359 writer.writePlacedElement(element)
360
361 element = eb.createImage(withMatrix: mask, mtx: PTMatrix2D(a: 200, b: 0, c: 0, d: -200, h: 40, v: 680))
362 element.getGState().setFillColor(with: PTColorPt(x: 0.1, y: 0, z: 0, w: 0))
363 writer.writePlacedElement(element)
364
365 element.getGState().setFill(PTColorSpace.createDeviceRGB())
366 element.getGState().setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0))
367 element = eb.createImage(withMatrix: mask, mtx: PTMatrix2D(a: 200, b: 0, c: 0, d: -200, h: 320, v: 680))
368 writer.writePlacedElement(element)
369
370 element.getGState().setFillColor(with: PTColorPt(x: 0, y: 1, z: 0, w: 0))
371 element = eb.createImage(withMatrix: mask, mtx: PTMatrix2D(a: 200, b: 0, c: 0, d: -200, h: 40, v: 380))
372 writer.writePlacedElement(element)
373
374 do {
375 // This sample illustrates Explicit Masking.
376 let img: PTImage = PTImage.create(withFile: doc.getSDFDoc(), filename: Bundle.main.path(forResource: "peppers", ofType: "jpg"), encoder_hints: PTObj())
377
378 // mask is the explicit mask for the primary (base) image
379 img.setMaskWith(mask)
380 element = eb.createImage(withMatrix: img, mtx: PTMatrix2D(a: 200, b: 0, c: 0, d: -200, h: 320, v: 380))
381 writer.writePlacedElement(element)
382 }
383
384 writer.end() // save changes to the current page
385 doc.pagePushBack(page)
386
387 // Transparency sample ----------------------------------
388
389 // Start a new page -------------------------------------
390 page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 792))
391 writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
392 eb.reset(PTGState()) // Reset the GState to default
393
394 // Write some transparent text at the bottom of the page.
395 element = eb.createTextBegin(with: PTFont.create(doc.getSDFDoc(), type: e_pttimes_roman, embed: false), font_sz: 100)
396
397 // Set the text knockout attribute. Text knockout must be set outside of
398 // the text group.
399 gstate = element.getGState()
400 gstate.setTextKnockout(false)
401 gstate.setBlendMode(e_ptbl_difference)
402 writer.write(element)
403
404 element = eb.createTextRun("Transparency")
405 element.setTextMatrix(1, b: 0, c: 0, d: 1, h: 30, v: 30)
406 gstate = element.getGState()
407 gstate.setFill(PTColorSpace.createDeviceCMYK())
408 gstate.setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0))
409
410 gstate.setFillOpacity(0.5)
411 writer.write(element)
412
413 // Write the same text on top the old; shifted by 3 points
414 element.setTextMatrix(1, b: 0, c: 0, d: 1, h: 33, v: 33)
415 gstate.setFillColor(with: PTColorPt(x: 0, y: 1, z: 0, w: 0))
416 gstate.setFillOpacity(0.5)
417
418 writer.write(element)
419 writer.write(eb.createTextEnd())
420
421 // Draw three overlapping transparent circles.
422 eb.pathBegin() // start constructing the path
423 eb.move(to: 459.223, y: 505.646)
424 eb.curve(to: 459.223, cy1: 415.841, cx2: 389.85, cy2: 343.04, x2: 304.273, y2: 343.04)
425 eb.curve(to: 218.697, cy1: 343.04, cx2: 149.324, cy2: 415.841, x2: 149.324, y2: 505.646)
426 eb.curve(to: 149.324, cy1: 595.45, cx2: 218.697, cy2: 668.25, x2: 304.273, y2: 668.25)
427 eb.curve(to: 389.85, cy1: 668.25, cx2: 459.223, cy2: 595.45, x2: 459.223, y2: 505.646)
428 element = eb.pathEnd()
429 element.setPathFill(true)
430
431 gstate = element.getGState()
432 gstate.setFill(PTColorSpace.createDeviceRGB())
433 gstate.setFillColor(with: PTColorPt(x: 0, y: 0, z: 1, w: 0)) // Blue Circle
434
435 gstate.setBlendMode(e_ptbl_normal)
436 gstate.setFillOpacity(0.5)
437 writer.write(element)
438
439 // Translate relative to the Blue Circle
440 gstate.setTransform(1, b: 0, c: 0, d: 1, h: 113, v: -185)
441 gstate.setFillColor(with: PTColorPt(x: 0, y: 1, z: 0, w: 0)) // Green Circle
442 gstate.setFillOpacity(0.5)
443 writer.write(element)
444
445 // Translate relative to the Green Circle
446 gstate.setTransform(1, b: 0, c: 0, d: 1, h: -220, v: 0)
447 gstate.setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // Red Circle
448 gstate.setFillOpacity(0.5)
449 writer.write(element)
450
451 writer.end() // save changes to the current page
452 doc.pagePushBack(page)
453
454 // End page ------------------------------------
455
456 doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("element_builder.pdf").path, flags: e_ptremove_unused.rawValue)
457
458 // doc.Save((output_path + "element_builder.pdf").c_str(), Doc::e_ptlinearized, NULL);
459
460 print("Done. Result saved in element_builder.pdf...")
461 }
462 } catch let e as NSError {
463 print("Uncaught exception: \(e)")
464 ret = 1
465 }
466
467 return ret
468 }
469}
Did you find this helpful?
Trial setup questions?
Ask experts on DiscordNeed other help?
Contact SupportPricing or product questions?
Contact Sales