@digicole/pdfmake-rtl 1.2.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/.vscode/tasks.json +17 -0
  2. package/CHANGELOG.md +83 -128
  3. package/LICENSE +22 -22
  4. package/README.md +188 -681
  5. package/build/fonts/Cairo/Cairo-Black.ttf +0 -0
  6. package/build/fonts/Cairo/Cairo-Bold.ttf +0 -0
  7. package/build/fonts/Cairo/Cairo-ExtraLight.ttf +0 -0
  8. package/build/fonts/Cairo/Cairo-Light.ttf +0 -0
  9. package/build/fonts/Cairo/Cairo-Regular.ttf +0 -0
  10. package/build/fonts/Cairo/Cairo-SemiBold.ttf +0 -0
  11. package/build/fonts/Cairo.js +27 -0
  12. package/build/fonts/Roboto/Roboto-Italic.ttf +0 -0
  13. package/build/fonts/Roboto/Roboto-Medium.ttf +0 -0
  14. package/build/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  15. package/build/fonts/Roboto/Roboto-Regular.ttf +0 -0
  16. package/build/fonts/Roboto.js +27 -0
  17. package/build/pdfmake.js +63736 -71285
  18. package/build/pdfmake.js.map +1 -1
  19. package/build/pdfmake.min.js +2 -2
  20. package/build/pdfmake.min.js.map +1 -1
  21. package/build/standard-fonts/Courier.js +27 -0
  22. package/build/standard-fonts/Helvetica.js +27 -0
  23. package/build/standard-fonts/Symbol.js +21 -0
  24. package/build/standard-fonts/Times.js +27 -0
  25. package/build/standard-fonts/ZapfDingbats.js +21 -0
  26. package/build/vfs_fonts.js +11 -7
  27. package/build-vfs.js +44 -44
  28. package/fonts/Cairo/Cairo-Black.ttf +0 -0
  29. package/fonts/Cairo/Cairo-Bold.ttf +0 -0
  30. package/fonts/Cairo/Cairo-ExtraLight.ttf +0 -0
  31. package/fonts/Cairo/Cairo-Light.ttf +0 -0
  32. package/fonts/Cairo/Cairo-Regular.ttf +0 -0
  33. package/fonts/Cairo/Cairo-SemiBold.ttf +0 -0
  34. package/fonts/Cairo.js +8 -0
  35. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  36. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  37. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  38. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  39. package/fonts/Roboto.js +8 -0
  40. package/index.js +26 -26
  41. package/package.json +42 -39
  42. package/src/3rd-party/svg-to-pdfkit/LICENSE +9 -9
  43. package/src/3rd-party/svg-to-pdfkit/source.js +229 -36
  44. package/src/3rd-party/svg-to-pdfkit.js +3 -3
  45. package/src/OutputDocument.js +64 -0
  46. package/src/OutputDocumentServer.js +32 -0
  47. package/src/PDFDocument.js +174 -0
  48. package/src/PageSize.js +53 -0
  49. package/src/Renderer.js +445 -0
  50. package/src/TextBreaker.js +168 -0
  51. package/src/TextInlines.js +263 -0
  52. package/src/URLResolver.js +43 -0
  53. package/src/base.js +70 -0
  54. package/src/browser-extensions/OutputDocumentBrowser.js +80 -0
  55. package/src/browser-extensions/fonts/Cairo.js +27 -0
  56. package/src/browser-extensions/fonts/Roboto.js +27 -0
  57. package/src/browser-extensions/index.js +61 -0
  58. package/src/browser-extensions/pdfMake.js +1 -355
  59. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  60. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  61. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  62. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  63. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  64. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  65. package/src/columnCalculator.js +154 -157
  66. package/src/docMeasure.js +802 -810
  67. package/src/docPreprocessor.js +306 -273
  68. package/src/documentContext.js +345 -340
  69. package/src/elementWriter.js +736 -411
  70. package/src/helpers/node.js +136 -0
  71. package/src/helpers/tools.js +44 -0
  72. package/src/helpers/variableType.js +50 -0
  73. package/src/index.js +16 -0
  74. package/src/layoutBuilder.js +1393 -1197
  75. package/src/line.js +122 -104
  76. package/src/pageElementWriter.js +187 -174
  77. package/src/printer.js +370 -727
  78. package/src/qrEnc.js +796 -791
  79. package/src/rtlUtils.js +500 -485
  80. package/src/standardPageSizes.js +52 -54
  81. package/src/styleContextStack.js +208 -138
  82. package/src/svgMeasure.js +109 -70
  83. package/src/tableLayouts.js +100 -0
  84. package/src/tableProcessor.js +620 -606
  85. package/src/textDecorator.js +175 -157
  86. package/src/virtual-fs.js +66 -0
  87. package/standard-fonts/Courier.js +8 -0
  88. package/standard-fonts/Helvetica.js +8 -0
  89. package/standard-fonts/Symbol.js +5 -0
  90. package/standard-fonts/Times.js +8 -0
  91. package/standard-fonts/ZapfDingbats.js +5 -0
  92. package/index.html +0 -396
  93. package/src/browser-extensions/URLBrowserResolver.js +0 -96
  94. package/src/browser-extensions/virtual-fs.js +0 -55
  95. package/src/fontProvider.js +0 -68
  96. package/src/helpers.js +0 -138
  97. package/src/imageMeasure.js +0 -62
  98. package/src/pdfKitEngine.js +0 -21
  99. package/src/textTools.js +0 -391
  100. package/src/traversalTracker.js +0 -47
package/src/printer.js CHANGED
@@ -1,727 +1,370 @@
1
- /*eslint no-unused-vars: ["error", {"args": "none"}]*/
2
- 'use strict';
3
-
4
- var PdfKitEngine = require('./pdfKitEngine');
5
- var FontProvider = require('./fontProvider');
6
- var LayoutBuilder = require('./layoutBuilder');
7
- var sizes = require('./standardPageSizes');
8
- var ImageMeasure = require('./imageMeasure');
9
- var SVGMeasure = require('./svgMeasure');
10
- var textDecorator = require('./textDecorator');
11
- var TextTools = require('./textTools');
12
- var isFunction = require('./helpers').isFunction;
13
- var isString = require('./helpers').isString;
14
- var isNumber = require('./helpers').isNumber;
15
- var isBoolean = require('./helpers').isBoolean;
16
- var isArray = require('./helpers').isArray;
17
- var isUndefined = require('./helpers').isUndefined;
18
- var isPattern = require('./helpers').isPattern;
19
- var getPattern = require('./helpers').getPattern;
20
- var SVGtoPDF = require('./3rd-party/svg-to-pdfkit');
21
-
22
- var findFont = function (fonts, requiredFonts, defaultFont) {
23
- for (var i = 0; i < requiredFonts.length; i++) {
24
- var requiredFont = requiredFonts[i].toLowerCase();
25
-
26
- for (var font in fonts) {
27
- if (font.toLowerCase() === requiredFont) {
28
- return font;
29
- }
30
- }
31
- }
32
-
33
- return defaultFont;
34
- };
35
-
36
- ////////////////////////////////////////
37
- // PdfPrinter
38
-
39
- /**
40
- * @class Creates an instance of a PdfPrinter which turns document definition into a pdf
41
- *
42
- * @param {Object} fontDescriptors font definition dictionary
43
- *
44
- * @example
45
- * var fontDescriptors = {
46
- * Roboto: {
47
- * normal: 'fonts/Roboto-Regular.ttf',
48
- * bold: 'fonts/Roboto-Medium.ttf',
49
- * italics: 'fonts/Roboto-Italic.ttf',
50
- * bolditalics: 'fonts/Roboto-MediumItalic.ttf'
51
- * }
52
- * };
53
- *
54
- * var printer = new PdfPrinter(fontDescriptors);
55
- */
56
- function PdfPrinter(fontDescriptors) {
57
- this.fontDescriptors = fontDescriptors;
58
- }
59
-
60
- /**
61
- * Executes layout engine for the specified document and renders it into a pdfkit document
62
- * ready to be saved.
63
- *
64
- * @param {Object} docDefinition document definition
65
- * @param {Object} docDefinition.content an array describing the pdf structure (for more information take a look at the examples in the /examples folder)
66
- * @param {Object} [docDefinition.defaultStyle] default (implicit) style definition
67
- * @param {Object} [docDefinition.styles] dictionary defining all styles which can be used in the document
68
- * @param {Object} [docDefinition.pageSize] page size (pdfkit units, A4 dimensions by default)
69
- * @param {Number} docDefinition.pageSize.width width
70
- * @param {Number} docDefinition.pageSize.height height
71
- * @param {Object} [docDefinition.pageMargins] page margins (pdfkit units)
72
- * @param {Number} docDefinition.maxPagesNumber maximum number of pages to render
73
- *
74
- * @example
75
- *
76
- * var docDefinition = {
77
- * info: {
78
- * title: 'awesome Document',
79
- * author: 'john doe',
80
- * subject: 'subject of document',
81
- * keywords: 'keywords for document',
82
- * },
83
- * content: [
84
- * 'First paragraph',
85
- * 'Second paragraph, this time a little bit longer',
86
- * { text: 'Third paragraph, slightly bigger font size', fontSize: 20 },
87
- * { text: 'Another paragraph using a named style', style: 'header' },
88
- * { text: ['playing with ', 'inlines' ] },
89
- * { text: ['and ', { text: 'restyling ', bold: true }, 'them'] },
90
- * ],
91
- * styles: {
92
- * header: { fontSize: 30, bold: true }
93
- * },
94
- * patterns: {
95
- * stripe45d: {
96
- * boundingBox: [1, 1, 4, 4],
97
- * xStep: 3,
98
- * yStep: 3,
99
- * pattern: '1 w 0 1 m 4 5 l s 2 0 m 5 3 l s'
100
- * }
101
- * }
102
- * };
103
- *
104
- * var pdfKitDoc = printer.createPdfKitDocument(docDefinition);
105
- *
106
- * pdfKitDoc.pipe(fs.createWriteStream('sample.pdf'));
107
- * pdfKitDoc.end();
108
- *
109
- * @return {Object} a pdfKit document object which can be saved or encode to data-url
110
- */
111
- PdfPrinter.prototype.createPdfKitDocument = function (docDefinition, options) {
112
- options = options || {};
113
-
114
- docDefinition.version = docDefinition.version || '1.3';
115
- docDefinition.subset = docDefinition.subset || undefined;
116
- docDefinition.tagged = typeof docDefinition.tagged === 'boolean' ? docDefinition.tagged : false;
117
- docDefinition.displayTitle = typeof docDefinition.displayTitle === 'boolean' ? docDefinition.displayTitle : false;
118
- docDefinition.compress = isBoolean(docDefinition.compress) ? docDefinition.compress : true;
119
- docDefinition.images = docDefinition.images || {};
120
- docDefinition.pageMargins = ((docDefinition.pageMargins !== undefined) && (docDefinition.pageMargins !== null)) ? docDefinition.pageMargins : 40;
121
-
122
- var pageSize = fixPageSize(docDefinition.pageSize, docDefinition.pageOrientation);
123
-
124
- var pdfOptions = {
125
- size: [pageSize.width, pageSize.height],
126
- pdfVersion: docDefinition.version,
127
- subset: docDefinition.subset,
128
- tagged: docDefinition.tagged,
129
- displayTitle: docDefinition.displayTitle,
130
- compress: docDefinition.compress,
131
- userPassword: docDefinition.userPassword,
132
- ownerPassword: docDefinition.ownerPassword,
133
- permissions: docDefinition.permissions,
134
- lang: docDefinition.language,
135
- fontLayoutCache: isBoolean(options.fontLayoutCache) ? options.fontLayoutCache : true,
136
- bufferPages: options.bufferPages || false,
137
- autoFirstPage: false,
138
- info: createMetadata(docDefinition),
139
- font: null
140
- };
141
-
142
- this.pdfKitDoc = PdfKitEngine.createPdfDocument(pdfOptions);
143
-
144
- this.fontProvider = new FontProvider(this.fontDescriptors, this.pdfKitDoc);
145
-
146
- var builder = new LayoutBuilder(pageSize, fixPageMargins(docDefinition.pageMargins), new ImageMeasure(this.pdfKitDoc, docDefinition.images), new SVGMeasure());
147
-
148
- registerDefaultTableLayouts(builder);
149
- if (options.tableLayouts) {
150
- builder.registerTableLayouts(options.tableLayouts);
151
- }
152
-
153
- var pages = builder.layoutDocument(docDefinition.content, this.fontProvider, docDefinition.styles || {}, docDefinition.defaultStyle || {
154
- fontSize: 12,
155
- font: 'Roboto'
156
- }, docDefinition.background, docDefinition.header, docDefinition.footer, docDefinition.images, docDefinition.watermark, docDefinition.pageBreakBefore);
157
- var maxNumberPages = docDefinition.maxPagesNumber || -1;
158
- if (isNumber(maxNumberPages) && maxNumberPages > -1) {
159
- pages = pages.slice(0, maxNumberPages);
160
- }
161
-
162
- // if pageSize.height is set to Infinity, calculate the actual height of the page that
163
- // was laid out using the height of each of the items in the page.
164
- if (pageSize.height === Infinity) {
165
- var pageHeight = calculatePageHeight(pages, docDefinition.pageMargins);
166
- this.pdfKitDoc.options.size = [pageSize.width, pageHeight];
167
- }
168
-
169
- var patterns = createPatterns(docDefinition.patterns || {}, this.pdfKitDoc);
170
-
171
- renderPages(pages, this.fontProvider, this.pdfKitDoc, patterns, options.progressCallback);
172
-
173
- if (options.autoPrint) {
174
- var printActionRef = this.pdfKitDoc.ref({
175
- Type: 'Action',
176
- S: 'Named',
177
- N: 'Print'
178
- });
179
- this.pdfKitDoc._root.data.OpenAction = printActionRef;
180
- printActionRef.end();
181
- }
182
- return this.pdfKitDoc;
183
- };
184
-
185
- function createMetadata(docDefinition) {
186
- // PDF standard has these properties reserved: Title, Author, Subject, Keywords,
187
- // Creator, Producer, CreationDate, ModDate, Trapped.
188
- // To keep the pdfmake api consistent, the info field are defined lowercase.
189
- // Custom properties don't contain a space.
190
- function standardizePropertyKey(key) {
191
- var standardProperties = ['Title', 'Author', 'Subject', 'Keywords',
192
- 'Creator', 'Producer', 'CreationDate', 'ModDate', 'Trapped'];
193
- var standardizedKey = key.charAt(0).toUpperCase() + key.slice(1);
194
- if (standardProperties.indexOf(standardizedKey) !== -1) {
195
- return standardizedKey;
196
- }
197
-
198
- return key.replace(/\s+/g, '');
199
- }
200
-
201
- var info = {
202
- Producer: 'pdfmake',
203
- Creator: 'pdfmake'
204
- };
205
-
206
- if (docDefinition.info) {
207
- for (var key in docDefinition.info) {
208
- var value = docDefinition.info[key];
209
- if (value) {
210
- key = standardizePropertyKey(key);
211
- info[key] = value;
212
- }
213
- }
214
- }
215
- return info;
216
- }
217
-
218
- function calculatePageHeight(pages, margins) {
219
- function getItemHeight(item) {
220
- if (isFunction(item.item.getHeight)) {
221
- return item.item.getHeight();
222
- } else if (item.item._height) {
223
- return item.item._height;
224
- } else if (item.type === 'vector') {
225
- if (typeof item.item.y1 !== 'undefined') {
226
- return item.item.y1 > item.item.y2 ? item.item.y1 : item.item.y2;
227
- } else {
228
- return item.item.h;
229
- }
230
- } else {
231
- // TODO: add support for next item types
232
- return 0;
233
- }
234
- }
235
-
236
- function getBottomPosition(item) {
237
- var top = item.item.y || 0;
238
- var height = getItemHeight(item);
239
- return top + height;
240
- }
241
-
242
- var fixedMargins = fixPageMargins(margins || 40);
243
- var height = fixedMargins.top;
244
-
245
- pages.forEach(function (page) {
246
- page.items.forEach(function (item) {
247
- var bottomPosition = getBottomPosition(item);
248
- if (bottomPosition > height) {
249
- height = bottomPosition;
250
- }
251
- });
252
- });
253
-
254
- height += fixedMargins.bottom;
255
-
256
- return height;
257
- }
258
-
259
- function fixPageSize(pageSize, pageOrientation) {
260
- function isNeedSwapPageSizes(pageOrientation) {
261
- if (isString(pageOrientation)) {
262
- pageOrientation = pageOrientation.toLowerCase();
263
- return ((pageOrientation === 'portrait') && (size.width > size.height)) ||
264
- ((pageOrientation === 'landscape') && (size.width < size.height));
265
- }
266
- return false;
267
- }
268
-
269
- // if pageSize.height is set to auto, set the height to infinity so there are no page breaks.
270
- if (pageSize && pageSize.height === 'auto') {
271
- pageSize.height = Infinity;
272
- }
273
-
274
- var size = pageSize2widthAndHeight(pageSize || 'A4');
275
- if (isNeedSwapPageSizes(pageOrientation)) { // swap page sizes
276
- size = { width: size.height, height: size.width };
277
- }
278
- size.orientation = size.width > size.height ? 'landscape' : 'portrait';
279
- return size;
280
- }
281
-
282
- function fixPageMargins(margin) {
283
- if (isNumber(margin)) {
284
- margin = { left: margin, right: margin, top: margin, bottom: margin };
285
- } else if (isArray(margin)) {
286
- if (margin.length === 2) {
287
- margin = { left: margin[0], top: margin[1], right: margin[0], bottom: margin[1] };
288
- } else if (margin.length === 4) {
289
- margin = { left: margin[0], top: margin[1], right: margin[2], bottom: margin[3] };
290
- } else {
291
- throw 'Invalid pageMargins definition';
292
- }
293
- }
294
-
295
- return margin;
296
- }
297
-
298
- function registerDefaultTableLayouts(layoutBuilder) {
299
- layoutBuilder.registerTableLayouts({
300
- noBorders: {
301
- hLineWidth: function (i) {
302
- return 0;
303
- },
304
- vLineWidth: function (i) {
305
- return 0;
306
- },
307
- paddingLeft: function (i) {
308
- return i && 4 || 0;
309
- },
310
- paddingRight: function (i, node) {
311
- return (i < node.table.widths.length - 1) ? 4 : 0;
312
- }
313
- },
314
- headerLineOnly: {
315
- hLineWidth: function (i, node) {
316
- if (i === 0 || i === node.table.body.length) {
317
- return 0;
318
- }
319
- return (i === node.table.headerRows) ? 2 : 0;
320
- },
321
- vLineWidth: function (i) {
322
- return 0;
323
- },
324
- paddingLeft: function (i) {
325
- return i === 0 ? 0 : 8;
326
- },
327
- paddingRight: function (i, node) {
328
- return (i === node.table.widths.length - 1) ? 0 : 8;
329
- }
330
- },
331
- lightHorizontalLines: {
332
- hLineWidth: function (i, node) {
333
- if (i === 0 || i === node.table.body.length) {
334
- return 0;
335
- }
336
- return (i === node.table.headerRows) ? 2 : 1;
337
- },
338
- vLineWidth: function (i) {
339
- return 0;
340
- },
341
- hLineColor: function (i) {
342
- return i === 1 ? 'black' : '#aaa';
343
- },
344
- paddingLeft: function (i) {
345
- return i === 0 ? 0 : 8;
346
- },
347
- paddingRight: function (i, node) {
348
- return (i === node.table.widths.length - 1) ? 0 : 8;
349
- }
350
- }
351
- });
352
- }
353
-
354
- function pageSize2widthAndHeight(pageSize) {
355
- if (isString(pageSize)) {
356
- var size = sizes[pageSize.toUpperCase()];
357
- if (!size) {
358
- throw 'Page size ' + pageSize + ' not recognized';
359
- }
360
- return { width: size[0], height: size[1] };
361
- }
362
-
363
- return pageSize;
364
- }
365
-
366
- function updatePageOrientationInOptions(currentPage, pdfKitDoc) {
367
- var previousPageOrientation = pdfKitDoc.options.size[0] > pdfKitDoc.options.size[1] ? 'landscape' : 'portrait';
368
-
369
- if (currentPage.pageSize.orientation !== previousPageOrientation) {
370
- var width = pdfKitDoc.options.size[0];
371
- var height = pdfKitDoc.options.size[1];
372
- pdfKitDoc.options.size = [height, width];
373
- }
374
- }
375
-
376
- function renderPages(pages, fontProvider, pdfKitDoc, patterns, progressCallback) {
377
- pdfKitDoc._pdfMakePages = pages;
378
- pdfKitDoc.addPage();
379
-
380
- var totalItems = 0;
381
- if (progressCallback) {
382
- pages.forEach(function (page) {
383
- totalItems += page.items.length;
384
- });
385
- }
386
-
387
- var renderedItems = 0;
388
- progressCallback = progressCallback || function () {
389
- };
390
-
391
- for (var i = 0; i < pages.length; i++) {
392
- if (i > 0) {
393
- updatePageOrientationInOptions(pages[i], pdfKitDoc);
394
- pdfKitDoc.addPage(pdfKitDoc.options);
395
- }
396
-
397
- var page = pages[i];
398
- for (var ii = 0, il = page.items.length; ii < il; ii++) {
399
- var item = page.items[ii];
400
- switch (item.type) {
401
- case 'vector':
402
- renderVector(item.item, patterns, pdfKitDoc);
403
- break;
404
- case 'line':
405
- renderLine(item.item, item.item.x, item.item.y, patterns, pdfKitDoc);
406
- break;
407
- case 'image':
408
- renderImage(item.item, item.item.x, item.item.y, pdfKitDoc);
409
- break;
410
- case 'svg':
411
- renderSVG(item.item, item.item.x, item.item.y, pdfKitDoc, fontProvider);
412
- break;
413
- case 'beginClip':
414
- beginClip(item.item, pdfKitDoc);
415
- break;
416
- case 'endClip':
417
- endClip(pdfKitDoc);
418
- break;
419
- }
420
- renderedItems++;
421
- progressCallback(renderedItems / totalItems);
422
- }
423
- if (page.watermark) {
424
- renderWatermark(page, pdfKitDoc);
425
- }
426
- }
427
- }
428
-
429
- /**
430
- * Shift the "y" height of the text baseline up or down (superscript or subscript,
431
- * respectively). The exact shift can / should be changed according to standard
432
- * conventions.
433
- *
434
- * @param {number} y
435
- * @param {any} inline
436
- */
437
- function offsetText(y, inline) {
438
- var newY = y;
439
- if (inline.sup) {
440
- newY -= inline.fontSize * 0.75;
441
- }
442
- if (inline.sub) {
443
- newY += inline.fontSize * 0.35;
444
- }
445
- return newY;
446
- }
447
-
448
- function renderLine(line, x, y, patterns, pdfKitDoc) {
449
- function preparePageNodeRefLine(_pageNodeRef, inline) {
450
- var newWidth;
451
- var diffWidth;
452
- var textTools = new TextTools(null);
453
-
454
- if (isUndefined(_pageNodeRef.positions)) {
455
- throw 'Page reference id not found';
456
- }
457
-
458
- var pageNumber = _pageNodeRef.positions[0].pageNumber.toString();
459
-
460
- inline.text = pageNumber;
461
- newWidth = textTools.widthOfString(inline.text, inline.font, inline.fontSize, inline.characterSpacing, inline.fontFeatures);
462
- diffWidth = inline.width - newWidth;
463
- inline.width = newWidth;
464
-
465
- switch (inline.alignment) {
466
- case 'right':
467
- inline.x += diffWidth;
468
- break;
469
- case 'center':
470
- inline.x += diffWidth / 2;
471
- break;
472
- }
473
- }
474
-
475
- if (line._pageNodeRef) {
476
- preparePageNodeRefLine(line._pageNodeRef, line.inlines[0]);
477
- }
478
-
479
- x = x || 0;
480
- y = y || 0;
481
-
482
- var lineHeight = line.getHeight();
483
- var ascenderHeight = line.getAscenderHeight();
484
- var descent = lineHeight - ascenderHeight;
485
-
486
- textDecorator.drawBackground(line, x, y, patterns, pdfKitDoc);
487
-
488
- //TODO: line.optimizeInlines();
489
- for (var i = 0, l = line.inlines.length; i < l; i++) {
490
- var inline = line.inlines[i];
491
- var shiftToBaseline = lineHeight - ((inline.font.ascender / 1000) * inline.fontSize) - descent;
492
-
493
- if (inline._pageNodeRef) {
494
- preparePageNodeRefLine(inline._pageNodeRef, inline);
495
- }
496
-
497
- var options = {
498
- lineBreak: false,
499
- textWidth: inline.width,
500
- characterSpacing: inline.characterSpacing,
501
- wordCount: 1,
502
- link: inline.link
503
- };
504
-
505
- if (inline.linkToDestination) {
506
- options.goTo = inline.linkToDestination;
507
- }
508
-
509
- if (line.id && i === 0) {
510
- options.destination = line.id;
511
- }
512
-
513
- if (inline.fontFeatures) {
514
- options.features = inline.fontFeatures;
515
- }
516
-
517
- var opacity = isNumber(inline.opacity) ? inline.opacity : 1;
518
- pdfKitDoc.opacity(opacity);
519
- pdfKitDoc.fill(inline.color || 'black');
520
-
521
- pdfKitDoc._font = inline.font;
522
- pdfKitDoc.fontSize(inline.fontSize);
523
-
524
- var shiftedY = offsetText(y + shiftToBaseline, inline);
525
- pdfKitDoc.text(inline.text, x + inline.x, shiftedY, options);
526
-
527
- if (inline.linkToPage) {
528
- var _ref = pdfKitDoc.ref({ Type: 'Action', S: 'GoTo', D: [inline.linkToPage, 0, 0] }).end();
529
- pdfKitDoc.annotate(x + inline.x, shiftedY, inline.width, inline.height, {
530
- Subtype: 'Link',
531
- Dest: [inline.linkToPage - 1, 'XYZ', null, null, null]
532
- });
533
- }
534
-
535
- }
536
- // Decorations won't draw correctly for superscript
537
- textDecorator.drawDecorations(line, x, y, pdfKitDoc);
538
- }
539
-
540
- function renderWatermark(page, pdfKitDoc) {
541
- var watermark = page.watermark;
542
-
543
- pdfKitDoc.fill(watermark.color);
544
- pdfKitDoc.opacity(watermark.opacity);
545
-
546
- pdfKitDoc.save();
547
-
548
- pdfKitDoc.rotate(watermark.angle, { origin: [pdfKitDoc.page.width / 2, pdfKitDoc.page.height / 2] });
549
-
550
- var x = pdfKitDoc.page.width / 2 - watermark._size.size.width / 2;
551
- var y = pdfKitDoc.page.height / 2 - watermark._size.size.height / 2;
552
-
553
- pdfKitDoc._font = watermark.font;
554
- pdfKitDoc.fontSize(watermark.fontSize);
555
- pdfKitDoc.text(watermark.text, x, y, { lineBreak: false });
556
-
557
- pdfKitDoc.restore();
558
- }
559
-
560
- function renderVector(vector, patterns, pdfKitDoc) {
561
- //TODO: pdf optimization (there's no need to write all properties everytime)
562
- pdfKitDoc.lineWidth(vector.lineWidth || 1);
563
- if (vector.dash) {
564
- pdfKitDoc.dash(vector.dash.length, { space: vector.dash.space || vector.dash.length, phase: vector.dash.phase || 0 });
565
- } else {
566
- pdfKitDoc.undash();
567
- }
568
- pdfKitDoc.lineJoin(vector.lineJoin || 'miter');
569
- pdfKitDoc.lineCap(vector.lineCap || 'butt');
570
-
571
- //TODO: clipping
572
-
573
- var gradient = null;
574
-
575
- switch (vector.type) {
576
- case 'ellipse':
577
- pdfKitDoc.ellipse(vector.x, vector.y, vector.r1, vector.r2);
578
-
579
- if (vector.linearGradient) {
580
- gradient = pdfKitDoc.linearGradient(vector.x - vector.r1, vector.y, vector.x + vector.r1, vector.y);
581
- }
582
- break;
583
- case 'rect':
584
- if (vector.r) {
585
- pdfKitDoc.roundedRect(vector.x, vector.y, vector.w, vector.h, vector.r);
586
- } else {
587
- pdfKitDoc.rect(vector.x, vector.y, vector.w, vector.h);
588
- }
589
-
590
- if (vector.linearGradient) {
591
- gradient = pdfKitDoc.linearGradient(vector.x, vector.y, vector.x + vector.w, vector.y);
592
- }
593
- break;
594
- case 'line':
595
- pdfKitDoc.moveTo(vector.x1, vector.y1);
596
- pdfKitDoc.lineTo(vector.x2, vector.y2);
597
- break;
598
- case 'polyline':
599
- if (vector.points.length === 0) {
600
- break;
601
- }
602
-
603
- pdfKitDoc.moveTo(vector.points[0].x, vector.points[0].y);
604
- for (var i = 1, l = vector.points.length; i < l; i++) {
605
- pdfKitDoc.lineTo(vector.points[i].x, vector.points[i].y);
606
- }
607
-
608
- if (vector.points.length > 1) {
609
- var p1 = vector.points[0];
610
- var pn = vector.points[vector.points.length - 1];
611
-
612
- if (vector.closePath || p1.x === pn.x && p1.y === pn.y) {
613
- pdfKitDoc.closePath();
614
- }
615
- }
616
- break;
617
- case 'path':
618
- pdfKitDoc.path(vector.d);
619
- break;
620
- }
621
-
622
- if (vector.linearGradient && gradient) {
623
- var step = 1 / (vector.linearGradient.length - 1);
624
-
625
- for (var i = 0; i < vector.linearGradient.length; i++) {
626
- gradient.stop(i * step, vector.linearGradient[i]);
627
- }
628
-
629
- vector.color = gradient;
630
- }
631
-
632
- if (isPattern(vector.color)) {
633
- vector.color = getPattern(vector.color, patterns);
634
- }
635
-
636
- var fillOpacity = isNumber(vector.fillOpacity) ? vector.fillOpacity : 1;
637
- var strokeOpacity = isNumber(vector.strokeOpacity) ? vector.strokeOpacity : 1;
638
-
639
- if (vector.color && vector.lineColor) {
640
- pdfKitDoc.fillColor(vector.color, fillOpacity);
641
- pdfKitDoc.strokeColor(vector.lineColor, strokeOpacity);
642
- pdfKitDoc.fillAndStroke();
643
- } else if (vector.color) {
644
- pdfKitDoc.fillColor(vector.color, fillOpacity);
645
- pdfKitDoc.fill();
646
- } else {
647
- pdfKitDoc.strokeColor(vector.lineColor || 'black', strokeOpacity);
648
- pdfKitDoc.stroke();
649
- }
650
- }
651
-
652
- function renderImage(image, x, y, pdfKitDoc) {
653
- var opacity = isNumber(image.opacity) ? image.opacity : 1;
654
- pdfKitDoc.opacity(opacity);
655
- if (image.cover) {
656
- var align = image.cover.align || 'center';
657
- var valign = image.cover.valign || 'center';
658
- var width = image.cover.width ? image.cover.width : image.width;
659
- var height = image.cover.height ? image.cover.height : image.height;
660
- pdfKitDoc.save();
661
- pdfKitDoc.rect(image.x, image.y, width, height).clip();
662
- pdfKitDoc.image(image.image, image.x, image.y, { cover: [width, height], align: align, valign: valign });
663
- pdfKitDoc.restore();
664
- } else {
665
- pdfKitDoc.image(image.image, image.x, image.y, { width: image._width, height: image._height });
666
- }
667
- if (image.link) {
668
- pdfKitDoc.link(image.x, image.y, image._width, image._height, image.link);
669
- }
670
- if (image.linkToPage) {
671
- pdfKitDoc.ref({ Type: 'Action', S: 'GoTo', D: [image.linkToPage, 0, 0] }).end();
672
- pdfKitDoc.annotate(image.x, image.y, image._width, image._height, { Subtype: 'Link', Dest: [image.linkToPage - 1, 'XYZ', null, null, null] });
673
- }
674
- if (image.linkToDestination) {
675
- pdfKitDoc.goTo(image.x, image.y, image._width, image._height, image.linkToDestination);
676
- }
677
- }
678
-
679
- function renderSVG(svg, x, y, pdfKitDoc, fontProvider) {
680
- var options = Object.assign({ width: svg._width, height: svg._height, assumePt: true }, svg.options);
681
- options.fontCallback = function (family, bold, italic) {
682
- var fontsFamily = family.split(',').map(function (f) { return f.trim().replace(/('|")/g, ''); });
683
- var font = findFont(fontProvider.fonts, fontsFamily, svg.font || 'Roboto');
684
-
685
- var fontFile = fontProvider.getFontFile(font, bold, italic);
686
- if (fontFile === null) {
687
- var type = fontProvider.getFontType(bold, italic);
688
- throw new Error('Font \'' + font + '\' in style \'' + type + '\' is not defined in the font section of the document definition.');
689
- }
690
-
691
- return fontFile;
692
- };
693
-
694
- SVGtoPDF(pdfKitDoc, svg.svg, svg.x, svg.y, options);
695
-
696
- if (svg.link) {
697
- pdfKitDoc.link(svg.x, svg.y, svg._width, svg._height, svg.link);
698
- }
699
- if (svg.linkToPage) {
700
- pdfKitDoc.ref({Type: 'Action', S: 'GoTo', D: [svg.linkToPage, 0, 0]}).end();
701
- pdfKitDoc.annotate(svg.x, svg.y, svg._width, svg._height, { Subtype: 'Link', Dest: [svg.linkToPage - 1, 'XYZ', null, null, null] });
702
- }
703
- if (svg.linkToDestination) {
704
- pdfKitDoc.goTo(svg.x, svg.y, svg._width, svg._height, svg.linkToDestination);
705
- }
706
- }
707
-
708
- function beginClip(rect, pdfKitDoc) {
709
- pdfKitDoc.save();
710
- pdfKitDoc.addContent('' + rect.x + ' ' + rect.y + ' ' + rect.width + ' ' + rect.height + ' re');
711
- pdfKitDoc.clip();
712
- }
713
-
714
- function endClip(pdfKitDoc) {
715
- pdfKitDoc.restore();
716
- }
717
-
718
- function createPatterns(patternDefinitions, pdfKitDoc) {
719
- var patterns = {};
720
- Object.keys(patternDefinitions).forEach(function (p) {
721
- var pattern = patternDefinitions[p];
722
- patterns[p] = pdfKitDoc.pattern(pattern.boundingBox, pattern.xStep, pattern.yStep, pattern.pattern, pattern.colored);
723
- });
724
- return patterns;
725
- }
726
-
727
- module.exports = PdfPrinter;
1
+ import PDFDocument from './PDFDocument';
2
+ import LayoutBuilder from './LayoutBuilder';
3
+ import SVGMeasure from './SVGMeasure';
4
+ import { normalizePageSize, normalizePageMargin } from './PageSize';
5
+ import { tableLayouts } from './tableLayouts';
6
+ import Renderer from './Renderer';
7
+ import { isNumber, isValue } from './helpers/variableType';
8
+ import { convertToDynamicContent } from './helpers/tools';
9
+ import { containsRTL } from './rtlUtils';
10
+
11
+ /**
12
+ * Printer which turns document definition into a pdf
13
+ *
14
+ * @example
15
+ * var fontDescriptors = {
16
+ * Roboto: {
17
+ * normal: 'fonts/Roboto-Regular.ttf',
18
+ * bold: 'fonts/Roboto-Medium.ttf',
19
+ * italics: 'fonts/Roboto-Italic.ttf',
20
+ * bolditalics: 'fonts/Roboto-MediumItalic.ttf'
21
+ * }
22
+ * };
23
+ *
24
+ * var printer = new PdfPrinter(fontDescriptors);
25
+ */
26
+ class PdfPrinter {
27
+
28
+ /**
29
+ * @param {object} fontDescriptors font definition dictionary
30
+ * @param {object} virtualfs
31
+ * @param {object} urlResolver
32
+ */
33
+ constructor(fontDescriptors, virtualfs = null, urlResolver = null) {
34
+ this.fontDescriptors = fontDescriptors;
35
+ this.virtualfs = virtualfs;
36
+ this.urlResolver = urlResolver;
37
+ }
38
+
39
+ /**
40
+ * Executes layout engine for the specified document and renders it into a pdfkit document
41
+ * ready to be saved.
42
+ *
43
+ * @param {object} docDefinition
44
+ * @param {object} options
45
+ * @returns {Promise<PDFDocument>} resolved promise return a pdfkit document
46
+ */
47
+ async createPdfKitDocument(docDefinition, options = {}) {
48
+ await this.resolveUrls(docDefinition);
49
+
50
+ docDefinition.version = docDefinition.version || '1.3';
51
+ docDefinition.subset = docDefinition.subset || undefined;
52
+ docDefinition.tagged = typeof docDefinition.tagged === 'boolean' ? docDefinition.tagged : false;
53
+ docDefinition.displayTitle = typeof docDefinition.displayTitle === 'boolean' ? docDefinition.displayTitle : false;
54
+ docDefinition.compress = typeof docDefinition.compress === 'boolean' ? docDefinition.compress : true;
55
+ docDefinition.images = docDefinition.images || {};
56
+ docDefinition.attachments = docDefinition.attachments || {};
57
+ docDefinition.pageMargins = isValue(docDefinition.pageMargins) ? docDefinition.pageMargins : 40;
58
+ docDefinition.patterns = docDefinition.patterns || {};
59
+
60
+ if (docDefinition.header && typeof docDefinition.header !== 'function') {
61
+ docDefinition.header = convertToDynamicContent(docDefinition.header);
62
+ }
63
+
64
+ if (docDefinition.footer && typeof docDefinition.footer !== 'function') {
65
+ docDefinition.footer = convertToDynamicContent(docDefinition.footer);
66
+ }
67
+
68
+ let pageSize = normalizePageSize(docDefinition.pageSize, docDefinition.pageOrientation);
69
+
70
+ let pdfOptions = {
71
+ size: [pageSize.width, pageSize.height],
72
+ pdfVersion: docDefinition.version,
73
+ subset: docDefinition.subset,
74
+ tagged: docDefinition.tagged,
75
+ displayTitle: docDefinition.displayTitle,
76
+ compress: docDefinition.compress,
77
+ userPassword: docDefinition.userPassword,
78
+ ownerPassword: docDefinition.ownerPassword,
79
+ permissions: docDefinition.permissions,
80
+ lang: docDefinition.language,
81
+ fontLayoutCache: typeof options.fontLayoutCache === 'boolean' ? options.fontLayoutCache : true,
82
+ bufferPages: options.bufferPages || false,
83
+ autoFirstPage: false,
84
+ info: createMetadata(docDefinition),
85
+ font: null
86
+ };
87
+
88
+ this.pdfKitDoc = new PDFDocument(this.fontDescriptors, docDefinition.images, docDefinition.patterns, docDefinition.attachments, pdfOptions, this.virtualfs);
89
+ embedFiles(docDefinition, this.pdfKitDoc);
90
+
91
+ const builder = new LayoutBuilder(pageSize, normalizePageMargin(docDefinition.pageMargins), new SVGMeasure());
92
+
93
+ builder.registerTableLayouts(tableLayouts);
94
+ if (options.tableLayouts) {
95
+ builder.registerTableLayouts(options.tableLayouts);
96
+ }
97
+
98
+ // Set default style with Cairo font for RTL content if available
99
+ const defaultStyle = docDefinition.defaultStyle || ((docDefinition.rtl === true || this._containsRTLContent(docDefinition.content)) ? { fontSize: 14, font: 'Cairo' } : { fontSize: 12, font: 'Roboto' });
100
+
101
+
102
+
103
+ let pages = builder.layoutDocument(docDefinition.content, this.pdfKitDoc, docDefinition.styles || {}, defaultStyle, docDefinition.background, docDefinition.header, docDefinition.footer, docDefinition.watermark, docDefinition.pageBreakBefore);
104
+ let maxNumberPages = docDefinition.maxPagesNumber || -1;
105
+ if (isNumber(maxNumberPages) && maxNumberPages > -1) {
106
+ pages = pages.slice(0, maxNumberPages);
107
+ }
108
+
109
+ // if pageSize.height is set to Infinity, calculate the actual height of the page that
110
+ // was laid out using the height of each of the items in the page.
111
+ pages.forEach(page => {
112
+ if (page.pageSize.height === Infinity) {
113
+ page.pageSize.height = calculatePageHeight(page, page.pageMargins);
114
+ }
115
+ });
116
+
117
+ const renderer = new Renderer(this.pdfKitDoc, options.progressCallback);
118
+ renderer.renderPages(pages);
119
+
120
+ return this.pdfKitDoc;
121
+ }
122
+
123
+ /**
124
+ * @param {object} docDefinition
125
+ * @returns {Promise}
126
+ */
127
+ async resolveUrls(docDefinition) {
128
+ const getExtendedUrl = url => {
129
+ if (typeof url === 'object') {
130
+ return { url: url.url, headers: url.headers };
131
+ }
132
+
133
+ return { url: url, headers: {} };
134
+ };
135
+
136
+ if (this.urlResolver === null) {
137
+ return;
138
+ }
139
+
140
+ for (let font in this.fontDescriptors) {
141
+ if (this.fontDescriptors.hasOwnProperty(font)) {
142
+ if (this.fontDescriptors[font].normal) {
143
+ if (Array.isArray(this.fontDescriptors[font].normal)) { // TrueType Collection
144
+ let url = getExtendedUrl(this.fontDescriptors[font].normal[0]);
145
+ this.urlResolver.resolve(url.url, url.headers);
146
+ this.fontDescriptors[font].normal[0] = url.url;
147
+ } else {
148
+ let url = getExtendedUrl(this.fontDescriptors[font].normal);
149
+ this.urlResolver.resolve(url.url, url.headers);
150
+ this.fontDescriptors[font].normal = url.url;
151
+ }
152
+ }
153
+ if (this.fontDescriptors[font].bold) {
154
+ if (Array.isArray(this.fontDescriptors[font].bold)) { // TrueType Collection
155
+ let url = getExtendedUrl(this.fontDescriptors[font].bold[0]);
156
+ this.urlResolver.resolve(url.url, url.headers);
157
+ this.fontDescriptors[font].bold[0] = url.url;
158
+ } else {
159
+ let url = getExtendedUrl(this.fontDescriptors[font].bold);
160
+ this.urlResolver.resolve(url.url, url.headers);
161
+ this.fontDescriptors[font].bold = url.url;
162
+ }
163
+ }
164
+ if (this.fontDescriptors[font].italics) {
165
+ if (Array.isArray(this.fontDescriptors[font].italics)) { // TrueType Collection
166
+ let url = getExtendedUrl(this.fontDescriptors[font].italics[0]);
167
+ this.urlResolver.resolve(url.url, url.headers);
168
+ this.fontDescriptors[font].italics[0] = url.url;
169
+ } else {
170
+ let url = getExtendedUrl(this.fontDescriptors[font].italics);
171
+ this.urlResolver.resolve(url.url, url.headers);
172
+ this.fontDescriptors[font].italics = url.url;
173
+ }
174
+ }
175
+ if (this.fontDescriptors[font].bolditalics) {
176
+ if (Array.isArray(this.fontDescriptors[font].bolditalics)) { // TrueType Collection
177
+ let url = getExtendedUrl(this.fontDescriptors[font].bolditalics[0]);
178
+ this.urlResolver.resolve(url.url, url.headers);
179
+ this.fontDescriptors[font].bolditalics[0] = url.url;
180
+ } else {
181
+ let url = getExtendedUrl(this.fontDescriptors[font].bolditalics);
182
+ this.urlResolver.resolve(url.url, url.headers);
183
+ this.fontDescriptors[font].bolditalics = url.url;
184
+ }
185
+ }
186
+ }
187
+ }
188
+
189
+ if (docDefinition.images) {
190
+ for (let image in docDefinition.images) {
191
+ if (docDefinition.images.hasOwnProperty(image)) {
192
+ let url = getExtendedUrl(docDefinition.images[image]);
193
+ this.urlResolver.resolve(url.url, url.headers);
194
+ docDefinition.images[image] = url.url;
195
+ }
196
+ }
197
+ }
198
+
199
+ if (docDefinition.attachments) {
200
+ for (let attachment in docDefinition.attachments) {
201
+ if (docDefinition.attachments.hasOwnProperty(attachment) && docDefinition.attachments[attachment].src) {
202
+ let url = getExtendedUrl(docDefinition.attachments[attachment].src);
203
+ this.urlResolver.resolve(url.url, url.headers);
204
+ docDefinition.attachments[attachment].src = url.url;
205
+ }
206
+ }
207
+ }
208
+
209
+ if (docDefinition.files) {
210
+ for (let file in docDefinition.files) {
211
+ if (docDefinition.files.hasOwnProperty(file) && docDefinition.files[file].src) {
212
+ let url = getExtendedUrl(docDefinition.files[file].src);
213
+ this.urlResolver.resolve(url.url, url.headers);
214
+ docDefinition.files[file].src = url.url;
215
+ }
216
+ }
217
+ }
218
+
219
+ await this.urlResolver.resolved();
220
+ }
221
+
222
+ /**
223
+ * Check if content contains RTL characters
224
+ * @param {any} content - Document content
225
+ * @returns {boolean} - True if content contains RTL characters
226
+ * @private
227
+ */
228
+ _containsRTLContent(content) {
229
+ if (!content) {
230
+ return false;
231
+ }
232
+
233
+ // Handle arrays
234
+ if (Array.isArray(content)) {
235
+ return content.some(item => this._containsRTLContent(item));
236
+ }
237
+
238
+ // Handle strings
239
+ if (typeof content === 'string') {
240
+ return containsRTL(content);
241
+ }
242
+
243
+ // Handle objects
244
+ if (typeof content === 'object') {
245
+ // Check rtl property
246
+ if (content.rtl === true) {
247
+ return true;
248
+ }
249
+
250
+ // Check text content
251
+ if (content.text) {
252
+ const textStr = typeof content.text === 'string' ? content.text :
253
+ Array.isArray(content.text) ? content.text.join('') : String(content.text);
254
+ if (containsRTL(textStr)) {
255
+ return true;
256
+ }
257
+ }
258
+
259
+ // Check nested structures
260
+ if (content.stack && this._containsRTLContent(content.stack)) {
261
+ return true;
262
+ }
263
+ if (content.columns && this._containsRTLContent(content.columns)) {
264
+ return true;
265
+ }
266
+ if (content.ul && this._containsRTLContent(content.ul)) {
267
+ return true;
268
+ }
269
+ if (content.ol && this._containsRTLContent(content.ol)) {
270
+ return true;
271
+ }
272
+ if (content.table && content.table.body && this._containsRTLContent(content.table.body)) {
273
+ return true;
274
+ }
275
+ }
276
+
277
+ return false;
278
+ }
279
+ }
280
+
281
+ function createMetadata(docDefinition) {
282
+ // PDF standard has these properties reserved: Title, Author, Subject, Keywords,
283
+ // Creator, Producer, CreationDate, ModDate, Trapped.
284
+ // To keep the pdfmake api consistent, the info field are defined lowercase.
285
+ // Custom properties don't contain a space.
286
+ function standardizePropertyKey(key) {
287
+ let standardProperties = ['Title', 'Author', 'Subject', 'Keywords',
288
+ 'Creator', 'Producer', 'CreationDate', 'ModDate', 'Trapped'];
289
+ let standardizedKey = key.charAt(0).toUpperCase() + key.slice(1);
290
+ if (standardProperties.includes(standardizedKey)) {
291
+ return standardizedKey;
292
+ }
293
+
294
+ return key.replace(/\s+/g, '');
295
+ }
296
+
297
+ let info = {
298
+ Producer: 'pdfmake',
299
+ Creator: 'pdfmake'
300
+ };
301
+
302
+ if (docDefinition.info) {
303
+ for (let key in docDefinition.info) {
304
+ let value = docDefinition.info[key];
305
+ if (value) {
306
+ key = standardizePropertyKey(key);
307
+ info[key] = value;
308
+ }
309
+ }
310
+ }
311
+ return info;
312
+ }
313
+
314
+ function embedFiles(docDefinition, pdfKitDoc) {
315
+ if (docDefinition.files) {
316
+ for (const key in docDefinition.files) {
317
+ const file = docDefinition.files[key];
318
+
319
+ if (!file.src) return;
320
+
321
+ if (pdfKitDoc.virtualfs && pdfKitDoc.virtualfs.existsSync(file.src)) {
322
+ file.src = pdfKitDoc.virtualfs.readFileSync(file.src);
323
+ }
324
+
325
+ file.name = file.name || key;
326
+ pdfKitDoc.file(file.src, file);
327
+ }
328
+ }
329
+ }
330
+
331
+ function calculatePageHeight(page, margins) {
332
+ function getItemHeight(item) {
333
+ if (typeof item.item.getHeight === 'function') {
334
+ return item.item.getHeight();
335
+ } else if (item.item._height) {
336
+ return item.item._height;
337
+ } else if (item.type === 'vector') {
338
+ if (typeof item.item.y1 !== 'undefined') {
339
+ return item.item.y1 > item.item.y2 ? item.item.y1 : item.item.y2;
340
+ } else {
341
+ return item.item.h;
342
+ }
343
+ } else {
344
+ // TODO: add support for next item types
345
+ return 0;
346
+ }
347
+ }
348
+
349
+ function getBottomPosition(item) {
350
+ let top = item.item.y || 0;
351
+ let height = getItemHeight(item);
352
+ return top + height;
353
+ }
354
+
355
+ let fixedMargins = normalizePageMargin(margins || 40);
356
+ let height = fixedMargins.top;
357
+
358
+ page.items.forEach(item => {
359
+ let bottomPosition = getBottomPosition(item);
360
+ if (bottomPosition > height) {
361
+ height = bottomPosition;
362
+ }
363
+ });
364
+
365
+ height += fixedMargins.bottom;
366
+
367
+ return height;
368
+ }
369
+
370
+ export default PdfPrinter;