pdfmake 0.2.13 → 0.3.0-beta.10

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 (136) hide show
  1. package/CHANGELOG.md +23 -41
  2. package/README.md +11 -7
  3. package/build/pdfmake.js +22291 -23202
  4. package/build/pdfmake.js.map +1 -1
  5. package/build/pdfmake.min.js +2 -2
  6. package/build/pdfmake.min.js.map +1 -1
  7. package/build/standard-fonts/Courier.js +27 -0
  8. package/build/standard-fonts/Helvetica.js +27 -0
  9. package/build/standard-fonts/Symbol.js +21 -0
  10. package/build/standard-fonts/Times.js +27 -0
  11. package/build/standard-fonts/ZapfDingbats.js +21 -0
  12. package/build/vfs_fonts.js +2 -2
  13. package/build-vfs.js +2 -2
  14. package/eslint.config.mjs +52 -0
  15. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  16. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  17. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  18. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  19. package/fonts/Roboto.js +8 -0
  20. package/js/3rd-party/svg-to-pdfkit/source.js +3626 -0
  21. package/js/3rd-party/svg-to-pdfkit.js +7 -0
  22. package/js/DocMeasure.js +626 -0
  23. package/js/DocPreprocessor.js +238 -0
  24. package/js/DocumentContext.js +288 -0
  25. package/js/ElementWriter.js +342 -0
  26. package/js/LayoutBuilder.js +881 -0
  27. package/js/Line.js +105 -0
  28. package/js/OutputDocument.js +76 -0
  29. package/js/OutputDocumentServer.js +27 -0
  30. package/js/PDFDocument.js +144 -0
  31. package/js/PageElementWriter.js +140 -0
  32. package/js/PageSize.js +74 -0
  33. package/js/Printer.js +291 -0
  34. package/js/Renderer.js +375 -0
  35. package/js/SVGMeasure.js +69 -0
  36. package/js/StyleContextStack.js +164 -0
  37. package/js/TableProcessor.js +524 -0
  38. package/js/TextBreaker.js +139 -0
  39. package/js/TextDecorator.js +143 -0
  40. package/js/TextInlines.js +206 -0
  41. package/js/URLResolver.js +73 -0
  42. package/js/base.js +52 -0
  43. package/js/browser-extensions/OutputDocumentBrowser.js +118 -0
  44. package/js/browser-extensions/URLBrowserResolver.js +76 -0
  45. package/js/browser-extensions/fonts/Roboto.js +38 -0
  46. package/js/browser-extensions/index.js +53 -0
  47. package/js/browser-extensions/pdfMake.js +3 -0
  48. package/js/browser-extensions/standard-fonts/Courier.js +38 -0
  49. package/js/browser-extensions/standard-fonts/Helvetica.js +38 -0
  50. package/js/browser-extensions/standard-fonts/Symbol.js +23 -0
  51. package/js/browser-extensions/standard-fonts/Times.js +38 -0
  52. package/js/browser-extensions/standard-fonts/ZapfDingbats.js +23 -0
  53. package/js/browser-extensions/virtual-fs-cjs.js +3 -0
  54. package/js/columnCalculator.js +148 -0
  55. package/js/helpers/node.js +98 -0
  56. package/js/helpers/tools.js +40 -0
  57. package/js/helpers/variableType.js +59 -0
  58. package/js/index.js +15 -0
  59. package/js/qrEnc.js +721 -0
  60. package/js/standardPageSizes.js +56 -0
  61. package/js/tableLayouts.js +98 -0
  62. package/js/virtual-fs.js +60 -0
  63. package/package.json +34 -28
  64. package/src/3rd-party/svg-to-pdfkit.js +2 -2
  65. package/src/DocMeasure.js +707 -0
  66. package/src/DocPreprocessor.js +264 -0
  67. package/src/DocumentContext.js +324 -0
  68. package/src/ElementWriter.js +405 -0
  69. package/src/LayoutBuilder.js +997 -0
  70. package/src/Line.js +114 -0
  71. package/src/OutputDocument.js +78 -0
  72. package/src/OutputDocumentServer.js +26 -0
  73. package/src/PDFDocument.js +174 -0
  74. package/src/PageElementWriter.js +160 -0
  75. package/src/PageSize.js +53 -0
  76. package/src/Printer.js +306 -0
  77. package/src/Renderer.js +405 -0
  78. package/src/SVGMeasure.js +79 -0
  79. package/src/StyleContextStack.js +175 -0
  80. package/src/TableProcessor.js +580 -0
  81. package/src/TextBreaker.js +149 -0
  82. package/src/TextDecorator.js +161 -0
  83. package/src/TextInlines.js +223 -0
  84. package/src/URLResolver.js +77 -0
  85. package/src/base.js +61 -0
  86. package/src/browser-extensions/OutputDocumentBrowser.js +117 -0
  87. package/src/browser-extensions/URLBrowserResolver.js +45 -57
  88. package/src/browser-extensions/fonts/Roboto.js +27 -0
  89. package/src/browser-extensions/index.js +55 -0
  90. package/src/browser-extensions/pdfMake.js +1 -329
  91. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  92. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  93. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  94. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  95. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  96. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  97. package/src/columnCalculator.js +35 -38
  98. package/src/helpers/node.js +110 -0
  99. package/src/helpers/tools.js +39 -0
  100. package/src/helpers/variableType.js +50 -0
  101. package/src/index.js +16 -0
  102. package/src/qrEnc.js +15 -10
  103. package/src/standardPageSizes.js +1 -3
  104. package/src/tableLayouts.js +100 -0
  105. package/src/virtual-fs.js +66 -0
  106. package/standard-fonts/Courier.js +8 -0
  107. package/standard-fonts/Helvetica.js +9 -0
  108. package/standard-fonts/Symbol.js +5 -0
  109. package/standard-fonts/Times.js +8 -0
  110. package/standard-fonts/ZapfDingbats.js +5 -0
  111. package/.idea/codeStyles/Project.xml +0 -7
  112. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  113. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  114. package/.idea/misc.xml +0 -6
  115. package/.idea/modules.xml +0 -8
  116. package/.idea/pdfmake.iml +0 -11
  117. package/.idea/vcs.xml +0 -6
  118. package/src/browser-extensions/virtual-fs.js +0 -55
  119. package/src/docMeasure.js +0 -810
  120. package/src/docPreprocessor.js +0 -255
  121. package/src/documentContext.js +0 -328
  122. package/src/elementWriter.js +0 -333
  123. package/src/fontProvider.js +0 -68
  124. package/src/helpers.js +0 -138
  125. package/src/imageMeasure.js +0 -55
  126. package/src/layoutBuilder.js +0 -989
  127. package/src/line.js +0 -91
  128. package/src/pageElementWriter.js +0 -174
  129. package/src/pdfKitEngine.js +0 -21
  130. package/src/printer.js +0 -710
  131. package/src/styleContextStack.js +0 -138
  132. package/src/svgMeasure.js +0 -70
  133. package/src/tableProcessor.js +0 -584
  134. package/src/textDecorator.js +0 -157
  135. package/src/textTools.js +0 -373
  136. package/src/traversalTracker.js +0 -47
@@ -0,0 +1,149 @@
1
+ import LineBreaker from '@foliojs-fork/linebreak';
2
+ import { isObject } from './helpers/variableType';
3
+ import StyleContextStack from './StyleContextStack';
4
+
5
+ /**
6
+ * @param {string} text
7
+ * @param {boolean} noWrap
8
+ * @returns {Array}
9
+ */
10
+ const splitWords = (text, noWrap) => {
11
+ let words = [];
12
+
13
+ if (noWrap) {
14
+ words.push({ text: text });
15
+ return words;
16
+ }
17
+
18
+ let breaker = new LineBreaker(text);
19
+ let last = 0;
20
+ let bk;
21
+
22
+ while ((bk = breaker.nextBreak())) {
23
+ let word = text.slice(last, bk.position);
24
+
25
+ if (bk.required || word.match(/\r?\n$|\r$/)) { // new line
26
+ word = word.replace(/\r?\n$|\r$/, '');
27
+ words.push({ text: word, lineEnd: true });
28
+ } else {
29
+ words.push({ text: word });
30
+ }
31
+
32
+ last = bk.position;
33
+ }
34
+
35
+ return words;
36
+ };
37
+
38
+ /**
39
+ * @param {Array} words
40
+ * @param {boolean} noWrap
41
+ * @returns {?string}
42
+ */
43
+ const getFirstWord = (words, noWrap) => {
44
+ let word = words[0];
45
+ if (word === undefined) {
46
+ return null;
47
+ }
48
+
49
+ if (noWrap) { // text was not wrapped, we need only first word
50
+ let tmpWords = splitWords(word.text, false);
51
+ if (tmpWords[0] === undefined) {
52
+ return null;
53
+ }
54
+ word = tmpWords[0];
55
+ }
56
+
57
+ return word.text;
58
+ };
59
+
60
+ /**
61
+ * @param {Array} words
62
+ * @param {boolean} noWrap
63
+ * @returns {?string}
64
+ */
65
+ const getLastWord = (words, noWrap) => {
66
+ let word = words[words.length - 1];
67
+ if (word === undefined) {
68
+ return null;
69
+ }
70
+
71
+ if (word.lineEnd) {
72
+ return null;
73
+ }
74
+
75
+ if (noWrap) { // text was not wrapped, we need only last word
76
+ let tmpWords = splitWords(word.text, false);
77
+ if (tmpWords[tmpWords.length - 1] === undefined) {
78
+ return null;
79
+ }
80
+ word = tmpWords[tmpWords.length - 1];
81
+ }
82
+
83
+ return word.text;
84
+ };
85
+
86
+ class TextBreaker {
87
+ /**
88
+ * @param {string|Array} texts
89
+ * @param {StyleContextStack} styleContextStack
90
+ * @returns {Array}
91
+ */
92
+ getBreaks(texts, styleContextStack) {
93
+ let results = [];
94
+
95
+ if (!Array.isArray(texts)) {
96
+ texts = [texts];
97
+ }
98
+
99
+ let lastWord = null;
100
+ for (let i = 0, l = texts.length; i < l; i++) {
101
+ let item = texts[i];
102
+ let style = null;
103
+ let words;
104
+
105
+ let noWrap = StyleContextStack.getStyleProperty(item || {}, styleContextStack, 'noWrap', false);
106
+ if (isObject(item)) {
107
+ if (item._textRef && item._textRef._textNodeRef.text) {
108
+ item.text = item._textRef._textNodeRef.text;
109
+ }
110
+ words = splitWords(item.text, noWrap);
111
+ style = StyleContextStack.copyStyle(item);
112
+ } else {
113
+ words = splitWords(item, noWrap);
114
+ }
115
+
116
+ if (lastWord && words.length) {
117
+ let firstWord = getFirstWord(words, noWrap);
118
+
119
+ let wrapWords = splitWords(lastWord + firstWord, false);
120
+ if (wrapWords.length === 1) {
121
+ results[results.length - 1].noNewLine = true;
122
+ }
123
+ }
124
+
125
+ for (let i2 = 0, l2 = words.length; i2 < l2; i2++) {
126
+ let result = {
127
+ text: words[i2].text
128
+ };
129
+
130
+ if (words[i2].lineEnd) {
131
+ result.lineEnd = true;
132
+ }
133
+
134
+ StyleContextStack.copyStyle(style, result);
135
+
136
+ results.push(result);
137
+ }
138
+
139
+ lastWord = null;
140
+ if (i + 1 < l) {
141
+ lastWord = getLastWord(words, noWrap);
142
+ }
143
+ }
144
+
145
+ return results;
146
+ }
147
+ }
148
+
149
+ export default TextBreaker;
@@ -0,0 +1,161 @@
1
+ const groupDecorations = line => {
2
+ let groups = [];
3
+ let currentGroup = null;
4
+ for (let i = 0, l = line.inlines.length; i < l; i++) {
5
+ let inline = line.inlines[i];
6
+ let decoration = inline.decoration;
7
+ if (!decoration) {
8
+ currentGroup = null;
9
+ continue;
10
+ }
11
+ if (!Array.isArray(decoration)) {
12
+ decoration = [decoration];
13
+ }
14
+ let color = inline.decorationColor || inline.color || 'black';
15
+ let style = inline.decorationStyle || 'solid';
16
+ for (let ii = 0, ll = decoration.length; ii < ll; ii++) {
17
+ let decorationItem = decoration[ii];
18
+ if (!currentGroup || decorationItem !== currentGroup.decoration ||
19
+ style !== currentGroup.decorationStyle || color !== currentGroup.decorationColor) {
20
+
21
+ currentGroup = {
22
+ line: line,
23
+ decoration: decorationItem,
24
+ decorationColor: color,
25
+ decorationStyle: style,
26
+ inlines: [inline]
27
+ };
28
+ groups.push(currentGroup);
29
+ } else {
30
+ currentGroup.inlines.push(inline);
31
+ }
32
+ }
33
+ }
34
+
35
+ return groups;
36
+ };
37
+
38
+ class TextDecorator {
39
+
40
+ constructor(pdfDocument) {
41
+ this.pdfDocument = pdfDocument;
42
+ }
43
+
44
+ drawBackground(line, x, y) {
45
+ let height = line.getHeight();
46
+ for (let i = 0, l = line.inlines.length; i < l; i++) {
47
+ let inline = line.inlines[i];
48
+ if (!inline.background) {
49
+ continue;
50
+ }
51
+
52
+ let color = inline.background;
53
+ let patternColor = this.pdfDocument.providePattern(inline.background);
54
+ if (patternColor !== null) {
55
+ color = patternColor;
56
+ }
57
+
58
+ let justifyShift = (inline.justifyShift || 0);
59
+ this.pdfDocument.fillColor(color)
60
+ .rect(x + inline.x - justifyShift, y, inline.width + justifyShift, height)
61
+ .fill();
62
+ }
63
+ }
64
+
65
+ drawDecorations(line, x, y) {
66
+ let groups = groupDecorations(line);
67
+ for (let i = 0, l = groups.length; i < l; i++) {
68
+ this._drawDecoration(groups[i], x, y);
69
+ }
70
+ }
71
+
72
+ _drawDecoration(group, x, y) {
73
+ const maxInline = () => {
74
+ let max = 0;
75
+ for (let i = 0, l = group.inlines.length; i < l; i++) {
76
+ let inline = group.inlines[i];
77
+ max = inline.fontSize > max ? i : max;
78
+ }
79
+ return group.inlines[max];
80
+ };
81
+
82
+ const width = () => {
83
+ let sum = 0;
84
+ for (let i = 0, l = group.inlines.length; i < l; i++) {
85
+ let justifyShift = (group.inlines[i].justifyShift || 0);
86
+ sum += group.inlines[i].width + justifyShift;
87
+ }
88
+ return sum;
89
+ };
90
+
91
+ let firstInline = group.inlines[0];
92
+ let biggerInline = maxInline();
93
+ let totalWidth = width();
94
+ let lineAscent = group.line.getAscenderHeight();
95
+ let ascent = biggerInline.font.ascender / 1000 * biggerInline.fontSize;
96
+ let height = biggerInline.height;
97
+ let descent = height - ascent;
98
+
99
+ let lw = 0.5 + Math.floor(Math.max(biggerInline.fontSize - 8, 0) / 2) * 0.12;
100
+
101
+ switch (group.decoration) {
102
+ case 'underline':
103
+ y += lineAscent + descent * 0.45;
104
+ break;
105
+ case 'overline':
106
+ y += lineAscent - (ascent * 0.85);
107
+ break;
108
+ case 'lineThrough':
109
+ y += lineAscent - (ascent * 0.25);
110
+ break;
111
+ default:
112
+ throw new Error(`Unknown decoration : ${group.decoration}`);
113
+ }
114
+ this.pdfDocument.save();
115
+
116
+ if (group.decorationStyle === 'double') {
117
+ let gap = Math.max(0.5, lw * 2);
118
+ this.pdfDocument.fillColor(group.decorationColor)
119
+ .rect(x + firstInline.x, y - lw / 2, totalWidth, lw / 2).fill()
120
+ .rect(x + firstInline.x, y + gap - lw / 2, totalWidth, lw / 2).fill();
121
+ } else if (group.decorationStyle === 'dashed') {
122
+ let nbDashes = Math.ceil(totalWidth / (3.96 + 2.84));
123
+ let rdx = x + firstInline.x;
124
+ this.pdfDocument.rect(rdx, y, totalWidth, lw).clip();
125
+ this.pdfDocument.fillColor(group.decorationColor);
126
+ for (let i = 0; i < nbDashes; i++) {
127
+ this.pdfDocument.rect(rdx, y - lw / 2, 3.96, lw).fill();
128
+ rdx += 3.96 + 2.84;
129
+ }
130
+ } else if (group.decorationStyle === 'dotted') {
131
+ let nbDots = Math.ceil(totalWidth / (lw * 3));
132
+ let rx = x + firstInline.x;
133
+ this.pdfDocument.rect(rx, y, totalWidth, lw).clip();
134
+ this.pdfDocument.fillColor(group.decorationColor);
135
+ for (let i = 0; i < nbDots; i++) {
136
+ this.pdfDocument.rect(rx, y - lw / 2, lw, lw).fill();
137
+ rx += (lw * 3);
138
+ }
139
+ } else if (group.decorationStyle === 'wavy') {
140
+ let sh = 0.7, sv = 1;
141
+ let nbWaves = Math.ceil(totalWidth / (sh * 2)) + 1;
142
+ let rwx = x + firstInline.x - 1;
143
+ this.pdfDocument.rect(x + firstInline.x, y - sv, totalWidth, y + sv).clip();
144
+ this.pdfDocument.lineWidth(0.24);
145
+ this.pdfDocument.moveTo(rwx, y);
146
+ for (let i = 0; i < nbWaves; i++) {
147
+ this.pdfDocument.bezierCurveTo(rwx + sh, y - sv, rwx + sh * 2, y - sv, rwx + sh * 3, y)
148
+ .bezierCurveTo(rwx + sh * 4, y + sv, rwx + sh * 5, y + sv, rwx + sh * 6, y);
149
+ rwx += sh * 6;
150
+ }
151
+ this.pdfDocument.stroke(group.decorationColor);
152
+ } else {
153
+ this.pdfDocument.fillColor(group.decorationColor)
154
+ .rect(x + firstInline.x, y - lw / 2, totalWidth, lw)
155
+ .fill();
156
+ }
157
+ this.pdfDocument.restore();
158
+ }
159
+ }
160
+
161
+ export default TextDecorator;
@@ -0,0 +1,223 @@
1
+ import TextBreaker from './TextBreaker';
2
+ import StyleContextStack from './StyleContextStack';
3
+
4
+ const LEADING = /^(\s)+/g;
5
+ const TRAILING = /(\s)+$/g;
6
+
7
+ /**
8
+ * @param {Array} array
9
+ * @returns {Array}
10
+ */
11
+ const flattenTextArray = array => {
12
+ function flatten(array) {
13
+ return array.reduce((prev, cur) => {
14
+ let current = Array.isArray(cur.text) ? flatten(cur.text) : cur;
15
+ let more = [].concat(current).some(Array.isArray);
16
+ return prev.concat(more ? flatten(current) : current);
17
+ }, []);
18
+ }
19
+
20
+ if (!Array.isArray(array)) {
21
+ array = [array];
22
+ }
23
+
24
+ // TODO: Styling in nested text (issue: https://github.com/bpampuch/pdfmake/issues/1174)
25
+
26
+ array = flatten(array);
27
+
28
+ return array;
29
+ };
30
+
31
+
32
+ /**
33
+ * Text measurement utility
34
+ */
35
+ class TextInlines {
36
+
37
+ /**
38
+ * @param {object} pdfDocument object is instance of PDFDocument
39
+ */
40
+ constructor(pdfDocument) {
41
+ this.pdfDocument = pdfDocument;
42
+ }
43
+
44
+ /**
45
+ * Converts an array of strings (or inline-definition-objects) into a collection
46
+ * of inlines and calculated minWidth/maxWidth and their min/max widths
47
+ *
48
+ * @param {Array} textArray an array of inline-definition-objects (or strings)
49
+ * @param {StyleContextStack} styleContextStack current style stack
50
+ * @returns {object} collection of inlines, minWidth, maxWidth
51
+ */
52
+ buildInlines(textArray, styleContextStack) {
53
+ const getTrimmedWidth = item => {
54
+ return Math.max(0, item.width - item.leadingCut - item.trailingCut);
55
+ };
56
+
57
+ let minWidth = 0;
58
+ let maxWidth = 0;
59
+ let currentLineWidth;
60
+
61
+ let flattenedTextArray = flattenTextArray(textArray);
62
+
63
+ const textBreaker = new TextBreaker();
64
+ let breakedText = textBreaker.getBreaks(flattenedTextArray, styleContextStack);
65
+
66
+ let measuredText = this.measure(breakedText, styleContextStack);
67
+
68
+ measuredText.forEach(inline => {
69
+ minWidth = Math.max(minWidth, getTrimmedWidth(inline));
70
+
71
+ if (!currentLineWidth) {
72
+ currentLineWidth = { width: 0, leadingCut: inline.leadingCut, trailingCut: 0 };
73
+ }
74
+
75
+ currentLineWidth.width += inline.width;
76
+ currentLineWidth.trailingCut = inline.trailingCut;
77
+
78
+ maxWidth = Math.max(maxWidth, getTrimmedWidth(currentLineWidth));
79
+
80
+ if (inline.lineEnd) {
81
+ currentLineWidth = null;
82
+ }
83
+ });
84
+
85
+ if (StyleContextStack.getStyleProperty({}, styleContextStack, 'noWrap', false)) {
86
+ minWidth = maxWidth;
87
+ }
88
+
89
+ return {
90
+ items: measuredText,
91
+ minWidth: minWidth,
92
+ maxWidth: maxWidth
93
+ };
94
+ }
95
+
96
+ measure(array, styleContextStack) {
97
+ if (array.length) {
98
+ let leadingIndent = StyleContextStack.getStyleProperty(array[0], styleContextStack, 'leadingIndent', 0);
99
+ if (leadingIndent) {
100
+ array[0].leadingCut = -leadingIndent;
101
+ array[0].leadingIndent = leadingIndent;
102
+ }
103
+ }
104
+
105
+ array.forEach(item => {
106
+ let font = StyleContextStack.getStyleProperty(item, styleContextStack, 'font', 'Roboto');
107
+ let bold = StyleContextStack.getStyleProperty(item, styleContextStack, 'bold', false);
108
+ let italics = StyleContextStack.getStyleProperty(item, styleContextStack, 'italics', false);
109
+
110
+ item.font = this.pdfDocument.provideFont(font, bold, italics);
111
+
112
+ item.alignment = StyleContextStack.getStyleProperty(item, styleContextStack, 'alignment', 'left');
113
+ item.fontSize = StyleContextStack.getStyleProperty(item, styleContextStack, 'fontSize', 12);
114
+ item.fontFeatures = StyleContextStack.getStyleProperty(item, styleContextStack, 'fontFeatures', null);
115
+ item.characterSpacing = StyleContextStack.getStyleProperty(item, styleContextStack, 'characterSpacing', 0);
116
+ item.color = StyleContextStack.getStyleProperty(item, styleContextStack, 'color', 'black');
117
+ item.decoration = StyleContextStack.getStyleProperty(item, styleContextStack, 'decoration', null);
118
+ item.decorationColor = StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationColor', null);
119
+ item.decorationStyle = StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationStyle', null);
120
+ item.background = StyleContextStack.getStyleProperty(item, styleContextStack, 'background', null);
121
+ item.link = StyleContextStack.getStyleProperty(item, styleContextStack, 'link', null);
122
+ item.linkToPage = StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToPage', null);
123
+ item.linkToDestination = StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToDestination', null);
124
+ item.noWrap = StyleContextStack.getStyleProperty(item, styleContextStack, 'noWrap', null);
125
+ item.opacity = StyleContextStack.getStyleProperty(item, styleContextStack, 'opacity', 1);
126
+ item.sup = StyleContextStack.getStyleProperty(item, styleContextStack, 'sup', false);
127
+ item.sub = StyleContextStack.getStyleProperty(item, styleContextStack, 'sub', false);
128
+
129
+ if (item.sup || item.sub) {
130
+ // font size reduction taken from here: https://en.wikipedia.org/wiki/Subscript_and_superscript#Desktop_publishing
131
+ item.fontSize *= 0.58;
132
+ }
133
+
134
+ let lineHeight = StyleContextStack.getStyleProperty(item, styleContextStack, 'lineHeight', 1);
135
+
136
+ item.width = this.widthOfText(item.text, item);
137
+ item.height = item.font.lineHeight(item.fontSize) * lineHeight;
138
+
139
+ if (!item.leadingCut) {
140
+ item.leadingCut = 0;
141
+ }
142
+
143
+ let preserveLeadingSpaces = StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false);
144
+ if (!preserveLeadingSpaces) {
145
+ let leadingSpaces = item.text.match(LEADING);
146
+ if (leadingSpaces) {
147
+ item.leadingCut += this.widthOfText(leadingSpaces[0], item);
148
+ }
149
+ }
150
+
151
+ item.trailingCut = 0;
152
+
153
+ let preserveTrailingSpaces = StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveTrailingSpaces', false);
154
+ if (!preserveTrailingSpaces) {
155
+ let trailingSpaces = item.text.match(TRAILING);
156
+ if (trailingSpaces) {
157
+ item.trailingCut = this.widthOfText(trailingSpaces[0], item);
158
+ }
159
+ }
160
+ }, this);
161
+
162
+ return array;
163
+ }
164
+
165
+ /**
166
+ * Width of text
167
+ *
168
+ * @param {string} text
169
+ * @param {object} inline
170
+ * @returns {number}
171
+ */
172
+ widthOfText(text, inline) {
173
+ return inline.font.widthOfString(text, inline.fontSize, inline.fontFeatures) + ((inline.characterSpacing || 0) * (text.length - 1));
174
+ }
175
+
176
+ /**
177
+ * Returns size of the specified string (without breaking it) using the current style
178
+ *
179
+ * @param {string} text text to be measured
180
+ * @param {object} styleContextStack current style stack
181
+ * @returns {object} size of the specified string
182
+ */
183
+ sizeOfText(text, styleContextStack) {
184
+ //TODO: refactor - extract from measure
185
+ let fontName = StyleContextStack.getStyleProperty({}, styleContextStack, 'font', 'Roboto');
186
+ let fontSize = StyleContextStack.getStyleProperty({}, styleContextStack, 'fontSize', 12);
187
+ let fontFeatures = StyleContextStack.getStyleProperty({}, styleContextStack, 'fontFeatures', null);
188
+ let bold = StyleContextStack.getStyleProperty({}, styleContextStack, 'bold', false);
189
+ let italics = StyleContextStack.getStyleProperty({}, styleContextStack, 'italics', false);
190
+ let lineHeight = StyleContextStack.getStyleProperty({}, styleContextStack, 'lineHeight', 1);
191
+ let characterSpacing = StyleContextStack.getStyleProperty({}, styleContextStack, 'characterSpacing', 0);
192
+
193
+ let font = this.pdfDocument.provideFont(fontName, bold, italics);
194
+
195
+ return {
196
+ width: this.widthOfText(text, { font: font, fontSize: fontSize, characterSpacing: characterSpacing, fontFeatures: fontFeatures }),
197
+ height: font.lineHeight(fontSize) * lineHeight,
198
+ fontSize: fontSize,
199
+ lineHeight: lineHeight,
200
+ ascender: font.ascender / 1000 * fontSize,
201
+ descender: font.descender / 1000 * fontSize
202
+ };
203
+ }
204
+
205
+ /**
206
+ * Returns size of the specified rotated string (without breaking it) using the current style
207
+ *
208
+ * @param {string} text text to be measured
209
+ * @param {number} angle
210
+ * @param {object} styleContextStack current style stack
211
+ * @returns {object} size of the specified string
212
+ */
213
+ sizeOfRotatedText(text, angle, styleContextStack) {
214
+ let angleRad = angle * Math.PI / -180;
215
+ let size = this.sizeOfText(text, styleContextStack);
216
+ return {
217
+ width: Math.abs(size.height * Math.sin(angleRad)) + Math.abs(size.width * Math.cos(angleRad)),
218
+ height: Math.abs(size.width * Math.sin(angleRad)) + Math.abs(size.height * Math.cos(angleRad))
219
+ };
220
+ }
221
+ }
222
+
223
+ export default TextInlines;
@@ -0,0 +1,77 @@
1
+ import http from 'http';
2
+ import https from 'https';
3
+
4
+ const fetchUrl = (url, headers = {}) => {
5
+ return new Promise((resolve, reject) => {
6
+ const parsedUrl = new URL(url);
7
+ const h = (parsedUrl.protocol === 'https:') ? https : http;
8
+ let options = {
9
+ headers: headers
10
+ };
11
+
12
+ h.get(url, options, res => {
13
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { // redirect url
14
+ fetchUrl(res.headers.location).then(buffer => {
15
+ resolve(buffer);
16
+ }, result => {
17
+ reject(result);
18
+ });
19
+ return;
20
+ }
21
+
22
+ const ok = res.statusCode >= 200 && res.statusCode < 300;
23
+ if (!ok) {
24
+ reject(new TypeError(`Failed to fetch (status code: ${res.statusCode}, url: "${url}")`));
25
+ }
26
+
27
+ const chunks = [];
28
+ res.on('end', () => resolve(Buffer.concat(chunks)));
29
+ res.on('data', d => chunks.push(d));
30
+ }).on('error', reject);
31
+ });
32
+ };
33
+
34
+ class URLResolver {
35
+ constructor(fs) {
36
+ this.fs = fs;
37
+ this.resolving = {};
38
+ }
39
+
40
+ resolve(url, headers = {}) {
41
+ if (!this.resolving[url]) {
42
+ this.resolving[url] = new Promise((resolve, reject) => {
43
+ if (url.toLowerCase().indexOf('https://') === 0 || url.toLowerCase().indexOf('http://') === 0) {
44
+ if (this.fs.existsSync(url)) {
45
+ // url was downloaded earlier
46
+ resolve();
47
+ } else {
48
+ fetchUrl(url, headers).then(buffer => {
49
+ this.fs.writeFileSync(url, buffer);
50
+ resolve();
51
+ }, result => {
52
+ reject(result);
53
+ });
54
+ }
55
+ } else {
56
+ // cannot be resolved
57
+ resolve();
58
+ }
59
+ });
60
+ }
61
+
62
+ return this.resolving[url];
63
+ }
64
+
65
+ resolved() {
66
+ return new Promise((resolve, reject) => {
67
+ Promise.all(Object.values(this.resolving)).then(() => {
68
+ resolve();
69
+ }, result => {
70
+ reject(result);
71
+ });
72
+ });
73
+ }
74
+
75
+ }
76
+
77
+ export default URLResolver;
package/src/base.js ADDED
@@ -0,0 +1,61 @@
1
+ import Printer from './Printer';
2
+ import virtualfs from './virtual-fs';
3
+ import { pack } from './helpers/tools';
4
+
5
+ class pdfmake {
6
+
7
+ constructor() {
8
+ this.virtualfs = virtualfs;
9
+ this.urlResolver = null;
10
+ }
11
+
12
+ /**
13
+ * @param {object} docDefinition
14
+ * @param {?object} options
15
+ * @returns {object}
16
+ */
17
+ createPdf(docDefinition, options = {}) {
18
+ options.progressCallback = this.progressCallback;
19
+ options.tableLayouts = this.tableLayouts;
20
+
21
+ let printer = new Printer(this.fonts, this.virtualfs, this.urlResolver);
22
+ const pdfDocumentPromise = printer.createPdfKitDocument(docDefinition, options);
23
+
24
+ return this._transformToDocument(pdfDocumentPromise);
25
+ }
26
+
27
+ setProgressCallback(callback) {
28
+ this.progressCallback = callback;
29
+ }
30
+
31
+ addTableLayouts(tableLayouts) {
32
+ this.tableLayouts = pack(this.tableLayouts, tableLayouts);
33
+ }
34
+
35
+ setTableLayouts(tableLayouts) {
36
+ this.tableLayouts = tableLayouts;
37
+ }
38
+
39
+ clearTableLayouts() {
40
+ this.tableLayouts = {};
41
+ }
42
+
43
+ addFonts(fonts) {
44
+ this.fonts = pack(this.fonts, fonts);
45
+ }
46
+
47
+ setFonts(fonts) {
48
+ this.fonts = fonts;
49
+ }
50
+
51
+ clearFonts() {
52
+ this.fonts = {};
53
+ }
54
+
55
+ _transformToDocument(doc) {
56
+ return doc;
57
+ }
58
+
59
+ }
60
+
61
+ export default pdfmake;