Sample Obj-C code for using Apryse SDK with interactive forms (also known as AcroForms). Capabilities include programatically creating new fields and widget annotations, form filling, modifying existing field values, form templating, and flattening form fields. Learn more about our iOS SDK and PDF Data Extraction SDK Capabilities.
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#import <Foundation/NSDictionary.h>
9#import <Foundation/NSArray.h>
10
11//---------------------------------------------------------------------------------------
12// This sample illustrates basic PDFNet capabilities related to interactive
13// forms (also known as AcroForms).
14//---------------------------------------------------------------------------------------
15
16// field_nums has to be greater than 0.
17void RenameAllFields(PTPDFDoc* doc, NSString* name, int field_nums)
18{
19 PTFieldIterator * itr = [doc GetFieldIteratorWithName: name];
20 int counter;
21 for (counter=1; [itr HasNext]; itr=[doc GetFieldIteratorWithName: name], ++counter)
22 {
23 PTField *f = [itr Current];
24 int update_count = (int)(ceil(counter/(double)field_nums));
25 [f Rename: [name stringByAppendingFormat: @"-%d", update_count]];
26 }
27}
28
29PTObj* CreateCustomButtonAppearance(PTPDFDoc* doc, bool button_down)
30{
31 // Create a button appearance stream ------------------------------------
32 PTElementBuilder *build = [[PTElementBuilder alloc] init];
33 PTElementWriter *writer = [[PTElementWriter alloc] init];
34 [writer WriterBeginWithSDFDoc: [doc GetSDFDoc] compress: YES];
35
36 // Draw background
37 PTElement *element = [build CreateRect: 0 y: 0 width: 101 height: 137];
38 [element SetPathFill: YES];
39 [element SetPathStroke: NO];
40 [[element GetGState] SetFillColorSpace: [PTColorSpace CreateDeviceGray]];
41 [[element GetGState] SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0.75 y: 0 z: 0 w: 0]];
42 [writer WriteElement: element];
43
44 // Draw 'Submit' text
45 [writer WriteElement: [build CreateTextBegin]];
46 {
47 NSString *text = @"Submit";
48 element = [build CreateTextRunWithFont: text font: [PTFont Create: [doc GetSDFDoc] type: e_pthelvetica_bold embed: NO] font_sz: 12];
49 [[element GetGState] SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0 y: 0 z: 0 w: 0]];
50
51 if (button_down)
52 [element SetTextMatrixWithMatrix2D: [[PTMatrix2D alloc] initWithA: 1 b: 0 c: 0 d: 1 h: 33 v: 10]];
53 else
54 [element SetTextMatrixWithMatrix2D: [[PTMatrix2D alloc] initWithA: 1 b: 0 c: 0 d: 1 h: 30 v: 13]];
55 [writer WriteElement: element];
56 }
57 [writer WriteElement: [build CreateTextEnd]];
58
59 PTObj * stm = [writer End];
60
61 // Set the bounding box
62 [stm PutRect: @"BBox" x1: 0 y1: 0 x2: 101 y2: 37];
63 [stm PutName: @"Subtype" name: @"Form"];
64 return stm;
65}
66
67int main(int argc, char *argv[])
68{
69 @autoreleasepool {
70 int ret = 0;
71 [PTPDFNet Initialize: 0];
72
73 // The vector used to store the name and count of all fields.
74 // This is used later on to clone the fields
75 NSMutableDictionary *field_names = [[NSMutableDictionary alloc] init];
76
77 //----------------------------------------------------------------------------------
78 // Example 1: Programatically create new Form Fields and Widget Annotations.
79 //----------------------------------------------------------------------------------
80 @try
81 {
82 PTPDFDoc *doc = [[PTPDFDoc alloc] init];
83 // Create a blank new page and add some form fields.
84 PTPage *blank_page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 612 y2: 792]];
85
86 // Text Widget Creation
87 // Create an empty text widget with black text.
88 PTTextWidget *text1 = [PTTextWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 110 y1: 700 x2: 380 y2: 730] field_name: @""];
89 [text1 SetText: @"Basic Text Field"];
90 [text1 RefreshAppearance];
91 [blank_page AnnotPushBack: text1];
92 // Create a vertical text widget with blue text and a yellow background.
93 PTTextWidget *text2 = [PTTextWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 50 y1: 400 x2: 90 y2: 730] field_name: @""];
94 [text2 SetRotation: 90];
95 // Set the text content.
96 [text2 SetText: @" ****Lucky Stars!****"];
97 // Set the font type, text color, font size, border color and background color.
98 [text2 SetFont: [PTFont Create: [doc GetSDFDoc] type: e_pthelvetica_oblique embed: NO]];
99 [text2 SetFontSize: 28];
100 [text2 SetTextColor: [[PTColorPt alloc] initWithX: 0 y: 0 z: 1 w: 0] col_comp: 3];
101 [text2 SetBorderColor: [[PTColorPt alloc] initWithX: 0 y: 0 z: 0 w: 0] compnum: 3];
102 [text2 SetBackgroundColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 0 w: 0] compnum: 3];
103 [text2 RefreshAppearance];
104 // Add the annotation to the page.
105 [blank_page AnnotPushBack: text2];
106 // Create two new text widget with Field names employee.name.first and employee.name.last
107 // This logic shows how these widgets can be created using either a field name string or
108 // a Field object
109 PTTextWidget *text3 = [PTTextWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 110 y1: 660 x2: 380 y2: 690] field_name: @"employee.name.first"];
110 [text3 SetText: @"Levi"];
111 [text3 SetFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_bold embed: NO]];
112 [text3 RefreshAppearance];
113 [blank_page AnnotPushBack: text3];
114 PTField *emp_last_name = [doc FieldCreateWithString: @"employee.name.last" type: e_pttext field_value: @"Ackerman" def_field_value: @""];
115 PTTextWidget *text4 = [PTTextWidget CreateWithField: doc pos: [[PTPDFRect alloc] initWithX1: 110 y1: 620 x2: 380 y2: 650] field: emp_last_name];
116 [text4 SetFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_bold embed: NO]];
117 [text4 RefreshAppearance];
118 [blank_page AnnotPushBack: text4];
119
120 // Signature Widget Creation (unsigned)
121 PTSignatureWidget *signature1 = [PTSignatureWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 110 y1: 560 x2: 260 y2: 610] field_name: @""];
122 [signature1 RefreshAppearance];
123 [blank_page AnnotPushBack: signature1];
124
125 // CheckBox Widget Creation
126 // Create a check box widget that is not checked.
127 PTCheckBoxWidget *check1 = [PTCheckBoxWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 140 y1: 490 x2: 170 y2: 520] field_name: @""];
128 [check1 RefreshAppearance];
129 [blank_page AnnotPushBack: check1];
130 // Create a check box widget that is checked.
131 PTCheckBoxWidget *check2 = [PTCheckBoxWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 190 y1: 490 x2: 250 y2: 540] field_name: @"employee.name.check1"];
132 [check2 SetBackgroundColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 1 w: 0] compnum: 3];
133 [check2 SetBorderColor: [[PTColorPt alloc] initWithX: 0 y: 0 z: 0 w: 0] compnum: 3];
134 // Check the widget (by default it is unchecked).
135 [check2 SetChecked: true];
136 [check2 RefreshAppearance];
137 [blank_page AnnotPushBack: check2];
138
139 // PushButton Widget Creation
140 PTPushButtonWidget *pushbutton1 = [PTPushButtonWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 380 y1: 490 x2: 520 y2: 540] field_name: @""];
141 [pushbutton1 SetTextColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 1 w: 0] col_comp: 3];
142 [pushbutton1 SetFontSize: 36];
143 [pushbutton1 SetBackgroundColor: [[PTColorPt alloc] initWithX: 0 y: 0 z: 0 w: 0] compnum: 3];
144 // Add a caption for the pushbutton.
145 [pushbutton1 SetStaticCaptionText: @"PushButton"];
146 [pushbutton1 RefreshAppearance];
147 [blank_page AnnotPushBack: pushbutton1];
148
149 // ComboBox Widget Creation
150 PTComboBoxWidget *combo1 = [PTComboBoxWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 280 y1: 560 x2: 580 y2: 610] field_name: @""];
151 // Add options to the combobox widget.
152 [combo1 AddOption: @"Combo Box No.1"];
153 [combo1 AddOption: @"Combo Box No.2"];
154 [combo1 AddOption: @"Combo Box No.3"];
155 // Make one of the options in the combo box selected by default.
156 [combo1 SetSelectedOption: @"Combo Box No.2"];
157 [combo1 SetTextColor: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w: 0] col_comp: 3];
158 [combo1 SetFontSize: 28];
159 [combo1 RefreshAppearance];
160 [blank_page AnnotPushBack: combo1];
161
162 // ListBox Widget Creation
163 PTListBoxWidget *list1 = [PTListBoxWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 400 y1: 620 x2: 580 y2: 730] field_name: @""];
164 // Add one option to the listbox widget.
165 [list1 AddOption: @"List Box No.1"];
166 // Add multiple options to the listbox widget in a batch.
167 NSArray *list_options = [NSArray arrayWithObjects: @"List Box No.2", @"List Box No.3", nil];
168 [list1 AddOptions: list_options];
169 // Select some of the options in list box as default options
170 [list1 SetSelectedOptions: list_options];
171 // Enable list box to have multi-select when editing.
172 [[list1 GetField] SetFlag: e_ptmultiselect value: true];
173 [list1 SetFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_italic embed: NO]];
174 [list1 SetTextColor: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w: 0] col_comp: 3];
175 [list1 SetFontSize: 28];
176 [list1 SetBackgroundColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 1 w: 0] compnum: 3];
177 [list1 RefreshAppearance];
178 [blank_page AnnotPushBack: list1];
179
180 // RadioButton Widget Creation
181 // Create a radio button group and add three radio buttons in it.
182 PTRadioButtonGroup *radio_group = [PTRadioButtonGroup Create: doc field_name: @"RadioGroup"];
183 PTRadioButtonWidget *radiobutton1 = [radio_group Add: [[PTPDFRect alloc] initWithX1: 140 y1: 410 x2: 190 y2: 460] onstate: @""];
184 [radiobutton1 SetBackgroundColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 0 w: 0] compnum: 3];
185 [radiobutton1 RefreshAppearance];
186 PTRadioButtonWidget *radiobutton2 = [radio_group Add: [[PTPDFRect alloc] initWithX1: 310 y1: 410 x2: 360 y2: 460] onstate: @""];
187 [radiobutton2 SetBackgroundColor: [[PTColorPt alloc] initWithX: 0 y: 1 z: 0 w: 0] compnum: 3];
188 [radiobutton2 RefreshAppearance];
189 PTRadioButtonWidget *radiobutton3 = [radio_group Add: [[PTPDFRect alloc] initWithX1: 480 y1: 410 x2: 530 y2: 460] onstate: @""];
190 // Enable the third radio button. By default the first one is selected
191 [radiobutton3 EnableButton];
192 [radiobutton3 SetBackgroundColor: [[PTColorPt alloc] initWithX: 0 y: 1 z: 1 w: 0] compnum: 3];
193 [radiobutton3 RefreshAppearance];
194 [radio_group AddGroupButtonsToPage: blank_page];
195
196 // Custom push button annotation creation
197 PTPushButtonWidget *custom_pushbutton1 = [PTPushButtonWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 260 y1: 320 x2: 360 y2: 360] field_name: @""];
198 // Set the annotation appearance.
199 [custom_pushbutton1 SetAppearance: CreateCustomButtonAppearance(doc, NO) annot_state: e_ptnormal app_state: nil];
200 // Create 'SubmitForm' action. The action will be linked to the button.
201 PTFileSpec *url = [PTFileSpec CreateURL: [doc GetSDFDoc] url: @"http://www.pdftron.com"];
202 PTAction *button_action = [PTAction CreateSubmitForm: url];
203 // Associate the above action with 'Down' event in annotations action dictionary.
204 PTObj * annot_action = [[custom_pushbutton1 GetSDFObj] PutDict: @"AA"];
205 [annot_action Put: @"D" obj: [button_action GetSDFObj]];
206 [blank_page AnnotPushBack: custom_pushbutton1];
207
208 // Add the page as the last page in the document.
209 [doc PagePushBack: blank_page];
210
211 // If you are not satisfied with the look of default auto-generated appearance
212 // streams you can delete "AP" entry from the Widget annotation and set
213 // "NeedAppearances" flag in AcroForm dictionary:
214 // doc.GetAcroForm().PutBool("NeedAppearances", true);
215 // This will force the viewer application to auto-generate new appearance streams
216 // every time the document is opened.
217 //
218 // Alternatively you can generate custom annotation appearance using ElementWriter
219 // and then set the "AP" entry in the widget dictionary to the new appearance
220 // stream.
221 //
222 // Yet another option is to pre-populate field entries with dummy text. When
223 // you edit the field values using PDFNet the new field appearances will match
224 // the old ones.
225
226 //doc.GetAcroForm().PutBool("NeedAppearances", true);
227 [doc RefreshFieldAppearances];
228
229 [doc SaveToFile: @"../../TestFiles/Output/forms_test1.pdf" flags: 0];
230 printf("Done.\n");
231 }
232 @catch (NSException *e)
233 {
234 NSLog(@"%@", e.reason);
235 ret = 1;
236 }
237
238 //----------------------------------------------------------------------------------
239 // Example 2:
240 // Fill-in forms / Modify values of existing fields.
241 // Traverse all form fields in the document (and print out their names).
242 // Search for specific fields in the document.
243 //----------------------------------------------------------------------------------
244 @try
245 {
246 PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: @"../../TestFiles/Output/forms_test1.pdf"];
247 [doc InitSecurityHandler];
248
249 PTFieldIterator * itr = [doc GetFieldIterator];
250 for(; [itr HasNext]; [itr Next])
251 {
252 NSString *cur_field_name = [[itr Current] GetName];
253 // Add one to the count for this field name for later processing
254 if ([field_names objectForKey: cur_field_name] != nil)
255 {
256 int same_field_name_count = [[field_names objectForKey: cur_field_name] intValue] + 1;
257 [field_names setObject: [NSNumber numberWithInt: same_field_name_count] forKey: cur_field_name];
258 }
259 else
260 {
261 [field_names setObject: @"1" forKey: cur_field_name];
262 }
263
264 printf("Field name: %s\n", [[[itr Current] GetName] UTF8String]);
265 printf("Field partial name: %s\n", [[[itr Current] GetPartialName] UTF8String]);
266
267 printf("Field type: ");
268 PTFieldType type = [[itr Current] GetType];
269 NSString *str_val = [[itr Current] GetValueAsString];
270
271 switch(type)
272 {
273 case e_ptcheck:
274 [[itr Current] SetValueWithBool: YES];
275 printf("Check box: Value = %s\n", [str_val UTF8String]);
276 break;
277 case e_ptbutton:
278 printf("Button\n");
279 break;
280 case e_ptradio:
281 printf("Radio button: Value = %s\n", [str_val UTF8String]);
282 break;
283 case e_pttext:
284 {
285 printf("Text\n");
286 // Edit all variable text in the document
287 [[itr Current] SetValueWithString: [@"This is a new value. The old one was: " stringByAppendingString: str_val]];
288 }
289 break;
290 case e_ptchoice: printf("Choice\n"); break;
291 case e_ptsignature: printf("Signature\n"); break;
292 default: break;
293 }
294
295 printf("------------------------------\n");
296 }
297
298 // Search for a specific field
299 PTField *f = [doc GetField: @"employee.name.first"];
300 if (f)
301 {
302 printf("Field search for %s was successful\n", [[f GetName] UTF8String]);
303 }
304 else
305 {
306 printf("Field search failed \n");
307 }
308
309 // Regenerate field appearances.
310 [doc RefreshFieldAppearances];
311 [doc SaveToFile: @"../../TestFiles/Output/forms_test_edit.pdf" flags: 0];
312 printf("Done.\n");
313 }
314 @catch(NSException *e)
315 {
316 NSLog(@"%@", e.reason);
317 ret = 1;
318 }
319
320 //----------------------------------------------------------------------------------
321 // Sample: Form templating
322 // Replicate pages and form data within a document. Then rename field names to make
323 // them unique.
324 //----------------------------------------------------------------------------------
325 @try
326 {
327 // Sample: Copying the page with forms within the same document
328 PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: @"../../TestFiles/Output/forms_test1.pdf"];
329 [doc InitSecurityHandler];
330
331 PTPage *src_page = [doc GetPage: 1];
332 [doc PagePushBack: src_page]; // Append several copies of the first page
333 [doc PagePushBack: src_page]; // Note that forms are successfully copied
334 [doc PagePushBack: src_page];
335 [doc PagePushBack: src_page];
336
337 // Now we rename fields in order to make every field unique.
338 // You can use this technique for dynamic template filling where you have a 'master'
339 // form page that should be replicated, but with unique field names on every page.
340 for (NSString* key in field_names)
341 {
342 RenameAllFields(doc, key, [[field_names valueForKey: key] intValue]);
343 }
344
345 [doc SaveToFile: @"../../TestFiles/Output/forms_test1_cloned.pdf" flags: 0];
346 printf("Done.\n");
347 }
348 @catch(NSException *e)
349 {
350 NSLog(@"%@", e.reason);
351 ret = 1;
352 }
353
354 //----------------------------------------------------------------------------------
355 // Sample:
356 // Flatten all form fields in a document.
357 // Note that this sample is intended to show that it is possible to flatten
358 // individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
359 // that will automatically flatten all fields.
360 //----------------------------------------------------------------------------------
361 @try
362 {
363 PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: @"../../TestFiles/Output/forms_test1.pdf"];
364 [doc InitSecurityHandler];
365
366 // Traverse all pages
367 if (true) {
368 [doc FlattenAnnotations: NO];
369 }
370 else // Manual flattening
371 {
372 PTPageIterator *pitr;
373 for (pitr = [doc GetPageIterator: 1];
374 [pitr HasNext]; [pitr Next])
375 {
376 PTPage *page = [pitr Current];
377 for (int i = (int)[page GetNumAnnots] - 1; i >= 0; --i)
378 {
379 PTAnnot *annot = [page GetAnnot: i];
380 if ([annot GetType] == e_ptWidget)
381 {
382 [annot Flatten: page];
383 }
384 }
385 }
386 }
387
388 [doc SaveToFile: @"../../TestFiles/Output/forms_test1_flattened.pdf" flags: 0];
389 printf("Done.\n");
390 }
391 @catch(NSException *e)
392 {
393 NSLog(@"%@", e.reason);
394 ret = 1;
395 }
396 [PTPDFNet Terminate: 0];
397 return ret;
398 }
399}
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
9//---------------------------------------------------------------------------------------
10// This sample illustrates basic PDFNet capabilities related to interactive
11// forms (also known as AcroForms).
12//---------------------------------------------------------------------------------------
13
14func RenameAllFields(doc: PTPDFDoc, name: String) {
15 var itr: PTFieldIterator = doc.getFieldIterator(withName: name)
16 var counter: Int = 0
17 while itr.hasNext() {
18 let f: PTField = itr.current()
19 f.rename(name + ("\(counter)"))
20 itr = doc.getFieldIterator(withName: name)
21 counter += 1
22 }
23}
24
25enum CheckStyle : Int {
26 case e_tick
27 case e_circle
28 case e_cross
29 case e_diamond
30 case e_square
31 case e_star
32}
33
34// Note: The visual appearance of check-marks and radio-buttons in PDF documents is
35// not limited to CheckStyle-s. It is possible to create a visual appearance using
36// arbitrary glyph, text, raster image, or path object. Although most PDF producers
37// limit the options to the above 'standard' styles, using PDFNet you can generate
38// arbitrary appearances.
39func CreateCheckmarkAppearance(doc: PTPDFDoc, style: CheckStyle) -> PTObj {
40 // Create a checkmark appearance stream ------------------------------------
41 let build: PTElementBuilder = PTElementBuilder()
42 let writer: PTElementWriter = PTElementWriter()
43 writer.writerBegin(with: doc.getSDFDoc(), compress: true)
44 writer.write(build.createTextBegin())
45
46 var symbol: String
47 switch style {
48 case .e_circle:
49 symbol = "\u{154}"
50 case .e_diamond:
51 symbol = "\u{165}"
52 case .e_cross:
53 symbol = "\u{65}"
54 case .e_square:
55 symbol = "\u{156}"
56 case .e_star:
57 symbol = "\u{110}"
58 default:
59 // e_tick
60 symbol = "\u{64}"
61 }
62
63 let checkmark: PTElement = build.createTextRun(withFont: symbol, font: PTFont.create(doc.getSDFDoc(), type: e_ptzapf_dingbats, embed: false), font_sz: 1)
64 writer.write(checkmark)
65 writer.write(build.createTextEnd())
66
67 let stm: PTObj = writer.end()
68 stm.putRect("BBox", x1: -0.2, y1: -0.2, x2: 1, y2: 1) // Clip
69 stm.putName("Subtype", name: "Form")
70 return stm
71}
72
73func CreateButtonAppearance(doc: PTPDFDoc, button_down: Bool) -> PTObj {
74 // Create a button appearance stream ------------------------------------
75 let build: PTElementBuilder = PTElementBuilder()
76 let writer: PTElementWriter = PTElementWriter()
77 writer.writerBegin(with: doc.getSDFDoc(), compress: true)
78
79 // Draw background
80 var element: PTElement = build.createRect(0, y: 0, width: 101, height: 137)
81 element.setPathFill(true)
82 element.setPathStroke(false)
83 element.getGState().setFill(PTColorSpace.createDeviceGray())
84 element.getGState().setFillColor(with: PTColorPt(x: 0.75, y: 0, z: 0, w: 0))
85 writer.write(element)
86
87 // Draw 'Submit' text
88 writer.write(build.createTextBegin())
89 do {
90 let text = "Submit"
91 element = build.createTextRun(withFont: text, font: PTFont.create(doc.getSDFDoc(), type: e_pthelvetica_bold, embed: false), font_sz: 12)
92 element.getGState().setFillColor(with: PTColorPt(x: 0, y: 0, z: 0, w: 0))
93
94 if button_down {
95 element.setTextMatrix(with: PTMatrix2D(a: 1, b: 0, c: 0, d: 1, h: 33, v: 10))
96 }
97 else {
98 element.setTextMatrix(with: PTMatrix2D(a: 1, b: 0, c: 0, d: 1, h: 30, v: 13))
99 }
100 writer.write(element)
101 }
102 writer.write(build.createTextEnd())
103
104 let stm: PTObj = writer.end()
105
106 // Set the bounding box
107 stm.putRect("BBox", x1: 0, y1: 0, x2: 101, y2: 37)
108 stm.putName("Subtype", name: "Form")
109 return stm
110}
111
112func runInteractiveFormsTest() -> Int {
113 return autoreleasepool {
114 var ret: Int = 0
115
116
117 //----------------------------------------------------------------------------------
118 // Example 1: Programatically create new Form Fields and Widget Annotations.
119 //----------------------------------------------------------------------------------
120 do {
121 try PTPDFNet.catchException {
122 let doc: PTPDFDoc = PTPDFDoc()
123 let blank_page: PTPage = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 792)) // Create a blank new page and add some form fields.
124
125 // Create new fields.
126 let emp_first_name: PTField = doc.fieldCreate(with: "employee.name.first", type: e_pttext, field_value: "John", def_field_value: "")
127 let emp_last_name: PTField = doc.fieldCreate(with: "employee.name.last", type: e_pttext, field_value: "Doe", def_field_value: "")
128 let emp_last_check1: PTField = doc.fieldCreate(with: "employee.name.check1", type: e_ptcheck, field_value: "Yes", def_field_value: "")
129
130 let submit: PTField = doc.fieldCreate("submit", type: e_ptbutton, field_value: PTObj())
131
132 // Create page annotations for the above fields.
133
134 // Create text annotations
135 let annot1: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 50, y1: 550, x2: 350, y2: 600), field: emp_first_name)
136 let annot2: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 50, y1: 450, x2: 350, y2: 500), field: emp_last_name)
137
138 // Create a check-box annotation
139 let annot3: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 64, y1: 356, x2: 120, y2: 410), field: emp_last_check1)
140 // Set the annotation appearance for the "Yes" state...
141 annot3.setAppearance(CreateCheckmarkAppearance(doc: doc, style: .e_tick), annot_state: e_ptnormal, app_state: "Yes")
142
143 // Create button annotation
144 let annot4: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 64, y1: 284, x2: 163, y2: 320), field: submit)
145 // Set the annotation appearances for the down and up state...
146 annot4.setAppearance(CreateButtonAppearance(doc: doc, button_down: false), annot_state: e_ptnormal, app_state: "")
147 annot4.setAppearance(CreateButtonAppearance(doc: doc, button_down: true), annot_state: e_ptdown, app_state: "")
148
149 // Create 'SubmitForm' action. The action will be linked to the button.
150 let url = PTFileSpec.createURL(doc.getSDFDoc(), url: "http://www.pdftron.com")
151 let button_action: PTAction = PTAction.createSubmitForm(url)
152
153 // Associate the above action with 'Down' event in annotations action dictionary.
154 let annot_action: PTObj = annot4.getSDFObj().putDict("AA")
155 annot_action.put("D", obj: button_action.getSDFObj())
156
157 blank_page.annotPushBack(annot1) // Add annotations to the page
158 blank_page.annotPushBack(annot2)
159 blank_page.annotPushBack(annot3)
160 blank_page.annotPushBack(annot4)
161
162 doc.pagePushBack(blank_page)
163
164 // Add the page as the last page in the document.
165 // If you are not satisfied with the look of default auto-generated appearance
166 // streams you can delete "AP" entry from the Widget annotation and set
167 // "NeedAppearances" flag in AcroForm dictionary:
168 // doc.GetAcroForm().PutBool("NeedAppearances", true);
169 // This will force the viewer application to auto-generate new appearance streams
170 // every time the document is opened.
171 //
172 // Alternatively you can generate custom annotation appearance using ElementWriter
173 // and then set the "AP" entry in the widget dictionary to the new appearance
174 // stream.
175 //
176 // Yet another option is to pre-populate field entries with dummy text. When
177 // you edit the field values using PDFNet the new field appearances will match
178 // the old ones.
179
180 //doc.getAcroForm().putBool("NeedAppearances", value: true)
181 doc.refreshFieldAppearances()
182
183 doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1.pdf").path, flags: 0)
184 print("Done.")
185 }
186 } catch let e as NSError {
187 print("\(e)")
188 ret = 1
189 }
190
191 //----------------------------------------------------------------------------------
192 // Example 2:
193 // Fill-in forms / Modify values of existing fields.
194 // Traverse all form fields in the document (and print out their names).
195 // Search for specific fields in the document.
196 //----------------------------------------------------------------------------------
197
198 do {
199 try PTPDFNet.catchException {
200 let doc: PTPDFDoc = PTPDFDoc(filepath: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1.pdf").path)
201 doc.initSecurityHandler()
202
203 let itr: PTFieldIterator = doc.getFieldIterator()
204 while itr.hasNext() {
205 print("Field name: \(itr.current().getName()!)")
206 print("Field partial name: \(itr.current().getPartialName()!)")
207
208 print("Field type: ")
209 let type: PTFieldType = itr.current().getType()
210 let str_val = itr.current().getValueAsString()
211
212 switch type {
213 case e_ptcheck:
214 itr.current().setValueWith(true)
215 print("Check box: Value = \(str_val!)")
216 case e_ptbutton:
217 print("Button")
218 case e_ptradio:
219 print("Radio button: Value = \(str_val!)")
220 case e_pttext:
221 print("Text")
222 // Edit all variable text in the document
223 itr.current()?.setValueWith("This is a new value. The old one was: \(str_val!)")
224 case e_ptchoice:
225 print("Choice")
226 case e_ptsignature:
227 print("Signature")
228 default:
229 break
230 }
231
232 print("------------------------------")
233 itr.next()
234 }
235
236 // Search for a specific field
237 if let f: PTField = doc.getField("employee.name.first") {
238 print("Field search for \(f.getName()!) was successful")
239 }
240 else {
241 print("Field search failed")
242 }
243
244 // Regenerate field appearances.
245 doc.refreshFieldAppearances()
246 doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test_edit.pdf").path, flags: 0)
247 print("Done.")
248
249 }
250 } catch let e as NSError {
251 print("\(e)")
252 ret = 1
253 }
254
255 //----------------------------------------------------------------------------------
256 // Sample: Form templating
257 // Replicate pages and form data within a document. Then rename field names to make
258 // them unique.
259 //----------------------------------------------------------------------------------
260 do {
261 try PTPDFNet.catchException {
262 // Sample: Copying the page with forms within the same document
263 let doc: PTPDFDoc = PTPDFDoc(filepath: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1.pdf").path)
264 doc.initSecurityHandler()
265
266 let src_page: PTPage = doc.getPage(1)
267 doc.pagePushBack(src_page)
268 // Append several copies of the first page
269 doc.pagePushBack(src_page)
270 // Note that forms are successfully copied
271 doc.pagePushBack(src_page)
272 doc.pagePushBack(src_page)
273
274 // Now we rename fields in order to make every field unique.
275 // You can use this technique for dynamic template filling where you have a 'master'
276 // form page that should be replicated, but with unique field names on every page.
277 RenameAllFields(doc: doc, name: "employee.name.first")
278 RenameAllFields(doc: doc, name: "employee.name.last")
279 RenameAllFields(doc: doc, name: "employee.name.check1")
280 RenameAllFields(doc: doc, name: "submit")
281
282 doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1_cloned.pdf").path, flags: 0)
283 print("Done.")
284 }
285 } catch let e as NSError {
286 print("\(e)")
287 ret = 1
288 }
289
290 //----------------------------------------------------------------------------------
291 // Sample:
292 // Flatten all form fields in a document.
293 // Note that this sample is intended to show that it is possible to flatten
294 // individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
295 // that will automatically flatten all fields.
296 //----------------------------------------------------------------------------------
297 do {
298 try PTPDFNet.catchException {
299 let doc: PTPDFDoc = PTPDFDoc(filepath: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1.pdf").path)
300 doc.initSecurityHandler()
301
302 // Traverse all pages
303 if true {
304 doc.flattenAnnotations(false)
305 } else { // Manual flattening
306// let pitr: PTPageIterator = doc.getPageIterator(1)
307// while pitr.hasNext() {
308// let page: PTPage = pitr.current()
309// if let annots: PTObj = page.getAnnots() {
310// // Look for all widget annotations (in reverse order)
311// var i: Int = Int(annots.size()) - 1
312// while i >= 0 {
313// if (annots.getAt(UInt(i)).get("Subtype").value().getName() == "Widget") {
314// let field: PTField = PTField(field_dict: annots.getAt(UInt(i)))
315// field.flatten(page)
316//
317// // Another way of making a read only field is by modifying
318// // field's e_read_only flag:
319// // field.SetFlag(Field::e_read_only, true);
320// }
321// i -= 1
322// }
323// }
324// pitr.next()
325// }
326 }
327 doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1_flattened.pdf").path, flags: 0)
328 print("Done.")
329 }
330 } catch let e as NSError {
331 print("\(e)")
332 ret = 1
333 }
334
335 return ret
336 }
337}
Did you find this helpful?
Trial setup questions?
Ask experts on DiscordNeed other help?
Contact SupportPricing or product questions?
Contact Sales