@digicole/pdfmake-rtl 2.1.0 → 2.1.2
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.
- package/CHANGELOG.md +118 -83
- package/README.md +11 -10
- package/build/pdfmake.js +71 -42
- package/build/pdfmake.js.map +1 -1
- package/build/pdfmake.min.js +2 -2
- package/build/pdfmake.min.js.map +1 -1
- package/build/vfs_fonts.js +11 -11
- package/js/3rd-party/svg-to-pdfkit/source.js +3823 -0
- package/js/3rd-party/svg-to-pdfkit.js +7 -0
- package/js/DocMeasure.js +713 -0
- package/js/DocPreprocessor.js +275 -0
- package/js/DocumentContext.js +310 -0
- package/js/ElementWriter.js +687 -0
- package/js/LayoutBuilder.js +1240 -0
- package/js/Line.js +113 -0
- package/js/OutputDocument.js +64 -0
- package/js/OutputDocumentServer.js +29 -0
- package/js/PDFDocument.js +144 -0
- package/js/PageElementWriter.js +161 -0
- package/js/PageSize.js +74 -0
- package/js/Printer.js +351 -0
- package/js/Renderer.js +417 -0
- package/js/SVGMeasure.js +92 -0
- package/js/StyleContextStack.js +191 -0
- package/js/TableProcessor.js +575 -0
- package/js/TextBreaker.js +166 -0
- package/js/TextDecorator.js +152 -0
- package/js/TextInlines.js +244 -0
- package/js/URLResolver.js +43 -0
- package/js/base.js +59 -0
- package/js/browser-extensions/OutputDocumentBrowser.js +82 -0
- package/js/browser-extensions/fonts/Cairo.js +38 -0
- package/js/browser-extensions/fonts/Roboto.js +38 -0
- package/js/browser-extensions/index.js +59 -0
- package/js/browser-extensions/pdfMake.js +3 -0
- package/js/browser-extensions/standard-fonts/Courier.js +38 -0
- package/js/browser-extensions/standard-fonts/Helvetica.js +38 -0
- package/js/browser-extensions/standard-fonts/Symbol.js +23 -0
- package/js/browser-extensions/standard-fonts/Times.js +38 -0
- package/js/browser-extensions/standard-fonts/ZapfDingbats.js +23 -0
- package/js/browser-extensions/virtual-fs-cjs.js +3 -0
- package/js/columnCalculator.js +148 -0
- package/js/helpers/node.js +123 -0
- package/js/helpers/tools.js +46 -0
- package/js/helpers/variableType.js +59 -0
- package/js/index.js +15 -0
- package/js/qrEnc.js +721 -0
- package/js/rtlUtils.js +519 -0
- package/js/standardPageSizes.js +56 -0
- package/js/tableLayouts.js +98 -0
- package/js/virtual-fs.js +60 -0
- package/package.json +1 -1
- package/src/{docMeasure.js → DocMeasure.js} +8 -8
- package/src/{elementWriter.js → ElementWriter.js} +3 -3
- package/src/{layoutBuilder.js → LayoutBuilder.js} +1406 -1393
- package/src/{tableProcessor.js → TableProcessor.js} +633 -620
- package/src/rtlUtils.js +503 -500
- /package/src/{docPreprocessor.js → DocPreprocessor.js} +0 -0
- /package/src/{documentContext.js → DocumentContext.js} +0 -0
- /package/src/{line.js → Line.js} +0 -0
- /package/src/{pageElementWriter.js → PageElementWriter.js} +0 -0
- /package/src/{printer.js → Printer.js} +0 -0
- /package/src/{svgMeasure.js → SVGMeasure.js} +0 -0
- /package/src/{styleContextStack.js → StyleContextStack.js} +0 -0
- /package/src/{textDecorator.js → TextDecorator.js} +0 -0
package/js/Renderer.js
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _TextDecorator = _interopRequireDefault(require("./TextDecorator"));
|
|
6
|
+
var _TextInlines = _interopRequireDefault(require("./TextInlines"));
|
|
7
|
+
var _variableType = require("./helpers/variableType");
|
|
8
|
+
var _svgToPdfkit = _interopRequireDefault(require("./3rd-party/svg-to-pdfkit"));
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
const findFont = (fonts, requiredFonts, defaultFont) => {
|
|
11
|
+
for (let i = 0; i < requiredFonts.length; i++) {
|
|
12
|
+
let requiredFont = requiredFonts[i].toLowerCase();
|
|
13
|
+
for (let font in fonts) {
|
|
14
|
+
if (font.toLowerCase() === requiredFont) {
|
|
15
|
+
return font;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return defaultFont;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Shift the "y" height of the text baseline up or down (superscript or subscript,
|
|
24
|
+
* respectively). The exact shift can / should be changed according to standard
|
|
25
|
+
* conventions.
|
|
26
|
+
*
|
|
27
|
+
* @param {number} y
|
|
28
|
+
* @param {object} inline
|
|
29
|
+
* @returns {number}
|
|
30
|
+
*/
|
|
31
|
+
const offsetText = (y, inline) => {
|
|
32
|
+
let newY = y;
|
|
33
|
+
if (inline.sup) {
|
|
34
|
+
newY -= inline.fontSize * 0.75;
|
|
35
|
+
}
|
|
36
|
+
if (inline.sub) {
|
|
37
|
+
newY += inline.fontSize * 0.35;
|
|
38
|
+
}
|
|
39
|
+
return newY;
|
|
40
|
+
};
|
|
41
|
+
class Renderer {
|
|
42
|
+
constructor(pdfDocument, progressCallback) {
|
|
43
|
+
this.pdfDocument = pdfDocument;
|
|
44
|
+
this.progressCallback = progressCallback;
|
|
45
|
+
}
|
|
46
|
+
renderPages(pages) {
|
|
47
|
+
this.pdfDocument._pdfMakePages = pages; // TODO: Why?
|
|
48
|
+
|
|
49
|
+
let totalItems = 0;
|
|
50
|
+
if (this.progressCallback) {
|
|
51
|
+
pages.forEach(page => {
|
|
52
|
+
totalItems += page.items.length;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
let renderedItems = 0;
|
|
56
|
+
for (let i = 0; i < pages.length; i++) {
|
|
57
|
+
this.pdfDocument.addPage({
|
|
58
|
+
size: [pages[i].pageSize.width, pages[i].pageSize.height]
|
|
59
|
+
});
|
|
60
|
+
let page = pages[i];
|
|
61
|
+
for (let ii = 0, il = page.items.length; ii < il; ii++) {
|
|
62
|
+
let item = page.items[ii];
|
|
63
|
+
switch (item.type) {
|
|
64
|
+
case 'vector':
|
|
65
|
+
this.renderVector(item.item);
|
|
66
|
+
break;
|
|
67
|
+
case 'line':
|
|
68
|
+
this.renderLine(item.item, item.item.x, item.item.y);
|
|
69
|
+
break;
|
|
70
|
+
case 'image':
|
|
71
|
+
this.renderImage(item.item);
|
|
72
|
+
break;
|
|
73
|
+
case 'svg':
|
|
74
|
+
this.renderSVG(item.item);
|
|
75
|
+
break;
|
|
76
|
+
case 'attachment':
|
|
77
|
+
this.renderAttachment(item.item);
|
|
78
|
+
break;
|
|
79
|
+
case 'beginClip':
|
|
80
|
+
this.beginClip(item.item);
|
|
81
|
+
break;
|
|
82
|
+
case 'endClip':
|
|
83
|
+
this.endClip();
|
|
84
|
+
break;
|
|
85
|
+
case 'beginVerticalAlignment':
|
|
86
|
+
this.beginVerticalAlignment(item.item);
|
|
87
|
+
break;
|
|
88
|
+
case 'endVerticalAlignment':
|
|
89
|
+
this.endVerticalAlignment(item.item);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
renderedItems++;
|
|
93
|
+
if (this.progressCallback) {
|
|
94
|
+
this.progressCallback(renderedItems / totalItems);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (page.watermark) {
|
|
98
|
+
this.renderWatermark(page);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
renderLine(line, x, y) {
|
|
103
|
+
function preparePageNodeRefLine(_pageNodeRef, inline) {
|
|
104
|
+
let newWidth;
|
|
105
|
+
let diffWidth;
|
|
106
|
+
let textInlines = new _TextInlines.default(null);
|
|
107
|
+
if (_pageNodeRef.positions === undefined) {
|
|
108
|
+
throw new Error('Page reference id not found');
|
|
109
|
+
}
|
|
110
|
+
let pageNumber = _pageNodeRef.positions[0].pageNumber.toString();
|
|
111
|
+
inline.text = pageNumber;
|
|
112
|
+
newWidth = textInlines.widthOfText(inline.text, inline);
|
|
113
|
+
diffWidth = inline.width - newWidth;
|
|
114
|
+
inline.width = newWidth;
|
|
115
|
+
switch (inline.alignment) {
|
|
116
|
+
case 'right':
|
|
117
|
+
inline.x += diffWidth;
|
|
118
|
+
break;
|
|
119
|
+
case 'center':
|
|
120
|
+
inline.x += diffWidth / 2;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (line._pageNodeRef) {
|
|
125
|
+
preparePageNodeRefLine(line._pageNodeRef, line.inlines[0]);
|
|
126
|
+
}
|
|
127
|
+
x = x || 0;
|
|
128
|
+
y = y || 0;
|
|
129
|
+
let lineHeight = line.getHeight();
|
|
130
|
+
let ascenderHeight = line.getAscenderHeight();
|
|
131
|
+
let descent = lineHeight - ascenderHeight;
|
|
132
|
+
const textDecorator = new _TextDecorator.default(this.pdfDocument);
|
|
133
|
+
textDecorator.drawBackground(line, x, y);
|
|
134
|
+
|
|
135
|
+
//TODO: line.optimizeInlines();
|
|
136
|
+
//TODO: lines without differently styled inlines should be written to pdf as one stream
|
|
137
|
+
for (let i = 0, l = line.inlines.length; i < l; i++) {
|
|
138
|
+
let inline = line.inlines[i];
|
|
139
|
+
let shiftToBaseline = lineHeight - inline.font.ascender / 1000 * inline.fontSize - descent;
|
|
140
|
+
if (inline._pageNodeRef) {
|
|
141
|
+
preparePageNodeRefLine(inline._pageNodeRef, inline);
|
|
142
|
+
}
|
|
143
|
+
let options = {
|
|
144
|
+
lineBreak: false,
|
|
145
|
+
textWidth: inline.width,
|
|
146
|
+
characterSpacing: inline.characterSpacing,
|
|
147
|
+
wordCount: 1,
|
|
148
|
+
link: inline.link
|
|
149
|
+
};
|
|
150
|
+
if (inline.linkToDestination) {
|
|
151
|
+
options.goTo = inline.linkToDestination;
|
|
152
|
+
}
|
|
153
|
+
if (line.id && i === 0) {
|
|
154
|
+
options.destination = line.id;
|
|
155
|
+
}
|
|
156
|
+
if (inline.fontFeatures) {
|
|
157
|
+
options.features = inline.fontFeatures;
|
|
158
|
+
}
|
|
159
|
+
let opacity = (0, _variableType.isNumber)(inline.opacity) ? inline.opacity : 1;
|
|
160
|
+
this.pdfDocument.opacity(opacity);
|
|
161
|
+
this.pdfDocument.fill(inline.color || 'black');
|
|
162
|
+
this.pdfDocument._font = inline.font;
|
|
163
|
+
this.pdfDocument.fontSize(inline.fontSize);
|
|
164
|
+
let shiftedY = offsetText(y + shiftToBaseline, inline);
|
|
165
|
+
this.pdfDocument.text(inline.text, x + inline.x, shiftedY, options);
|
|
166
|
+
if (inline.linkToPage) {
|
|
167
|
+
this.pdfDocument.ref({
|
|
168
|
+
Type: 'Action',
|
|
169
|
+
S: 'GoTo',
|
|
170
|
+
D: [inline.linkToPage, 0, 0]
|
|
171
|
+
}).end();
|
|
172
|
+
this.pdfDocument.annotate(x + inline.x, shiftedY, inline.width, inline.height, {
|
|
173
|
+
Subtype: 'Link',
|
|
174
|
+
Dest: [inline.linkToPage - 1, 'XYZ', null, null, null]
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Decorations won't draw correctly for superscript
|
|
180
|
+
textDecorator.drawDecorations(line, x, y);
|
|
181
|
+
}
|
|
182
|
+
renderVector(vector) {
|
|
183
|
+
//TODO: pdf optimization (there's no need to write all properties everytime)
|
|
184
|
+
this.pdfDocument.lineWidth(vector.lineWidth || 1);
|
|
185
|
+
if (vector.dash) {
|
|
186
|
+
this.pdfDocument.dash(vector.dash.length, {
|
|
187
|
+
space: vector.dash.space || vector.dash.length,
|
|
188
|
+
phase: vector.dash.phase || 0
|
|
189
|
+
});
|
|
190
|
+
} else {
|
|
191
|
+
this.pdfDocument.undash();
|
|
192
|
+
}
|
|
193
|
+
this.pdfDocument.lineJoin(vector.lineJoin || 'miter');
|
|
194
|
+
this.pdfDocument.lineCap(vector.lineCap || 'butt');
|
|
195
|
+
|
|
196
|
+
//TODO: clipping
|
|
197
|
+
|
|
198
|
+
let gradient = null;
|
|
199
|
+
switch (vector.type) {
|
|
200
|
+
case 'ellipse':
|
|
201
|
+
this.pdfDocument.ellipse(vector.x, vector.y, vector.r1, vector.r2);
|
|
202
|
+
if (vector.linearGradient) {
|
|
203
|
+
gradient = this.pdfDocument.linearGradient(vector.x - vector.r1, vector.y, vector.x + vector.r1, vector.y);
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
case 'rect':
|
|
207
|
+
if (vector.r) {
|
|
208
|
+
this.pdfDocument.roundedRect(vector.x, vector.y, vector.w, vector.h, vector.r);
|
|
209
|
+
} else {
|
|
210
|
+
this.pdfDocument.rect(vector.x, vector.y, vector.w, vector.h);
|
|
211
|
+
}
|
|
212
|
+
if (vector.linearGradient) {
|
|
213
|
+
gradient = this.pdfDocument.linearGradient(vector.x, vector.y, vector.x + vector.w, vector.y);
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
case 'line':
|
|
217
|
+
this.pdfDocument.moveTo(vector.x1, vector.y1);
|
|
218
|
+
this.pdfDocument.lineTo(vector.x2, vector.y2);
|
|
219
|
+
break;
|
|
220
|
+
case 'polyline':
|
|
221
|
+
if (vector.points.length === 0) {
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
this.pdfDocument.moveTo(vector.points[0].x, vector.points[0].y);
|
|
225
|
+
for (let i = 1, l = vector.points.length; i < l; i++) {
|
|
226
|
+
this.pdfDocument.lineTo(vector.points[i].x, vector.points[i].y);
|
|
227
|
+
}
|
|
228
|
+
if (vector.points.length > 1) {
|
|
229
|
+
let p1 = vector.points[0];
|
|
230
|
+
let pn = vector.points[vector.points.length - 1];
|
|
231
|
+
if (vector.closePath || p1.x === pn.x && p1.y === pn.y) {
|
|
232
|
+
this.pdfDocument.closePath();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
case 'path':
|
|
237
|
+
this.pdfDocument.path(vector.d);
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
if (vector.linearGradient && gradient) {
|
|
241
|
+
let step = 1 / (vector.linearGradient.length - 1);
|
|
242
|
+
for (let i = 0; i < vector.linearGradient.length; i++) {
|
|
243
|
+
gradient.stop(i * step, vector.linearGradient[i]);
|
|
244
|
+
}
|
|
245
|
+
vector.color = gradient;
|
|
246
|
+
}
|
|
247
|
+
let patternColor = this.pdfDocument.providePattern(vector.color);
|
|
248
|
+
if (patternColor !== null) {
|
|
249
|
+
vector.color = patternColor;
|
|
250
|
+
}
|
|
251
|
+
let fillOpacity = (0, _variableType.isNumber)(vector.fillOpacity) ? vector.fillOpacity : 1;
|
|
252
|
+
let strokeOpacity = (0, _variableType.isNumber)(vector.strokeOpacity) ? vector.strokeOpacity : 1;
|
|
253
|
+
if (vector.color && vector.lineColor) {
|
|
254
|
+
this.pdfDocument.fillColor(vector.color, fillOpacity);
|
|
255
|
+
this.pdfDocument.strokeColor(vector.lineColor, strokeOpacity);
|
|
256
|
+
this.pdfDocument.fillAndStroke();
|
|
257
|
+
} else if (vector.color) {
|
|
258
|
+
this.pdfDocument.fillColor(vector.color, fillOpacity);
|
|
259
|
+
this.pdfDocument.fill();
|
|
260
|
+
} else {
|
|
261
|
+
this.pdfDocument.strokeColor(vector.lineColor || 'black', strokeOpacity);
|
|
262
|
+
this.pdfDocument.stroke();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
renderImage(image) {
|
|
266
|
+
let opacity = (0, _variableType.isNumber)(image.opacity) ? image.opacity : 1;
|
|
267
|
+
this.pdfDocument.opacity(opacity);
|
|
268
|
+
if (image.cover) {
|
|
269
|
+
const align = image.cover.align || 'center';
|
|
270
|
+
const valign = image.cover.valign || 'center';
|
|
271
|
+
const width = image.cover.width ? image.cover.width : image.width;
|
|
272
|
+
const height = image.cover.height ? image.cover.height : image.height;
|
|
273
|
+
this.pdfDocument.save();
|
|
274
|
+
this.pdfDocument.rect(image.x, image.y, width, height).clip();
|
|
275
|
+
this.pdfDocument.image(image.image, image.x, image.y, {
|
|
276
|
+
cover: [width, height],
|
|
277
|
+
align: align,
|
|
278
|
+
valign: valign
|
|
279
|
+
});
|
|
280
|
+
this.pdfDocument.restore();
|
|
281
|
+
} else {
|
|
282
|
+
this.pdfDocument.image(image.image, image.x, image.y, {
|
|
283
|
+
width: image._width,
|
|
284
|
+
height: image._height
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
if (image.link) {
|
|
288
|
+
this.pdfDocument.link(image.x, image.y, image._width, image._height, image.link);
|
|
289
|
+
}
|
|
290
|
+
if (image.linkToPage) {
|
|
291
|
+
this.pdfDocument.ref({
|
|
292
|
+
Type: 'Action',
|
|
293
|
+
S: 'GoTo',
|
|
294
|
+
D: [image.linkToPage, 0, 0]
|
|
295
|
+
}).end();
|
|
296
|
+
this.pdfDocument.annotate(image.x, image.y, image._width, image._height, {
|
|
297
|
+
Subtype: 'Link',
|
|
298
|
+
Dest: [image.linkToPage - 1, 'XYZ', null, null, null]
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
if (image.linkToDestination) {
|
|
302
|
+
this.pdfDocument.goTo(image.x, image.y, image._width, image._height, image.linkToDestination);
|
|
303
|
+
}
|
|
304
|
+
if (image.linkToFile) {
|
|
305
|
+
const attachment = this.pdfDocument.provideAttachment(image.linkToFile);
|
|
306
|
+
this.pdfDocument.fileAnnotation(image.x, image.y, image._width, image._height, attachment,
|
|
307
|
+
// add empty rectangle as file annotation appearance with the same size as the rendered image
|
|
308
|
+
{
|
|
309
|
+
AP: {
|
|
310
|
+
N: {
|
|
311
|
+
Type: 'XObject',
|
|
312
|
+
Subtype: 'Form',
|
|
313
|
+
FormType: 1,
|
|
314
|
+
BBox: [image.x, image.y, image._width, image._height]
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
renderSVG(svg) {
|
|
321
|
+
let options = {
|
|
322
|
+
width: svg._width,
|
|
323
|
+
height: svg._height,
|
|
324
|
+
assumePt: true,
|
|
325
|
+
useCSS: !(0, _variableType.isString)(svg.svg),
|
|
326
|
+
...svg.options
|
|
327
|
+
};
|
|
328
|
+
options.fontCallback = (family, bold, italic) => {
|
|
329
|
+
let fontsFamily = family.split(',').map(f => f.trim().replace(/('|")/g, ''));
|
|
330
|
+
let font = findFont(this.pdfDocument.fonts, fontsFamily, svg.font || 'Roboto');
|
|
331
|
+
let fontFile = this.pdfDocument.getFontFile(font, bold, italic);
|
|
332
|
+
if (fontFile === null) {
|
|
333
|
+
let type = this.pdfDocument.getFontType(bold, italic);
|
|
334
|
+
throw new Error(`Font '${font}' in style '${type}' is not defined in the font section of the document definition.`);
|
|
335
|
+
}
|
|
336
|
+
return fontFile;
|
|
337
|
+
};
|
|
338
|
+
(0, _svgToPdfkit.default)(this.pdfDocument, svg.svg, svg.x, svg.y, options);
|
|
339
|
+
if (svg.link) {
|
|
340
|
+
this.pdfDocument.link(svg.x, svg.y, svg._width, svg._height, svg.link);
|
|
341
|
+
}
|
|
342
|
+
if (svg.linkToPage) {
|
|
343
|
+
this.pdfDocument.ref({
|
|
344
|
+
Type: 'Action',
|
|
345
|
+
S: 'GoTo',
|
|
346
|
+
D: [svg.linkToPage, 0, 0]
|
|
347
|
+
}).end();
|
|
348
|
+
this.pdfDocument.annotate(svg.x, svg.y, svg._width, svg._height, {
|
|
349
|
+
Subtype: 'Link',
|
|
350
|
+
Dest: [svg.linkToPage - 1, 'XYZ', null, null, null]
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
if (svg.linkToDestination) {
|
|
354
|
+
this.pdfDocument.goTo(svg.x, svg.y, svg._width, svg._height, svg.linkToDestination);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
renderAttachment(attachment) {
|
|
358
|
+
const file = this.pdfDocument.provideAttachment(attachment.attachment);
|
|
359
|
+
const options = {};
|
|
360
|
+
if (attachment.icon) {
|
|
361
|
+
options.Name = attachment.icon;
|
|
362
|
+
}
|
|
363
|
+
this.pdfDocument.fileAnnotation(attachment.x, attachment.y, attachment._width, attachment._height, file, options);
|
|
364
|
+
}
|
|
365
|
+
beginClip(rect) {
|
|
366
|
+
this.pdfDocument.save();
|
|
367
|
+
this.pdfDocument.addContent(`${rect.x} ${rect.y} ${rect.width} ${rect.height} re`);
|
|
368
|
+
this.pdfDocument.clip();
|
|
369
|
+
}
|
|
370
|
+
endClip() {
|
|
371
|
+
this.pdfDocument.restore();
|
|
372
|
+
}
|
|
373
|
+
beginVerticalAlignment(item) {
|
|
374
|
+
if (item.isCellContentMultiPage) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
switch (item.verticalAlignment) {
|
|
378
|
+
case 'middle':
|
|
379
|
+
this.pdfDocument.save();
|
|
380
|
+
this.pdfDocument.translate(0, -(item.getNodeHeight() - item.getViewHeight()) / 2);
|
|
381
|
+
break;
|
|
382
|
+
case 'bottom':
|
|
383
|
+
this.pdfDocument.save();
|
|
384
|
+
this.pdfDocument.translate(0, -(item.getNodeHeight() - item.getViewHeight()));
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
endVerticalAlignment(item) {
|
|
389
|
+
if (item.isCellContentMultiPage) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
switch (item.verticalAlignment) {
|
|
393
|
+
case 'middle':
|
|
394
|
+
case 'bottom':
|
|
395
|
+
this.pdfDocument.restore();
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
renderWatermark(page) {
|
|
400
|
+
let watermark = page.watermark;
|
|
401
|
+
this.pdfDocument.fill(watermark.color);
|
|
402
|
+
this.pdfDocument.opacity(watermark.opacity);
|
|
403
|
+
this.pdfDocument.save();
|
|
404
|
+
this.pdfDocument.rotate(watermark.angle, {
|
|
405
|
+
origin: [this.pdfDocument.page.width / 2, this.pdfDocument.page.height / 2]
|
|
406
|
+
});
|
|
407
|
+
let x = this.pdfDocument.page.width / 2 - watermark._size.size.width / 2;
|
|
408
|
+
let y = this.pdfDocument.page.height / 2 - watermark._size.size.height / 2;
|
|
409
|
+
this.pdfDocument._font = watermark.font;
|
|
410
|
+
this.pdfDocument.fontSize(watermark.fontSize);
|
|
411
|
+
this.pdfDocument.text(watermark.text, x, y, {
|
|
412
|
+
lineBreak: false
|
|
413
|
+
});
|
|
414
|
+
this.pdfDocument.restore();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
var _default = exports.default = Renderer;
|
package/js/SVGMeasure.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _xmldoc = require("xmldoc");
|
|
6
|
+
var _variableType = require("./helpers/variableType");
|
|
7
|
+
/**
|
|
8
|
+
* Strip unit postfix, parse number, but return undefined instead of NaN for bad input
|
|
9
|
+
*
|
|
10
|
+
* @param {string} textVal
|
|
11
|
+
* @returns {?number}
|
|
12
|
+
*/
|
|
13
|
+
const stripUnits = textVal => {
|
|
14
|
+
let n = parseFloat(textVal);
|
|
15
|
+
if (typeof n !== 'number' || isNaN(n)) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
return n;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Make sure it's valid XML and the root tag is <svg/>, returns xmldoc DOM
|
|
23
|
+
*
|
|
24
|
+
* @param {string} svgString
|
|
25
|
+
* @returns {object}
|
|
26
|
+
*/
|
|
27
|
+
const parseSVG = svgString => {
|
|
28
|
+
let doc;
|
|
29
|
+
try {
|
|
30
|
+
doc = new _xmldoc.XmlDocument(svgString);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
throw new Error('Invalid svg document (' + err + ')');
|
|
33
|
+
}
|
|
34
|
+
if (doc.name !== "svg") {
|
|
35
|
+
throw new Error('Invalid svg document (expected <svg>)');
|
|
36
|
+
}
|
|
37
|
+
return doc;
|
|
38
|
+
};
|
|
39
|
+
class SVGMeasure {
|
|
40
|
+
constructor() {}
|
|
41
|
+
measureSVG(svg) {
|
|
42
|
+
let width, height, viewBox;
|
|
43
|
+
if ((0, _variableType.isString)(svg)) {
|
|
44
|
+
let doc = parseSVG(svg);
|
|
45
|
+
width = doc.attr.width;
|
|
46
|
+
height = doc.attr.height;
|
|
47
|
+
viewBox = doc.attr.viewBox;
|
|
48
|
+
} else if (typeof SVGElement !== 'undefined' && svg instanceof SVGElement && typeof getComputedStyle === 'function') {
|
|
49
|
+
width = svg.getAttribute("width");
|
|
50
|
+
height = svg.getAttribute("height");
|
|
51
|
+
viewBox = svg.getAttribute("viewBox");
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error('Invalid SVG document');
|
|
54
|
+
}
|
|
55
|
+
let docWidth = stripUnits(width);
|
|
56
|
+
let docHeight = stripUnits(height);
|
|
57
|
+
if ((docWidth === undefined || docHeight === undefined) && typeof viewBox === 'string') {
|
|
58
|
+
let viewBoxParts = viewBox.split(/[,\s]+/);
|
|
59
|
+
if (viewBoxParts.length !== 4) {
|
|
60
|
+
throw new Error("Unexpected svg viewBox format, should have 4 entries but found: '" + viewBox + "'");
|
|
61
|
+
}
|
|
62
|
+
if (docWidth === undefined) {
|
|
63
|
+
docWidth = stripUnits(viewBoxParts[2]);
|
|
64
|
+
}
|
|
65
|
+
if (docHeight === undefined) {
|
|
66
|
+
docHeight = stripUnits(viewBoxParts[3]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
width: docWidth,
|
|
71
|
+
height: docHeight
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
writeDimensions(svg, dimensions) {
|
|
75
|
+
if ((0, _variableType.isString)(svg)) {
|
|
76
|
+
let doc = parseSVG(svg);
|
|
77
|
+
if (typeof doc.attr.viewBox !== 'string') {
|
|
78
|
+
doc.attr.viewBox = `0 0 ${stripUnits(doc.attr.width)} ${stripUnits(doc.attr.height)}`;
|
|
79
|
+
}
|
|
80
|
+
doc.attr.width = "" + dimensions.width;
|
|
81
|
+
doc.attr.height = "" + dimensions.height;
|
|
82
|
+
return doc.toString();
|
|
83
|
+
}
|
|
84
|
+
if (!svg.hasAttribute('viewBox')) {
|
|
85
|
+
svg.setAttribute('viewBox', `0 0 ${stripUnits(svg.getAttribute('width'))} ${stripUnits(svg.getAttribute('height'))}`);
|
|
86
|
+
}
|
|
87
|
+
svg.setAttribute('width', "" + dimensions.width);
|
|
88
|
+
svg.setAttribute('height', "" + dimensions.height);
|
|
89
|
+
return svg;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
var _default = exports.default = SVGMeasure;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _variableType = require("./helpers/variableType");
|
|
6
|
+
/**
|
|
7
|
+
* Used for style inheritance and style overrides
|
|
8
|
+
*/
|
|
9
|
+
class StyleContextStack {
|
|
10
|
+
/**
|
|
11
|
+
* @param {object} styleDictionary named styles dictionary
|
|
12
|
+
* @param {object} defaultStyle optional default style definition
|
|
13
|
+
*/
|
|
14
|
+
constructor(styleDictionary, defaultStyle = {}) {
|
|
15
|
+
this.styleDictionary = styleDictionary;
|
|
16
|
+
this.defaultStyle = defaultStyle;
|
|
17
|
+
this.styleOverrides = [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates cloned version of current stack
|
|
22
|
+
*
|
|
23
|
+
* @returns {StyleContextStack} current stack snapshot
|
|
24
|
+
*/
|
|
25
|
+
clone() {
|
|
26
|
+
let stack = new StyleContextStack(this.styleDictionary, this.defaultStyle);
|
|
27
|
+
this.styleOverrides.forEach(item => {
|
|
28
|
+
stack.styleOverrides.push(item);
|
|
29
|
+
});
|
|
30
|
+
return stack;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Pushes style-name or style-overrides-object onto the stack for future evaluation
|
|
35
|
+
*
|
|
36
|
+
* @param {string|object} styleNameOrOverride style-name (referring to styleDictionary) or
|
|
37
|
+
* a new dictionary defining overriding properties
|
|
38
|
+
*/
|
|
39
|
+
push(styleNameOrOverride) {
|
|
40
|
+
this.styleOverrides.push(styleNameOrOverride);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Removes last style-name or style-overrides-object from the stack
|
|
45
|
+
*
|
|
46
|
+
* @param {number} howMany optional number of elements to be popped (if not specified,
|
|
47
|
+
* one element will be removed from the stack)
|
|
48
|
+
*/
|
|
49
|
+
pop(howMany = 1) {
|
|
50
|
+
while (howMany-- > 0) {
|
|
51
|
+
this.styleOverrides.pop();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates a set of named styles or/and a style-overrides-object based on the item,
|
|
57
|
+
* pushes those elements onto the stack for future evaluation and returns the number
|
|
58
|
+
* of elements pushed, so they can be easily popped then.
|
|
59
|
+
*
|
|
60
|
+
* @param {object} item - an object with optional style property and/or style overrides
|
|
61
|
+
* @returns {number} the number of items pushed onto the stack
|
|
62
|
+
*/
|
|
63
|
+
autopush(item) {
|
|
64
|
+
if ((0, _variableType.isString)(item)) {
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
if (typeof item.section !== 'undefined') {
|
|
68
|
+
// section node not support style overrides
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
let styleNames = [];
|
|
72
|
+
if (item.style) {
|
|
73
|
+
if (Array.isArray(item.style)) {
|
|
74
|
+
styleNames = item.style;
|
|
75
|
+
} else {
|
|
76
|
+
styleNames = [item.style];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
for (let i = 0, l = styleNames.length; i < l; i++) {
|
|
80
|
+
this.push(styleNames[i]);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// rather than spend significant time making a styleOverrideObject, just add item
|
|
84
|
+
this.push(item);
|
|
85
|
+
return styleNames.length + 1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Automatically pushes elements onto the stack, using autopush based on item,
|
|
90
|
+
* executes callback and then pops elements back. Returns value returned by callback
|
|
91
|
+
*
|
|
92
|
+
* @param {object} item - an object with optional style property and/or style overrides
|
|
93
|
+
* @param {Function} callback to be called between autopush and pop
|
|
94
|
+
* @returns {object} value returned by callback
|
|
95
|
+
*/
|
|
96
|
+
auto(item, callback) {
|
|
97
|
+
let pushedItems = this.autopush(item);
|
|
98
|
+
let result = callback();
|
|
99
|
+
if (pushedItems > 0) {
|
|
100
|
+
this.pop(pushedItems);
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Evaluates stack and returns value of a named property
|
|
107
|
+
*
|
|
108
|
+
* @param {string} property - property name
|
|
109
|
+
* @returns {?any} property value or null if not found
|
|
110
|
+
*/
|
|
111
|
+
getProperty(property) {
|
|
112
|
+
const getStylePropertyFromStyle = (styleName, property, visited = new Set()) => {
|
|
113
|
+
if (visited.has(styleName)) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
visited.add(styleName);
|
|
117
|
+
const style = this.styleDictionary[styleName];
|
|
118
|
+
if (!style) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
if ((0, _variableType.isValue)(style[property])) {
|
|
122
|
+
return style[property];
|
|
123
|
+
}
|
|
124
|
+
if (style.extends) {
|
|
125
|
+
let parents = Array.isArray(style.extends) ? style.extends : [style.extends];
|
|
126
|
+
for (let i = parents.length - 1; i >= 0; i--) {
|
|
127
|
+
let value = getStylePropertyFromStyle(parents[i], property, visited);
|
|
128
|
+
if ((0, _variableType.isValue)(value)) {
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
};
|
|
135
|
+
if (this.styleOverrides) {
|
|
136
|
+
for (let i = this.styleOverrides.length - 1; i >= 0; i--) {
|
|
137
|
+
let item = this.styleOverrides[i];
|
|
138
|
+
if ((0, _variableType.isString)(item)) {
|
|
139
|
+
// named-style-override
|
|
140
|
+
let value = getStylePropertyFromStyle(item, property);
|
|
141
|
+
if ((0, _variableType.isValue)(value)) {
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
} else if ((0, _variableType.isValue)(item[property])) {
|
|
145
|
+
// style-overrides-object
|
|
146
|
+
return item[property];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return this.defaultStyle && this.defaultStyle[property];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param {object} item
|
|
155
|
+
* @param {StyleContextStack} styleContextStack
|
|
156
|
+
* @param {string} property
|
|
157
|
+
* @param {any} defaultValue
|
|
158
|
+
* @returns {any}
|
|
159
|
+
*/
|
|
160
|
+
static getStyleProperty(item, styleContextStack, property, defaultValue) {
|
|
161
|
+
let value;
|
|
162
|
+
if ((0, _variableType.isValue)(item[property])) {
|
|
163
|
+
// item defines this property
|
|
164
|
+
return item[property];
|
|
165
|
+
}
|
|
166
|
+
if (!styleContextStack) {
|
|
167
|
+
return defaultValue;
|
|
168
|
+
}
|
|
169
|
+
styleContextStack.auto(item, () => {
|
|
170
|
+
value = styleContextStack.getProperty(property);
|
|
171
|
+
});
|
|
172
|
+
return (0, _variableType.isValue)(value) ? value : defaultValue;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @param {object} source
|
|
177
|
+
* @param {object} destination
|
|
178
|
+
* @returns {object}
|
|
179
|
+
*/
|
|
180
|
+
static copyStyle(source = {}, destination = {}) {
|
|
181
|
+
// TODO: default style to source
|
|
182
|
+
|
|
183
|
+
for (let key in source) {
|
|
184
|
+
if (key != 'text' && source.hasOwnProperty(key)) {
|
|
185
|
+
destination[key] = source[key];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return destination;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
var _default = exports.default = StyleContextStack;
|