pdfmake 0.3.0-beta.9 → 0.3.0

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 (74) hide show
  1. package/CHANGELOG.md +7 -48
  2. package/LICENSE +1 -1
  3. package/README.md +78 -85
  4. package/build/pdfmake.js +66833 -75014
  5. package/build/pdfmake.js.map +1 -1
  6. package/build/pdfmake.min.js +2 -2
  7. package/build/pdfmake.min.js.map +1 -1
  8. package/build/vfs_fonts.js +4 -4
  9. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  10. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  11. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  12. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  13. package/js/DocMeasure.js +20 -1
  14. package/js/DocPreprocessor.js +21 -6
  15. package/js/DocumentContext.js +64 -17
  16. package/js/ElementWriter.js +31 -8
  17. package/js/LayoutBuilder.js +488 -127
  18. package/js/OutputDocument.js +22 -34
  19. package/js/OutputDocumentServer.js +6 -11
  20. package/js/PDFDocument.js +1 -1
  21. package/js/PageElementWriter.js +17 -2
  22. package/js/Printer.js +133 -133
  23. package/js/Renderer.js +22 -14
  24. package/js/SVGMeasure.js +2 -2
  25. package/js/StyleContextStack.js +4 -0
  26. package/js/TableProcessor.js +40 -14
  27. package/js/TextBreaker.js +31 -4
  28. package/js/TextInlines.js +1 -1
  29. package/js/URLResolver.js +25 -55
  30. package/js/base.js +1 -1
  31. package/js/browser-extensions/OutputDocumentBrowser.js +35 -72
  32. package/js/browser-extensions/index.js +2 -2
  33. package/js/browser-extensions/pdfMake.js +0 -12
  34. package/js/browser-extensions/standard-fonts/Courier.js +4 -4
  35. package/js/browser-extensions/standard-fonts/Helvetica.js +4 -4
  36. package/js/browser-extensions/standard-fonts/Symbol.js +1 -1
  37. package/js/browser-extensions/standard-fonts/Times.js +4 -4
  38. package/js/browser-extensions/standard-fonts/ZapfDingbats.js +1 -1
  39. package/js/helpers/tools.js +6 -0
  40. package/js/index.js +1 -1
  41. package/package.json +25 -24
  42. package/src/DocMeasure.js +21 -1
  43. package/src/DocPreprocessor.js +25 -6
  44. package/src/DocumentContext.js +56 -20
  45. package/src/ElementWriter.js +30 -7
  46. package/src/LayoutBuilder.js +531 -144
  47. package/src/OutputDocument.js +23 -37
  48. package/src/OutputDocumentServer.js +6 -11
  49. package/src/PDFDocument.js +1 -1
  50. package/src/PageElementWriter.js +21 -2
  51. package/src/Printer.js +134 -131
  52. package/src/Renderer.js +13 -15
  53. package/src/SVGMeasure.js +2 -2
  54. package/src/StyleContextStack.js +4 -0
  55. package/src/TableProcessor.js +42 -18
  56. package/src/TextBreaker.js +24 -5
  57. package/src/TextInlines.js +1 -1
  58. package/src/URLResolver.js +24 -58
  59. package/src/base.js +1 -1
  60. package/src/browser-extensions/OutputDocumentBrowser.js +33 -71
  61. package/src/browser-extensions/index.js +3 -3
  62. package/src/browser-extensions/pdfMake.js +0 -14
  63. package/src/browser-extensions/standard-fonts/Courier.js +4 -4
  64. package/src/browser-extensions/standard-fonts/Helvetica.js +4 -4
  65. package/src/browser-extensions/standard-fonts/Symbol.js +1 -1
  66. package/src/browser-extensions/standard-fonts/Times.js +4 -4
  67. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +1 -1
  68. package/src/columnCalculator.js +12 -12
  69. package/src/helpers/tools.js +5 -0
  70. package/src/helpers/variableType.js +1 -1
  71. package/src/index.js +1 -1
  72. package/standard-fonts/Helvetica.js +0 -1
  73. package/js/browser-extensions/URLBrowserResolver.js +0 -76
  74. package/src/browser-extensions/URLBrowserResolver.js +0 -84
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdfmake",
3
- "version": "0.3.0-beta.9",
3
+ "version": "0.3.0",
4
4
  "description": "Client/server side PDF printing in pure JavaScript",
5
5
  "main": "js/index.js",
6
6
  "esnext": "src/index.js",
@@ -9,44 +9,45 @@
9
9
  "test": "tests"
10
10
  },
11
11
  "dependencies": {
12
- "@foliojs-fork/linebreak": "^1.1.1",
13
- "@foliojs-fork/pdfkit": "^0.14.0",
14
- "iconv-lite": "^0.6.3",
15
- "xmldoc": "^1.3.0"
12
+ "linebreak": "^1.1.0",
13
+ "pdfkit": "^0.17.2",
14
+ "xmldoc": "^2.0.3"
16
15
  },
17
16
  "devDependencies": {
18
- "@babel/cli": "^7.23.4",
19
- "@babel/core": "^7.23.6",
20
- "@babel/plugin-transform-modules-commonjs": "^7.23.3",
21
- "@babel/preset-env": "^7.23.6",
17
+ "@babel/cli": "^7.28.3",
18
+ "@babel/core": "^7.28.5",
19
+ "@babel/plugin-transform-modules-commonjs": "^7.27.1",
20
+ "@babel/preset-env": "^7.28.5",
21
+ "@eslint/js": "^9.39.2",
22
22
  "assert": "^2.1.0",
23
- "babel-loader": "^9.1.3",
23
+ "babel-loader": "^10.0.0",
24
24
  "brfs": "^2.0.2",
25
25
  "browserify-zlib": "^0.2.0",
26
- "buffer": "6.0.3",
27
- "core-js": "3.19.0",
28
- "eslint": "^8.55.0",
29
- "eslint-plugin-jsdoc": "^46.9.1",
30
- "expose-loader": "^4.1.0",
26
+ "buffer": "^6.0.3",
27
+ "core-js": "^3.47.0",
28
+ "eslint": "^9.39.2",
29
+ "eslint-plugin-jsdoc": "^61.5.0",
30
+ "expose-loader": "^5.0.1",
31
31
  "file-saver": "^2.0.5",
32
- "mocha": "^10.2.0",
32
+ "globals": "^16.5.0",
33
+ "mocha": "^11.7.5",
33
34
  "npm-run-all": "^4.1.5",
34
35
  "process": "^0.11.10",
35
- "rewire": "^7.0.0",
36
- "shx": "^0.3.4",
37
- "sinon": "^17.0.1",
38
- "source-map-loader": "^4.0.1",
36
+ "rewire": "^9.0.1",
37
+ "shx": "^0.4.0",
38
+ "sinon": "^21.0.1",
39
+ "source-map-loader": "^5.0.0",
39
40
  "stream-browserify": "^3.0.0",
40
41
  "string-replace-webpack-plugin": "^0.1.3",
41
42
  "svg-to-pdfkit": "^0.1.8",
42
- "terser-webpack-plugin": "^5.3.9",
43
+ "terser-webpack-plugin": "^5.3.16",
43
44
  "transform-loader": "^0.2.4",
44
45
  "util": "^0.12.5",
45
- "webpack": "^5.89.0",
46
- "webpack-cli": "^5.1.4"
46
+ "webpack": "^5.104.1",
47
+ "webpack-cli": "^6.0.1"
47
48
  },
48
49
  "engines": {
49
- "node": ">=16"
50
+ "node": ">=20"
50
51
  },
51
52
  "scripts": {
52
53
  "test": "run-s build mocha lint",
package/src/DocMeasure.js CHANGED
@@ -34,12 +34,18 @@ class DocMeasure {
34
34
  return this.measureNode(docStructure);
35
35
  }
36
36
 
37
+ measureBlock(node) {
38
+ return this.measureNode(node);
39
+ }
40
+
37
41
  measureNode(node) {
38
42
  return this.styleStack.auto(node, () => {
39
43
  // TODO: refactor + rethink whether this is the proper way to handle margins
40
44
  node._margin = getNodeMargin(node, this.styleStack);
41
45
 
42
- if (node.columns) {
46
+ if (node.section) {
47
+ return extendMargins(this.measureSection(node));
48
+ } else if (node.columns) {
43
49
  return extendMargins(this.measureColumns(node));
44
50
  } else if (node.stack) {
45
51
  return extendMargins(this.measureVerticalContainer(node));
@@ -128,8 +134,14 @@ class DocMeasure {
128
134
  this.convertIfBase64Image(node);
129
135
 
130
136
  let image = this.pdfDocument.provideImage(node.image);
137
+
131
138
  let imageSize = { width: image.width, height: image.height };
132
139
 
140
+ // If EXIF orientation calls for it, swap width and height
141
+ if (image.orientation > 4) {
142
+ imageSize = { width: image.height, height: image.width };
143
+ }
144
+
133
145
  this.measureImageWithDimensions(node, imageSize);
134
146
 
135
147
  return node;
@@ -459,6 +471,14 @@ class DocMeasure {
459
471
  return node;
460
472
  }
461
473
 
474
+ measureSection(node) {
475
+ // TODO: properties
476
+
477
+ node.section = this.measureNode(node.section);
478
+
479
+ return node;
480
+ }
481
+
462
482
  measureColumns(node) {
463
483
  let columns = node.columns;
464
484
  node._gap = this.styleStack.getProperty('columnGap') || 0;
@@ -20,10 +20,17 @@ class DocPreprocessor {
20
20
  this.parentNode = null;
21
21
  this.tocs = [];
22
22
  this.nodeReferences = [];
23
- return this.preprocessNode(docStructure);
23
+ return this.preprocessNode(docStructure, true);
24
24
  }
25
25
 
26
- preprocessNode(node) {
26
+ preprocessBlock(node) {
27
+ this.parentNode = null;
28
+ this.tocs = [];
29
+ this.nodeReferences = [];
30
+ return this.preprocessNode(node);
31
+ }
32
+
33
+ preprocessNode(node, isSectionAllowed = false) {
27
34
  // expand shortcuts and casting values
28
35
  if (Array.isArray(node)) {
29
36
  node = { stack: node };
@@ -33,10 +40,16 @@ class DocPreprocessor {
33
40
  node.text = convertValueToString(node.text);
34
41
  }
35
42
 
36
- if (node.columns) {
43
+ if (node.section) {
44
+ if (!isSectionAllowed) {
45
+ throw new Error(`Incorrect document structure, section node is only allowed at the root level of document structure: ${stringifyNode(node)}`);
46
+ }
47
+
48
+ return this.preprocessSection(node);
49
+ } else if (node.columns) {
37
50
  return this.preprocessColumns(node);
38
51
  } else if (node.stack) {
39
- return this.preprocessVerticalContainer(node);
52
+ return this.preprocessVerticalContainer(node, isSectionAllowed);
40
53
  } else if (node.ul) {
41
54
  return this.preprocessList(node);
42
55
  } else if (node.ol) {
@@ -64,6 +77,12 @@ class DocPreprocessor {
64
77
  }
65
78
  }
66
79
 
80
+ preprocessSection(node) {
81
+ node.section = this.preprocessNode(node.section);
82
+
83
+ return node;
84
+ }
85
+
67
86
  preprocessColumns(node) {
68
87
  let columns = node.columns;
69
88
 
@@ -74,11 +93,11 @@ class DocPreprocessor {
74
93
  return node;
75
94
  }
76
95
 
77
- preprocessVerticalContainer(node) {
96
+ preprocessVerticalContainer(node, isSectionAllowed) {
78
97
  let items = node.stack;
79
98
 
80
99
  for (let i = 0, l = items.length; i < l; i++) {
81
- items[i] = this.preprocessNode(items[i]);
100
+ items[i] = this.preprocessNode(items[i], isSectionAllowed);
82
101
  }
83
102
 
84
103
  return node;
@@ -6,30 +6,27 @@ import { EventEmitter } from 'events';
6
6
  * It facilitates column divisions and vertical sync
7
7
  */
8
8
  class DocumentContext extends EventEmitter {
9
- constructor(pageSize, pageMargins) {
9
+ constructor() {
10
10
  super();
11
11
  this.pages = [];
12
-
13
- this.pageMargins = pageMargins;
14
-
15
- this.x = pageMargins.left;
16
- this.availableWidth = pageSize.width - pageMargins.left - pageMargins.right;
17
- this.availableHeight = 0;
12
+ this.pageMargins = undefined;
13
+ this.x = undefined;
14
+ this.availableWidth = undefined;
15
+ this.availableHeight = undefined;
18
16
  this.page = -1;
19
17
 
20
18
  this.snapshots = [];
21
19
  this.backgroundLength = [];
22
-
23
- this.addPage(pageSize);
24
20
  }
25
21
 
26
- beginColumnGroup() {
22
+ beginColumnGroup(marginXTopParent, bottomByPage = {}) {
27
23
  this.snapshots.push({
28
24
  x: this.x,
29
25
  y: this.y,
30
26
  availableHeight: this.availableHeight,
31
27
  availableWidth: this.availableWidth,
32
28
  page: this.page,
29
+ bottomByPage: bottomByPage ? bottomByPage : {},
33
30
  bottomMost: {
34
31
  x: this.x,
35
32
  y: this.y,
@@ -41,6 +38,23 @@ class DocumentContext extends EventEmitter {
41
38
  });
42
39
 
43
40
  this.lastColumnWidth = 0;
41
+ if (marginXTopParent) {
42
+ this.marginXTopParent = marginXTopParent;
43
+ }
44
+ }
45
+
46
+ updateBottomByPage() {
47
+ const lastSnapshot = this.snapshots[this.snapshots.length - 1];
48
+ const lastPage = this.page;
49
+ let previousBottom = -Number.MIN_VALUE;
50
+ if (lastSnapshot.bottomByPage[lastPage]) {
51
+ previousBottom = lastSnapshot.bottomByPage[lastPage];
52
+ }
53
+ lastSnapshot.bottomByPage[lastPage] = Math.max(previousBottom, this.y);
54
+ }
55
+
56
+ resetMarginXTopParent() {
57
+ this.marginXTopParent = null;
44
58
  }
45
59
 
46
60
  beginColumn(width, offset, endingCell) {
@@ -65,10 +79,10 @@ class DocumentContext extends EventEmitter {
65
79
  }
66
80
  }
67
81
 
68
- markEnding(endingCell) {
82
+ markEnding(endingCell, originalXOffset, discountY) {
69
83
  this.page = endingCell._columnEndingContext.page;
70
- this.x = endingCell._columnEndingContext.x;
71
- this.y = endingCell._columnEndingContext.y;
84
+ this.x = endingCell._columnEndingContext.x + originalXOffset;
85
+ this.y = endingCell._columnEndingContext.y - discountY;
72
86
  this.availableWidth = endingCell._columnEndingContext.availableWidth;
73
87
  this.availableHeight = endingCell._columnEndingContext.availableHeight;
74
88
  this.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth;
@@ -111,6 +125,7 @@ class DocumentContext extends EventEmitter {
111
125
  this.availableHeight -= (y - saved.bottomMost.y);
112
126
  }
113
127
  this.lastColumnWidth = saved.lastColumnWidth;
128
+ return saved.bottomByPage;
114
129
  }
115
130
 
116
131
  addMargin(left, right) {
@@ -128,14 +143,19 @@ class DocumentContext extends EventEmitter {
128
143
  initializePage() {
129
144
  this.y = this.pageMargins.top;
130
145
  this.availableHeight = this.getCurrentPage().pageSize.height - this.pageMargins.top - this.pageMargins.bottom;
131
- this.pageSnapshot().availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right;
146
+ const { pageCtx, isSnapshot } = this.pageSnapshot();
147
+ pageCtx.availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right;
148
+ if (isSnapshot && this.marginXTopParent) {
149
+ pageCtx.availableWidth -= this.marginXTopParent[0];
150
+ pageCtx.availableWidth -= this.marginXTopParent[1];
151
+ }
132
152
  }
133
153
 
134
154
  pageSnapshot() {
135
155
  if (this.snapshots[0]) {
136
- return this.snapshots[0];
156
+ return { pageCtx: this.snapshots[0], isSnapshot: true };
137
157
  } else {
138
- return this;
158
+ return { pageCtx: this, isSnapshot: false };
139
159
  }
140
160
  }
141
161
 
@@ -186,13 +206,23 @@ class DocumentContext extends EventEmitter {
186
206
  let prevPage = this.page;
187
207
  let prevY = this.y;
188
208
 
209
+ // If we are in a column group
210
+ if (this.snapshots.length > 0) {
211
+ let lastSnapshot = this.snapshots[this.snapshots.length - 1];
212
+ // We have to update prevY accordingly by also taking into consideration
213
+ // the 'y' of cells that don't break page
214
+ if (lastSnapshot.bottomMost && lastSnapshot.bottomMost.y) {
215
+ prevY = Math.max(this.y, lastSnapshot.bottomMost.y);
216
+ }
217
+ }
218
+
189
219
  let createNewPage = nextPageIndex >= this.pages.length;
190
220
  if (createNewPage) {
191
221
  let currentAvailableWidth = this.availableWidth;
192
222
  let currentPageOrientation = this.getCurrentPage().pageSize.orientation;
193
223
 
194
224
  let pageSize = getPageSize(this.getCurrentPage(), pageOrientation);
195
- this.addPage(pageSize);
225
+ this.addPage(pageSize, null, this.getCurrentPage().customProperties);
196
226
 
197
227
  if (currentPageOrientation === pageSize.orientation) {
198
228
  this.availableWidth = currentAvailableWidth;
@@ -210,14 +240,20 @@ class DocumentContext extends EventEmitter {
210
240
  };
211
241
  }
212
242
 
213
- addPage(pageSize) {
214
- let page = { items: [], pageSize: pageSize };
243
+ addPage(pageSize, pageMargin = null, customProperties = {}) {
244
+ if (pageMargin !== null) {
245
+ this.pageMargins = pageMargin;
246
+ this.x = pageMargin.left;
247
+ this.availableWidth = pageSize.width - pageMargin.left - pageMargin.right;
248
+ }
249
+
250
+ let page = { items: [], pageSize: pageSize, pageMargins: this.pageMargins, customProperties: customProperties };
215
251
  this.pages.push(page);
216
252
  this.backgroundLength.push(0);
217
253
  this.page = this.pages.length - 1;
218
254
  this.initializePage();
219
255
 
220
- this.emit('pageAdded');
256
+ this.emit('pageAdded', page);
221
257
 
222
258
  return page;
223
259
  }
@@ -8,12 +8,19 @@ import { EventEmitter } from 'events';
8
8
  * their positions based on the context
9
9
  */
10
10
  class ElementWriter extends EventEmitter {
11
+
12
+ /**
13
+ * @param {DocumentContext} context
14
+ */
11
15
  constructor(context) {
12
16
  super();
13
17
  this._context = context;
14
18
  this.contextStack = [];
15
19
  }
16
20
 
21
+ /**
22
+ * @returns {DocumentContext}
23
+ */
17
24
  context() {
18
25
  return this._context;
19
26
  }
@@ -259,9 +266,12 @@ class ElementWriter extends EventEmitter {
259
266
  }
260
267
  }
261
268
 
262
- addVector(vector, ignoreContextX, ignoreContextY, index) {
269
+ addVector(vector, ignoreContextX, ignoreContextY, index, forcePage) {
263
270
  let context = this.context();
264
271
  let page = context.getCurrentPage();
272
+ if (isNumber(forcePage)) {
273
+ page = context.pages[forcePage];
274
+ }
265
275
  let position = this.getCurrentPositionOnPage();
266
276
 
267
277
  if (page) {
@@ -322,10 +332,21 @@ class ElementWriter extends EventEmitter {
322
332
  var v = pack(item.item);
323
333
 
324
334
  offsetVector(v, useBlockXOffset ? (block.xOffset || 0) : ctx.x, useBlockYOffset ? (block.yOffset || 0) : ctx.y);
325
- page.items.push({
326
- type: 'vector',
327
- item: v
328
- });
335
+ if (v._isFillColorFromUnbreakable) {
336
+ // If the item is a fillColor from an unbreakable block
337
+ // We have to add it at the beginning of the items body array of the page
338
+ delete v._isFillColorFromUnbreakable;
339
+ const endOfBackgroundItemsIndex = ctx.backgroundLength[ctx.page];
340
+ page.items.splice(endOfBackgroundItemsIndex, 0, {
341
+ type: 'vector',
342
+ item: v
343
+ });
344
+ } else {
345
+ page.items.push({
346
+ type: 'vector',
347
+ item: v
348
+ });
349
+ }
329
350
  break;
330
351
 
331
352
  case 'image':
@@ -357,7 +378,7 @@ class ElementWriter extends EventEmitter {
357
378
  * pushContext(width, height) - creates and pushes a new context with the specified width and height
358
379
  * pushContext() - creates a new context for unbreakable blocks (with current availableWidth and full-page-height)
359
380
  *
360
- * @param {object|number} contextOrWidth
381
+ * @param {DocumentContext|number} contextOrWidth
361
382
  * @param {number} height
362
383
  */
363
384
  pushContext(contextOrWidth, height) {
@@ -367,7 +388,9 @@ class ElementWriter extends EventEmitter {
367
388
  }
368
389
 
369
390
  if (isNumber(contextOrWidth)) {
370
- contextOrWidth = new DocumentContext({ width: contextOrWidth, height: height }, { left: 0, right: 0, top: 0, bottom: 0 });
391
+ let width = contextOrWidth;
392
+ contextOrWidth = new DocumentContext();
393
+ contextOrWidth.addPage({ width: width, height: height }, { left: 0, right: 0, top: 0, bottom: 0 });
371
394
  }
372
395
 
373
396
  this.contextStack.push(this.context());