ElementBuilder

Sample JavaScript 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 Web SDK and PDF Editing & Manipulation Library.

1(exports => {
2
3
4
5
6
7
8
9
10
11
12
13 exports.runElementBuilderTest = () => {
14 const PDFNet = exports.Core.PDFNet;
15
16 const main = async () => {
17 let ret = 0;
18
19 // Relative path to the folder containing test files.
20 const inputUrl = '../TestFiles/';
21
22 try {
23 const doc = await PDFNet.PDFDoc.create();
24
25 // ElementBuilder is used to build new Element objects
26 const eb = await PDFNet.ElementBuilder.create();
27 // ElementWriter is used to write Elements to the page
28 const writer = await PDFNet.ElementWriter.create();
29
30 let element;
31 let gstate;
32
33 // Start a new page ------------------------------------
34
35 const pageRect = await PDFNet.Rect.init(0, 0, 612, 794);
36 let page = await doc.pageCreate(pageRect);
37
38 // begin writing to the page
39 writer.beginOnPage(page);
40
41 // Create an Image that can be reused in the document or on the same page.
42 const img = await PDFNet.Image.createFromURL(doc, inputUrl + 'peppers.jpg');
43
44 element = await eb.createImageFromMatrix(img, await PDFNet.Matrix2D.create((await img.getImageWidth()) / 2, -145, 20, (await img.getImageHeight()) / 2, 200, 150));
45 writer.writePlacedElement(element);
46
47 // use the same image (just change its matrix)
48 gstate = await element.getGState();
49 gstate.setTransform(200, 0, 0, 300, 50, 450);
50 writer.writePlacedElement(element);
51
52 // use the same image again (just change its matrix).
53 writer.writePlacedElement(await eb.createImageScaled(img, 300, 600, 200, -150));
54
55 writer.end(); // save changes to the current page
56 doc.pagePushBack(page);
57
58 // Start a new page ------------------------------------
59 // Construct and draw a path object using different styles
60 page = await doc.pageCreate(pageRect);
61
62 // begin writing to this page
63 writer.beginOnPage(page);
64 // Reset the GState to default
65 eb.reset();
66
67 // start constructing the path
68 eb.pathBegin();
69 eb.moveTo(306, 396);
70 eb.curveTo(681, 771, 399.75, 864.75, 306, 771);
71 eb.curveTo(212.25, 864.75, -69, 771, 306, 396);
72 eb.closePath();
73 // the path is now finished
74 element = await eb.pathEnd();
75 // the path should be filled
76 element.setPathFill(true);
77
78 // Set the path color space and color
79 gstate = await element.getGState();
80 gstate.setFillColorSpace(await PDFNet.ColorSpace.createDeviceCMYK());
81 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(1, 0, 0, 0)); // cyan
82 gstate.setTransform(0.5, 0, 0, 0.5, -20, 300);
83 writer.writePlacedElement(element);
84
85 // Draw the same path using a different stroke color
86 // this path is should be filled and stroked
87 element.setPathStroke(true);
88 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(0, 0, 1, 0)); // yellow
89 gstate.setStrokeColorSpace(await PDFNet.ColorSpace.createDeviceRGB());
90 gstate.setStrokeColorWithColorPt(await PDFNet.ColorPt.init(1, 0, 0)); // red
91 gstate.setTransform(0.5, 0, 0, 0.5, 280, 300);
92 gstate.setLineWidth(20);
93 writer.writePlacedElement(element);
94
95 // Draw the same path with with a given dash pattern
96 // this path is should be only stroked
97 element.setPathFill(false);
98 gstate.setStrokeColorWithColorPt(await PDFNet.ColorPt.init(0, 0, 1)); // blue
99 gstate.setTransform(0.5, 0, 0, 0.5, 280, 0);
100 const dashPattern = [];
101 dashPattern.push(30);
102 gstate.setDashPattern(dashPattern, 0);
103 writer.writePlacedElement(element);
104
105 // Use the path as a clipping path
106 // Save the graphics state
107 writer.writeElement(await eb.createGroupBegin());
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 // path is now constructed
116 element = await eb.pathEnd();
117 // this path is a clipping path
118 element.setPathClip(true);
119 // this path should be filled and stroked
120 element.setPathStroke(true);
121 gstate = await element.getGState();
122 gstate.setTransform(0.5, 0, 0, 0.5, -20, 0);
123
124 writer.writeElement(element);
125
126 writer.writeElement(await eb.createImageScaled(img, 100, 300, 400, 600));
127
128 // Restore the graphics state
129 writer.writeElement(await eb.createGroupEnd());
130
131 writer.end(); // save changes to the current page
132 doc.pagePushBack(page);
133
134 // Start a new page ------------------------------------
135 page = await doc.pageCreate(pageRect);
136
137 // begin writing to this page
138 writer.beginOnPage(page);
139 // Reset the GState to default
140 eb.reset();
141
142 // Begin writing a block of text
143 element = await eb.createTextBeginWithFont(await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_times_roman), 12);
144 writer.writeElement(element);
145
146 element = await eb.createNewTextRun('Hello World!');
147 element.setTextMatrixEntries(10, 0, 0, 10, 0, 600);
148 gstate = await element.getGState();
149 // Set the spacing between lines
150 gstate.setLeading(15);
151 writer.writeElement(element);
152
153 writer.writeElement(await eb.createTextNewLine()); // New line
154
155 element = await eb.createNewTextRun('Hello World!');
156 gstate = await element.getGState();
157 gstate.setTextRenderMode(PDFNet.GState.TextRenderingMode.e_stroke_text);
158 gstate.setCharSpacing(-1.25);
159 gstate.setWordSpacing(-1.25);
160 writer.writeElement(element);
161
162 writer.writeElement(await eb.createTextNewLine()); // New line
163
164 element = await eb.createNewTextRun('Hello World!');
165 gstate = await element.getGState();
166 gstate.setCharSpacing(0);
167 gstate.setWordSpacing(0);
168 gstate.setLineWidth(3);
169 gstate.setTextRenderMode(PDFNet.GState.TextRenderingMode.e_fill_stroke_text);
170 gstate.setStrokeColorSpace(await PDFNet.ColorSpace.createDeviceRGB());
171 gstate.setStrokeColorWithColorPt(await PDFNet.ColorPt.init(1, 0, 0)); // red
172 gstate.setFillColorSpace(await PDFNet.ColorSpace.createDeviceCMYK());
173 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(1, 0, 0, 0)); // cyan
174 writer.writeElement(element);
175
176 writer.writeElement(await eb.createTextNewLine()); // New line
177
178 // Set text as a clipping path to the image.
179 element = await eb.createNewTextRun('Hello World!');
180 gstate = await element.getGState();
181 gstate.setTextRenderMode(PDFNet.GState.TextRenderingMode.e_clip_text);
182 writer.writeElement(element);
183
184 // Finish the block of text
185 writer.writeElement(await eb.createTextEnd());
186
187 // Draw an image that will be clipped by the above text
188 writer.writeElement(await eb.createImageScaled(img, 10, 100, 1300, 720));
189
190 writer.end(); // save changes to the current page
191 doc.pagePushBack(page);
192
193 // Start a new page ------------------------------------
194 //
195 // The example also shows how ElementReader can be used to copy and modify
196 // Elements between pages.
197
198 const reader = await PDFNet.ElementReader.create();
199
200 // Start reading Elements from the last page. We will copy all Elements to
201 // a new page but will modify the font associated with text.
202 reader.beginOnPage(await doc.getPage(await doc.getPageCount()));
203
204 page = await doc.pageCreate(await PDFNet.Rect.init(0, 0, 1300, 794));
205
206 // begin writing to this page
207 writer.beginOnPage(page);
208 // Reset the GState to default
209 eb.reset();
210
211 const font = await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_helvetica);
212
213 // Read page contents
214 while ((element = await reader.next())) {
215 if ((await element.getType()) === PDFNet.Element.Type.e_text) {
216 (await element.getGState()).setFont(font, 14);
217 }
218
219 writer.writeElement(element);
220 }
221
222 reader.end();
223 writer.end(); // save changes to the current page
224
225 doc.pagePushBack(page);
226
227 // Start a new page ------------------------------------
228 //
229 // The example also shows how ElementReader can be used to copy and modify
230 // Elements between pages.
231
232 // Start reading Elements from the last page. We will copy all Elements to
233 // a new page but will modify the font associated with text.
234 reader.beginOnPage(await doc.getPage(await doc.getPageCount()));
235
236 page = await doc.pageCreate(await PDFNet.Rect.init(0, 0, 1300, 794));
237
238 // begin writing to this page
239 writer.beginOnPage(page);
240 // Reset the GState to default
241 eb.reset();
242
243 // Embed an external font in the document.
244 // MISSING createType1Font
245 // Font font2 = Font::CreateType1Font(doc, (inputUrl + "Misc-Fixed.pfa").c_str());
246 const font2 = await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_courier_bold);
247
248 // Read page contents
249 while ((element = await reader.next())) {
250 if ((await element.getType()) === PDFNet.Element.Type.e_text) {
251 (await element.getGState()).setFont(font2, 16);
252 }
253 writer.writeElement(element);
254 }
255
256 reader.end();
257 writer.end(); // save changes to the current page
258 doc.pagePushBack(page);
259
260 // Start a new page ------------------------------------
261 page = await doc.pageCreate();
262 // begin writing to this page
263 writer.beginOnPage(page);
264 // Reset the GState to default
265 eb.reset();
266
267 // Begin writing a block of text
268 element = await eb.createTextBeginWithFont(await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_times_roman), 12);
269 element.setTextMatrixEntries(1.5, 0, 0, 1.5, 50, 600);
270 // Set the spacing between lines
271 (await element.getGState()).setLeading(15);
272 writer.writeElement(element);
273
274 const para =
275 'A PDF text object consists of operators that can show ' +
276 'text strings, move the text position, and set text state and certain ' +
277 'other parameters. In addition, there are three parameters that are ' +
278 'defined only within a text object and do not persist from one text ' +
279 'object to the next: Tm, the text matrix, Tlm, the text line matrix, ' +
280 'Trm, the text rendering matrix, actually just an intermediate result ' +
281 'that combines the effects of text state parameters, the text matrix ' +
282 '(Tm), and the current transformation matrix';
283
284 const paraEnd = para.length;
285 let textRun = 0;
286 let textRunEnd;
287
288 const paraWidth = 300; // paragraph width is 300 units
289 let curWidth = 0;
290
291 while (textRun < paraEnd) {
292 textRunEnd = para.indexOf(' ', textRun);
293 if (textRunEnd < 0) {
294 textRunEnd = paraEnd - 1;
295 }
296
297 let text = para.substring(textRun, textRunEnd - textRun + 1);
298 element = await eb.createNewTextRun(text);
299 if (curWidth + (await element.getTextLength()) < paraWidth) {
300 writer.writeElement(element);
301 curWidth += await element.getTextLength();
302 } else {
303 writer.writeElement(await eb.createTextNewLine()); // New line
304 text = para.substr(textRun, textRunEnd - textRun + 1);
305 element = await eb.createNewTextRun(text);
306 curWidth = await element.getTextLength();
307 writer.writeElement(element);
308 }
309
310 textRun = textRunEnd + 1;
311 }
312
313 // -----------------------------------------------------------------------
314 // The following code snippet illustrates how to adjust spacing between
315 // characters (text runs).
316 element = await eb.createTextNewLine();
317 writer.writeElement(element); // Skip 2 lines
318 writer.writeElement(element);
319
320 writer.writeElement(await eb.createNewTextRun('An example of space adjustments between inter-characters:'));
321 writer.writeElement(await eb.createTextNewLine());
322
323 // Write string "AWAY" without space adjustments between characters.
324 element = await eb.createNewTextRun('AWAY');
325 writer.writeElement(element);
326
327 writer.writeElement(await eb.createTextNewLine());
328
329 // Write string "AWAY" with space adjustments between characters.
330 element = await eb.createNewTextRun('A');
331 writer.writeElement(element);
332
333 element = await eb.createNewTextRun('W');
334 element.setPosAdjustment(140);
335 writer.writeElement(element);
336
337 element = await eb.createNewTextRun('A');
338 element.setPosAdjustment(140);
339 writer.writeElement(element);
340
341 element = await eb.createNewTextRun('Y again');
342 element.setPosAdjustment(115);
343 writer.writeElement(element);
344
345 // Draw the same strings using direct content output...
346 writer.flush(); // flush pending Element writing operations.
347
348 // You can also write page content directly to the content stream using
349 // ElementWriter.WriteString(...) and ElementWriter.WriteBuffer(...) methods.
350 // Note that if you are planning to use these functions you need to be familiar
351 // with PDF page content operators (see Appendix A in PDF Reference Manual).
352 // Because it is easy to make mistakes during direct output we recommend that
353 // you use ElementBuilder and Element interface instead.
354
355 writer.writeString('T* T* '); // Skip 2 lines
356 writer.writeString('(Direct output to PDF page content stream:) Tj T* ');
357 writer.writeString('(AWAY) Tj T* ');
358 writer.writeString('[(A)140(W)140(A)115(Y again)] TJ ');
359
360 // Finish the block of text
361 writer.writeElement(await eb.createTextEnd());
362
363 writer.end(); // save changes to the current page
364 doc.pagePushBack(page);
365
366 // Start a new page ------------------------------------
367
368 // Image Masks
369 //
370 // In the opaque imaging model, images mark all areas they occupy on the page as
371 // if with opaque paint. All portions of the image, whether black, white, gray,
372 // or color, completely obscure any marks that may previously have existed in the
373 // same place on the page.
374 // In the graphic arts industry and page layout applications, however, it is common
375 // to crop or 'mask out' the background of an image and then place the masked image
376 // on a different background, allowing the existing background to show through the
377 // masked areas. This sample illustrates how to use image masks.
378
379 page = await doc.pageCreate();
380 // begin writing to the page
381 writer.beginOnPage(page);
382
383 // INVESTIGATE THIS SECTION
384
385 // Create the Image Mask
386 const embedFile = await PDFNet.Filter.createURLFilter(inputUrl + 'imagemask.dat');
387 const maskRead = await PDFNet.FilterReader.create(embedFile);
388
389 // INVESTIGATE THIS SECTION
390
391 const deviceGray = await PDFNet.ColorSpace.createDeviceGray();
392 const mask = await PDFNet.Image.createDirectFromStream(doc, maskRead, 64, 64, 1, deviceGray, PDFNet.Image.InputFilter.e_ascii_hex);
393
394 (await mask.getSDFObj()).putBool('ImageMask', true);
395
396 element = await eb.createRect(0, 0, 612, 794);
397 element.setPathStroke(false);
398 element.setPathFill(true);
399 gstate = await element.getGState();
400
401 gstate.setFillColorSpace(deviceGray);
402 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(0.8));
403 writer.writePlacedElement(element);
404
405 element = await eb.createImageFromMatrix(mask, await PDFNet.Matrix2D.create(200, 0, 0, -200, 40, 680));
406 (await element.getGState()).setFillColorWithColorPt(await PDFNet.ColorPt.init(0.1));
407 writer.writePlacedElement(element);
408
409 gstate = await element.getGState();
410 gstate.setFillColorSpace(await PDFNet.ColorSpace.createDeviceRGB());
411 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(1, 0, 0));
412 element = await eb.createImageFromMatrix(mask, await PDFNet.Matrix2D.create(200, 0, 0, -200, 320, 680));
413 writer.writePlacedElement(element);
414
415 (await element.getGState()).setFillColorWithColorPt(await PDFNet.ColorPt.init(0, 1, 0));
416 element = await eb.createImageFromMatrix(mask, await PDFNet.Matrix2D.create(200, 0, 0, -200, 40, 380));
417 writer.writePlacedElement(element);
418
419 {
420 // This sample illustrates Explicit Masking.
421 const img = await PDFNet.Image.createFromURL(doc, inputUrl + 'peppers.jpg');
422
423 // mask is the explicit mask for the primary (base) image
424 img.setMask(mask);
425
426 element = await eb.createImageFromMatrix(img, await PDFNet.Matrix2D.create(200, 0, 0, -200, 320, 380));
427 writer.writePlacedElement(element);
428 }
429
430 writer.end(); // save changes to the current page
431 doc.pagePushBack(page);
432
433 // Transparency sample ----------------------------------
434
435 // Start a new page -------------------------------------
436 page = await doc.pageCreate();
437 // begin writing to this page
438 writer.beginOnPage(page);
439 // Reset the GState to default
440 eb.reset();
441
442 // Write some transparent text at the bottom of the page.
443 element = await eb.createTextBeginWithFont(await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_times_roman), 100);
444
445 // Set the text knockout attribute. Text knockout must be set outside of
446 // the text group.
447 gstate = await element.getGState();
448 gstate.setTextKnockout(false);
449 gstate.setBlendMode(PDFNet.GState.BlendMode.e_bl_difference);
450 writer.writeElement(element);
451
452 element = await eb.createNewTextRun('Transparency');
453 element.setTextMatrixEntries(1, 0, 0, 1, 30, 30);
454 gstate = await element.getGState();
455 gstate.setFillColorSpace(await PDFNet.ColorSpace.createDeviceCMYK());
456 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(1, 0, 0, 0));
457
458 gstate.setFillOpacity(0.5);
459 writer.writeElement(element);
460
461 // Write the same text on top the old; shifted by 3 points
462 element.setTextMatrixEntries(1, 0, 0, 1, 33, 33);
463 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(0, 1, 0, 0));
464 gstate.setFillOpacity(0.5);
465
466 writer.writeElement(element);
467 writer.writeElement(await eb.createTextEnd());
468
469 // Draw three overlapping transparent circles.
470 // start constructing the path
471 eb.pathBegin();
472 eb.moveTo(459.223, 505.646);
473 eb.curveTo(459.223, 415.841, 389.85, 343.04, 304.273, 343.04);
474 eb.curveTo(218.697, 343.04, 149.324, 415.841, 149.324, 505.646);
475 eb.curveTo(149.324, 595.45, 218.697, 668.25, 304.273, 668.25);
476 eb.curveTo(389.85, 668.25, 459.223, 595.45, 459.223, 505.646);
477 element = await eb.pathEnd();
478 element.setPathFill(true);
479
480 gstate = await element.getGState();
481 gstate.setFillColorSpace(await PDFNet.ColorSpace.createDeviceRGB());
482 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(0, 0, 1)); // Blue Circle
483
484 gstate.setBlendMode(PDFNet.GState.BlendMode.e_bl_normal);
485 gstate.setFillOpacity(0.5);
486 writer.writeElement(element);
487
488 // Translate relative to the Blue Circle
489 gstate.setTransform(1, 0, 0, 1, 113, -185);
490 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(0, 1, 0)); // Green Circle
491 gstate.setFillOpacity(0.5);
492 writer.writeElement(element);
493
494 // Translate relative to the Green Circle
495 gstate.setTransform(1, 0, 0, 1, -220, 0);
496 gstate.setFillColorWithColorPt(await PDFNet.ColorPt.init(1, 0, 0)); // Red Circle
497 gstate.setFillOpacity(0.5);
498 writer.writeElement(element);
499
500 writer.end(); // save changes to the current page
501 doc.pagePushBack(page);
502
503 // End page ------------------------------------
504
505 const docBuffer = await doc.saveMemoryBuffer(PDFNet.SDFDoc.SaveOptions.e_remove_unused);
506 saveBufferAsPDFDoc(docBuffer, 'element_builder.pdf');
507
508 console.log('Done. Result saved in element_builder.pdf...');
509 } catch (e) {
510 console.log(e);
511 ret = 1;
512 }
513 return ret;
514 };
515
516 // add your own license key as the second parameter, e.g. PDFNet.runWithCleanup(main, 'YOUR_LICENSE_KEY')
517 PDFNet.runWithCleanup(main);
518 };
519})(window);
520// eslint-disable-next-line spaced-comment
521//# sourceURL=ElementBuilderTest.js

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales