pdfkit 0.16.0 → 0.17.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.
- package/CHANGELOG.md +19 -0
- package/js/pdfkit.es.js +1007 -798
- package/js/pdfkit.es.js.map +1 -1
- package/js/pdfkit.es5.js +7493 -0
- package/js/pdfkit.es5.js.map +1 -0
- package/js/pdfkit.esnext.js +6782 -0
- package/js/pdfkit.esnext.js.map +1 -0
- package/js/pdfkit.js +986 -799
- package/js/pdfkit.js.map +1 -1
- package/js/pdfkit.standalone.js +986 -799
- package/package.json +4 -4
package/js/pdfkit.js
CHANGED
|
@@ -10,23 +10,15 @@ var LineBreaker = require('linebreak');
|
|
|
10
10
|
var exif = require('jpeg-exif');
|
|
11
11
|
var PNG = require('png-js');
|
|
12
12
|
|
|
13
|
-
/*
|
|
14
|
-
PDFAbstractReference - abstract class for PDF reference
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
13
|
class PDFAbstractReference {
|
|
18
14
|
toString() {
|
|
19
15
|
throw new Error('Must be implemented by subclasses');
|
|
20
16
|
}
|
|
21
17
|
}
|
|
22
18
|
|
|
23
|
-
/*
|
|
24
|
-
PDFTree - abstract base class for name and number tree objects
|
|
25
|
-
*/
|
|
26
19
|
class PDFTree {
|
|
27
20
|
constructor(options = {}) {
|
|
28
21
|
this._items = {};
|
|
29
|
-
// disable /Limits output for this tree
|
|
30
22
|
this.limits = typeof options.limits === 'boolean' ? options.limits : true;
|
|
31
23
|
}
|
|
32
24
|
add(key, val) {
|
|
@@ -36,7 +28,6 @@ class PDFTree {
|
|
|
36
28
|
return this._items[key];
|
|
37
29
|
}
|
|
38
30
|
toString() {
|
|
39
|
-
// Needs to be sorted by key
|
|
40
31
|
const sortedKeys = Object.keys(this._items).sort((a, b) => this._compareKeys(a, b));
|
|
41
32
|
const out = ['<<'];
|
|
42
33
|
if (this.limits && sortedKeys.length > 1) {
|
|
@@ -52,15 +43,13 @@ class PDFTree {
|
|
|
52
43
|
out.push('>>');
|
|
53
44
|
return out.join('\n');
|
|
54
45
|
}
|
|
55
|
-
_compareKeys(
|
|
56
|
-
) {
|
|
46
|
+
_compareKeys() {
|
|
57
47
|
throw new Error('Must be implemented by subclasses');
|
|
58
48
|
}
|
|
59
49
|
_keysName() {
|
|
60
50
|
throw new Error('Must be implemented by subclasses');
|
|
61
51
|
}
|
|
62
|
-
_dataForKey(
|
|
63
|
-
) {
|
|
52
|
+
_dataForKey() {
|
|
64
53
|
throw new Error('Must be implemented by subclasses');
|
|
65
54
|
}
|
|
66
55
|
}
|
|
@@ -85,10 +74,6 @@ class SpotColor {
|
|
|
85
74
|
}
|
|
86
75
|
}
|
|
87
76
|
|
|
88
|
-
/*
|
|
89
|
-
PDFObject - converts JavaScript types into their corresponding PDF types.
|
|
90
|
-
By Devon Govett
|
|
91
|
-
*/
|
|
92
77
|
const pad = (str, length) => (Array(length + 1).join('0') + str).slice(-length);
|
|
93
78
|
const escapableRe = /[\n\r\t\b\f()\\]/g;
|
|
94
79
|
const escapable = {
|
|
@@ -101,8 +86,6 @@ const escapable = {
|
|
|
101
86
|
'(': '\\(',
|
|
102
87
|
')': '\\)'
|
|
103
88
|
};
|
|
104
|
-
|
|
105
|
-
// Convert little endian UTF-16 to big endian
|
|
106
89
|
const swapBytes = function (buff) {
|
|
107
90
|
const l = buff.length;
|
|
108
91
|
if (l & 0x01) {
|
|
@@ -118,14 +101,10 @@ const swapBytes = function (buff) {
|
|
|
118
101
|
};
|
|
119
102
|
class PDFObject {
|
|
120
103
|
static convert(object, encryptFn = null) {
|
|
121
|
-
// String literals are converted to the PDF name type
|
|
122
104
|
if (typeof object === 'string') {
|
|
123
105
|
return `/${object}`;
|
|
124
|
-
|
|
125
|
-
// String objects are converted to PDF strings (UTF-16)
|
|
126
106
|
} else if (object instanceof String) {
|
|
127
107
|
let string = object;
|
|
128
|
-
// Detect if this is a unicode string
|
|
129
108
|
let isUnicode = false;
|
|
130
109
|
for (let i = 0, end = string.length; i < end; i++) {
|
|
131
110
|
if (string.charCodeAt(i) > 0x7f) {
|
|
@@ -133,39 +112,27 @@ class PDFObject {
|
|
|
133
112
|
break;
|
|
134
113
|
}
|
|
135
114
|
}
|
|
136
|
-
|
|
137
|
-
// If so, encode it as big endian UTF-16
|
|
138
115
|
let stringBuffer;
|
|
139
116
|
if (isUnicode) {
|
|
140
117
|
stringBuffer = swapBytes(Buffer.from(`\ufeff${string}`, 'utf16le'));
|
|
141
118
|
} else {
|
|
142
119
|
stringBuffer = Buffer.from(string.valueOf(), 'ascii');
|
|
143
120
|
}
|
|
144
|
-
|
|
145
|
-
// Encrypt the string when necessary
|
|
146
121
|
if (encryptFn) {
|
|
147
122
|
string = encryptFn(stringBuffer).toString('binary');
|
|
148
123
|
} else {
|
|
149
124
|
string = stringBuffer.toString('binary');
|
|
150
125
|
}
|
|
151
|
-
|
|
152
|
-
// Escape characters as required by the spec
|
|
153
126
|
string = string.replace(escapableRe, c => escapable[c]);
|
|
154
127
|
return `(${string})`;
|
|
155
|
-
|
|
156
|
-
// Buffers are converted to PDF hex strings
|
|
157
128
|
} else if (Buffer.isBuffer(object)) {
|
|
158
129
|
return `<${object.toString('hex')}>`;
|
|
159
130
|
} else if (object instanceof PDFAbstractReference || object instanceof PDFTree || object instanceof SpotColor) {
|
|
160
131
|
return object.toString();
|
|
161
132
|
} else if (object instanceof Date) {
|
|
162
133
|
let string = `D:${pad(object.getUTCFullYear(), 4)}` + pad(object.getUTCMonth() + 1, 2) + pad(object.getUTCDate(), 2) + pad(object.getUTCHours(), 2) + pad(object.getUTCMinutes(), 2) + pad(object.getUTCSeconds(), 2) + 'Z';
|
|
163
|
-
|
|
164
|
-
// Encrypt the string when necessary
|
|
165
134
|
if (encryptFn) {
|
|
166
135
|
string = encryptFn(Buffer.from(string, 'ascii')).toString('binary');
|
|
167
|
-
|
|
168
|
-
// Escape characters as required by the spec
|
|
169
136
|
string = string.replace(escapableRe, c => escapable[c]);
|
|
170
137
|
}
|
|
171
138
|
return `(${string})`;
|
|
@@ -194,10 +161,6 @@ class PDFObject {
|
|
|
194
161
|
}
|
|
195
162
|
}
|
|
196
163
|
|
|
197
|
-
/*
|
|
198
|
-
PDFReference - represents a reference to another object in the PDF object heirarchy
|
|
199
|
-
By Devon Govett
|
|
200
|
-
*/
|
|
201
164
|
class PDFReference extends PDFAbstractReference {
|
|
202
165
|
constructor(document, id, data = {}) {
|
|
203
166
|
super();
|
|
@@ -220,14 +183,14 @@ class PDFReference extends PDFAbstractReference {
|
|
|
220
183
|
this.buffer.push(chunk);
|
|
221
184
|
this.data.Length += chunk.length;
|
|
222
185
|
if (this.compress) {
|
|
223
|
-
|
|
186
|
+
this.data.Filter = 'FlateDecode';
|
|
224
187
|
}
|
|
225
188
|
}
|
|
226
189
|
end(chunk) {
|
|
227
190
|
if (chunk) {
|
|
228
191
|
this.write(chunk);
|
|
229
192
|
}
|
|
230
|
-
|
|
193
|
+
this.finalize();
|
|
231
194
|
}
|
|
232
195
|
finalize() {
|
|
233
196
|
this.offset = this.document._offset;
|
|
@@ -247,7 +210,7 @@ class PDFReference extends PDFAbstractReference {
|
|
|
247
210
|
if (this.buffer.length) {
|
|
248
211
|
this.document._write('stream');
|
|
249
212
|
this.document._write(this.buffer);
|
|
250
|
-
this.buffer = [];
|
|
213
|
+
this.buffer = [];
|
|
251
214
|
this.document._write('\nendstream');
|
|
252
215
|
}
|
|
253
216
|
this.document._write('endobj');
|
|
@@ -258,10 +221,79 @@ class PDFReference extends PDFAbstractReference {
|
|
|
258
221
|
}
|
|
259
222
|
}
|
|
260
223
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
224
|
+
const fArray = new Float32Array(1);
|
|
225
|
+
const uArray = new Uint32Array(fArray.buffer);
|
|
226
|
+
function PDFNumber(n) {
|
|
227
|
+
const rounded = Math.fround(n);
|
|
228
|
+
if (rounded <= n) return rounded;
|
|
229
|
+
fArray[0] = n;
|
|
230
|
+
if (n <= 0) {
|
|
231
|
+
uArray[0] += 1;
|
|
232
|
+
} else {
|
|
233
|
+
uArray[0] -= 1;
|
|
234
|
+
}
|
|
235
|
+
return fArray[0];
|
|
236
|
+
}
|
|
237
|
+
function normalizeSides(sides, defaultDefinition = undefined, transformer = v => v) {
|
|
238
|
+
if (sides == null || typeof sides === 'object' && Object.keys(sides).length === 0) {
|
|
239
|
+
sides = defaultDefinition;
|
|
240
|
+
}
|
|
241
|
+
if (sides == null || typeof sides !== 'object') {
|
|
242
|
+
sides = {
|
|
243
|
+
top: sides,
|
|
244
|
+
right: sides,
|
|
245
|
+
bottom: sides,
|
|
246
|
+
left: sides
|
|
247
|
+
};
|
|
248
|
+
} else if (Array.isArray(sides)) {
|
|
249
|
+
if (sides.length === 2) {
|
|
250
|
+
sides = {
|
|
251
|
+
vertical: sides[0],
|
|
252
|
+
horizontal: sides[1]
|
|
253
|
+
};
|
|
254
|
+
} else {
|
|
255
|
+
sides = {
|
|
256
|
+
top: sides[0],
|
|
257
|
+
right: sides[1],
|
|
258
|
+
bottom: sides[2],
|
|
259
|
+
left: sides[3]
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if ('vertical' in sides || 'horizontal' in sides) {
|
|
264
|
+
sides = {
|
|
265
|
+
top: sides.vertical,
|
|
266
|
+
right: sides.horizontal,
|
|
267
|
+
bottom: sides.vertical,
|
|
268
|
+
left: sides.horizontal
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
top: transformer(sides.top),
|
|
273
|
+
right: transformer(sides.right),
|
|
274
|
+
bottom: transformer(sides.bottom),
|
|
275
|
+
left: transformer(sides.left)
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const MM_TO_CM = 1 / 10;
|
|
279
|
+
const CM_TO_IN = 1 / 2.54;
|
|
280
|
+
const PX_TO_IN = 1 / 96;
|
|
281
|
+
const IN_TO_PT = 72;
|
|
282
|
+
const PC_TO_PT = 12;
|
|
283
|
+
function cosine(a) {
|
|
284
|
+
if (a === 0) return 1;
|
|
285
|
+
if (a === 90) return 0;
|
|
286
|
+
if (a === 180) return -1;
|
|
287
|
+
if (a === 270) return 0;
|
|
288
|
+
return Math.cos(a * Math.PI / 180);
|
|
289
|
+
}
|
|
290
|
+
function sine(a) {
|
|
291
|
+
if (a === 0) return 0;
|
|
292
|
+
if (a === 90) return 1;
|
|
293
|
+
if (a === 180) return 0;
|
|
294
|
+
if (a === 270) return -1;
|
|
295
|
+
return Math.sin(a * Math.PI / 180);
|
|
296
|
+
}
|
|
265
297
|
|
|
266
298
|
const DEFAULT_MARGINS = {
|
|
267
299
|
top: 72,
|
|
@@ -324,35 +356,19 @@ const SIZES = {
|
|
|
324
356
|
class PDFPage {
|
|
325
357
|
constructor(document, options = {}) {
|
|
326
358
|
this.document = document;
|
|
359
|
+
this._options = options;
|
|
327
360
|
this.size = options.size || 'letter';
|
|
328
361
|
this.layout = options.layout || 'portrait';
|
|
329
|
-
|
|
330
|
-
// process margins
|
|
331
|
-
if (typeof options.margin === 'number') {
|
|
332
|
-
this.margins = {
|
|
333
|
-
top: options.margin,
|
|
334
|
-
left: options.margin,
|
|
335
|
-
bottom: options.margin,
|
|
336
|
-
right: options.margin
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
// default to 1 inch margins
|
|
340
|
-
} else {
|
|
341
|
-
this.margins = options.margins || DEFAULT_MARGINS;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// calculate page dimensions
|
|
345
362
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
346
363
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
347
364
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
348
365
|
this.content = this.document.ref();
|
|
349
|
-
|
|
350
|
-
|
|
366
|
+
if (options.font) document.font(options.font, options.fontFamily);
|
|
367
|
+
if (options.fontSize) document.fontSize(options.fontSize);
|
|
368
|
+
this.margins = normalizeSides(options.margin ?? options.margins, DEFAULT_MARGINS, x => document.sizeToPoint(x, 0, this));
|
|
351
369
|
this.resources = this.document.ref({
|
|
352
370
|
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI']
|
|
353
371
|
});
|
|
354
|
-
|
|
355
|
-
// The page dictionary
|
|
356
372
|
this.dictionary = this.document.ref({
|
|
357
373
|
Type: 'Page',
|
|
358
374
|
Parent: this.document._root.data.Pages,
|
|
@@ -362,8 +378,6 @@ class PDFPage {
|
|
|
362
378
|
});
|
|
363
379
|
this.markings = [];
|
|
364
380
|
}
|
|
365
|
-
|
|
366
|
-
// Lazily create these objects
|
|
367
381
|
get fonts() {
|
|
368
382
|
const data = this.resources.data;
|
|
369
383
|
return data.Font != null ? data.Font : data.Font = {};
|
|
@@ -392,14 +406,18 @@ class PDFPage {
|
|
|
392
406
|
const data = this.dictionary.data;
|
|
393
407
|
return data.StructParents != null ? data.StructParents : data.StructParents = this.document.createStructParentTreeNextKey();
|
|
394
408
|
}
|
|
409
|
+
get contentWidth() {
|
|
410
|
+
return this.width - this.margins.left - this.margins.right;
|
|
411
|
+
}
|
|
412
|
+
get contentHeight() {
|
|
413
|
+
return this.height - this.margins.top - this.margins.bottom;
|
|
414
|
+
}
|
|
395
415
|
maxY() {
|
|
396
416
|
return this.height - this.margins.bottom;
|
|
397
417
|
}
|
|
398
418
|
write(chunk) {
|
|
399
419
|
return this.content.write(chunk);
|
|
400
420
|
}
|
|
401
|
-
|
|
402
|
-
// Set tab order if document is tagged for accessibility.
|
|
403
421
|
_setTabOrder() {
|
|
404
422
|
if (!this.dictionary.Tabs && this.document.hasMarkInfoDictionary()) {
|
|
405
423
|
this.dictionary.data.Tabs = 'S';
|
|
@@ -417,191 +435,57 @@ class PDFPage {
|
|
|
417
435
|
}
|
|
418
436
|
}
|
|
419
437
|
|
|
420
|
-
/*
|
|
421
|
-
PDFNameTree - represents a name tree object
|
|
422
|
-
*/
|
|
423
438
|
class PDFNameTree extends PDFTree {
|
|
424
439
|
_compareKeys(a, b) {
|
|
425
440
|
return a.localeCompare(b);
|
|
426
441
|
}
|
|
427
442
|
_keysName() {
|
|
428
|
-
return
|
|
443
|
+
return 'Names';
|
|
429
444
|
}
|
|
430
445
|
_dataForKey(k) {
|
|
431
446
|
return new String(k);
|
|
432
447
|
}
|
|
433
448
|
}
|
|
434
449
|
|
|
435
|
-
/**
|
|
436
|
-
* Check if value is in a range group.
|
|
437
|
-
* @param {number} value
|
|
438
|
-
* @param {number[]} rangeGroup
|
|
439
|
-
* @returns {boolean}
|
|
440
|
-
*/
|
|
441
450
|
function inRange(value, rangeGroup) {
|
|
442
451
|
if (value < rangeGroup[0]) return false;
|
|
443
452
|
let startRange = 0;
|
|
444
453
|
let endRange = rangeGroup.length / 2;
|
|
445
454
|
while (startRange <= endRange) {
|
|
446
455
|
const middleRange = Math.floor((startRange + endRange) / 2);
|
|
447
|
-
|
|
448
|
-
// actual array index
|
|
449
456
|
const arrayIndex = middleRange * 2;
|
|
450
|
-
|
|
451
|
-
// Check if value is in range pointed by actual index
|
|
452
457
|
if (value >= rangeGroup[arrayIndex] && value <= rangeGroup[arrayIndex + 1]) {
|
|
453
458
|
return true;
|
|
454
459
|
}
|
|
455
460
|
if (value > rangeGroup[arrayIndex + 1]) {
|
|
456
|
-
// Search Right Side Of Array
|
|
457
461
|
startRange = middleRange + 1;
|
|
458
462
|
} else {
|
|
459
|
-
// Search Left Side Of Array
|
|
460
463
|
endRange = middleRange - 1;
|
|
461
464
|
}
|
|
462
465
|
}
|
|
463
466
|
return false;
|
|
464
467
|
}
|
|
465
468
|
|
|
466
|
-
// prettier-ignore-start
|
|
467
|
-
/**
|
|
468
|
-
* A.1 Unassigned code points in Unicode 3.2
|
|
469
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-A.1
|
|
470
|
-
*/
|
|
471
469
|
const unassigned_code_points = [0x0221, 0x0221, 0x0234, 0x024f, 0x02ae, 0x02af, 0x02ef, 0x02ff, 0x0350, 0x035f, 0x0370, 0x0373, 0x0376, 0x0379, 0x037b, 0x037d, 0x037f, 0x0383, 0x038b, 0x038b, 0x038d, 0x038d, 0x03a2, 0x03a2, 0x03cf, 0x03cf, 0x03f7, 0x03ff, 0x0487, 0x0487, 0x04cf, 0x04cf, 0x04f6, 0x04f7, 0x04fa, 0x04ff, 0x0510, 0x0530, 0x0557, 0x0558, 0x0560, 0x0560, 0x0588, 0x0588, 0x058b, 0x0590, 0x05a2, 0x05a2, 0x05ba, 0x05ba, 0x05c5, 0x05cf, 0x05eb, 0x05ef, 0x05f5, 0x060b, 0x060d, 0x061a, 0x061c, 0x061e, 0x0620, 0x0620, 0x063b, 0x063f, 0x0656, 0x065f, 0x06ee, 0x06ef, 0x06ff, 0x06ff, 0x070e, 0x070e, 0x072d, 0x072f, 0x074b, 0x077f, 0x07b2, 0x0900, 0x0904, 0x0904, 0x093a, 0x093b, 0x094e, 0x094f, 0x0955, 0x0957, 0x0971, 0x0980, 0x0984, 0x0984, 0x098d, 0x098e, 0x0991, 0x0992, 0x09a9, 0x09a9, 0x09b1, 0x09b1, 0x09b3, 0x09b5, 0x09ba, 0x09bb, 0x09bd, 0x09bd, 0x09c5, 0x09c6, 0x09c9, 0x09ca, 0x09ce, 0x09d6, 0x09d8, 0x09db, 0x09de, 0x09de, 0x09e4, 0x09e5, 0x09fb, 0x0a01, 0x0a03, 0x0a04, 0x0a0b, 0x0a0e, 0x0a11, 0x0a12, 0x0a29, 0x0a29, 0x0a31, 0x0a31, 0x0a34, 0x0a34, 0x0a37, 0x0a37, 0x0a3a, 0x0a3b, 0x0a3d, 0x0a3d, 0x0a43, 0x0a46, 0x0a49, 0x0a4a, 0x0a4e, 0x0a58, 0x0a5d, 0x0a5d, 0x0a5f, 0x0a65, 0x0a75, 0x0a80, 0x0a84, 0x0a84, 0x0a8c, 0x0a8c, 0x0a8e, 0x0a8e, 0x0a92, 0x0a92, 0x0aa9, 0x0aa9, 0x0ab1, 0x0ab1, 0x0ab4, 0x0ab4, 0x0aba, 0x0abb, 0x0ac6, 0x0ac6, 0x0aca, 0x0aca, 0x0ace, 0x0acf, 0x0ad1, 0x0adf, 0x0ae1, 0x0ae5, 0x0af0, 0x0b00, 0x0b04, 0x0b04, 0x0b0d, 0x0b0e, 0x0b11, 0x0b12, 0x0b29, 0x0b29, 0x0b31, 0x0b31, 0x0b34, 0x0b35, 0x0b3a, 0x0b3b, 0x0b44, 0x0b46, 0x0b49, 0x0b4a, 0x0b4e, 0x0b55, 0x0b58, 0x0b5b, 0x0b5e, 0x0b5e, 0x0b62, 0x0b65, 0x0b71, 0x0b81, 0x0b84, 0x0b84, 0x0b8b, 0x0b8d, 0x0b91, 0x0b91, 0x0b96, 0x0b98, 0x0b9b, 0x0b9b, 0x0b9d, 0x0b9d, 0x0ba0, 0x0ba2, 0x0ba5, 0x0ba7, 0x0bab, 0x0bad, 0x0bb6, 0x0bb6, 0x0bba, 0x0bbd, 0x0bc3, 0x0bc5, 0x0bc9, 0x0bc9, 0x0bce, 0x0bd6, 0x0bd8, 0x0be6, 0x0bf3, 0x0c00, 0x0c04, 0x0c04, 0x0c0d, 0x0c0d, 0x0c11, 0x0c11, 0x0c29, 0x0c29, 0x0c34, 0x0c34, 0x0c3a, 0x0c3d, 0x0c45, 0x0c45, 0x0c49, 0x0c49, 0x0c4e, 0x0c54, 0x0c57, 0x0c5f, 0x0c62, 0x0c65, 0x0c70, 0x0c81, 0x0c84, 0x0c84, 0x0c8d, 0x0c8d, 0x0c91, 0x0c91, 0x0ca9, 0x0ca9, 0x0cb4, 0x0cb4, 0x0cba, 0x0cbd, 0x0cc5, 0x0cc5, 0x0cc9, 0x0cc9, 0x0cce, 0x0cd4, 0x0cd7, 0x0cdd, 0x0cdf, 0x0cdf, 0x0ce2, 0x0ce5, 0x0cf0, 0x0d01, 0x0d04, 0x0d04, 0x0d0d, 0x0d0d, 0x0d11, 0x0d11, 0x0d29, 0x0d29, 0x0d3a, 0x0d3d, 0x0d44, 0x0d45, 0x0d49, 0x0d49, 0x0d4e, 0x0d56, 0x0d58, 0x0d5f, 0x0d62, 0x0d65, 0x0d70, 0x0d81, 0x0d84, 0x0d84, 0x0d97, 0x0d99, 0x0db2, 0x0db2, 0x0dbc, 0x0dbc, 0x0dbe, 0x0dbf, 0x0dc7, 0x0dc9, 0x0dcb, 0x0dce, 0x0dd5, 0x0dd5, 0x0dd7, 0x0dd7, 0x0de0, 0x0df1, 0x0df5, 0x0e00, 0x0e3b, 0x0e3e, 0x0e5c, 0x0e80, 0x0e83, 0x0e83, 0x0e85, 0x0e86, 0x0e89, 0x0e89, 0x0e8b, 0x0e8c, 0x0e8e, 0x0e93, 0x0e98, 0x0e98, 0x0ea0, 0x0ea0, 0x0ea4, 0x0ea4, 0x0ea6, 0x0ea6, 0x0ea8, 0x0ea9, 0x0eac, 0x0eac, 0x0eba, 0x0eba, 0x0ebe, 0x0ebf, 0x0ec5, 0x0ec5, 0x0ec7, 0x0ec7, 0x0ece, 0x0ecf, 0x0eda, 0x0edb, 0x0ede, 0x0eff, 0x0f48, 0x0f48, 0x0f6b, 0x0f70, 0x0f8c, 0x0f8f, 0x0f98, 0x0f98, 0x0fbd, 0x0fbd, 0x0fcd, 0x0fce, 0x0fd0, 0x0fff, 0x1022, 0x1022, 0x1028, 0x1028, 0x102b, 0x102b, 0x1033, 0x1035, 0x103a, 0x103f, 0x105a, 0x109f, 0x10c6, 0x10cf, 0x10f9, 0x10fa, 0x10fc, 0x10ff, 0x115a, 0x115e, 0x11a3, 0x11a7, 0x11fa, 0x11ff, 0x1207, 0x1207, 0x1247, 0x1247, 0x1249, 0x1249, 0x124e, 0x124f, 0x1257, 0x1257, 0x1259, 0x1259, 0x125e, 0x125f, 0x1287, 0x1287, 0x1289, 0x1289, 0x128e, 0x128f, 0x12af, 0x12af, 0x12b1, 0x12b1, 0x12b6, 0x12b7, 0x12bf, 0x12bf, 0x12c1, 0x12c1, 0x12c6, 0x12c7, 0x12cf, 0x12cf, 0x12d7, 0x12d7, 0x12ef, 0x12ef, 0x130f, 0x130f, 0x1311, 0x1311, 0x1316, 0x1317, 0x131f, 0x131f, 0x1347, 0x1347, 0x135b, 0x1360, 0x137d, 0x139f, 0x13f5, 0x1400, 0x1677, 0x167f, 0x169d, 0x169f, 0x16f1, 0x16ff, 0x170d, 0x170d, 0x1715, 0x171f, 0x1737, 0x173f, 0x1754, 0x175f, 0x176d, 0x176d, 0x1771, 0x1771, 0x1774, 0x177f, 0x17dd, 0x17df, 0x17ea, 0x17ff, 0x180f, 0x180f, 0x181a, 0x181f, 0x1878, 0x187f, 0x18aa, 0x1dff, 0x1e9c, 0x1e9f, 0x1efa, 0x1eff, 0x1f16, 0x1f17, 0x1f1e, 0x1f1f, 0x1f46, 0x1f47, 0x1f4e, 0x1f4f, 0x1f58, 0x1f58, 0x1f5a, 0x1f5a, 0x1f5c, 0x1f5c, 0x1f5e, 0x1f5e, 0x1f7e, 0x1f7f, 0x1fb5, 0x1fb5, 0x1fc5, 0x1fc5, 0x1fd4, 0x1fd5, 0x1fdc, 0x1fdc, 0x1ff0, 0x1ff1, 0x1ff5, 0x1ff5, 0x1fff, 0x1fff, 0x2053, 0x2056, 0x2058, 0x205e, 0x2064, 0x2069, 0x2072, 0x2073, 0x208f, 0x209f, 0x20b2, 0x20cf, 0x20eb, 0x20ff, 0x213b, 0x213c, 0x214c, 0x2152, 0x2184, 0x218f, 0x23cf, 0x23ff, 0x2427, 0x243f, 0x244b, 0x245f, 0x24ff, 0x24ff, 0x2614, 0x2615, 0x2618, 0x2618, 0x267e, 0x267f, 0x268a, 0x2700, 0x2705, 0x2705, 0x270a, 0x270b, 0x2728, 0x2728, 0x274c, 0x274c, 0x274e, 0x274e, 0x2753, 0x2755, 0x2757, 0x2757, 0x275f, 0x2760, 0x2795, 0x2797, 0x27b0, 0x27b0, 0x27bf, 0x27cf, 0x27ec, 0x27ef, 0x2b00, 0x2e7f, 0x2e9a, 0x2e9a, 0x2ef4, 0x2eff, 0x2fd6, 0x2fef, 0x2ffc, 0x2fff, 0x3040, 0x3040, 0x3097, 0x3098, 0x3100, 0x3104, 0x312d, 0x3130, 0x318f, 0x318f, 0x31b8, 0x31ef, 0x321d, 0x321f, 0x3244, 0x3250, 0x327c, 0x327e, 0x32cc, 0x32cf, 0x32ff, 0x32ff, 0x3377, 0x337a, 0x33de, 0x33df, 0x33ff, 0x33ff, 0x4db6, 0x4dff, 0x9fa6, 0x9fff, 0xa48d, 0xa48f, 0xa4c7, 0xabff, 0xd7a4, 0xd7ff, 0xfa2e, 0xfa2f, 0xfa6b, 0xfaff, 0xfb07, 0xfb12, 0xfb18, 0xfb1c, 0xfb37, 0xfb37, 0xfb3d, 0xfb3d, 0xfb3f, 0xfb3f, 0xfb42, 0xfb42, 0xfb45, 0xfb45, 0xfbb2, 0xfbd2, 0xfd40, 0xfd4f, 0xfd90, 0xfd91, 0xfdc8, 0xfdcf, 0xfdfd, 0xfdff, 0xfe10, 0xfe1f, 0xfe24, 0xfe2f, 0xfe47, 0xfe48, 0xfe53, 0xfe53, 0xfe67, 0xfe67, 0xfe6c, 0xfe6f, 0xfe75, 0xfe75, 0xfefd, 0xfefe, 0xff00, 0xff00, 0xffbf, 0xffc1, 0xffc8, 0xffc9, 0xffd0, 0xffd1, 0xffd8, 0xffd9, 0xffdd, 0xffdf, 0xffe7, 0xffe7, 0xffef, 0xfff8, 0x10000, 0x102ff, 0x1031f, 0x1031f, 0x10324, 0x1032f, 0x1034b, 0x103ff, 0x10426, 0x10427, 0x1044e, 0x1cfff, 0x1d0f6, 0x1d0ff, 0x1d127, 0x1d129, 0x1d1de, 0x1d3ff, 0x1d455, 0x1d455, 0x1d49d, 0x1d49d, 0x1d4a0, 0x1d4a1, 0x1d4a3, 0x1d4a4, 0x1d4a7, 0x1d4a8, 0x1d4ad, 0x1d4ad, 0x1d4ba, 0x1d4ba, 0x1d4bc, 0x1d4bc, 0x1d4c1, 0x1d4c1, 0x1d4c4, 0x1d4c4, 0x1d506, 0x1d506, 0x1d50b, 0x1d50c, 0x1d515, 0x1d515, 0x1d51d, 0x1d51d, 0x1d53a, 0x1d53a, 0x1d53f, 0x1d53f, 0x1d545, 0x1d545, 0x1d547, 0x1d549, 0x1d551, 0x1d551, 0x1d6a4, 0x1d6a7, 0x1d7ca, 0x1d7cd, 0x1d800, 0x1fffd, 0x2a6d7, 0x2f7ff, 0x2fa1e, 0x2fffd, 0x30000, 0x3fffd, 0x40000, 0x4fffd, 0x50000, 0x5fffd, 0x60000, 0x6fffd, 0x70000, 0x7fffd, 0x80000, 0x8fffd, 0x90000, 0x9fffd, 0xa0000, 0xafffd, 0xb0000, 0xbfffd, 0xc0000, 0xcfffd, 0xd0000, 0xdfffd, 0xe0000, 0xe0000, 0xe0002, 0xe001f, 0xe0080, 0xefffd];
|
|
472
|
-
// prettier-ignore-end
|
|
473
|
-
|
|
474
470
|
const isUnassignedCodePoint = character => inRange(character, unassigned_code_points);
|
|
475
|
-
|
|
476
|
-
// prettier-ignore-start
|
|
477
|
-
/**
|
|
478
|
-
* B.1 Commonly mapped to nothing
|
|
479
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-B.1
|
|
480
|
-
*/
|
|
481
471
|
const commonly_mapped_to_nothing = [0x00ad, 0x00ad, 0x034f, 0x034f, 0x1806, 0x1806, 0x180b, 0x180b, 0x180c, 0x180c, 0x180d, 0x180d, 0x200b, 0x200b, 0x200c, 0x200c, 0x200d, 0x200d, 0x2060, 0x2060, 0xfe00, 0xfe00, 0xfe01, 0xfe01, 0xfe02, 0xfe02, 0xfe03, 0xfe03, 0xfe04, 0xfe04, 0xfe05, 0xfe05, 0xfe06, 0xfe06, 0xfe07, 0xfe07, 0xfe08, 0xfe08, 0xfe09, 0xfe09, 0xfe0a, 0xfe0a, 0xfe0b, 0xfe0b, 0xfe0c, 0xfe0c, 0xfe0d, 0xfe0d, 0xfe0e, 0xfe0e, 0xfe0f, 0xfe0f, 0xfeff, 0xfeff];
|
|
482
|
-
// prettier-ignore-end
|
|
483
|
-
|
|
484
472
|
const isCommonlyMappedToNothing = character => inRange(character, commonly_mapped_to_nothing);
|
|
485
|
-
|
|
486
|
-
// prettier-ignore-start
|
|
487
|
-
/**
|
|
488
|
-
* C.1.2 Non-ASCII space characters
|
|
489
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.1.2
|
|
490
|
-
*/
|
|
491
|
-
const non_ASCII_space_characters = [0x00a0, 0x00a0 /* NO-BREAK SPACE */, 0x1680, 0x1680 /* OGHAM SPACE MARK */, 0x2000, 0x2000 /* EN QUAD */, 0x2001, 0x2001 /* EM QUAD */, 0x2002, 0x2002 /* EN SPACE */, 0x2003, 0x2003 /* EM SPACE */, 0x2004, 0x2004 /* THREE-PER-EM SPACE */, 0x2005, 0x2005 /* FOUR-PER-EM SPACE */, 0x2006, 0x2006 /* SIX-PER-EM SPACE */, 0x2007, 0x2007 /* FIGURE SPACE */, 0x2008, 0x2008 /* PUNCTUATION SPACE */, 0x2009, 0x2009 /* THIN SPACE */, 0x200a, 0x200a /* HAIR SPACE */, 0x200b, 0x200b /* ZERO WIDTH SPACE */, 0x202f, 0x202f /* NARROW NO-BREAK SPACE */, 0x205f, 0x205f /* MEDIUM MATHEMATICAL SPACE */, 0x3000, 0x3000 /* IDEOGRAPHIC SPACE */];
|
|
492
|
-
// prettier-ignore-end
|
|
493
|
-
|
|
473
|
+
const non_ASCII_space_characters = [0x00a0, 0x00a0, 0x1680, 0x1680, 0x2000, 0x2000, 0x2001, 0x2001, 0x2002, 0x2002, 0x2003, 0x2003, 0x2004, 0x2004, 0x2005, 0x2005, 0x2006, 0x2006, 0x2007, 0x2007, 0x2008, 0x2008, 0x2009, 0x2009, 0x200a, 0x200a, 0x200b, 0x200b, 0x202f, 0x202f, 0x205f, 0x205f, 0x3000, 0x3000];
|
|
494
474
|
const isNonASCIISpaceCharacter = character => inRange(character, non_ASCII_space_characters);
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const
|
|
498
|
-
/**
|
|
499
|
-
* C.2.2 Non-ASCII control characters
|
|
500
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.2.2
|
|
501
|
-
*/
|
|
502
|
-
0x0080, 0x009f /* [CONTROL CHARACTERS] */, 0x06dd, 0x06dd /* ARABIC END OF AYAH */, 0x070f, 0x070f /* SYRIAC ABBREVIATION MARK */, 0x180e, 0x180e /* MONGOLIAN VOWEL SEPARATOR */, 0x200c, 0x200c /* ZERO WIDTH NON-JOINER */, 0x200d, 0x200d /* ZERO WIDTH JOINER */, 0x2028, 0x2028 /* LINE SEPARATOR */, 0x2029, 0x2029 /* PARAGRAPH SEPARATOR */, 0x2060, 0x2060 /* WORD JOINER */, 0x2061, 0x2061 /* FUNCTION APPLICATION */, 0x2062, 0x2062 /* INVISIBLE TIMES */, 0x2063, 0x2063 /* INVISIBLE SEPARATOR */, 0x206a, 0x206f /* [CONTROL CHARACTERS] */, 0xfeff, 0xfeff /* ZERO WIDTH NO-BREAK SPACE */, 0xfff9, 0xfffc /* [CONTROL CHARACTERS] */, 0x1d173, 0x1d17a /* [MUSICAL CONTROL CHARACTERS] */];
|
|
503
|
-
const non_character_codepoints = [
|
|
504
|
-
/**
|
|
505
|
-
* C.4 Non-character code points
|
|
506
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.4
|
|
507
|
-
*/
|
|
508
|
-
0xfdd0, 0xfdef /* [NONCHARACTER CODE POINTS] */, 0xfffe, 0xffff /* [NONCHARACTER CODE POINTS] */, 0x1fffe, 0x1ffff /* [NONCHARACTER CODE POINTS] */, 0x2fffe, 0x2ffff /* [NONCHARACTER CODE POINTS] */, 0x3fffe, 0x3ffff /* [NONCHARACTER CODE POINTS] */, 0x4fffe, 0x4ffff /* [NONCHARACTER CODE POINTS] */, 0x5fffe, 0x5ffff /* [NONCHARACTER CODE POINTS] */, 0x6fffe, 0x6ffff /* [NONCHARACTER CODE POINTS] */, 0x7fffe, 0x7ffff /* [NONCHARACTER CODE POINTS] */, 0x8fffe, 0x8ffff /* [NONCHARACTER CODE POINTS] */, 0x9fffe, 0x9ffff /* [NONCHARACTER CODE POINTS] */, 0xafffe, 0xaffff /* [NONCHARACTER CODE POINTS] */, 0xbfffe, 0xbffff /* [NONCHARACTER CODE POINTS] */, 0xcfffe, 0xcffff /* [NONCHARACTER CODE POINTS] */, 0xdfffe, 0xdffff /* [NONCHARACTER CODE POINTS] */, 0xefffe, 0xeffff /* [NONCHARACTER CODE POINTS] */, 0x10fffe, 0x10ffff /* [NONCHARACTER CODE POINTS] */];
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* 2.3. Prohibited Output
|
|
512
|
-
*/
|
|
513
|
-
const prohibited_characters = [
|
|
514
|
-
/**
|
|
515
|
-
* C.2.1 ASCII control characters
|
|
516
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.2.1
|
|
517
|
-
*/
|
|
518
|
-
0, 0x001f /* [CONTROL CHARACTERS] */, 0x007f, 0x007f /* DELETE */,
|
|
519
|
-
/**
|
|
520
|
-
* C.8 Change display properties or are deprecated
|
|
521
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.8
|
|
522
|
-
*/
|
|
523
|
-
0x0340, 0x0340 /* COMBINING GRAVE TONE MARK */, 0x0341, 0x0341 /* COMBINING ACUTE TONE MARK */, 0x200e, 0x200e /* LEFT-TO-RIGHT MARK */, 0x200f, 0x200f /* RIGHT-TO-LEFT MARK */, 0x202a, 0x202a /* LEFT-TO-RIGHT EMBEDDING */, 0x202b, 0x202b /* RIGHT-TO-LEFT EMBEDDING */, 0x202c, 0x202c /* POP DIRECTIONAL FORMATTING */, 0x202d, 0x202d /* LEFT-TO-RIGHT OVERRIDE */, 0x202e, 0x202e /* RIGHT-TO-LEFT OVERRIDE */, 0x206a, 0x206a /* INHIBIT SYMMETRIC SWAPPING */, 0x206b, 0x206b /* ACTIVATE SYMMETRIC SWAPPING */, 0x206c, 0x206c /* INHIBIT ARABIC FORM SHAPING */, 0x206d, 0x206d /* ACTIVATE ARABIC FORM SHAPING */, 0x206e, 0x206e /* NATIONAL DIGIT SHAPES */, 0x206f, 0x206f /* NOMINAL DIGIT SHAPES */,
|
|
524
|
-
/**
|
|
525
|
-
* C.7 Inappropriate for canonical representation
|
|
526
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.7
|
|
527
|
-
*/
|
|
528
|
-
0x2ff0, 0x2ffb /* [IDEOGRAPHIC DESCRIPTION CHARACTERS] */,
|
|
529
|
-
/**
|
|
530
|
-
* C.5 Surrogate codes
|
|
531
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.5
|
|
532
|
-
*/
|
|
533
|
-
0xd800, 0xdfff,
|
|
534
|
-
/**
|
|
535
|
-
* C.3 Private use
|
|
536
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.3
|
|
537
|
-
*/
|
|
538
|
-
0xe000, 0xf8ff /* [PRIVATE USE, PLANE 0] */,
|
|
539
|
-
/**
|
|
540
|
-
* C.6 Inappropriate for plain text
|
|
541
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.6
|
|
542
|
-
*/
|
|
543
|
-
0xfff9, 0xfff9 /* INTERLINEAR ANNOTATION ANCHOR */, 0xfffa, 0xfffa /* INTERLINEAR ANNOTATION SEPARATOR */, 0xfffb, 0xfffb /* INTERLINEAR ANNOTATION TERMINATOR */, 0xfffc, 0xfffc /* OBJECT REPLACEMENT CHARACTER */, 0xfffd, 0xfffd /* REPLACEMENT CHARACTER */,
|
|
544
|
-
/**
|
|
545
|
-
* C.9 Tagging characters
|
|
546
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.9
|
|
547
|
-
*/
|
|
548
|
-
0xe0001, 0xe0001 /* LANGUAGE TAG */, 0xe0020, 0xe007f /* [TAGGING CHARACTERS] */,
|
|
549
|
-
/**
|
|
550
|
-
* C.3 Private use
|
|
551
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.3
|
|
552
|
-
*/
|
|
553
|
-
|
|
554
|
-
0xf0000, 0xffffd /* [PRIVATE USE, PLANE 15] */, 0x100000, 0x10fffd /* [PRIVATE USE, PLANE 16] */];
|
|
555
|
-
// prettier-ignore-end
|
|
556
|
-
|
|
475
|
+
const non_ASCII_controls_characters = [0x0080, 0x009f, 0x06dd, 0x06dd, 0x070f, 0x070f, 0x180e, 0x180e, 0x200c, 0x200c, 0x200d, 0x200d, 0x2028, 0x2028, 0x2029, 0x2029, 0x2060, 0x2060, 0x2061, 0x2061, 0x2062, 0x2062, 0x2063, 0x2063, 0x206a, 0x206f, 0xfeff, 0xfeff, 0xfff9, 0xfffc, 0x1d173, 0x1d17a];
|
|
476
|
+
const non_character_codepoints = [0xfdd0, 0xfdef, 0xfffe, 0xffff, 0x1fffe, 0x1ffff, 0x2fffe, 0x2ffff, 0x3fffe, 0x3ffff, 0x4fffe, 0x4ffff, 0x5fffe, 0x5ffff, 0x6fffe, 0x6ffff, 0x7fffe, 0x7ffff, 0x8fffe, 0x8ffff, 0x9fffe, 0x9ffff, 0xafffe, 0xaffff, 0xbfffe, 0xbffff, 0xcfffe, 0xcffff, 0xdfffe, 0xdffff, 0xefffe, 0xeffff, 0x10fffe, 0x10ffff];
|
|
477
|
+
const prohibited_characters = [0, 0x001f, 0x007f, 0x007f, 0x0340, 0x0340, 0x0341, 0x0341, 0x200e, 0x200e, 0x200f, 0x200f, 0x202a, 0x202a, 0x202b, 0x202b, 0x202c, 0x202c, 0x202d, 0x202d, 0x202e, 0x202e, 0x206a, 0x206a, 0x206b, 0x206b, 0x206c, 0x206c, 0x206d, 0x206d, 0x206e, 0x206e, 0x206f, 0x206f, 0x2ff0, 0x2ffb, 0xd800, 0xdfff, 0xe000, 0xf8ff, 0xfff9, 0xfff9, 0xfffa, 0xfffa, 0xfffb, 0xfffb, 0xfffc, 0xfffc, 0xfffd, 0xfffd, 0xe0001, 0xe0001, 0xe0020, 0xe007f, 0xf0000, 0xffffd, 0x100000, 0x10fffd];
|
|
557
478
|
const isProhibitedCharacter = character => inRange(character, non_ASCII_space_characters) || inRange(character, prohibited_characters) || inRange(character, non_ASCII_controls_characters) || inRange(character, non_character_codepoints);
|
|
558
|
-
|
|
559
|
-
// prettier-ignore-start
|
|
560
|
-
/**
|
|
561
|
-
* D.1 Characters with bidirectional property "R" or "AL"
|
|
562
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-D.1
|
|
563
|
-
*/
|
|
564
479
|
const bidirectional_r_al = [0x05be, 0x05be, 0x05c0, 0x05c0, 0x05c3, 0x05c3, 0x05d0, 0x05ea, 0x05f0, 0x05f4, 0x061b, 0x061b, 0x061f, 0x061f, 0x0621, 0x063a, 0x0640, 0x064a, 0x066d, 0x066f, 0x0671, 0x06d5, 0x06dd, 0x06dd, 0x06e5, 0x06e6, 0x06fa, 0x06fe, 0x0700, 0x070d, 0x0710, 0x0710, 0x0712, 0x072c, 0x0780, 0x07a5, 0x07b1, 0x07b1, 0x200f, 0x200f, 0xfb1d, 0xfb1d, 0xfb1f, 0xfb28, 0xfb2a, 0xfb36, 0xfb38, 0xfb3c, 0xfb3e, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44, 0xfb46, 0xfbb1, 0xfbd3, 0xfd3d, 0xfd50, 0xfd8f, 0xfd92, 0xfdc7, 0xfdf0, 0xfdfc, 0xfe70, 0xfe74, 0xfe76, 0xfefc];
|
|
565
|
-
// prettier-ignore-end
|
|
566
|
-
|
|
567
480
|
const isBidirectionalRAL = character => inRange(character, bidirectional_r_al);
|
|
568
|
-
|
|
569
|
-
// prettier-ignore-start
|
|
570
|
-
/**
|
|
571
|
-
* D.2 Characters with bidirectional property "L"
|
|
572
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-D.2
|
|
573
|
-
*/
|
|
574
481
|
const bidirectional_l = [0x0041, 0x005a, 0x0061, 0x007a, 0x00aa, 0x00aa, 0x00b5, 0x00b5, 0x00ba, 0x00ba, 0x00c0, 0x00d6, 0x00d8, 0x00f6, 0x00f8, 0x0220, 0x0222, 0x0233, 0x0250, 0x02ad, 0x02b0, 0x02b8, 0x02bb, 0x02c1, 0x02d0, 0x02d1, 0x02e0, 0x02e4, 0x02ee, 0x02ee, 0x037a, 0x037a, 0x0386, 0x0386, 0x0388, 0x038a, 0x038c, 0x038c, 0x038e, 0x03a1, 0x03a3, 0x03ce, 0x03d0, 0x03f5, 0x0400, 0x0482, 0x048a, 0x04ce, 0x04d0, 0x04f5, 0x04f8, 0x04f9, 0x0500, 0x050f, 0x0531, 0x0556, 0x0559, 0x055f, 0x0561, 0x0587, 0x0589, 0x0589, 0x0903, 0x0903, 0x0905, 0x0939, 0x093d, 0x0940, 0x0949, 0x094c, 0x0950, 0x0950, 0x0958, 0x0961, 0x0964, 0x0970, 0x0982, 0x0983, 0x0985, 0x098c, 0x098f, 0x0990, 0x0993, 0x09a8, 0x09aa, 0x09b0, 0x09b2, 0x09b2, 0x09b6, 0x09b9, 0x09be, 0x09c0, 0x09c7, 0x09c8, 0x09cb, 0x09cc, 0x09d7, 0x09d7, 0x09dc, 0x09dd, 0x09df, 0x09e1, 0x09e6, 0x09f1, 0x09f4, 0x09fa, 0x0a05, 0x0a0a, 0x0a0f, 0x0a10, 0x0a13, 0x0a28, 0x0a2a, 0x0a30, 0x0a32, 0x0a33, 0x0a35, 0x0a36, 0x0a38, 0x0a39, 0x0a3e, 0x0a40, 0x0a59, 0x0a5c, 0x0a5e, 0x0a5e, 0x0a66, 0x0a6f, 0x0a72, 0x0a74, 0x0a83, 0x0a83, 0x0a85, 0x0a8b, 0x0a8d, 0x0a8d, 0x0a8f, 0x0a91, 0x0a93, 0x0aa8, 0x0aaa, 0x0ab0, 0x0ab2, 0x0ab3, 0x0ab5, 0x0ab9, 0x0abd, 0x0ac0, 0x0ac9, 0x0ac9, 0x0acb, 0x0acc, 0x0ad0, 0x0ad0, 0x0ae0, 0x0ae0, 0x0ae6, 0x0aef, 0x0b02, 0x0b03, 0x0b05, 0x0b0c, 0x0b0f, 0x0b10, 0x0b13, 0x0b28, 0x0b2a, 0x0b30, 0x0b32, 0x0b33, 0x0b36, 0x0b39, 0x0b3d, 0x0b3e, 0x0b40, 0x0b40, 0x0b47, 0x0b48, 0x0b4b, 0x0b4c, 0x0b57, 0x0b57, 0x0b5c, 0x0b5d, 0x0b5f, 0x0b61, 0x0b66, 0x0b70, 0x0b83, 0x0b83, 0x0b85, 0x0b8a, 0x0b8e, 0x0b90, 0x0b92, 0x0b95, 0x0b99, 0x0b9a, 0x0b9c, 0x0b9c, 0x0b9e, 0x0b9f, 0x0ba3, 0x0ba4, 0x0ba8, 0x0baa, 0x0bae, 0x0bb5, 0x0bb7, 0x0bb9, 0x0bbe, 0x0bbf, 0x0bc1, 0x0bc2, 0x0bc6, 0x0bc8, 0x0bca, 0x0bcc, 0x0bd7, 0x0bd7, 0x0be7, 0x0bf2, 0x0c01, 0x0c03, 0x0c05, 0x0c0c, 0x0c0e, 0x0c10, 0x0c12, 0x0c28, 0x0c2a, 0x0c33, 0x0c35, 0x0c39, 0x0c41, 0x0c44, 0x0c60, 0x0c61, 0x0c66, 0x0c6f, 0x0c82, 0x0c83, 0x0c85, 0x0c8c, 0x0c8e, 0x0c90, 0x0c92, 0x0ca8, 0x0caa, 0x0cb3, 0x0cb5, 0x0cb9, 0x0cbe, 0x0cbe, 0x0cc0, 0x0cc4, 0x0cc7, 0x0cc8, 0x0cca, 0x0ccb, 0x0cd5, 0x0cd6, 0x0cde, 0x0cde, 0x0ce0, 0x0ce1, 0x0ce6, 0x0cef, 0x0d02, 0x0d03, 0x0d05, 0x0d0c, 0x0d0e, 0x0d10, 0x0d12, 0x0d28, 0x0d2a, 0x0d39, 0x0d3e, 0x0d40, 0x0d46, 0x0d48, 0x0d4a, 0x0d4c, 0x0d57, 0x0d57, 0x0d60, 0x0d61, 0x0d66, 0x0d6f, 0x0d82, 0x0d83, 0x0d85, 0x0d96, 0x0d9a, 0x0db1, 0x0db3, 0x0dbb, 0x0dbd, 0x0dbd, 0x0dc0, 0x0dc6, 0x0dcf, 0x0dd1, 0x0dd8, 0x0ddf, 0x0df2, 0x0df4, 0x0e01, 0x0e30, 0x0e32, 0x0e33, 0x0e40, 0x0e46, 0x0e4f, 0x0e5b, 0x0e81, 0x0e82, 0x0e84, 0x0e84, 0x0e87, 0x0e88, 0x0e8a, 0x0e8a, 0x0e8d, 0x0e8d, 0x0e94, 0x0e97, 0x0e99, 0x0e9f, 0x0ea1, 0x0ea3, 0x0ea5, 0x0ea5, 0x0ea7, 0x0ea7, 0x0eaa, 0x0eab, 0x0ead, 0x0eb0, 0x0eb2, 0x0eb3, 0x0ebd, 0x0ebd, 0x0ec0, 0x0ec4, 0x0ec6, 0x0ec6, 0x0ed0, 0x0ed9, 0x0edc, 0x0edd, 0x0f00, 0x0f17, 0x0f1a, 0x0f34, 0x0f36, 0x0f36, 0x0f38, 0x0f38, 0x0f3e, 0x0f47, 0x0f49, 0x0f6a, 0x0f7f, 0x0f7f, 0x0f85, 0x0f85, 0x0f88, 0x0f8b, 0x0fbe, 0x0fc5, 0x0fc7, 0x0fcc, 0x0fcf, 0x0fcf, 0x1000, 0x1021, 0x1023, 0x1027, 0x1029, 0x102a, 0x102c, 0x102c, 0x1031, 0x1031, 0x1038, 0x1038, 0x1040, 0x1057, 0x10a0, 0x10c5, 0x10d0, 0x10f8, 0x10fb, 0x10fb, 0x1100, 0x1159, 0x115f, 0x11a2, 0x11a8, 0x11f9, 0x1200, 0x1206, 0x1208, 0x1246, 0x1248, 0x1248, 0x124a, 0x124d, 0x1250, 0x1256, 0x1258, 0x1258, 0x125a, 0x125d, 0x1260, 0x1286, 0x1288, 0x1288, 0x128a, 0x128d, 0x1290, 0x12ae, 0x12b0, 0x12b0, 0x12b2, 0x12b5, 0x12b8, 0x12be, 0x12c0, 0x12c0, 0x12c2, 0x12c5, 0x12c8, 0x12ce, 0x12d0, 0x12d6, 0x12d8, 0x12ee, 0x12f0, 0x130e, 0x1310, 0x1310, 0x1312, 0x1315, 0x1318, 0x131e, 0x1320, 0x1346, 0x1348, 0x135a, 0x1361, 0x137c, 0x13a0, 0x13f4, 0x1401, 0x1676, 0x1681, 0x169a, 0x16a0, 0x16f0, 0x1700, 0x170c, 0x170e, 0x1711, 0x1720, 0x1731, 0x1735, 0x1736, 0x1740, 0x1751, 0x1760, 0x176c, 0x176e, 0x1770, 0x1780, 0x17b6, 0x17be, 0x17c5, 0x17c7, 0x17c8, 0x17d4, 0x17da, 0x17dc, 0x17dc, 0x17e0, 0x17e9, 0x1810, 0x1819, 0x1820, 0x1877, 0x1880, 0x18a8, 0x1e00, 0x1e9b, 0x1ea0, 0x1ef9, 0x1f00, 0x1f15, 0x1f18, 0x1f1d, 0x1f20, 0x1f45, 0x1f48, 0x1f4d, 0x1f50, 0x1f57, 0x1f59, 0x1f59, 0x1f5b, 0x1f5b, 0x1f5d, 0x1f5d, 0x1f5f, 0x1f7d, 0x1f80, 0x1fb4, 0x1fb6, 0x1fbc, 0x1fbe, 0x1fbe, 0x1fc2, 0x1fc4, 0x1fc6, 0x1fcc, 0x1fd0, 0x1fd3, 0x1fd6, 0x1fdb, 0x1fe0, 0x1fec, 0x1ff2, 0x1ff4, 0x1ff6, 0x1ffc, 0x200e, 0x200e, 0x2071, 0x2071, 0x207f, 0x207f, 0x2102, 0x2102, 0x2107, 0x2107, 0x210a, 0x2113, 0x2115, 0x2115, 0x2119, 0x211d, 0x2124, 0x2124, 0x2126, 0x2126, 0x2128, 0x2128, 0x212a, 0x212d, 0x212f, 0x2131, 0x2133, 0x2139, 0x213d, 0x213f, 0x2145, 0x2149, 0x2160, 0x2183, 0x2336, 0x237a, 0x2395, 0x2395, 0x249c, 0x24e9, 0x3005, 0x3007, 0x3021, 0x3029, 0x3031, 0x3035, 0x3038, 0x303c, 0x3041, 0x3096, 0x309d, 0x309f, 0x30a1, 0x30fa, 0x30fc, 0x30ff, 0x3105, 0x312c, 0x3131, 0x318e, 0x3190, 0x31b7, 0x31f0, 0x321c, 0x3220, 0x3243, 0x3260, 0x327b, 0x327f, 0x32b0, 0x32c0, 0x32cb, 0x32d0, 0x32fe, 0x3300, 0x3376, 0x337b, 0x33dd, 0x33e0, 0x33fe, 0x3400, 0x4db5, 0x4e00, 0x9fa5, 0xa000, 0xa48c, 0xac00, 0xd7a3, 0xd800, 0xfa2d, 0xfa30, 0xfa6a, 0xfb00, 0xfb06, 0xfb13, 0xfb17, 0xff21, 0xff3a, 0xff41, 0xff5a, 0xff66, 0xffbe, 0xffc2, 0xffc7, 0xffca, 0xffcf, 0xffd2, 0xffd7, 0xffda, 0xffdc, 0x10300, 0x1031e, 0x10320, 0x10323, 0x10330, 0x1034a, 0x10400, 0x10425, 0x10428, 0x1044d, 0x1d000, 0x1d0f5, 0x1d100, 0x1d126, 0x1d12a, 0x1d166, 0x1d16a, 0x1d172, 0x1d183, 0x1d184, 0x1d18c, 0x1d1a9, 0x1d1ae, 0x1d1dd, 0x1d400, 0x1d454, 0x1d456, 0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4a9, 0x1d4ac, 0x1d4ae, 0x1d4b9, 0x1d4bb, 0x1d4bb, 0x1d4bd, 0x1d4c0, 0x1d4c2, 0x1d4c3, 0x1d4c5, 0x1d505, 0x1d507, 0x1d50a, 0x1d50d, 0x1d514, 0x1d516, 0x1d51c, 0x1d51e, 0x1d539, 0x1d53b, 0x1d53e, 0x1d540, 0x1d544, 0x1d546, 0x1d546, 0x1d54a, 0x1d550, 0x1d552, 0x1d6a3, 0x1d6a8, 0x1d7c9, 0x20000, 0x2a6d6, 0x2f800, 0x2fa1d, 0xf0000, 0xffffd, 0x100000, 0x10fffd];
|
|
575
|
-
// prettier-ignore-end
|
|
576
|
-
|
|
577
482
|
const isBidirectionalL = character => inRange(character, bidirectional_l);
|
|
578
483
|
|
|
579
|
-
// 2.1. Mapping
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* non-ASCII space characters [StringPrep, C.1.2] that can be
|
|
583
|
-
* mapped to SPACE (U+0020)
|
|
584
|
-
*/
|
|
585
484
|
const mapping2space = isNonASCIISpaceCharacter;
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* the "commonly mapped to nothing" characters [StringPrep, B.1]
|
|
589
|
-
* that can be mapped to nothing.
|
|
590
|
-
*/
|
|
591
485
|
const mapping2nothing = isCommonlyMappedToNothing;
|
|
592
|
-
|
|
593
|
-
// utils
|
|
594
486
|
const getCodePoint = character => character.codePointAt(0);
|
|
595
487
|
const first = x => x[0];
|
|
596
488
|
const last = x => x[x.length - 1];
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* Convert provided string into an array of Unicode Code Points.
|
|
600
|
-
* Based on https://stackoverflow.com/a/21409165/1556249
|
|
601
|
-
* and https://www.npmjs.com/package/code-point-at.
|
|
602
|
-
* @param {string} input
|
|
603
|
-
* @returns {number[]}
|
|
604
|
-
*/
|
|
605
489
|
function toCodePoints(input) {
|
|
606
490
|
const codepoints = [];
|
|
607
491
|
const size = input.length;
|
|
@@ -619,14 +503,6 @@ function toCodePoints(input) {
|
|
|
619
503
|
}
|
|
620
504
|
return codepoints;
|
|
621
505
|
}
|
|
622
|
-
|
|
623
|
-
/**
|
|
624
|
-
* SASLprep.
|
|
625
|
-
* @param {string} input
|
|
626
|
-
* @param {Object} opts
|
|
627
|
-
* @param {boolean} opts.allowUnassigned
|
|
628
|
-
* @returns {string}
|
|
629
|
-
*/
|
|
630
506
|
function saslprep(input, opts = {}) {
|
|
631
507
|
if (typeof input !== 'string') {
|
|
632
508
|
throw new TypeError('Expected string.');
|
|
@@ -634,49 +510,24 @@ function saslprep(input, opts = {}) {
|
|
|
634
510
|
if (input.length === 0) {
|
|
635
511
|
return '';
|
|
636
512
|
}
|
|
637
|
-
|
|
638
|
-
// 1. Map
|
|
639
|
-
const mapped_input = toCodePoints(input)
|
|
640
|
-
// 1.1 mapping to space
|
|
641
|
-
.map(character => mapping2space(character) ? 0x20 : character)
|
|
642
|
-
// 1.2 mapping to nothing
|
|
643
|
-
.filter(character => !mapping2nothing(character));
|
|
644
|
-
|
|
645
|
-
// 2. Normalize
|
|
513
|
+
const mapped_input = toCodePoints(input).map(character => mapping2space(character) ? 0x20 : character).filter(character => !mapping2nothing(character));
|
|
646
514
|
const normalized_input = String.fromCodePoint.apply(null, mapped_input).normalize('NFKC');
|
|
647
515
|
const normalized_map = toCodePoints(normalized_input);
|
|
648
|
-
|
|
649
|
-
// 3. Prohibit
|
|
650
516
|
const hasProhibited = normalized_map.some(isProhibitedCharacter);
|
|
651
517
|
if (hasProhibited) {
|
|
652
518
|
throw new Error('Prohibited character, see https://tools.ietf.org/html/rfc4013#section-2.3');
|
|
653
519
|
}
|
|
654
|
-
|
|
655
|
-
// Unassigned Code Points
|
|
656
520
|
if (opts.allowUnassigned !== true) {
|
|
657
521
|
const hasUnassigned = normalized_map.some(isUnassignedCodePoint);
|
|
658
522
|
if (hasUnassigned) {
|
|
659
523
|
throw new Error('Unassigned code point, see https://tools.ietf.org/html/rfc4013#section-2.5');
|
|
660
524
|
}
|
|
661
525
|
}
|
|
662
|
-
|
|
663
|
-
// 4. check bidi
|
|
664
|
-
|
|
665
526
|
const hasBidiRAL = normalized_map.some(isBidirectionalRAL);
|
|
666
527
|
const hasBidiL = normalized_map.some(isBidirectionalL);
|
|
667
|
-
|
|
668
|
-
// 4.1 If a string contains any RandALCat character, the string MUST NOT
|
|
669
|
-
// contain any LCat character.
|
|
670
528
|
if (hasBidiRAL && hasBidiL) {
|
|
671
529
|
throw new Error('String must not contain RandALCat and LCat at the same time,' + ' see https://tools.ietf.org/html/rfc3454#section-6');
|
|
672
530
|
}
|
|
673
|
-
|
|
674
|
-
/**
|
|
675
|
-
* 4.2 If a string contains any RandALCat character, a RandALCat
|
|
676
|
-
* character MUST be the first character of the string, and a
|
|
677
|
-
* RandALCat character MUST be the last character of the string.
|
|
678
|
-
*/
|
|
679
|
-
|
|
680
531
|
const isFirstBidiRAL = isBidirectionalRAL(getCodePoint(first(normalized_input)));
|
|
681
532
|
const isLastBidiRAL = isBidirectionalRAL(getCodePoint(last(normalized_input)));
|
|
682
533
|
if (hasBidiRAL && !(isFirstBidiRAL && isLastBidiRAL)) {
|
|
@@ -685,15 +536,10 @@ function saslprep(input, opts = {}) {
|
|
|
685
536
|
return normalized_input;
|
|
686
537
|
}
|
|
687
538
|
|
|
688
|
-
/*
|
|
689
|
-
PDFSecurity - represents PDF security settings
|
|
690
|
-
By Yang Liu <hi@zesik.com>
|
|
691
|
-
*/
|
|
692
539
|
class PDFSecurity {
|
|
693
540
|
static generateFileID(info = {}) {
|
|
694
541
|
let infoStr = `${info.CreationDate.getTime()}\n`;
|
|
695
542
|
for (let key in info) {
|
|
696
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
697
543
|
if (!info.hasOwnProperty(key)) {
|
|
698
544
|
continue;
|
|
699
545
|
}
|
|
@@ -1067,8 +913,6 @@ class PDFGradient$1 {
|
|
|
1067
913
|
}
|
|
1068
914
|
this.embedded = true;
|
|
1069
915
|
this.matrix = m;
|
|
1070
|
-
|
|
1071
|
-
// if the last stop comes before 100%, add a copy at 100%
|
|
1072
916
|
const last = this.stops[stopsLength - 1];
|
|
1073
917
|
if (last[0] < 1) {
|
|
1074
918
|
this.stops.push([1, last[1], last[2]]);
|
|
@@ -1091,14 +935,11 @@ class PDFGradient$1 {
|
|
|
1091
935
|
stops.push(fn);
|
|
1092
936
|
fn.end();
|
|
1093
937
|
}
|
|
1094
|
-
|
|
1095
|
-
// if there are only two stops, we don't need a stitching function
|
|
1096
938
|
if (stopsLength === 1) {
|
|
1097
939
|
fn = stops[0];
|
|
1098
940
|
} else {
|
|
1099
941
|
fn = this.doc.ref({
|
|
1100
942
|
FunctionType: 3,
|
|
1101
|
-
// stitching function
|
|
1102
943
|
Domain: [0, 1],
|
|
1103
944
|
Functions: stops,
|
|
1104
945
|
Bounds: bounds,
|
|
@@ -1179,7 +1020,6 @@ class PDFGradient$1 {
|
|
|
1179
1020
|
return pattern;
|
|
1180
1021
|
}
|
|
1181
1022
|
apply(stroke) {
|
|
1182
|
-
// apply gradient transform to existing document ctm
|
|
1183
1023
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1184
1024
|
const [m11, m12, m21, m22, dx, dy] = this.transform;
|
|
1185
1025
|
const m = [m0 * m11 + m2 * m12, m1 * m11 + m3 * m12, m0 * m21 + m2 * m22, m1 * m21 + m3 * m22, m0 * dx + m2 * dy + m4, m1 * dx + m3 * dy + m5];
|
|
@@ -1242,10 +1082,6 @@ var Gradient = {
|
|
|
1242
1082
|
PDFRadialGradient: PDFRadialGradient$1
|
|
1243
1083
|
};
|
|
1244
1084
|
|
|
1245
|
-
/*
|
|
1246
|
-
PDF tiling pattern support. Uncolored only.
|
|
1247
|
-
*/
|
|
1248
|
-
|
|
1249
1085
|
const underlyingColorSpaces = ['DeviceCMYK', 'DeviceRGB'];
|
|
1250
1086
|
class PDFTilingPattern$1 {
|
|
1251
1087
|
constructor(doc, bBox, xStep, yStep, stream) {
|
|
@@ -1256,23 +1092,16 @@ class PDFTilingPattern$1 {
|
|
|
1256
1092
|
this.stream = stream;
|
|
1257
1093
|
}
|
|
1258
1094
|
createPattern() {
|
|
1259
|
-
// no resources needed for our current usage
|
|
1260
|
-
// required entry
|
|
1261
1095
|
const resources = this.doc.ref();
|
|
1262
1096
|
resources.end();
|
|
1263
|
-
// apply default transform matrix (flipped in the default doc._ctm)
|
|
1264
|
-
// see document.js & gradient.js
|
|
1265
1097
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1266
1098
|
const [m11, m12, m21, m22, dx, dy] = [1, 0, 0, 1, 0, 0];
|
|
1267
1099
|
const m = [m0 * m11 + m2 * m12, m1 * m11 + m3 * m12, m0 * m21 + m2 * m22, m1 * m21 + m3 * m22, m0 * dx + m2 * dy + m4, m1 * dx + m3 * dy + m5];
|
|
1268
1100
|
const pattern = this.doc.ref({
|
|
1269
1101
|
Type: 'Pattern',
|
|
1270
1102
|
PatternType: 1,
|
|
1271
|
-
// tiling
|
|
1272
1103
|
PaintType: 2,
|
|
1273
|
-
// 1-colored, 2-uncolored
|
|
1274
1104
|
TilingType: 2,
|
|
1275
|
-
// 2-no distortion
|
|
1276
1105
|
BBox: this.bBox,
|
|
1277
1106
|
XStep: this.xStep,
|
|
1278
1107
|
YStep: this.yStep,
|
|
@@ -1283,8 +1112,6 @@ class PDFTilingPattern$1 {
|
|
|
1283
1112
|
return pattern;
|
|
1284
1113
|
}
|
|
1285
1114
|
embedPatternColorSpaces() {
|
|
1286
|
-
// map each pattern to an underlying color space
|
|
1287
|
-
// and embed on each page
|
|
1288
1115
|
underlyingColorSpaces.forEach(csName => {
|
|
1289
1116
|
const csId = this.getPatternColorSpaceId(csName);
|
|
1290
1117
|
if (this.doc.page.colorSpaces[csId]) return;
|
|
@@ -1302,24 +1129,17 @@ class PDFTilingPattern$1 {
|
|
|
1302
1129
|
this.id = 'P' + this.doc._patternCount;
|
|
1303
1130
|
this.pattern = this.createPattern();
|
|
1304
1131
|
}
|
|
1305
|
-
|
|
1306
|
-
// patterns are embedded in each page
|
|
1307
1132
|
if (!this.doc.page.patterns[this.id]) {
|
|
1308
1133
|
this.doc.page.patterns[this.id] = this.pattern;
|
|
1309
1134
|
}
|
|
1310
1135
|
}
|
|
1311
1136
|
apply(stroke, patternColor) {
|
|
1312
|
-
// do any embedding/creating that might be needed
|
|
1313
1137
|
this.embedPatternColorSpaces();
|
|
1314
1138
|
this.embed();
|
|
1315
1139
|
const normalizedColor = this.doc._normalizeColor(patternColor);
|
|
1316
1140
|
if (!normalizedColor) throw Error(`invalid pattern color. (value: ${patternColor})`);
|
|
1317
|
-
|
|
1318
|
-
// select one of the pattern color spaces
|
|
1319
1141
|
const csId = this.getPatternColorSpaceId(this.doc._getColorSpace(normalizedColor));
|
|
1320
1142
|
this.doc._setColorSpace(csId, stroke);
|
|
1321
|
-
|
|
1322
|
-
// stroke/fill using the pattern and color (in the above underlying color space)
|
|
1323
1143
|
const op = stroke ? 'SCN' : 'scn';
|
|
1324
1144
|
return this.doc.addContent(`${normalizedColor.join(' ')} /${this.id} ${op}`);
|
|
1325
1145
|
}
|
|
@@ -1339,11 +1159,10 @@ const {
|
|
|
1339
1159
|
var ColorMixin = {
|
|
1340
1160
|
initColor() {
|
|
1341
1161
|
this.spotColors = {};
|
|
1342
|
-
// The opacity dictionaries
|
|
1343
1162
|
this._opacityRegistry = {};
|
|
1344
1163
|
this._opacityCount = 0;
|
|
1345
1164
|
this._patternCount = 0;
|
|
1346
|
-
|
|
1165
|
+
this._gradCount = 0;
|
|
1347
1166
|
},
|
|
1348
1167
|
_normalizeColor(color) {
|
|
1349
1168
|
if (typeof color === 'string') {
|
|
@@ -1360,10 +1179,8 @@ var ColorMixin = {
|
|
|
1360
1179
|
}
|
|
1361
1180
|
}
|
|
1362
1181
|
if (Array.isArray(color)) {
|
|
1363
|
-
// RGB
|
|
1364
1182
|
if (color.length === 3) {
|
|
1365
1183
|
color = color.map(part => part / 255);
|
|
1366
|
-
// CMYK
|
|
1367
1184
|
} else if (color.length === 4) {
|
|
1368
1185
|
color = color.map(part => part / 100);
|
|
1369
1186
|
}
|
|
@@ -1375,12 +1192,10 @@ var ColorMixin = {
|
|
|
1375
1192
|
if (color instanceof PDFGradient) {
|
|
1376
1193
|
color.apply(stroke);
|
|
1377
1194
|
return true;
|
|
1378
|
-
// see if tiling pattern, decode & apply it it
|
|
1379
1195
|
} else if (Array.isArray(color) && color[0] instanceof PDFTilingPattern) {
|
|
1380
1196
|
color[0].apply(stroke, color[1]);
|
|
1381
1197
|
return true;
|
|
1382
1198
|
}
|
|
1383
|
-
// any other case should be a normal color and not a pattern
|
|
1384
1199
|
return this._setColorCore(color, stroke);
|
|
1385
1200
|
},
|
|
1386
1201
|
_setColorCore(color, stroke) {
|
|
@@ -1414,9 +1229,6 @@ var ColorMixin = {
|
|
|
1414
1229
|
if (set) {
|
|
1415
1230
|
this.fillOpacity(opacity);
|
|
1416
1231
|
}
|
|
1417
|
-
|
|
1418
|
-
// save this for text wrapper, which needs to reset
|
|
1419
|
-
// the fill color on new pages
|
|
1420
1232
|
this._fillColor = [color, opacity];
|
|
1421
1233
|
return this;
|
|
1422
1234
|
},
|
|
@@ -1672,7 +1484,6 @@ const parse = function (path) {
|
|
|
1672
1484
|
if (parameters[c] != null) {
|
|
1673
1485
|
params = parameters[c];
|
|
1674
1486
|
if (cmd) {
|
|
1675
|
-
// save existing command
|
|
1676
1487
|
if (curArg.length > 0) {
|
|
1677
1488
|
args[args.length] = +curArg;
|
|
1678
1489
|
}
|
|
@@ -1690,14 +1501,11 @@ const parse = function (path) {
|
|
|
1690
1501
|
continue;
|
|
1691
1502
|
}
|
|
1692
1503
|
if (args.length === params) {
|
|
1693
|
-
// handle reused commands
|
|
1694
1504
|
ret[ret.length] = {
|
|
1695
1505
|
cmd,
|
|
1696
1506
|
args
|
|
1697
1507
|
};
|
|
1698
1508
|
args = [+curArg];
|
|
1699
|
-
|
|
1700
|
-
// handle assumed commands
|
|
1701
1509
|
if (cmd === 'M') {
|
|
1702
1510
|
cmd = 'L';
|
|
1703
1511
|
}
|
|
@@ -1708,8 +1516,6 @@ const parse = function (path) {
|
|
|
1708
1516
|
args[args.length] = +curArg;
|
|
1709
1517
|
}
|
|
1710
1518
|
foundDecimal = c === '.';
|
|
1711
|
-
|
|
1712
|
-
// fix for negative numbers or repeated decimals with no delimeter between commands
|
|
1713
1519
|
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1714
1520
|
} else {
|
|
1715
1521
|
curArg += c;
|
|
@@ -1718,18 +1524,13 @@ const parse = function (path) {
|
|
|
1718
1524
|
}
|
|
1719
1525
|
}
|
|
1720
1526
|
}
|
|
1721
|
-
|
|
1722
|
-
// add the last command
|
|
1723
1527
|
if (curArg.length > 0) {
|
|
1724
1528
|
if (args.length === params) {
|
|
1725
|
-
// handle reused commands
|
|
1726
1529
|
ret[ret.length] = {
|
|
1727
1530
|
cmd,
|
|
1728
1531
|
args
|
|
1729
1532
|
};
|
|
1730
1533
|
args = [+curArg];
|
|
1731
|
-
|
|
1732
|
-
// handle assumed commands
|
|
1733
1534
|
if (cmd === 'M') {
|
|
1734
1535
|
cmd = 'L';
|
|
1735
1536
|
}
|
|
@@ -1747,10 +1548,7 @@ const parse = function (path) {
|
|
|
1747
1548
|
return ret;
|
|
1748
1549
|
};
|
|
1749
1550
|
const apply = function (commands, doc) {
|
|
1750
|
-
// current point, control point, and subpath starting point
|
|
1751
1551
|
cx = cy = px = py = sx = sy = 0;
|
|
1752
|
-
|
|
1753
|
-
// run the commands
|
|
1754
1552
|
for (let i = 0; i < commands.length; i++) {
|
|
1755
1553
|
const c = commands[i];
|
|
1756
1554
|
if (typeof runners[c.cmd] === 'function') {
|
|
@@ -1914,8 +1712,6 @@ const solveArc = function (doc, x, y, coords) {
|
|
|
1914
1712
|
doc.bezierCurveTo(...bez);
|
|
1915
1713
|
}
|
|
1916
1714
|
};
|
|
1917
|
-
|
|
1918
|
-
// from Inkscape svgtopdf, thanks!
|
|
1919
1715
|
const arcToSegments = function (x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
|
1920
1716
|
const th = rotateX * (Math.PI / 180);
|
|
1921
1717
|
const sin_th = Math.sin(th);
|
|
@@ -1991,18 +1787,14 @@ class SVGPath {
|
|
|
1991
1787
|
const {
|
|
1992
1788
|
number: number$1
|
|
1993
1789
|
} = PDFObject;
|
|
1994
|
-
|
|
1995
|
-
// This constant is used to approximate a symmetrical arc using a cubic
|
|
1996
|
-
// Bezier curve.
|
|
1997
1790
|
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
|
|
1998
1791
|
var VectorMixin = {
|
|
1999
1792
|
initVector() {
|
|
2000
|
-
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
2001
|
-
|
|
1793
|
+
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
1794
|
+
this._ctmStack = [];
|
|
2002
1795
|
},
|
|
2003
1796
|
save() {
|
|
2004
1797
|
this._ctmStack.push(this._ctm.slice());
|
|
2005
|
-
// TODO: save/restore colorspace and styles so not setting it unnessesarily all the time?
|
|
2006
1798
|
return this.addContent('q');
|
|
2007
1799
|
},
|
|
2008
1800
|
restore() {
|
|
@@ -2075,8 +1867,6 @@ var VectorMixin = {
|
|
|
2075
1867
|
r = 0;
|
|
2076
1868
|
}
|
|
2077
1869
|
r = Math.min(r, 0.5 * w, 0.5 * h);
|
|
2078
|
-
|
|
2079
|
-
// amount to inset control points from corners (see `ellipse`)
|
|
2080
1870
|
const c = r * (1.0 - KAPPA);
|
|
2081
1871
|
this.moveTo(x + r, y);
|
|
2082
1872
|
this.lineTo(x + w - r, y);
|
|
@@ -2090,7 +1880,6 @@ var VectorMixin = {
|
|
|
2090
1880
|
return this.closePath();
|
|
2091
1881
|
},
|
|
2092
1882
|
ellipse(x, y, r1, r2) {
|
|
2093
|
-
// based on http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas/2173084#2173084
|
|
2094
1883
|
if (r2 == null) {
|
|
2095
1884
|
r2 = r1;
|
|
2096
1885
|
}
|
|
@@ -2120,10 +1909,8 @@ var VectorMixin = {
|
|
|
2120
1909
|
const HALF_PI = 0.5 * Math.PI;
|
|
2121
1910
|
let deltaAng = endAngle - startAngle;
|
|
2122
1911
|
if (Math.abs(deltaAng) > TWO_PI) {
|
|
2123
|
-
// draw only full circle if more than that is specified
|
|
2124
1912
|
deltaAng = TWO_PI;
|
|
2125
1913
|
} else if (deltaAng !== 0 && anticlockwise !== deltaAng < 0) {
|
|
2126
|
-
// necessary to flip direction of rendering
|
|
2127
1914
|
const dir = anticlockwise ? -1 : 1;
|
|
2128
1915
|
deltaAng = dir * TWO_PI + deltaAng;
|
|
2129
1916
|
}
|
|
@@ -2131,38 +1918,21 @@ var VectorMixin = {
|
|
|
2131
1918
|
const segAng = deltaAng / numSegs;
|
|
2132
1919
|
const handleLen = segAng / HALF_PI * KAPPA * radius;
|
|
2133
1920
|
let curAng = startAngle;
|
|
2134
|
-
|
|
2135
|
-
// component distances between anchor point and control point
|
|
2136
1921
|
let deltaCx = -Math.sin(curAng) * handleLen;
|
|
2137
1922
|
let deltaCy = Math.cos(curAng) * handleLen;
|
|
2138
|
-
|
|
2139
|
-
// anchor point
|
|
2140
1923
|
let ax = x + Math.cos(curAng) * radius;
|
|
2141
1924
|
let ay = y + Math.sin(curAng) * radius;
|
|
2142
|
-
|
|
2143
|
-
// calculate and render segments
|
|
2144
1925
|
this.moveTo(ax, ay);
|
|
2145
1926
|
for (let segIdx = 0; segIdx < numSegs; segIdx++) {
|
|
2146
|
-
// starting control point
|
|
2147
1927
|
const cp1x = ax + deltaCx;
|
|
2148
1928
|
const cp1y = ay + deltaCy;
|
|
2149
|
-
|
|
2150
|
-
// step angle
|
|
2151
1929
|
curAng += segAng;
|
|
2152
|
-
|
|
2153
|
-
// next anchor point
|
|
2154
1930
|
ax = x + Math.cos(curAng) * radius;
|
|
2155
1931
|
ay = y + Math.sin(curAng) * radius;
|
|
2156
|
-
|
|
2157
|
-
// next control point delta
|
|
2158
1932
|
deltaCx = -Math.sin(curAng) * handleLen;
|
|
2159
1933
|
deltaCy = Math.cos(curAng) * handleLen;
|
|
2160
|
-
|
|
2161
|
-
// ending control point
|
|
2162
1934
|
const cp2x = ax - deltaCx;
|
|
2163
1935
|
const cp2y = ay - deltaCy;
|
|
2164
|
-
|
|
2165
|
-
// render segment
|
|
2166
1936
|
this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, ax, ay);
|
|
2167
1937
|
}
|
|
2168
1938
|
return this;
|
|
@@ -2223,9 +1993,7 @@ var VectorMixin = {
|
|
|
2223
1993
|
return this.addContent(`W${this._windingRule(rule)} n`);
|
|
2224
1994
|
},
|
|
2225
1995
|
transform(m11, m12, m21, m22, dx, dy) {
|
|
2226
|
-
// keep track of the current transformation matrix
|
|
2227
1996
|
if (m11 === 1 && m12 === 0 && m21 === 0 && m22 === 1 && dx === 0 && dy === 0) {
|
|
2228
|
-
// Ignore identity transforms
|
|
2229
1997
|
return this;
|
|
2230
1998
|
}
|
|
2231
1999
|
const m = this._ctm;
|
|
@@ -2379,21 +2147,12 @@ oslash ugrave uacute ucircumflex
|
|
|
2379
2147
|
udieresis yacute thorn ydieresis\
|
|
2380
2148
|
`.split(/\s+/);
|
|
2381
2149
|
class AFMFont {
|
|
2382
|
-
static open(filename) {
|
|
2383
|
-
return new AFMFont(fs.readFileSync(filename, 'utf8'));
|
|
2384
|
-
}
|
|
2385
2150
|
constructor(contents) {
|
|
2386
|
-
this.contents = contents;
|
|
2387
2151
|
this.attributes = {};
|
|
2388
2152
|
this.glyphWidths = {};
|
|
2389
2153
|
this.boundingBoxes = {};
|
|
2390
2154
|
this.kernPairs = {};
|
|
2391
|
-
this.parse();
|
|
2392
|
-
// todo: remove charWidths since appears to not be used
|
|
2393
|
-
this.charWidths = new Array(256);
|
|
2394
|
-
for (let char = 0; char <= 255; char++) {
|
|
2395
|
-
this.charWidths[char] = this.glyphWidths[characters[char]];
|
|
2396
|
-
}
|
|
2155
|
+
this.parse(contents);
|
|
2397
2156
|
this.bbox = this.attributes['FontBBox'].split(/\s+/).map(e => +e);
|
|
2398
2157
|
this.ascender = +(this.attributes['Ascender'] || 0);
|
|
2399
2158
|
this.descender = +(this.attributes['Descender'] || 0);
|
|
@@ -2401,9 +2160,9 @@ class AFMFont {
|
|
|
2401
2160
|
this.capHeight = +(this.attributes['CapHeight'] || 0);
|
|
2402
2161
|
this.lineGap = this.bbox[3] - this.bbox[1] - (this.ascender - this.descender);
|
|
2403
2162
|
}
|
|
2404
|
-
parse() {
|
|
2163
|
+
parse(contents) {
|
|
2405
2164
|
let section = '';
|
|
2406
|
-
for (let line of
|
|
2165
|
+
for (let line of contents.split('\n')) {
|
|
2407
2166
|
var match;
|
|
2408
2167
|
var a;
|
|
2409
2168
|
if (match = line.match(/^Start(\w+)/)) {
|
|
@@ -2496,21 +2255,17 @@ class PDFFont {
|
|
|
2496
2255
|
return;
|
|
2497
2256
|
}
|
|
2498
2257
|
this.embed();
|
|
2499
|
-
|
|
2258
|
+
this.embedded = true;
|
|
2500
2259
|
}
|
|
2501
2260
|
embed() {
|
|
2502
2261
|
throw new Error('Must be implemented by subclasses');
|
|
2503
2262
|
}
|
|
2504
|
-
lineHeight(size, includeGap) {
|
|
2505
|
-
if (includeGap == null) {
|
|
2506
|
-
includeGap = false;
|
|
2507
|
-
}
|
|
2263
|
+
lineHeight(size, includeGap = false) {
|
|
2508
2264
|
const gap = includeGap ? this.lineGap : 0;
|
|
2509
2265
|
return (this.ascender + gap - this.descender) / 1000 * size;
|
|
2510
2266
|
}
|
|
2511
2267
|
}
|
|
2512
2268
|
|
|
2513
|
-
// This insanity is so bundlers can inline the font files
|
|
2514
2269
|
const STANDARD_FONTS = {
|
|
2515
2270
|
Courier() {
|
|
2516
2271
|
return fs.readFileSync(__dirname + '/data/Courier.afm', 'utf8');
|
|
@@ -2638,8 +2393,6 @@ class EmbeddedFont extends PDFFont {
|
|
|
2638
2393
|
}
|
|
2639
2394
|
layoutRun(text, features) {
|
|
2640
2395
|
const run = this.font.layout(text, features);
|
|
2641
|
-
|
|
2642
|
-
// Normalize position values
|
|
2643
2396
|
for (let i = 0; i < run.positions.length; i++) {
|
|
2644
2397
|
const position = run.positions[i];
|
|
2645
2398
|
for (let key in position) {
|
|
@@ -2662,16 +2415,12 @@ class EmbeddedFont extends PDFFont {
|
|
|
2662
2415
|
return run;
|
|
2663
2416
|
}
|
|
2664
2417
|
layout(text, features, onlyWidth) {
|
|
2665
|
-
// Skip the cache if any user defined features are applied
|
|
2666
2418
|
if (features) {
|
|
2667
2419
|
return this.layoutRun(text, features);
|
|
2668
2420
|
}
|
|
2669
2421
|
let glyphs = onlyWidth ? null : [];
|
|
2670
2422
|
let positions = onlyWidth ? null : [];
|
|
2671
2423
|
let advanceWidth = 0;
|
|
2672
|
-
|
|
2673
|
-
// Split the string by words to increase cache efficiency.
|
|
2674
|
-
// For this purpose, spaces and tabs are a good enough delimeter.
|
|
2675
2424
|
let last = 0;
|
|
2676
2425
|
let index = 0;
|
|
2677
2426
|
while (index <= text.length) {
|
|
@@ -2733,17 +2482,15 @@ class EmbeddedFont extends PDFFont {
|
|
|
2733
2482
|
if (1 <= familyClass && familyClass <= 7) {
|
|
2734
2483
|
flags |= 1 << 1;
|
|
2735
2484
|
}
|
|
2736
|
-
flags |= 1 << 2;
|
|
2485
|
+
flags |= 1 << 2;
|
|
2737
2486
|
if (familyClass === 10) {
|
|
2738
2487
|
flags |= 1 << 3;
|
|
2739
2488
|
}
|
|
2740
2489
|
if (this.font.head.macStyle.italic) {
|
|
2741
2490
|
flags |= 1 << 6;
|
|
2742
2491
|
}
|
|
2743
|
-
|
|
2744
|
-
// generate a tag (6 uppercase letters. 17 is the char code offset from '0' to 'A'. 73 will map to 'Z')
|
|
2745
2492
|
const tag = [1, 2, 3, 4, 5, 6].map(i => String.fromCharCode((this.id.charCodeAt(i) || 73) + 17)).join('');
|
|
2746
|
-
const name = tag + '+' + this.font.postscriptName
|
|
2493
|
+
const name = tag + '+' + this.font.postscriptName?.replaceAll(' ', '_');
|
|
2747
2494
|
const {
|
|
2748
2495
|
bbox
|
|
2749
2496
|
} = this.font;
|
|
@@ -2758,8 +2505,7 @@ class EmbeddedFont extends PDFFont {
|
|
|
2758
2505
|
CapHeight: (this.font.capHeight || this.font.ascent) * this.scale,
|
|
2759
2506
|
XHeight: (this.font.xHeight || 0) * this.scale,
|
|
2760
2507
|
StemV: 0
|
|
2761
|
-
});
|
|
2762
|
-
|
|
2508
|
+
});
|
|
2763
2509
|
if (isCFF) {
|
|
2764
2510
|
descriptor.data.FontFile3 = fontFile;
|
|
2765
2511
|
} else {
|
|
@@ -2801,17 +2547,11 @@ class EmbeddedFont extends PDFFont {
|
|
|
2801
2547
|
};
|
|
2802
2548
|
return this.dictionary.end();
|
|
2803
2549
|
}
|
|
2804
|
-
|
|
2805
|
-
// Maps the glyph ids encoded in the PDF back to unicode strings
|
|
2806
|
-
// Because of ligature substitutions and the like, there may be one or more
|
|
2807
|
-
// unicode characters represented by each glyph.
|
|
2808
2550
|
toUnicodeCmap() {
|
|
2809
2551
|
const cmap = this.document.ref();
|
|
2810
2552
|
const entries = [];
|
|
2811
2553
|
for (let codePoints of this.unicode) {
|
|
2812
2554
|
const encoded = [];
|
|
2813
|
-
|
|
2814
|
-
// encode codePoints to utf16
|
|
2815
2555
|
for (let value of codePoints) {
|
|
2816
2556
|
if (value > 0xffff) {
|
|
2817
2557
|
value -= 0x10000;
|
|
@@ -2878,31 +2618,26 @@ class PDFFontFactory {
|
|
|
2878
2618
|
}
|
|
2879
2619
|
|
|
2880
2620
|
const isEqualFont = (font1, font2) => {
|
|
2881
|
-
// compare font checksum
|
|
2882
2621
|
if (font1.font._tables?.head?.checkSumAdjustment !== font2.font._tables?.head?.checkSumAdjustment) {
|
|
2883
2622
|
return false;
|
|
2884
2623
|
}
|
|
2885
|
-
|
|
2886
|
-
// compare font name table
|
|
2887
2624
|
if (JSON.stringify(font1.font._tables?.name?.records) !== JSON.stringify(font2.font._tables?.name?.records)) {
|
|
2888
2625
|
return false;
|
|
2889
2626
|
}
|
|
2890
2627
|
return true;
|
|
2891
2628
|
};
|
|
2892
2629
|
var FontsMixin = {
|
|
2893
|
-
initFonts(defaultFont = 'Helvetica') {
|
|
2894
|
-
// Lookup table for embedded fonts
|
|
2630
|
+
initFonts(defaultFont = 'Helvetica', defaultFontFamily = null, defaultFontSize = 12) {
|
|
2895
2631
|
this._fontFamilies = {};
|
|
2896
2632
|
this._fontCount = 0;
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
this._fontSize =
|
|
2633
|
+
this._fontSource = defaultFont;
|
|
2634
|
+
this._fontFamily = defaultFontFamily;
|
|
2635
|
+
this._fontSize = defaultFontSize;
|
|
2900
2636
|
this._font = null;
|
|
2637
|
+
this._remSize = defaultFontSize;
|
|
2901
2638
|
this._registeredFonts = {};
|
|
2902
|
-
|
|
2903
|
-
// Set the default font
|
|
2904
2639
|
if (defaultFont) {
|
|
2905
|
-
this.font(defaultFont);
|
|
2640
|
+
this.font(defaultFont, defaultFontFamily);
|
|
2906
2641
|
}
|
|
2907
2642
|
},
|
|
2908
2643
|
font(src, family, size) {
|
|
@@ -2911,8 +2646,6 @@ var FontsMixin = {
|
|
|
2911
2646
|
size = family;
|
|
2912
2647
|
family = null;
|
|
2913
2648
|
}
|
|
2914
|
-
|
|
2915
|
-
// check registered fonts if src is a string
|
|
2916
2649
|
if (typeof src === 'string' && this._registeredFonts[src]) {
|
|
2917
2650
|
cacheKey = src;
|
|
2918
2651
|
({
|
|
@@ -2925,28 +2658,21 @@ var FontsMixin = {
|
|
|
2925
2658
|
cacheKey = null;
|
|
2926
2659
|
}
|
|
2927
2660
|
}
|
|
2661
|
+
this._fontSource = src;
|
|
2662
|
+
this._fontFamily = family;
|
|
2928
2663
|
if (size != null) {
|
|
2929
2664
|
this.fontSize(size);
|
|
2930
2665
|
}
|
|
2931
|
-
|
|
2932
|
-
// fast path: check if the font is already in the PDF
|
|
2933
2666
|
if (font = this._fontFamilies[cacheKey]) {
|
|
2934
2667
|
this._font = font;
|
|
2935
2668
|
return this;
|
|
2936
2669
|
}
|
|
2937
|
-
|
|
2938
|
-
// load the font
|
|
2939
2670
|
const id = `F${++this._fontCount}`;
|
|
2940
2671
|
this._font = PDFFontFactory.open(this, src, family, id);
|
|
2941
|
-
|
|
2942
|
-
// check for existing font familes with the same name already in the PDF
|
|
2943
|
-
// useful if the font was passed as a buffer
|
|
2944
2672
|
if ((font = this._fontFamilies[this._font.name]) && isEqualFont(this._font, font)) {
|
|
2945
2673
|
this._font = font;
|
|
2946
2674
|
return this;
|
|
2947
2675
|
}
|
|
2948
|
-
|
|
2949
|
-
// save the font for reuse later
|
|
2950
2676
|
if (cacheKey) {
|
|
2951
2677
|
this._fontFamilies[cacheKey] = this._font;
|
|
2952
2678
|
}
|
|
@@ -2956,13 +2682,10 @@ var FontsMixin = {
|
|
|
2956
2682
|
return this;
|
|
2957
2683
|
},
|
|
2958
2684
|
fontSize(_fontSize) {
|
|
2959
|
-
this._fontSize = _fontSize;
|
|
2685
|
+
this._fontSize = this.sizeToPoint(_fontSize);
|
|
2960
2686
|
return this;
|
|
2961
2687
|
},
|
|
2962
2688
|
currentLineHeight(includeGap) {
|
|
2963
|
-
if (includeGap == null) {
|
|
2964
|
-
includeGap = false;
|
|
2965
|
-
}
|
|
2966
2689
|
return this._font.lineHeight(this._fontSize, includeGap);
|
|
2967
2690
|
},
|
|
2968
2691
|
registerFont(name, src, family) {
|
|
@@ -2971,6 +2694,64 @@ var FontsMixin = {
|
|
|
2971
2694
|
family
|
|
2972
2695
|
};
|
|
2973
2696
|
return this;
|
|
2697
|
+
},
|
|
2698
|
+
sizeToPoint(size, defaultValue = 0, page = this.page, percentageWidth = undefined) {
|
|
2699
|
+
if (!percentageWidth) percentageWidth = this._fontSize;
|
|
2700
|
+
if (typeof defaultValue !== 'number') defaultValue = this.sizeToPoint(defaultValue);
|
|
2701
|
+
if (size === undefined) return defaultValue;
|
|
2702
|
+
if (typeof size === 'number') return size;
|
|
2703
|
+
if (typeof size === 'boolean') return Number(size);
|
|
2704
|
+
const match = String(size).match(/((\d+)?(\.\d+)?)(em|in|px|cm|mm|pc|ex|ch|rem|vw|vh|vmin|vmax|%|pt)?/);
|
|
2705
|
+
if (!match) throw new Error(`Unsupported size '${size}'`);
|
|
2706
|
+
let multiplier;
|
|
2707
|
+
switch (match[4]) {
|
|
2708
|
+
case 'em':
|
|
2709
|
+
multiplier = this._fontSize;
|
|
2710
|
+
break;
|
|
2711
|
+
case 'in':
|
|
2712
|
+
multiplier = IN_TO_PT;
|
|
2713
|
+
break;
|
|
2714
|
+
case 'px':
|
|
2715
|
+
multiplier = PX_TO_IN * IN_TO_PT;
|
|
2716
|
+
break;
|
|
2717
|
+
case 'cm':
|
|
2718
|
+
multiplier = CM_TO_IN * IN_TO_PT;
|
|
2719
|
+
break;
|
|
2720
|
+
case 'mm':
|
|
2721
|
+
multiplier = MM_TO_CM * CM_TO_IN * IN_TO_PT;
|
|
2722
|
+
break;
|
|
2723
|
+
case 'pc':
|
|
2724
|
+
multiplier = PC_TO_PT;
|
|
2725
|
+
break;
|
|
2726
|
+
case 'ex':
|
|
2727
|
+
multiplier = this.currentLineHeight();
|
|
2728
|
+
break;
|
|
2729
|
+
case 'ch':
|
|
2730
|
+
multiplier = this.widthOfString('0');
|
|
2731
|
+
break;
|
|
2732
|
+
case 'rem':
|
|
2733
|
+
multiplier = this._remSize;
|
|
2734
|
+
break;
|
|
2735
|
+
case 'vw':
|
|
2736
|
+
multiplier = page.width / 100;
|
|
2737
|
+
break;
|
|
2738
|
+
case 'vh':
|
|
2739
|
+
multiplier = page.height / 100;
|
|
2740
|
+
break;
|
|
2741
|
+
case 'vmin':
|
|
2742
|
+
multiplier = Math.min(page.width, page.height) / 100;
|
|
2743
|
+
break;
|
|
2744
|
+
case 'vmax':
|
|
2745
|
+
multiplier = Math.max(page.width, page.height) / 100;
|
|
2746
|
+
break;
|
|
2747
|
+
case '%':
|
|
2748
|
+
multiplier = percentageWidth / 100;
|
|
2749
|
+
break;
|
|
2750
|
+
case 'pt':
|
|
2751
|
+
default:
|
|
2752
|
+
multiplier = 1;
|
|
2753
|
+
}
|
|
2754
|
+
return multiplier * Number(match[1]);
|
|
2974
2755
|
}
|
|
2975
2756
|
};
|
|
2976
2757
|
|
|
@@ -2985,7 +2766,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2985
2766
|
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
2986
2767
|
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
2987
2768
|
this.columns = options.columns || 1;
|
|
2988
|
-
this.columnGap = (options.columnGap != null ? options.columnGap : 18) * this.horizontalScaling / 100;
|
|
2769
|
+
this.columnGap = (options.columnGap != null ? options.columnGap : 18) * this.horizontalScaling / 100;
|
|
2989
2770
|
this.lineWidth = (options.width * this.horizontalScaling / 100 - this.columnGap * (this.columns - 1)) / this.columns;
|
|
2990
2771
|
this.spaceLeft = this.lineWidth;
|
|
2991
2772
|
this.startX = this.document.x;
|
|
@@ -2994,44 +2775,30 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2994
2775
|
this.ellipsis = options.ellipsis;
|
|
2995
2776
|
this.continuedX = 0;
|
|
2996
2777
|
this.features = options.features;
|
|
2997
|
-
|
|
2998
|
-
// calculate the maximum Y position the text can appear at
|
|
2999
2778
|
if (options.height != null) {
|
|
3000
2779
|
this.height = options.height;
|
|
3001
|
-
this.maxY = this.startY + options.height;
|
|
2780
|
+
this.maxY = PDFNumber(this.startY + options.height);
|
|
3002
2781
|
} else {
|
|
3003
|
-
this.maxY = this.document.page.maxY();
|
|
2782
|
+
this.maxY = PDFNumber(this.document.page.maxY());
|
|
3004
2783
|
}
|
|
3005
|
-
|
|
3006
|
-
// handle paragraph indents
|
|
3007
2784
|
this.on('firstLine', options => {
|
|
3008
|
-
// if this is the first line of the text segment, and
|
|
3009
|
-
// we're continuing where we left off, indent that much
|
|
3010
|
-
// otherwise use the user specified indent option
|
|
3011
2785
|
const indent = this.continuedX || this.indent;
|
|
3012
2786
|
this.document.x += indent;
|
|
3013
2787
|
this.lineWidth -= indent;
|
|
3014
|
-
|
|
3015
|
-
// if indentAllLines is set to true
|
|
3016
|
-
// we're not resetting the indentation for this paragraph after the first line
|
|
3017
2788
|
if (options.indentAllLines) {
|
|
3018
2789
|
return;
|
|
3019
2790
|
}
|
|
3020
|
-
|
|
3021
|
-
// otherwise we start the next line without indent
|
|
3022
|
-
return this.once('line', () => {
|
|
2791
|
+
this.once('line', () => {
|
|
3023
2792
|
this.document.x -= indent;
|
|
3024
2793
|
this.lineWidth += indent;
|
|
3025
2794
|
if (options.continued && !this.continuedX) {
|
|
3026
2795
|
this.continuedX = this.indent;
|
|
3027
2796
|
}
|
|
3028
2797
|
if (!options.continued) {
|
|
3029
|
-
|
|
2798
|
+
this.continuedX = 0;
|
|
3030
2799
|
}
|
|
3031
2800
|
});
|
|
3032
2801
|
});
|
|
3033
|
-
|
|
3034
|
-
// handle left aligning last lines of paragraphs
|
|
3035
2802
|
this.on('lastLine', options => {
|
|
3036
2803
|
const {
|
|
3037
2804
|
align
|
|
@@ -3040,7 +2807,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3040
2807
|
options.align = 'left';
|
|
3041
2808
|
}
|
|
3042
2809
|
this.lastLine = true;
|
|
3043
|
-
|
|
2810
|
+
this.once('line', () => {
|
|
3044
2811
|
this.document.y += options.paragraphGap || 0;
|
|
3045
2812
|
options.align = align;
|
|
3046
2813
|
return this.lastLine = false;
|
|
@@ -3048,7 +2815,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3048
2815
|
});
|
|
3049
2816
|
}
|
|
3050
2817
|
wordWidth(word) {
|
|
3051
|
-
return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing;
|
|
2818
|
+
return PDFNumber(this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing);
|
|
3052
2819
|
}
|
|
3053
2820
|
canFit(word, w) {
|
|
3054
2821
|
if (word[word.length - 1] != SOFT_HYPHEN) {
|
|
@@ -3057,7 +2824,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3057
2824
|
return w + this.wordWidth(HYPHEN) <= this.spaceLeft;
|
|
3058
2825
|
}
|
|
3059
2826
|
eachWord(text, fn) {
|
|
3060
|
-
// setup a unicode line breaker
|
|
3061
2827
|
let bk;
|
|
3062
2828
|
const breaker = new LineBreaker(text);
|
|
3063
2829
|
let last = null;
|
|
@@ -3066,19 +2832,12 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3066
2832
|
var shouldContinue;
|
|
3067
2833
|
let word = text.slice((last != null ? last.position : undefined) || 0, bk.position);
|
|
3068
2834
|
let w = wordWidths[word] != null ? wordWidths[word] : wordWidths[word] = this.wordWidth(word);
|
|
3069
|
-
|
|
3070
|
-
// if the word is longer than the whole line, chop it up
|
|
3071
|
-
// TODO: break by grapheme clusters, not JS string characters
|
|
3072
2835
|
if (w > this.lineWidth + this.continuedX) {
|
|
3073
|
-
// make some fake break objects
|
|
3074
2836
|
let lbk = last;
|
|
3075
2837
|
const fbk = {};
|
|
3076
2838
|
while (word.length) {
|
|
3077
|
-
// fit as much of the word as possible into the space we have
|
|
3078
2839
|
var l, mightGrow;
|
|
3079
2840
|
if (w > this.spaceLeft) {
|
|
3080
|
-
// start our check at the end of our available space - this method is faster than a loop of each character and it resolves
|
|
3081
|
-
// an issue with long loops when processing massive words, such as a huge number of spaces
|
|
3082
2841
|
l = Math.ceil(this.spaceLeft / (w / word.length));
|
|
3083
2842
|
w = this.wordWidth(word.slice(0, l));
|
|
3084
2843
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
@@ -3086,7 +2845,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3086
2845
|
l = word.length;
|
|
3087
2846
|
}
|
|
3088
2847
|
let mustShrink = w > this.spaceLeft && l > 0;
|
|
3089
|
-
// shrink or grow word as necessary after our near-guess above
|
|
3090
2848
|
while (mustShrink || mightGrow) {
|
|
3091
2849
|
if (mustShrink) {
|
|
3092
2850
|
w = this.wordWidth(word.slice(0, --l));
|
|
@@ -3097,20 +2855,14 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3097
2855
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
3098
2856
|
}
|
|
3099
2857
|
}
|
|
3100
|
-
|
|
3101
|
-
// check for the edge case where a single character cannot fit into a line.
|
|
3102
2858
|
if (l === 0 && this.spaceLeft === this.lineWidth) {
|
|
3103
2859
|
l = 1;
|
|
3104
2860
|
}
|
|
3105
|
-
|
|
3106
|
-
// send a required break unless this is the last piece and a linebreak is not specified
|
|
3107
2861
|
fbk.required = bk.required || l < word.length;
|
|
3108
2862
|
shouldContinue = fn(word.slice(0, l), w, fbk, lbk);
|
|
3109
2863
|
lbk = {
|
|
3110
2864
|
required: false
|
|
3111
2865
|
};
|
|
3112
|
-
|
|
3113
|
-
// get the remaining piece of the word
|
|
3114
2866
|
word = word.slice(l);
|
|
3115
2867
|
w = this.wordWidth(word);
|
|
3116
2868
|
if (shouldContinue === false) {
|
|
@@ -3118,7 +2870,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3118
2870
|
}
|
|
3119
2871
|
}
|
|
3120
2872
|
} else {
|
|
3121
|
-
// otherwise just emit the break as it was given to us
|
|
3122
2873
|
shouldContinue = fn(word, w, bk, last);
|
|
3123
2874
|
}
|
|
3124
2875
|
if (shouldContinue === false) {
|
|
@@ -3128,7 +2879,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3128
2879
|
}
|
|
3129
2880
|
}
|
|
3130
2881
|
wrap(text, options) {
|
|
3131
|
-
// override options from previous continued fragments
|
|
3132
2882
|
this.horizontalScaling = options.horizontalScaling || 100;
|
|
3133
2883
|
if (options.indent != null) {
|
|
3134
2884
|
this.indent = options.indent * this.horizontalScaling / 100;
|
|
@@ -3142,10 +2892,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3142
2892
|
if (options.ellipsis != null) {
|
|
3143
2893
|
this.ellipsis = options.ellipsis;
|
|
3144
2894
|
}
|
|
3145
|
-
|
|
3146
|
-
// make sure we're actually on the page
|
|
3147
|
-
// and that the first line of is never by
|
|
3148
|
-
// itself at the bottom of a page (orphans)
|
|
3149
2895
|
const nextY = this.document.y + this.document.currentLineHeight(true);
|
|
3150
2896
|
if (this.document.y > this.maxY || nextY > this.maxY) {
|
|
3151
2897
|
this.nextSection();
|
|
@@ -3156,7 +2902,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3156
2902
|
let lc = 0;
|
|
3157
2903
|
let {
|
|
3158
2904
|
y
|
|
3159
|
-
} = this.document;
|
|
2905
|
+
} = this.document;
|
|
3160
2906
|
const emitLine = () => {
|
|
3161
2907
|
options.textWidth = textWidth + this.wordSpacing * (wc - 1);
|
|
3162
2908
|
options.wordCount = wc;
|
|
@@ -3179,23 +2925,17 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3179
2925
|
wc++;
|
|
3180
2926
|
}
|
|
3181
2927
|
if (bk.required || !this.canFit(word, w)) {
|
|
3182
|
-
// if the user specified a max height and an ellipsis, and is about to pass the
|
|
3183
|
-
// max height and max columns after the next line, append the ellipsis
|
|
3184
2928
|
const lh = this.document.currentLineHeight(true);
|
|
3185
|
-
if (this.height != null && this.ellipsis && this.document.y + lh * 2 > this.maxY && this.column >= this.columns) {
|
|
2929
|
+
if (this.height != null && this.ellipsis && PDFNumber(this.document.y + lh * 2) > this.maxY && this.column >= this.columns) {
|
|
3186
2930
|
if (this.ellipsis === true) {
|
|
3187
2931
|
this.ellipsis = '…';
|
|
3188
|
-
}
|
|
2932
|
+
}
|
|
3189
2933
|
buffer = buffer.replace(/\s+$/, '');
|
|
3190
2934
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3191
|
-
|
|
3192
|
-
// remove characters from the buffer until the ellipsis fits
|
|
3193
|
-
// to avoid infinite loop need to stop while-loop if buffer is empty string
|
|
3194
2935
|
while (buffer && textWidth > this.lineWidth) {
|
|
3195
2936
|
buffer = buffer.slice(0, -1).replace(/\s+$/, '');
|
|
3196
2937
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3197
2938
|
}
|
|
3198
|
-
// need to add ellipsis only if there is enough space for it
|
|
3199
2939
|
if (textWidth <= this.lineWidth) {
|
|
3200
2940
|
buffer = buffer + this.ellipsis;
|
|
3201
2941
|
}
|
|
@@ -3210,35 +2950,25 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3210
2950
|
}
|
|
3211
2951
|
this.emit('lastLine', options, this);
|
|
3212
2952
|
}
|
|
3213
|
-
|
|
3214
|
-
// Previous entry is a soft hyphen - add visible hyphen.
|
|
3215
2953
|
if (buffer[buffer.length - 1] == SOFT_HYPHEN) {
|
|
3216
2954
|
buffer = buffer.slice(0, -1) + HYPHEN;
|
|
3217
2955
|
this.spaceLeft -= this.wordWidth(HYPHEN);
|
|
3218
2956
|
}
|
|
3219
2957
|
emitLine();
|
|
3220
|
-
|
|
3221
|
-
// if we've reached the edge of the page,
|
|
3222
|
-
// continue on a new page or column
|
|
3223
|
-
if (this.document.y + lh > this.maxY) {
|
|
2958
|
+
if (PDFNumber(this.document.y + lh) > this.maxY) {
|
|
3224
2959
|
const shouldContinue = this.nextSection();
|
|
3225
|
-
|
|
3226
|
-
// stop if we reached the maximum height
|
|
3227
2960
|
if (!shouldContinue) {
|
|
3228
2961
|
wc = 0;
|
|
3229
2962
|
buffer = '';
|
|
3230
2963
|
return false;
|
|
3231
2964
|
}
|
|
3232
2965
|
}
|
|
3233
|
-
|
|
3234
|
-
// reset the space left and buffer
|
|
3235
2966
|
if (bk.required) {
|
|
3236
2967
|
this.spaceLeft = this.lineWidth;
|
|
3237
2968
|
buffer = '';
|
|
3238
2969
|
textWidth = 0;
|
|
3239
2970
|
return wc = 0;
|
|
3240
2971
|
} else {
|
|
3241
|
-
// reset the space left and buffer
|
|
3242
2972
|
this.spaceLeft = this.lineWidth - w;
|
|
3243
2973
|
buffer = word;
|
|
3244
2974
|
textWidth = w;
|
|
@@ -3253,25 +2983,19 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3253
2983
|
emitLine();
|
|
3254
2984
|
}
|
|
3255
2985
|
this.emit('sectionEnd', options, this);
|
|
3256
|
-
|
|
3257
|
-
// if the wrap is set to be continued, save the X position
|
|
3258
|
-
// to start the first line of the next segment at, and reset
|
|
3259
|
-
// the y position
|
|
3260
2986
|
if (options.continued === true) {
|
|
3261
2987
|
if (lc > 1) {
|
|
3262
2988
|
this.continuedX = 0;
|
|
3263
2989
|
}
|
|
3264
2990
|
this.continuedX += options.textWidth || 0;
|
|
3265
|
-
|
|
2991
|
+
this.document.y = y;
|
|
3266
2992
|
} else {
|
|
3267
|
-
|
|
2993
|
+
this.document.x = this.startX;
|
|
3268
2994
|
}
|
|
3269
2995
|
}
|
|
3270
2996
|
nextSection(options) {
|
|
3271
2997
|
this.emit('sectionEnd', options, this);
|
|
3272
2998
|
if (++this.column > this.columns) {
|
|
3273
|
-
// if a max height was specified by the user, we're done.
|
|
3274
|
-
// otherwise, the default is to make a new page at the bottom.
|
|
3275
2999
|
if (this.height != null) {
|
|
3276
3000
|
return false;
|
|
3277
3001
|
}
|
|
@@ -3300,10 +3024,9 @@ const {
|
|
|
3300
3024
|
var TextMixin = {
|
|
3301
3025
|
initText() {
|
|
3302
3026
|
this._line = this._line.bind(this);
|
|
3303
|
-
// Current coordinates
|
|
3304
3027
|
this.x = 0;
|
|
3305
3028
|
this.y = 0;
|
|
3306
|
-
|
|
3029
|
+
this._lineGap = 0;
|
|
3307
3030
|
},
|
|
3308
3031
|
lineGap(_lineGap) {
|
|
3309
3032
|
this._lineGap = _lineGap;
|
|
@@ -3325,11 +3048,7 @@ var TextMixin = {
|
|
|
3325
3048
|
},
|
|
3326
3049
|
_text(text, x, y, options, lineCallback) {
|
|
3327
3050
|
options = this._initOptions(x, y, options);
|
|
3328
|
-
|
|
3329
|
-
// Convert text to a string
|
|
3330
3051
|
text = text == null ? '' : `${text}`;
|
|
3331
|
-
|
|
3332
|
-
// if the wordSpacing option is specified, remove multiple consecutive spaces
|
|
3333
3052
|
if (options.wordSpacing) {
|
|
3334
3053
|
text = text.replace(/\s{2,}/g, ' ');
|
|
3335
3054
|
}
|
|
@@ -3338,8 +3057,12 @@ var TextMixin = {
|
|
|
3338
3057
|
options.structParent.add(this.struct(options.structType || 'P', [this.markStructureContent(options.structType || 'P')]));
|
|
3339
3058
|
}
|
|
3340
3059
|
};
|
|
3341
|
-
|
|
3342
|
-
|
|
3060
|
+
if (options.rotation !== 0) {
|
|
3061
|
+
this.save();
|
|
3062
|
+
this.rotate(-options.rotation, {
|
|
3063
|
+
origin: [this.x, this.y]
|
|
3064
|
+
});
|
|
3065
|
+
}
|
|
3343
3066
|
if (options.width) {
|
|
3344
3067
|
let wrapper = this._wrapper;
|
|
3345
3068
|
if (!wrapper) {
|
|
@@ -3350,14 +3073,13 @@ var TextMixin = {
|
|
|
3350
3073
|
this._wrapper = options.continued ? wrapper : null;
|
|
3351
3074
|
this._textOptions = options.continued ? options : null;
|
|
3352
3075
|
wrapper.wrap(text, options);
|
|
3353
|
-
|
|
3354
|
-
// render paragraphs as single lines
|
|
3355
3076
|
} else {
|
|
3356
3077
|
for (let line of text.split('\n')) {
|
|
3357
3078
|
addStructure();
|
|
3358
3079
|
lineCallback(line, options);
|
|
3359
3080
|
}
|
|
3360
3081
|
}
|
|
3082
|
+
if (options.rotation !== 0) this.restore();
|
|
3361
3083
|
return this;
|
|
3362
3084
|
},
|
|
3363
3085
|
text(text, x, y, options) {
|
|
@@ -3367,17 +3089,108 @@ var TextMixin = {
|
|
|
3367
3089
|
const horizontalScaling = options.horizontalScaling || 100;
|
|
3368
3090
|
return (this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1)) * horizontalScaling / 100;
|
|
3369
3091
|
},
|
|
3092
|
+
boundsOfString(string, x, y, options) {
|
|
3093
|
+
options = this._initOptions(x, y, options);
|
|
3094
|
+
({
|
|
3095
|
+
x,
|
|
3096
|
+
y
|
|
3097
|
+
} = this);
|
|
3098
|
+
const lineGap = options.lineGap ?? this._lineGap ?? 0;
|
|
3099
|
+
const lineHeight = this.currentLineHeight(true) + lineGap;
|
|
3100
|
+
let contentWidth = 0;
|
|
3101
|
+
string = String(string ?? '');
|
|
3102
|
+
if (options.wordSpacing) {
|
|
3103
|
+
string = string.replace(/\s{2,}/g, ' ');
|
|
3104
|
+
}
|
|
3105
|
+
if (options.width) {
|
|
3106
|
+
let wrapper = new LineWrapper(this, options);
|
|
3107
|
+
wrapper.on('line', (text, options) => {
|
|
3108
|
+
this.y += lineHeight;
|
|
3109
|
+
text = text.replace(/\n/g, '');
|
|
3110
|
+
if (text.length) {
|
|
3111
|
+
let wordSpacing = options.wordSpacing ?? 0;
|
|
3112
|
+
const characterSpacing = options.characterSpacing ?? 0;
|
|
3113
|
+
if (options.width && options.align === 'justify') {
|
|
3114
|
+
const words = text.trim().split(/\s+/);
|
|
3115
|
+
const textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3116
|
+
const spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
3117
|
+
wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth);
|
|
3118
|
+
}
|
|
3119
|
+
contentWidth = Math.max(contentWidth, options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1));
|
|
3120
|
+
}
|
|
3121
|
+
});
|
|
3122
|
+
wrapper.wrap(string, options);
|
|
3123
|
+
} else {
|
|
3124
|
+
for (let line of string.split('\n')) {
|
|
3125
|
+
const lineWidth = this.widthOfString(line, options);
|
|
3126
|
+
this.y += lineHeight;
|
|
3127
|
+
contentWidth = Math.max(contentWidth, lineWidth);
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
let contentHeight = this.y - y;
|
|
3131
|
+
if (options.height) contentHeight = Math.min(contentHeight, options.height);
|
|
3132
|
+
this.x = x;
|
|
3133
|
+
this.y = y;
|
|
3134
|
+
if (options.rotation === 0) {
|
|
3135
|
+
return {
|
|
3136
|
+
x,
|
|
3137
|
+
y,
|
|
3138
|
+
width: contentWidth,
|
|
3139
|
+
height: contentHeight
|
|
3140
|
+
};
|
|
3141
|
+
} else if (options.rotation === 90) {
|
|
3142
|
+
return {
|
|
3143
|
+
x: x,
|
|
3144
|
+
y: y - contentWidth,
|
|
3145
|
+
width: contentHeight,
|
|
3146
|
+
height: contentWidth
|
|
3147
|
+
};
|
|
3148
|
+
} else if (options.rotation === 180) {
|
|
3149
|
+
return {
|
|
3150
|
+
x: x - contentWidth,
|
|
3151
|
+
y: y - contentHeight,
|
|
3152
|
+
width: contentWidth,
|
|
3153
|
+
height: contentHeight
|
|
3154
|
+
};
|
|
3155
|
+
} else if (options.rotation === 270) {
|
|
3156
|
+
return {
|
|
3157
|
+
x: x - contentHeight,
|
|
3158
|
+
y: y,
|
|
3159
|
+
width: contentHeight,
|
|
3160
|
+
height: contentWidth
|
|
3161
|
+
};
|
|
3162
|
+
}
|
|
3163
|
+
const cos = cosine(options.rotation);
|
|
3164
|
+
const sin = sine(options.rotation);
|
|
3165
|
+
const x1 = x;
|
|
3166
|
+
const y1 = y;
|
|
3167
|
+
const x2 = x + contentWidth * cos;
|
|
3168
|
+
const y2 = y - contentWidth * sin;
|
|
3169
|
+
const x3 = x + contentWidth * cos + contentHeight * sin;
|
|
3170
|
+
const y3 = y - contentWidth * sin + contentHeight * cos;
|
|
3171
|
+
const x4 = x + contentHeight * sin;
|
|
3172
|
+
const y4 = y + contentHeight * cos;
|
|
3173
|
+
const xMin = Math.min(x1, x2, x3, x4);
|
|
3174
|
+
const xMax = Math.max(x1, x2, x3, x4);
|
|
3175
|
+
const yMin = Math.min(y1, y2, y3, y4);
|
|
3176
|
+
const yMax = Math.max(y1, y2, y3, y4);
|
|
3177
|
+
return {
|
|
3178
|
+
x: xMin,
|
|
3179
|
+
y: yMin,
|
|
3180
|
+
width: xMax - xMin,
|
|
3181
|
+
height: yMax - yMin
|
|
3182
|
+
};
|
|
3183
|
+
},
|
|
3370
3184
|
heightOfString(text, options) {
|
|
3371
3185
|
const {
|
|
3372
3186
|
x,
|
|
3373
3187
|
y
|
|
3374
3188
|
} = this;
|
|
3375
3189
|
options = this._initOptions(options);
|
|
3376
|
-
options.height = Infinity;
|
|
3377
|
-
|
|
3190
|
+
options.height = Infinity;
|
|
3378
3191
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3379
3192
|
this._text(text, this.x, this.y, options, () => {
|
|
3380
|
-
|
|
3193
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3381
3194
|
});
|
|
3382
3195
|
const height = this.y - y;
|
|
3383
3196
|
this.x = x;
|
|
@@ -3475,12 +3288,12 @@ var TextMixin = {
|
|
|
3475
3288
|
wrapper.on('sectionStart', () => {
|
|
3476
3289
|
const pos = indent + itemIndent * (level - 1);
|
|
3477
3290
|
this.x += pos;
|
|
3478
|
-
|
|
3291
|
+
wrapper.lineWidth -= pos;
|
|
3479
3292
|
});
|
|
3480
3293
|
wrapper.on('sectionEnd', () => {
|
|
3481
3294
|
const pos = indent + itemIndent * (level - 1);
|
|
3482
3295
|
this.x -= pos;
|
|
3483
|
-
|
|
3296
|
+
wrapper.lineWidth += pos;
|
|
3484
3297
|
});
|
|
3485
3298
|
wrapper.wrap(listItem, options);
|
|
3486
3299
|
};
|
|
@@ -3494,11 +3307,7 @@ var TextMixin = {
|
|
|
3494
3307
|
options = x;
|
|
3495
3308
|
x = null;
|
|
3496
3309
|
}
|
|
3497
|
-
|
|
3498
|
-
// clone options object
|
|
3499
3310
|
const result = Object.assign({}, options);
|
|
3500
|
-
|
|
3501
|
-
// extend options with previous values for continued text
|
|
3502
3311
|
if (this._textOptions) {
|
|
3503
3312
|
for (let key in this._textOptions) {
|
|
3504
3313
|
const val = this._textOptions[key];
|
|
@@ -3509,16 +3318,12 @@ var TextMixin = {
|
|
|
3509
3318
|
}
|
|
3510
3319
|
}
|
|
3511
3320
|
}
|
|
3512
|
-
|
|
3513
|
-
// Update the current position
|
|
3514
3321
|
if (x != null) {
|
|
3515
3322
|
this.x = x;
|
|
3516
3323
|
}
|
|
3517
3324
|
if (y != null) {
|
|
3518
3325
|
this.y = y;
|
|
3519
3326
|
}
|
|
3520
|
-
|
|
3521
|
-
// wrap to margins if no x or y position passed
|
|
3522
3327
|
if (result.lineBreak !== false) {
|
|
3523
3328
|
if (result.width == null) {
|
|
3524
3329
|
result.width = this.page.width - this.x - this.page.margins.right;
|
|
@@ -3530,17 +3335,18 @@ var TextMixin = {
|
|
|
3530
3335
|
}
|
|
3531
3336
|
if (result.columnGap == null) {
|
|
3532
3337
|
result.columnGap = 18;
|
|
3533
|
-
}
|
|
3534
|
-
|
|
3338
|
+
}
|
|
3339
|
+
result.rotation = Number(options.rotation ?? 0) % 360;
|
|
3340
|
+
if (result.rotation < 0) result.rotation += 360;
|
|
3535
3341
|
return result;
|
|
3536
3342
|
},
|
|
3537
3343
|
_line(text, options = {}, wrapper) {
|
|
3538
3344
|
this._fragment(text, this.x, this.y, options);
|
|
3539
3345
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3540
3346
|
if (!wrapper) {
|
|
3541
|
-
|
|
3347
|
+
this.x += this.widthOfString(text, options);
|
|
3542
3348
|
} else {
|
|
3543
|
-
|
|
3349
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3544
3350
|
}
|
|
3545
3351
|
},
|
|
3546
3352
|
_fragment(text, x, y, options) {
|
|
@@ -3549,14 +3355,10 @@ var TextMixin = {
|
|
|
3549
3355
|
if (text.length === 0) {
|
|
3550
3356
|
return;
|
|
3551
3357
|
}
|
|
3552
|
-
|
|
3553
|
-
// handle options
|
|
3554
3358
|
const align = options.align || 'left';
|
|
3555
3359
|
let wordSpacing = options.wordSpacing || 0;
|
|
3556
3360
|
const characterSpacing = options.characterSpacing || 0;
|
|
3557
3361
|
const horizontalScaling = options.horizontalScaling || 100;
|
|
3558
|
-
|
|
3559
|
-
// text alignments
|
|
3560
3362
|
if (options.width) {
|
|
3561
3363
|
switch (align) {
|
|
3562
3364
|
case 'right':
|
|
@@ -3567,7 +3369,6 @@ var TextMixin = {
|
|
|
3567
3369
|
x += options.lineWidth / 2 - options.textWidth / 2;
|
|
3568
3370
|
break;
|
|
3569
3371
|
case 'justify':
|
|
3570
|
-
// calculate the word spacing value
|
|
3571
3372
|
words = text.trim().split(/\s+/);
|
|
3572
3373
|
textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3573
3374
|
var spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
@@ -3575,8 +3376,6 @@ var TextMixin = {
|
|
|
3575
3376
|
break;
|
|
3576
3377
|
}
|
|
3577
3378
|
}
|
|
3578
|
-
|
|
3579
|
-
// text baseline alignments based on http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
|
|
3580
3379
|
if (typeof options.baseline === 'number') {
|
|
3581
3380
|
dy = -options.baseline;
|
|
3582
3381
|
} else {
|
|
@@ -3609,11 +3408,7 @@ var TextMixin = {
|
|
|
3609
3408
|
}
|
|
3610
3409
|
dy = dy / 1000 * this._fontSize;
|
|
3611
3410
|
}
|
|
3612
|
-
|
|
3613
|
-
// calculate the actual rendered width of the string after word and character spacing
|
|
3614
3411
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3615
|
-
|
|
3616
|
-
// create link annotations if the link option is given
|
|
3617
3412
|
if (options.link != null) {
|
|
3618
3413
|
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);
|
|
3619
3414
|
}
|
|
@@ -3623,8 +3418,6 @@ var TextMixin = {
|
|
|
3623
3418
|
if (options.destination != null) {
|
|
3624
3419
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
3625
3420
|
}
|
|
3626
|
-
|
|
3627
|
-
// create underline
|
|
3628
3421
|
if (options.underline) {
|
|
3629
3422
|
this.save();
|
|
3630
3423
|
if (!options.stroke) {
|
|
@@ -3638,8 +3431,6 @@ var TextMixin = {
|
|
|
3638
3431
|
this.stroke();
|
|
3639
3432
|
this.restore();
|
|
3640
3433
|
}
|
|
3641
|
-
|
|
3642
|
-
// create strikethrough line
|
|
3643
3434
|
if (options.strike) {
|
|
3644
3435
|
this.save();
|
|
3645
3436
|
if (!options.stroke) {
|
|
@@ -3654,8 +3445,6 @@ var TextMixin = {
|
|
|
3654
3445
|
this.restore();
|
|
3655
3446
|
}
|
|
3656
3447
|
this.save();
|
|
3657
|
-
|
|
3658
|
-
// oblique (angle in degrees or boolean)
|
|
3659
3448
|
if (options.oblique) {
|
|
3660
3449
|
let skew;
|
|
3661
3450
|
if (typeof options.oblique === 'number') {
|
|
@@ -3667,45 +3456,24 @@ var TextMixin = {
|
|
|
3667
3456
|
this.transform(1, 0, skew, 1, -skew * dy, 0);
|
|
3668
3457
|
this.transform(1, 0, 0, 1, -x, -y);
|
|
3669
3458
|
}
|
|
3670
|
-
|
|
3671
|
-
// flip coordinate system
|
|
3672
3459
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
3673
3460
|
y = this.page.height - y - dy;
|
|
3674
|
-
|
|
3675
|
-
// add current font to page if necessary
|
|
3676
3461
|
if (this.page.fonts[this._font.id] == null) {
|
|
3677
3462
|
this.page.fonts[this._font.id] = this._font.ref();
|
|
3678
3463
|
}
|
|
3679
|
-
|
|
3680
|
-
// begin the text object
|
|
3681
3464
|
this.addContent('BT');
|
|
3682
|
-
|
|
3683
|
-
// text position
|
|
3684
3465
|
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3685
|
-
|
|
3686
|
-
// font and font size
|
|
3687
3466
|
this.addContent(`/${this._font.id} ${number(this._fontSize)} Tf`);
|
|
3688
|
-
|
|
3689
|
-
// rendering mode
|
|
3690
3467
|
const mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;
|
|
3691
3468
|
if (mode) {
|
|
3692
3469
|
this.addContent(`${mode} Tr`);
|
|
3693
3470
|
}
|
|
3694
|
-
|
|
3695
|
-
// Character spacing
|
|
3696
3471
|
if (characterSpacing) {
|
|
3697
3472
|
this.addContent(`${number(characterSpacing)} Tc`);
|
|
3698
3473
|
}
|
|
3699
|
-
|
|
3700
|
-
// Horizontal scaling
|
|
3701
3474
|
if (horizontalScaling !== 100) {
|
|
3702
3475
|
this.addContent(`${horizontalScaling} Tz`);
|
|
3703
3476
|
}
|
|
3704
|
-
|
|
3705
|
-
// Add the actual text
|
|
3706
|
-
// If we have a word spacing value, we need to encode each word separately
|
|
3707
|
-
// since the normal Tw operator only works on character code 32, which isn't
|
|
3708
|
-
// used for embedded fonts.
|
|
3709
3477
|
if (wordSpacing) {
|
|
3710
3478
|
words = text.trim().split(/\s+/);
|
|
3711
3479
|
wordSpacing += this.widthOfString(' ') + characterSpacing;
|
|
@@ -3716,9 +3484,6 @@ var TextMixin = {
|
|
|
3716
3484
|
const [encodedWord, positionsWord] = this._font.encode(word, options.features);
|
|
3717
3485
|
encoded = encoded.concat(encodedWord);
|
|
3718
3486
|
positions = positions.concat(positionsWord);
|
|
3719
|
-
|
|
3720
|
-
// add the word spacing to the end of the word
|
|
3721
|
-
// clone object because of cache
|
|
3722
3487
|
const space = {};
|
|
3723
3488
|
const object = positions[positions.length - 1];
|
|
3724
3489
|
for (let key in object) {
|
|
@@ -3735,60 +3500,42 @@ var TextMixin = {
|
|
|
3735
3500
|
const commands = [];
|
|
3736
3501
|
let last = 0;
|
|
3737
3502
|
let hadOffset = false;
|
|
3738
|
-
|
|
3739
|
-
// Adds a segment of text to the TJ command buffer
|
|
3740
3503
|
const addSegment = cur => {
|
|
3741
3504
|
if (last < cur) {
|
|
3742
3505
|
const hex = encoded.slice(last, cur).join('');
|
|
3743
3506
|
const advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;
|
|
3744
3507
|
commands.push(`<${hex}> ${number(-advance)}`);
|
|
3745
3508
|
}
|
|
3746
|
-
|
|
3509
|
+
last = cur;
|
|
3747
3510
|
};
|
|
3748
|
-
|
|
3749
|
-
// Flushes the current TJ commands to the output stream
|
|
3750
3511
|
const flush = i => {
|
|
3751
3512
|
addSegment(i);
|
|
3752
3513
|
if (commands.length > 0) {
|
|
3753
3514
|
this.addContent(`[${commands.join(' ')}] TJ`);
|
|
3754
|
-
|
|
3515
|
+
commands.length = 0;
|
|
3755
3516
|
}
|
|
3756
3517
|
};
|
|
3757
3518
|
for (i = 0; i < positions.length; i++) {
|
|
3758
|
-
// If we have an x or y offset, we have to break out of the current TJ command
|
|
3759
|
-
// so we can move the text position.
|
|
3760
3519
|
const pos = positions[i];
|
|
3761
3520
|
if (pos.xOffset || pos.yOffset) {
|
|
3762
|
-
// Flush the current buffer
|
|
3763
3521
|
flush(i);
|
|
3764
|
-
|
|
3765
|
-
// Move the text position and flush just the current character
|
|
3766
3522
|
this.addContent(`1 0 0 1 ${number(x + pos.xOffset * scale)} ${number(y + pos.yOffset * scale)} Tm`);
|
|
3767
3523
|
flush(i + 1);
|
|
3768
3524
|
hadOffset = true;
|
|
3769
3525
|
} else {
|
|
3770
|
-
// If the last character had an offset, reset the text position
|
|
3771
3526
|
if (hadOffset) {
|
|
3772
3527
|
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3773
3528
|
hadOffset = false;
|
|
3774
3529
|
}
|
|
3775
|
-
|
|
3776
|
-
// Group segments that don't have any advance adjustments
|
|
3777
3530
|
if (pos.xAdvance - pos.advanceWidth !== 0) {
|
|
3778
3531
|
addSegment(i + 1);
|
|
3779
3532
|
}
|
|
3780
3533
|
}
|
|
3781
3534
|
x += pos.xAdvance * scale;
|
|
3782
3535
|
}
|
|
3783
|
-
|
|
3784
|
-
// Flush any remaining commands
|
|
3785
3536
|
flush(i);
|
|
3786
|
-
|
|
3787
|
-
// end the text object
|
|
3788
3537
|
this.addContent('ET');
|
|
3789
|
-
|
|
3790
|
-
// restore flipped coordinate system
|
|
3791
|
-
return this.restore();
|
|
3538
|
+
this.restore();
|
|
3792
3539
|
}
|
|
3793
3540
|
};
|
|
3794
3541
|
|
|
@@ -3806,8 +3553,6 @@ class JPEG {
|
|
|
3806
3553
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3807
3554
|
throw 'SOI not found in JPEG';
|
|
3808
3555
|
}
|
|
3809
|
-
|
|
3810
|
-
// Parse the EXIF orientation
|
|
3811
3556
|
this.orientation = exif.fromBuffer(this.data).Orientation || 1;
|
|
3812
3557
|
let pos = 2;
|
|
3813
3558
|
while (pos < this.data.length) {
|
|
@@ -3844,16 +3589,10 @@ class JPEG {
|
|
|
3844
3589
|
ColorSpace: this.colorSpace,
|
|
3845
3590
|
Filter: 'DCTDecode'
|
|
3846
3591
|
});
|
|
3847
|
-
|
|
3848
|
-
// add extra decode params for CMYK images. By swapping the
|
|
3849
|
-
// min and max values from the default, we invert the colors. See
|
|
3850
|
-
// section 4.8.4 of the spec.
|
|
3851
3592
|
if (this.colorSpace === 'DeviceCMYK') {
|
|
3852
3593
|
this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];
|
|
3853
3594
|
}
|
|
3854
3595
|
this.obj.end(this.data);
|
|
3855
|
-
|
|
3856
|
-
// free memory
|
|
3857
3596
|
return this.data = null;
|
|
3858
3597
|
}
|
|
3859
3598
|
}
|
|
@@ -3896,24 +3635,14 @@ class PNGImage {
|
|
|
3896
3635
|
if (this.image.palette.length === 0) {
|
|
3897
3636
|
this.obj.data['ColorSpace'] = this.image.colorSpace;
|
|
3898
3637
|
} else {
|
|
3899
|
-
// embed the color palette in the PDF as an object stream
|
|
3900
3638
|
const palette = this.document.ref();
|
|
3901
3639
|
palette.end(Buffer.from(this.image.palette));
|
|
3902
|
-
|
|
3903
|
-
// build the color space array for the image
|
|
3904
3640
|
this.obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', this.image.palette.length / 3 - 1, palette];
|
|
3905
3641
|
}
|
|
3906
|
-
|
|
3907
|
-
// For PNG color types 0, 2 and 3, the transparency data is stored in
|
|
3908
|
-
// a dedicated PNG chunk.
|
|
3909
3642
|
if (this.image.transparency.grayscale != null) {
|
|
3910
|
-
// Use Color Key Masking (spec section 4.8.5)
|
|
3911
|
-
// An array with N elements, where N is two times the number of color components.
|
|
3912
3643
|
const val = this.image.transparency.grayscale;
|
|
3913
3644
|
this.obj.data['Mask'] = [val, val];
|
|
3914
3645
|
} else if (this.image.transparency.rgb) {
|
|
3915
|
-
// Use Color Key Masking (spec section 4.8.5)
|
|
3916
|
-
// An array with N elements, where N is two times the number of color components.
|
|
3917
3646
|
const {
|
|
3918
3647
|
rgb
|
|
3919
3648
|
} = this.image.transparency;
|
|
@@ -3923,14 +3652,9 @@ class PNGImage {
|
|
|
3923
3652
|
}
|
|
3924
3653
|
this.obj.data['Mask'] = mask;
|
|
3925
3654
|
} else if (this.image.transparency.indexed) {
|
|
3926
|
-
// Create a transparency SMask for the image based on the data
|
|
3927
|
-
// in the PLTE and tRNS sections. See below for details on SMasks.
|
|
3928
3655
|
dataDecoded = true;
|
|
3929
3656
|
return this.loadIndexedAlphaChannel();
|
|
3930
3657
|
} else if (hasAlphaChannel) {
|
|
3931
|
-
// For PNG color types 4 and 6, the transparency data is stored as a alpha
|
|
3932
|
-
// channel mixed in with the main image data. Separate this data out into an
|
|
3933
|
-
// SMask object and store it separately in the PDF.
|
|
3934
3658
|
dataDecoded = true;
|
|
3935
3659
|
return this.splitAlphaChannel();
|
|
3936
3660
|
}
|
|
@@ -3954,11 +3678,7 @@ class PNGImage {
|
|
|
3954
3678
|
sMask.end(this.alphaChannel);
|
|
3955
3679
|
this.obj.data['SMask'] = sMask;
|
|
3956
3680
|
}
|
|
3957
|
-
|
|
3958
|
-
// add the actual image data
|
|
3959
3681
|
this.obj.end(this.imgData);
|
|
3960
|
-
|
|
3961
|
-
// free memory
|
|
3962
3682
|
this.image = null;
|
|
3963
3683
|
return this.imgData = null;
|
|
3964
3684
|
}
|
|
@@ -3971,7 +3691,6 @@ class PNGImage {
|
|
|
3971
3691
|
const alphaChannel = Buffer.alloc(pixelCount);
|
|
3972
3692
|
let i = p = a = 0;
|
|
3973
3693
|
const len = pixels.length;
|
|
3974
|
-
// For 16bit images copy only most significant byte (MSB) - PNG data is always stored in network byte order (MSB first)
|
|
3975
3694
|
const skipByteCount = this.image.bits === 16 ? 1 : 0;
|
|
3976
3695
|
while (i < len) {
|
|
3977
3696
|
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
|
|
@@ -4006,10 +3725,6 @@ class PNGImage {
|
|
|
4006
3725
|
}
|
|
4007
3726
|
}
|
|
4008
3727
|
|
|
4009
|
-
/*
|
|
4010
|
-
PDFImage - embeds images in PDF documents
|
|
4011
|
-
By Devon Govett
|
|
4012
|
-
*/
|
|
4013
3728
|
class PDFImage {
|
|
4014
3729
|
static open(src, label) {
|
|
4015
3730
|
let data;
|
|
@@ -4018,8 +3733,8 @@ class PDFImage {
|
|
|
4018
3733
|
} else if (src instanceof ArrayBuffer) {
|
|
4019
3734
|
data = Buffer.from(new Uint8Array(src));
|
|
4020
3735
|
} else {
|
|
4021
|
-
|
|
4022
|
-
if (match
|
|
3736
|
+
const match = /^data:.+?;base64,(.*)$/.exec(src);
|
|
3737
|
+
if (match) {
|
|
4023
3738
|
data = Buffer.from(match[1], 'base64');
|
|
4024
3739
|
} else {
|
|
4025
3740
|
data = fs.readFileSync(src);
|
|
@@ -4041,17 +3756,16 @@ class PDFImage {
|
|
|
4041
3756
|
var ImagesMixin = {
|
|
4042
3757
|
initImages() {
|
|
4043
3758
|
this._imageRegistry = {};
|
|
4044
|
-
|
|
3759
|
+
this._imageCount = 0;
|
|
4045
3760
|
},
|
|
4046
3761
|
image(src, x, y, options = {}) {
|
|
4047
|
-
let bh, bp, bw, image, ip, left, left1,
|
|
3762
|
+
let bh, bp, bw, image, ip, left, left1, originX, originY;
|
|
4048
3763
|
if (typeof x === 'object') {
|
|
4049
3764
|
options = x;
|
|
4050
3765
|
x = null;
|
|
4051
3766
|
}
|
|
4052
|
-
|
|
4053
|
-
// Ignore orientation based on document options or image options
|
|
4054
3767
|
const ignoreOrientation = options.ignoreOrientation || options.ignoreOrientation !== false && this.options.ignoreOrientation;
|
|
3768
|
+
const inDocumentFlow = typeof y !== 'number';
|
|
4055
3769
|
x = (left = x != null ? x : options.x) != null ? left : this.x;
|
|
4056
3770
|
y = (left1 = y != null ? y : options.y) != null ? left1 : this.y;
|
|
4057
3771
|
if (typeof src === 'string') {
|
|
@@ -4074,8 +3788,6 @@ var ImagesMixin = {
|
|
|
4074
3788
|
width,
|
|
4075
3789
|
height
|
|
4076
3790
|
} = image;
|
|
4077
|
-
|
|
4078
|
-
// If EXIF orientation calls for it, swap width and height
|
|
4079
3791
|
if (!ignoreOrientation && image.orientation > 4) {
|
|
4080
3792
|
[width, height] = [height, width];
|
|
4081
3793
|
}
|
|
@@ -4127,80 +3839,70 @@ var ImagesMixin = {
|
|
|
4127
3839
|
y = y + bh - h;
|
|
4128
3840
|
}
|
|
4129
3841
|
}
|
|
3842
|
+
let rotateAngle = 0;
|
|
3843
|
+
let xTransform = x;
|
|
3844
|
+
let yTransform = y;
|
|
3845
|
+
let hTransform = h;
|
|
3846
|
+
let wTransform = w;
|
|
4130
3847
|
if (!ignoreOrientation) {
|
|
4131
3848
|
switch (image.orientation) {
|
|
4132
|
-
// No orientation (need to flip image, though, because of the default transform matrix on the document)
|
|
4133
3849
|
default:
|
|
4134
3850
|
case 1:
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
rotateAngle = 0;
|
|
3851
|
+
hTransform = -h;
|
|
3852
|
+
yTransform += h;
|
|
4138
3853
|
break;
|
|
4139
|
-
// Flip Horizontal
|
|
4140
3854
|
case 2:
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
rotateAngle = 0;
|
|
3855
|
+
wTransform = -w;
|
|
3856
|
+
hTransform = -h;
|
|
3857
|
+
xTransform += w;
|
|
3858
|
+
yTransform += h;
|
|
4146
3859
|
break;
|
|
4147
|
-
// Rotate 180 degrees
|
|
4148
3860
|
case 3:
|
|
4149
3861
|
originX = x;
|
|
4150
3862
|
originY = y;
|
|
4151
|
-
|
|
4152
|
-
|
|
3863
|
+
hTransform = -h;
|
|
3864
|
+
xTransform -= w;
|
|
4153
3865
|
rotateAngle = 180;
|
|
4154
3866
|
break;
|
|
4155
|
-
// Flip vertical
|
|
4156
3867
|
case 4:
|
|
4157
|
-
// Do nothing, image will be flipped
|
|
4158
|
-
|
|
4159
3868
|
break;
|
|
4160
|
-
// Flip horizontally and rotate 270 degrees CW
|
|
4161
3869
|
case 5:
|
|
4162
3870
|
originX = x;
|
|
4163
3871
|
originY = y;
|
|
4164
|
-
|
|
4165
|
-
|
|
3872
|
+
wTransform = h;
|
|
3873
|
+
hTransform = w;
|
|
3874
|
+
yTransform -= hTransform;
|
|
4166
3875
|
rotateAngle = 90;
|
|
4167
3876
|
break;
|
|
4168
|
-
// Rotate 90 degrees CW
|
|
4169
3877
|
case 6:
|
|
4170
3878
|
originX = x;
|
|
4171
3879
|
originY = y;
|
|
4172
|
-
|
|
4173
|
-
|
|
3880
|
+
wTransform = h;
|
|
3881
|
+
hTransform = -w;
|
|
4174
3882
|
rotateAngle = 90;
|
|
4175
3883
|
break;
|
|
4176
|
-
// Flip horizontally and rotate 90 degrees CW
|
|
4177
3884
|
case 7:
|
|
4178
3885
|
originX = x;
|
|
4179
3886
|
originY = y;
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
x -= w;
|
|
3887
|
+
hTransform = -w;
|
|
3888
|
+
wTransform = -h;
|
|
3889
|
+
xTransform += h;
|
|
4184
3890
|
rotateAngle = 90;
|
|
4185
3891
|
break;
|
|
4186
|
-
// Rotate 270 degrees CW
|
|
4187
3892
|
case 8:
|
|
4188
3893
|
originX = x;
|
|
4189
3894
|
originY = y;
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
3895
|
+
wTransform = h;
|
|
3896
|
+
hTransform = -w;
|
|
3897
|
+
xTransform -= h;
|
|
3898
|
+
yTransform += w;
|
|
4194
3899
|
rotateAngle = -90;
|
|
4195
3900
|
break;
|
|
4196
3901
|
}
|
|
4197
3902
|
} else {
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
rotateAngle = 0;
|
|
3903
|
+
hTransform = -h;
|
|
3904
|
+
yTransform += h;
|
|
4201
3905
|
}
|
|
4202
|
-
|
|
4203
|
-
// create link annotations if the link option is given
|
|
4204
3906
|
if (options.link != null) {
|
|
4205
3907
|
this.link(x, y, w, h, options.link);
|
|
4206
3908
|
}
|
|
@@ -4210,9 +3912,7 @@ var ImagesMixin = {
|
|
|
4210
3912
|
if (options.destination != null) {
|
|
4211
3913
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
4212
3914
|
}
|
|
4213
|
-
|
|
4214
|
-
// Set the current y position to below the image if it is in the document flow
|
|
4215
|
-
if (this.y === y) {
|
|
3915
|
+
if (inDocumentFlow) {
|
|
4216
3916
|
this.y += h;
|
|
4217
3917
|
}
|
|
4218
3918
|
this.save();
|
|
@@ -4221,7 +3921,7 @@ var ImagesMixin = {
|
|
|
4221
3921
|
origin: [originX, originY]
|
|
4222
3922
|
});
|
|
4223
3923
|
}
|
|
4224
|
-
this.transform(
|
|
3924
|
+
this.transform(wTransform, 0, 0, hTransform, xTransform, yTransform);
|
|
4225
3925
|
this.addContent(`/${image.label} Do`);
|
|
4226
3926
|
this.restore();
|
|
4227
3927
|
return this;
|
|
@@ -4247,19 +3947,17 @@ var AnnotationsMixin = {
|
|
|
4247
3947
|
options.Rect = this._convertRect(x, y, w, h);
|
|
4248
3948
|
options.Border = [0, 0, 0];
|
|
4249
3949
|
if (options.Subtype === 'Link' && typeof options.F === 'undefined') {
|
|
4250
|
-
options.F = 1 << 2;
|
|
3950
|
+
options.F = 1 << 2;
|
|
4251
3951
|
}
|
|
4252
3952
|
if (options.Subtype !== 'Link') {
|
|
4253
3953
|
if (options.C == null) {
|
|
4254
3954
|
options.C = this._normalizeColor(options.color || [0, 0, 0]);
|
|
4255
3955
|
}
|
|
4256
|
-
}
|
|
3956
|
+
}
|
|
4257
3957
|
delete options.color;
|
|
4258
3958
|
if (typeof options.Dest === 'string') {
|
|
4259
3959
|
options.Dest = new String(options.Dest);
|
|
4260
3960
|
}
|
|
4261
|
-
|
|
4262
|
-
// Capitalize keys
|
|
4263
3961
|
for (let key in options) {
|
|
4264
3962
|
const val = options[key];
|
|
4265
3963
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
@@ -4292,7 +3990,6 @@ var AnnotationsMixin = {
|
|
|
4292
3990
|
link(x, y, w, h, url, options = {}) {
|
|
4293
3991
|
options.Subtype = 'Link';
|
|
4294
3992
|
if (typeof url === 'number') {
|
|
4295
|
-
// Link to a page in the document (the page must already exist)
|
|
4296
3993
|
const pages = this._root.data.Pages.data;
|
|
4297
3994
|
if (url >= 0 && url < pages.Kids.length) {
|
|
4298
3995
|
options.A = this.ref({
|
|
@@ -4304,7 +4001,6 @@ var AnnotationsMixin = {
|
|
|
4304
4001
|
throw new Error(`The document has no page ${url}`);
|
|
4305
4002
|
}
|
|
4306
4003
|
} else {
|
|
4307
|
-
// Link to an external url
|
|
4308
4004
|
options.A = this.ref({
|
|
4309
4005
|
S: 'URI',
|
|
4310
4006
|
URI: new String(url)
|
|
@@ -4357,14 +4053,11 @@ var AnnotationsMixin = {
|
|
|
4357
4053
|
return this.annotate(x, y, w, h, options);
|
|
4358
4054
|
},
|
|
4359
4055
|
fileAnnotation(x, y, w, h, file = {}, options = {}) {
|
|
4360
|
-
// create hidden file
|
|
4361
4056
|
const filespec = this.file(file.src, Object.assign({
|
|
4362
4057
|
hidden: true
|
|
4363
4058
|
}, file));
|
|
4364
4059
|
options.Subtype = 'FileAttachment';
|
|
4365
4060
|
options.FS = filespec;
|
|
4366
|
-
|
|
4367
|
-
// add description from filespec unless description (Contents) has already been set
|
|
4368
4061
|
if (options.Contents) {
|
|
4369
4062
|
options.Contents = new String(options.Contents);
|
|
4370
4063
|
} else if (filespec.data.Desc) {
|
|
@@ -4373,14 +4066,9 @@ var AnnotationsMixin = {
|
|
|
4373
4066
|
return this.annotate(x, y, w, h, options);
|
|
4374
4067
|
},
|
|
4375
4068
|
_convertRect(x1, y1, w, h) {
|
|
4376
|
-
// flip y1 and y2
|
|
4377
4069
|
let y2 = y1;
|
|
4378
4070
|
y1 += h;
|
|
4379
|
-
|
|
4380
|
-
// make x2
|
|
4381
4071
|
let x2 = x1 + w;
|
|
4382
|
-
|
|
4383
|
-
// apply current transformation matrix to points
|
|
4384
4072
|
const [m0, m1, m2, m3, m4, m5] = this._ctm;
|
|
4385
4073
|
x1 = m0 * x1 + m2 * y1 + m4;
|
|
4386
4074
|
y1 = m1 * x1 + m3 * y1 + m5;
|
|
@@ -4442,7 +4130,7 @@ class PDFOutline {
|
|
|
4442
4130
|
|
|
4443
4131
|
var OutlineMixin = {
|
|
4444
4132
|
initOutline() {
|
|
4445
|
-
|
|
4133
|
+
this.outline = new PDFOutline(this, null, null, null);
|
|
4446
4134
|
},
|
|
4447
4135
|
endOutline() {
|
|
4448
4136
|
this.outline.endOutline();
|
|
@@ -4453,11 +4141,6 @@ var OutlineMixin = {
|
|
|
4453
4141
|
}
|
|
4454
4142
|
};
|
|
4455
4143
|
|
|
4456
|
-
/*
|
|
4457
|
-
PDFStructureContent - a reference to a marked structure content
|
|
4458
|
-
By Ben Schmidt
|
|
4459
|
-
*/
|
|
4460
|
-
|
|
4461
4144
|
class PDFStructureContent {
|
|
4462
4145
|
constructor(pageRef, mcid) {
|
|
4463
4146
|
this.refs = [{
|
|
@@ -4470,10 +4153,6 @@ class PDFStructureContent {
|
|
|
4470
4153
|
}
|
|
4471
4154
|
}
|
|
4472
4155
|
|
|
4473
|
-
/*
|
|
4474
|
-
PDFStructureElement - represents an element in the PDF logical structure tree
|
|
4475
|
-
By Ben Schmidt
|
|
4476
|
-
*/
|
|
4477
4156
|
class PDFStructureElement {
|
|
4478
4157
|
constructor(document, type, options = {}, children = null) {
|
|
4479
4158
|
this.document = document;
|
|
@@ -4481,7 +4160,6 @@ class PDFStructureElement {
|
|
|
4481
4160
|
this._ended = false;
|
|
4482
4161
|
this._flushed = false;
|
|
4483
4162
|
this.dictionary = document.ref({
|
|
4484
|
-
// Type: "StructElem",
|
|
4485
4163
|
S: type
|
|
4486
4164
|
});
|
|
4487
4165
|
const data = this.dictionary.data;
|
|
@@ -4530,7 +4208,6 @@ class PDFStructureElement {
|
|
|
4530
4208
|
this._addContentToParentTree(child);
|
|
4531
4209
|
}
|
|
4532
4210
|
if (typeof child === 'function' && this._attached) {
|
|
4533
|
-
// _contentForClosure() adds the content to the parent tree
|
|
4534
4211
|
child = this._contentForClosure(child);
|
|
4535
4212
|
}
|
|
4536
4213
|
this._children.push(child);
|
|
@@ -4606,10 +4283,6 @@ class PDFStructureElement {
|
|
|
4606
4283
|
this.dictionary.data.K = [];
|
|
4607
4284
|
this._children.forEach(child => this._flushChild(child));
|
|
4608
4285
|
this.dictionary.end();
|
|
4609
|
-
|
|
4610
|
-
// free memory used by children; the dictionary itself may still be
|
|
4611
|
-
// referenced by a parent structure element or root, but we can
|
|
4612
|
-
// at least trim the tree here
|
|
4613
4286
|
this._children = [];
|
|
4614
4287
|
this.dictionary.data.K = null;
|
|
4615
4288
|
this._flushed = true;
|
|
@@ -4630,7 +4303,7 @@ class PDFStructureElement {
|
|
|
4630
4303
|
this.dictionary.data.K.push(mcid);
|
|
4631
4304
|
} else {
|
|
4632
4305
|
this.dictionary.data.K.push({
|
|
4633
|
-
Type:
|
|
4306
|
+
Type: 'MCR',
|
|
4634
4307
|
Pg: pageRef,
|
|
4635
4308
|
MCID: mcid
|
|
4636
4309
|
});
|
|
@@ -4640,25 +4313,18 @@ class PDFStructureElement {
|
|
|
4640
4313
|
}
|
|
4641
4314
|
}
|
|
4642
4315
|
|
|
4643
|
-
/*
|
|
4644
|
-
PDFNumberTree - represents a number tree object
|
|
4645
|
-
*/
|
|
4646
4316
|
class PDFNumberTree extends PDFTree {
|
|
4647
4317
|
_compareKeys(a, b) {
|
|
4648
4318
|
return parseInt(a) - parseInt(b);
|
|
4649
4319
|
}
|
|
4650
4320
|
_keysName() {
|
|
4651
|
-
return
|
|
4321
|
+
return 'Nums';
|
|
4652
4322
|
}
|
|
4653
4323
|
_dataForKey(k) {
|
|
4654
4324
|
return parseInt(k);
|
|
4655
4325
|
}
|
|
4656
4326
|
}
|
|
4657
4327
|
|
|
4658
|
-
/*
|
|
4659
|
-
Markings mixin - support marked content sequences in content streams
|
|
4660
|
-
By Ben Schmidt
|
|
4661
|
-
*/
|
|
4662
4328
|
var MarkingsMixin = {
|
|
4663
4329
|
initMarkings(options) {
|
|
4664
4330
|
this.structChildren = [];
|
|
@@ -4794,7 +4460,6 @@ var MarkingsMixin = {
|
|
|
4794
4460
|
return this.getStructTreeRoot().data.ParentTree;
|
|
4795
4461
|
},
|
|
4796
4462
|
createStructParentTreeNextKey() {
|
|
4797
|
-
// initialise the MarkInfo dictionary
|
|
4798
4463
|
this.getMarkInfoDictionary();
|
|
4799
4464
|
const structTreeRoot = this.getStructTreeRoot();
|
|
4800
4465
|
const key = structTreeRoot.data.ParentTreeNextKey++;
|
|
@@ -4858,10 +4523,6 @@ const FORMAT_DEFAULT = {
|
|
|
4858
4523
|
}
|
|
4859
4524
|
};
|
|
4860
4525
|
var AcroFormMixin = {
|
|
4861
|
-
/**
|
|
4862
|
-
* Must call if adding AcroForms to a document. Must also call font() before
|
|
4863
|
-
* this method to set the default font.
|
|
4864
|
-
*/
|
|
4865
4526
|
initForm() {
|
|
4866
4527
|
if (!this._font) {
|
|
4867
4528
|
throw new Error('Must set a font before calling initForm method');
|
|
@@ -4884,9 +4545,6 @@ var AcroFormMixin = {
|
|
|
4884
4545
|
this._root.data.AcroForm = AcroForm;
|
|
4885
4546
|
return this;
|
|
4886
4547
|
},
|
|
4887
|
-
/**
|
|
4888
|
-
* Called automatically by document.js
|
|
4889
|
-
*/
|
|
4890
4548
|
endAcroForm() {
|
|
4891
4549
|
if (this._root.data.AcroForm) {
|
|
4892
4550
|
if (!Object.keys(this._acroform.fonts).length && !this._acroform.defaultFont) {
|
|
@@ -4912,38 +4570,18 @@ var AcroFormMixin = {
|
|
|
4912
4570
|
}
|
|
4913
4571
|
return this;
|
|
4914
4572
|
},
|
|
4915
|
-
/**
|
|
4916
|
-
* Creates and adds a form field to the document. Form fields are intermediate
|
|
4917
|
-
* nodes in a PDF form that are used to specify form name heirarchy and form
|
|
4918
|
-
* value defaults.
|
|
4919
|
-
* @param {string} name - field name (T attribute in field dictionary)
|
|
4920
|
-
* @param {object} options - other attributes to include in field dictionary
|
|
4921
|
-
*/
|
|
4922
4573
|
formField(name, options = {}) {
|
|
4923
4574
|
let fieldDict = this._fieldDict(name, null, options);
|
|
4924
4575
|
let fieldRef = this.ref(fieldDict);
|
|
4925
4576
|
this._addToParent(fieldRef);
|
|
4926
4577
|
return fieldRef;
|
|
4927
4578
|
},
|
|
4928
|
-
/**
|
|
4929
|
-
* Creates and adds a Form Annotation to the document. Form annotations are
|
|
4930
|
-
* called Widget annotations internally within a PDF file.
|
|
4931
|
-
* @param {string} name - form field name (T attribute of widget annotation
|
|
4932
|
-
* dictionary)
|
|
4933
|
-
* @param {number} x
|
|
4934
|
-
* @param {number} y
|
|
4935
|
-
* @param {number} w
|
|
4936
|
-
* @param {number} h
|
|
4937
|
-
* @param {object} options
|
|
4938
|
-
*/
|
|
4939
4579
|
formAnnotation(name, type, x, y, w, h, options = {}) {
|
|
4940
4580
|
let fieldDict = this._fieldDict(name, type, options);
|
|
4941
4581
|
fieldDict.Subtype = 'Widget';
|
|
4942
4582
|
if (fieldDict.F === undefined) {
|
|
4943
|
-
fieldDict.F = 4;
|
|
4583
|
+
fieldDict.F = 4;
|
|
4944
4584
|
}
|
|
4945
|
-
|
|
4946
|
-
// Add Field annot to page, and get it's ref
|
|
4947
4585
|
this.annotate(x, y, w, h, fieldDict);
|
|
4948
4586
|
let annotRef = this.page.annotations[this.page.annotations.length - 1];
|
|
4949
4587
|
return this._addToParent(annotRef);
|
|
@@ -5104,23 +4742,18 @@ var AcroFormMixin = {
|
|
|
5104
4742
|
delete options.align;
|
|
5105
4743
|
}
|
|
5106
4744
|
if (result !== 0) {
|
|
5107
|
-
options.Q = result;
|
|
4745
|
+
options.Q = result;
|
|
5108
4746
|
}
|
|
5109
4747
|
return options;
|
|
5110
4748
|
},
|
|
5111
4749
|
_resolveFont(options) {
|
|
5112
|
-
// add current font to document-level AcroForm dict if necessary
|
|
5113
4750
|
if (this._acroform.fonts[this._font.id] == null) {
|
|
5114
4751
|
this._acroform.fonts[this._font.id] = this._font.ref();
|
|
5115
4752
|
}
|
|
5116
|
-
|
|
5117
|
-
// add current font to field's resource dict (RD) if not the default acroform font
|
|
5118
4753
|
if (this._acroform.defaultFont !== this._font.name) {
|
|
5119
4754
|
options.DR = {
|
|
5120
4755
|
Font: {}
|
|
5121
4756
|
};
|
|
5122
|
-
|
|
5123
|
-
// Get the fontSize option. If not set use auto sizing
|
|
5124
4757
|
const fontSize = options.fontSize || 0;
|
|
5125
4758
|
options.DR.Font[this._font.id] = this._font.ref();
|
|
5126
4759
|
options.DA = new String(`/${this._font.id} ${fontSize} Tf 0 g`);
|
|
@@ -5172,19 +4805,6 @@ var AcroFormMixin = {
|
|
|
5172
4805
|
};
|
|
5173
4806
|
|
|
5174
4807
|
var AttachmentsMixin = {
|
|
5175
|
-
/**
|
|
5176
|
-
* Embed contents of `src` in PDF
|
|
5177
|
-
* @param {Buffer | ArrayBuffer | string} src input Buffer, ArrayBuffer, base64 encoded string or path to file
|
|
5178
|
-
* @param {object} options
|
|
5179
|
-
* * options.name: filename to be shown in PDF, will use `src` if none set
|
|
5180
|
-
* * options.type: filetype to be shown in PDF
|
|
5181
|
-
* * options.description: description to be shown in PDF
|
|
5182
|
-
* * options.hidden: if true, do not add attachment to EmbeddedFiles dictionary. Useful for file attachment annotations
|
|
5183
|
-
* * options.creationDate: override creation date
|
|
5184
|
-
* * options.modifiedDate: override modified date
|
|
5185
|
-
* * options.relationship: Relationship between the PDF document and its attached file. Can be 'Alternative', 'Data', 'Source', 'Supplement' or 'Unspecified'.
|
|
5186
|
-
* @returns filespec reference
|
|
5187
|
-
*/
|
|
5188
4808
|
file(src, options = {}) {
|
|
5189
4809
|
options.name = options.name || src;
|
|
5190
4810
|
options.relationship = options.relationship || 'Unspecified';
|
|
@@ -5201,8 +4821,8 @@ var AttachmentsMixin = {
|
|
|
5201
4821
|
} else if (src instanceof ArrayBuffer) {
|
|
5202
4822
|
data = Buffer.from(new Uint8Array(src));
|
|
5203
4823
|
} else {
|
|
5204
|
-
|
|
5205
|
-
if (match
|
|
4824
|
+
const match = /^data:(.*?);base64,(.*)$/.exec(src);
|
|
4825
|
+
if (match) {
|
|
5206
4826
|
if (match[1]) {
|
|
5207
4827
|
refBody.Subtype = match[1].replace('/', '#2F');
|
|
5208
4828
|
}
|
|
@@ -5212,8 +4832,6 @@ var AttachmentsMixin = {
|
|
|
5212
4832
|
if (!data) {
|
|
5213
4833
|
throw new Error(`Could not read contents of file at filepath ${src}`);
|
|
5214
4834
|
}
|
|
5215
|
-
|
|
5216
|
-
// update CreationDate and ModDate
|
|
5217
4835
|
const {
|
|
5218
4836
|
birthtime,
|
|
5219
4837
|
ctime
|
|
@@ -5222,26 +4840,18 @@ var AttachmentsMixin = {
|
|
|
5222
4840
|
refBody.Params.ModDate = ctime;
|
|
5223
4841
|
}
|
|
5224
4842
|
}
|
|
5225
|
-
|
|
5226
|
-
// override creation date and modified date
|
|
5227
4843
|
if (options.creationDate instanceof Date) {
|
|
5228
4844
|
refBody.Params.CreationDate = options.creationDate;
|
|
5229
4845
|
}
|
|
5230
4846
|
if (options.modifiedDate instanceof Date) {
|
|
5231
4847
|
refBody.Params.ModDate = options.modifiedDate;
|
|
5232
4848
|
}
|
|
5233
|
-
// add optional subtype
|
|
5234
4849
|
if (options.type) {
|
|
5235
4850
|
refBody.Subtype = options.type.replace('/', '#2F');
|
|
5236
4851
|
}
|
|
5237
|
-
|
|
5238
|
-
// add checksum and size information
|
|
5239
4852
|
const checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(new Uint8Array(data)));
|
|
5240
4853
|
refBody.Params.CheckSum = new String(checksum);
|
|
5241
4854
|
refBody.Params.Size = data.byteLength;
|
|
5242
|
-
|
|
5243
|
-
// save some space when embedding the same file again
|
|
5244
|
-
// if a file with the same name and metadata exists, reuse its reference
|
|
5245
4855
|
let ref;
|
|
5246
4856
|
if (!this._fileRegistry) this._fileRegistry = {};
|
|
5247
4857
|
let file = this._fileRegistry[options.name];
|
|
@@ -5255,7 +4865,6 @@ var AttachmentsMixin = {
|
|
|
5255
4865
|
ref
|
|
5256
4866
|
};
|
|
5257
4867
|
}
|
|
5258
|
-
// add filespec for embedded file
|
|
5259
4868
|
const fileSpecBody = {
|
|
5260
4869
|
Type: 'Filespec',
|
|
5261
4870
|
AFRelationship: options.relationship,
|
|
@@ -5273,8 +4882,6 @@ var AttachmentsMixin = {
|
|
|
5273
4882
|
if (!options.hidden) {
|
|
5274
4883
|
this.addNamedEmbeddedFile(options.name, filespec);
|
|
5275
4884
|
}
|
|
5276
|
-
|
|
5277
|
-
// Add file to the catalogue to be PDF/A3 compliant
|
|
5278
4885
|
if (this._root.data.AF) {
|
|
5279
4886
|
this._root.data.AF.push(filespec);
|
|
5280
4887
|
} else {
|
|
@@ -5283,8 +4890,6 @@ var AttachmentsMixin = {
|
|
|
5283
4890
|
return filespec;
|
|
5284
4891
|
}
|
|
5285
4892
|
};
|
|
5286
|
-
|
|
5287
|
-
/** check two embedded file metadata objects for equality */
|
|
5288
4893
|
function isEqual(a, b) {
|
|
5289
4894
|
return a.Subtype === b.Subtype && a.Params.CheckSum.toString() === b.Params.CheckSum.toString() && a.Params.Size === b.Params.Size && a.Params.CreationDate.getTime() === b.Params.CreationDate.getTime() && (a.Params.ModDate === undefined && b.Params.ModDate === undefined || a.Params.ModDate.getTime() === b.Params.ModDate.getTime());
|
|
5290
4895
|
}
|
|
@@ -5295,7 +4900,6 @@ var PDFA = {
|
|
|
5295
4900
|
this.subset_conformance = pSubset.charAt(pSubset.length - 1).toUpperCase();
|
|
5296
4901
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 2));
|
|
5297
4902
|
} else {
|
|
5298
|
-
// Default to Basic conformance when user doesn't specify
|
|
5299
4903
|
this.subset_conformance = 'B';
|
|
5300
4904
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 1));
|
|
5301
4905
|
}
|
|
@@ -5380,6 +4984,642 @@ var SubsetMixin = {
|
|
|
5380
4984
|
}
|
|
5381
4985
|
};
|
|
5382
4986
|
|
|
4987
|
+
const ROW_FIELDS = ['height', 'minHeight', 'maxHeight'];
|
|
4988
|
+
const COLUMN_FIELDS = ['width', 'minWidth', 'maxWidth'];
|
|
4989
|
+
function memoize(fn, maxSize) {
|
|
4990
|
+
const cache = new Map();
|
|
4991
|
+
return function (...args) {
|
|
4992
|
+
const key = args[0];
|
|
4993
|
+
if (!cache.has(key)) {
|
|
4994
|
+
cache.set(key, fn(...args));
|
|
4995
|
+
if (cache.size > maxSize) cache.delete(cache.keys().next());
|
|
4996
|
+
}
|
|
4997
|
+
return cache.get(key);
|
|
4998
|
+
};
|
|
4999
|
+
}
|
|
5000
|
+
function isObject(item) {
|
|
5001
|
+
return item && typeof item === 'object' && !Array.isArray(item);
|
|
5002
|
+
}
|
|
5003
|
+
function deepMerge(target, ...sources) {
|
|
5004
|
+
if (!isObject(target)) return target;
|
|
5005
|
+
target = deepClone(target);
|
|
5006
|
+
for (const source of sources) {
|
|
5007
|
+
if (isObject(source)) {
|
|
5008
|
+
for (const key in source) {
|
|
5009
|
+
if (isObject(source[key])) {
|
|
5010
|
+
if (!(key in target)) target[key] = {};
|
|
5011
|
+
target[key] = deepMerge(target[key], source[key]);
|
|
5012
|
+
} else if (source[key] !== undefined) {
|
|
5013
|
+
target[key] = deepClone(source[key]);
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
}
|
|
5017
|
+
}
|
|
5018
|
+
return target;
|
|
5019
|
+
}
|
|
5020
|
+
function deepClone(obj) {
|
|
5021
|
+
let result = obj;
|
|
5022
|
+
if (obj && typeof obj == 'object') {
|
|
5023
|
+
result = Array.isArray(obj) ? [] : {};
|
|
5024
|
+
for (const key in obj) result[key] = deepClone(obj[key]);
|
|
5025
|
+
}
|
|
5026
|
+
return result;
|
|
5027
|
+
}
|
|
5028
|
+
|
|
5029
|
+
function normalizedDefaultStyle(defaultStyleInternal) {
|
|
5030
|
+
let defaultStyle = defaultStyleInternal;
|
|
5031
|
+
if (typeof defaultStyle !== 'object') defaultStyle = {
|
|
5032
|
+
text: defaultStyle
|
|
5033
|
+
};
|
|
5034
|
+
const defaultRowStyle = Object.fromEntries(Object.entries(defaultStyle).filter(([k]) => ROW_FIELDS.includes(k)));
|
|
5035
|
+
const defaultColStyle = Object.fromEntries(Object.entries(defaultStyle).filter(([k]) => COLUMN_FIELDS.includes(k)));
|
|
5036
|
+
defaultStyle.padding = normalizeSides(defaultStyle.padding);
|
|
5037
|
+
defaultStyle.border = normalizeSides(defaultStyle.border);
|
|
5038
|
+
defaultStyle.borderColor = normalizeSides(defaultStyle.borderColor);
|
|
5039
|
+
defaultStyle.align = normalizeAlignment(defaultStyle.align);
|
|
5040
|
+
return {
|
|
5041
|
+
defaultStyle,
|
|
5042
|
+
defaultRowStyle,
|
|
5043
|
+
defaultColStyle
|
|
5044
|
+
};
|
|
5045
|
+
}
|
|
5046
|
+
function normalizedRowStyle(defaultRowStyle, rowStyleInternal, i) {
|
|
5047
|
+
let rowStyle = rowStyleInternal(i);
|
|
5048
|
+
if (rowStyle == null || typeof rowStyle !== 'object') {
|
|
5049
|
+
rowStyle = {
|
|
5050
|
+
height: rowStyle
|
|
5051
|
+
};
|
|
5052
|
+
}
|
|
5053
|
+
rowStyle.padding = normalizeSides(rowStyle.padding);
|
|
5054
|
+
rowStyle.border = normalizeSides(rowStyle.border);
|
|
5055
|
+
rowStyle.borderColor = normalizeSides(rowStyle.borderColor);
|
|
5056
|
+
rowStyle.align = normalizeAlignment(rowStyle.align);
|
|
5057
|
+
rowStyle = deepMerge(defaultRowStyle, rowStyle);
|
|
5058
|
+
const document = this.document;
|
|
5059
|
+
const page = document.page;
|
|
5060
|
+
const contentHeight = page.contentHeight;
|
|
5061
|
+
if (rowStyle.height == null || rowStyle.height === 'auto') {
|
|
5062
|
+
rowStyle.height = 'auto';
|
|
5063
|
+
} else {
|
|
5064
|
+
rowStyle.height = document.sizeToPoint(rowStyle.height, 0, page, contentHeight);
|
|
5065
|
+
}
|
|
5066
|
+
rowStyle.minHeight = document.sizeToPoint(rowStyle.minHeight, 0, page, contentHeight);
|
|
5067
|
+
rowStyle.maxHeight = document.sizeToPoint(rowStyle.maxHeight, 0, page, contentHeight);
|
|
5068
|
+
return rowStyle;
|
|
5069
|
+
}
|
|
5070
|
+
function normalizedColumnStyle(defaultColStyle, colStyleInternal, i) {
|
|
5071
|
+
let colStyle = colStyleInternal(i);
|
|
5072
|
+
if (colStyle == null || typeof colStyle !== 'object') {
|
|
5073
|
+
colStyle = {
|
|
5074
|
+
width: colStyle
|
|
5075
|
+
};
|
|
5076
|
+
}
|
|
5077
|
+
colStyle.padding = normalizeSides(colStyle.padding);
|
|
5078
|
+
colStyle.border = normalizeSides(colStyle.border);
|
|
5079
|
+
colStyle.borderColor = normalizeSides(colStyle.borderColor);
|
|
5080
|
+
colStyle.align = normalizeAlignment(colStyle.align);
|
|
5081
|
+
colStyle = deepMerge(defaultColStyle, colStyle);
|
|
5082
|
+
if (colStyle.width == null || colStyle.width === '*') {
|
|
5083
|
+
colStyle.width = '*';
|
|
5084
|
+
} else {
|
|
5085
|
+
colStyle.width = this.document.sizeToPoint(colStyle.width, 0, this.document.page, this._maxWidth);
|
|
5086
|
+
}
|
|
5087
|
+
colStyle.minWidth = this.document.sizeToPoint(colStyle.minWidth, 0, this.document.page, this._maxWidth);
|
|
5088
|
+
colStyle.maxWidth = this.document.sizeToPoint(colStyle.maxWidth, 0, this.document.page, this._maxWidth);
|
|
5089
|
+
return colStyle;
|
|
5090
|
+
}
|
|
5091
|
+
function normalizeAlignment(align) {
|
|
5092
|
+
return align == null || typeof align === 'string' ? {
|
|
5093
|
+
x: align,
|
|
5094
|
+
y: align
|
|
5095
|
+
} : align;
|
|
5096
|
+
}
|
|
5097
|
+
|
|
5098
|
+
function normalizeTable() {
|
|
5099
|
+
const doc = this.document;
|
|
5100
|
+
const opts = this.opts;
|
|
5101
|
+
let index = doc._tableIndex++;
|
|
5102
|
+
this._id = new String(opts.id ?? `table-${index}`);
|
|
5103
|
+
this._position = {
|
|
5104
|
+
x: doc.sizeToPoint(opts.position?.x, doc.x),
|
|
5105
|
+
y: doc.sizeToPoint(opts.position?.y, doc.y)
|
|
5106
|
+
};
|
|
5107
|
+
this._maxWidth = doc.sizeToPoint(opts.maxWidth, doc.page.width - doc.page.margins.right - this._position.x);
|
|
5108
|
+
const {
|
|
5109
|
+
defaultStyle,
|
|
5110
|
+
defaultColStyle,
|
|
5111
|
+
defaultRowStyle
|
|
5112
|
+
} = normalizedDefaultStyle(opts.defaultStyle);
|
|
5113
|
+
this._defaultStyle = defaultStyle;
|
|
5114
|
+
let colStyle;
|
|
5115
|
+
if (opts.columnStyles) {
|
|
5116
|
+
if (Array.isArray(opts.columnStyles)) {
|
|
5117
|
+
colStyle = i => opts.columnStyles[i];
|
|
5118
|
+
} else if (typeof opts.columnStyles === 'function') {
|
|
5119
|
+
colStyle = memoize(i => opts.columnStyles(i), Infinity);
|
|
5120
|
+
} else if (typeof opts.columnStyles === 'object') {
|
|
5121
|
+
colStyle = () => opts.columnStyles;
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
if (!colStyle) colStyle = () => ({});
|
|
5125
|
+
this._colStyle = normalizedColumnStyle.bind(this, defaultColStyle, colStyle);
|
|
5126
|
+
let rowStyle;
|
|
5127
|
+
if (opts.rowStyles) {
|
|
5128
|
+
if (Array.isArray(opts.rowStyles)) {
|
|
5129
|
+
rowStyle = i => opts.rowStyles[i];
|
|
5130
|
+
} else if (typeof opts.rowStyles === 'function') {
|
|
5131
|
+
rowStyle = memoize(i => opts.rowStyles(i), 10);
|
|
5132
|
+
} else if (typeof opts.rowStyles === 'object') {
|
|
5133
|
+
rowStyle = () => opts.rowStyles;
|
|
5134
|
+
}
|
|
5135
|
+
}
|
|
5136
|
+
if (!rowStyle) rowStyle = () => ({});
|
|
5137
|
+
this._rowStyle = normalizedRowStyle.bind(this, defaultRowStyle, rowStyle);
|
|
5138
|
+
}
|
|
5139
|
+
function normalizeText(text) {
|
|
5140
|
+
if (text != null) text = `${text}`;
|
|
5141
|
+
return text;
|
|
5142
|
+
}
|
|
5143
|
+
function normalizeCell(cell, rowIndex, colIndex) {
|
|
5144
|
+
const colStyle = this._colStyle(colIndex);
|
|
5145
|
+
let rowStyle = this._rowStyle(rowIndex);
|
|
5146
|
+
const font = deepMerge({}, colStyle.font, rowStyle.font, cell.font);
|
|
5147
|
+
const customFont = Object.values(font).filter(v => v != null).length > 0;
|
|
5148
|
+
const doc = this.document;
|
|
5149
|
+
const rollbackFont = doc._fontSource;
|
|
5150
|
+
const rollbackFontSize = doc._fontSize;
|
|
5151
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5152
|
+
if (customFont) {
|
|
5153
|
+
if (font.src) doc.font(font.src, font.family);
|
|
5154
|
+
if (font.size) doc.fontSize(font.size);
|
|
5155
|
+
rowStyle = this._rowStyle(rowIndex);
|
|
5156
|
+
}
|
|
5157
|
+
cell.padding = normalizeSides(cell.padding);
|
|
5158
|
+
cell.border = normalizeSides(cell.border);
|
|
5159
|
+
cell.borderColor = normalizeSides(cell.borderColor);
|
|
5160
|
+
const config = deepMerge(this._defaultStyle, colStyle, rowStyle, cell);
|
|
5161
|
+
config.rowIndex = rowIndex;
|
|
5162
|
+
config.colIndex = colIndex;
|
|
5163
|
+
config.font = font ?? {};
|
|
5164
|
+
config.customFont = customFont;
|
|
5165
|
+
config.text = normalizeText(config.text);
|
|
5166
|
+
config.rowSpan = config.rowSpan ?? 1;
|
|
5167
|
+
config.colSpan = config.colSpan ?? 1;
|
|
5168
|
+
config.padding = normalizeSides(config.padding, '0.25em', x => doc.sizeToPoint(x, '0.25em'));
|
|
5169
|
+
config.border = normalizeSides(config.border, 1, x => doc.sizeToPoint(x, 1));
|
|
5170
|
+
config.borderColor = normalizeSides(config.borderColor, 'black', x => x ?? 'black');
|
|
5171
|
+
config.align = normalizeAlignment(config.align);
|
|
5172
|
+
config.align.x = config.align.x ?? 'left';
|
|
5173
|
+
config.align.y = config.align.y ?? 'top';
|
|
5174
|
+
config.textStroke = doc.sizeToPoint(config.textStroke, 0);
|
|
5175
|
+
config.textStrokeColor = config.textStrokeColor ?? 'black';
|
|
5176
|
+
config.textColor = config.textColor ?? 'black';
|
|
5177
|
+
config.textOptions = config.textOptions ?? {};
|
|
5178
|
+
config.id = new String(config.id ?? `${this._id}-${rowIndex}-${colIndex}`);
|
|
5179
|
+
config.type = config.type?.toUpperCase() === 'TH' ? 'TH' : 'TD';
|
|
5180
|
+
if (config.scope) {
|
|
5181
|
+
config.scope = config.scope.toLowerCase();
|
|
5182
|
+
if (config.scope === 'row') config.scope = 'Row';else if (config.scope === 'both') config.scope = 'Both';else if (config.scope === 'column') config.scope = 'Column';
|
|
5183
|
+
}
|
|
5184
|
+
if (typeof this.opts.debug === 'boolean') config.debug = this.opts.debug;
|
|
5185
|
+
if (customFont) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5186
|
+
return config;
|
|
5187
|
+
}
|
|
5188
|
+
function normalizeRow(row, rowIndex) {
|
|
5189
|
+
if (!this._cellClaim) this._cellClaim = new Set();
|
|
5190
|
+
let colIndex = 0;
|
|
5191
|
+
return row.map(cell => {
|
|
5192
|
+
if (cell == null || typeof cell !== 'object') cell = {
|
|
5193
|
+
text: cell
|
|
5194
|
+
};
|
|
5195
|
+
while (this._cellClaim.has(`${rowIndex},${colIndex}`)) {
|
|
5196
|
+
colIndex++;
|
|
5197
|
+
}
|
|
5198
|
+
cell = normalizeCell.call(this, cell, rowIndex, colIndex);
|
|
5199
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5200
|
+
for (let j = 0; j < cell.colSpan; j++) {
|
|
5201
|
+
this._cellClaim.add(`${rowIndex + i},${colIndex + j}`);
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5204
|
+
colIndex += cell.colSpan;
|
|
5205
|
+
return cell;
|
|
5206
|
+
});
|
|
5207
|
+
}
|
|
5208
|
+
|
|
5209
|
+
function ensure(row) {
|
|
5210
|
+
this._columnWidths = [];
|
|
5211
|
+
ensureColumnWidths.call(this, row.reduce((a, cell) => a + cell.colSpan, 0));
|
|
5212
|
+
this._rowHeights = [];
|
|
5213
|
+
this._rowYPos = [this._position.y];
|
|
5214
|
+
this._rowBuffer = new Set();
|
|
5215
|
+
}
|
|
5216
|
+
function ensureColumnWidths(numCols) {
|
|
5217
|
+
let starColumnIndexes = [];
|
|
5218
|
+
let starMinAcc = 0;
|
|
5219
|
+
let unclaimedWidth = this._maxWidth;
|
|
5220
|
+
for (let i = 0; i < numCols; i++) {
|
|
5221
|
+
let col = this._colStyle(i);
|
|
5222
|
+
if (col.width === '*') {
|
|
5223
|
+
starColumnIndexes[i] = col;
|
|
5224
|
+
starMinAcc += col.minWidth;
|
|
5225
|
+
} else {
|
|
5226
|
+
unclaimedWidth -= col.width;
|
|
5227
|
+
this._columnWidths[i] = col.width;
|
|
5228
|
+
}
|
|
5229
|
+
}
|
|
5230
|
+
let starColCount = starColumnIndexes.reduce(x => x + 1, 0);
|
|
5231
|
+
if (starMinAcc >= unclaimedWidth) {
|
|
5232
|
+
starColumnIndexes.forEach((cell, i) => {
|
|
5233
|
+
this._columnWidths[i] = cell.minWidth;
|
|
5234
|
+
});
|
|
5235
|
+
} else if (starColCount > 0) {
|
|
5236
|
+
starColumnIndexes.forEach((col, i) => {
|
|
5237
|
+
let starSize = unclaimedWidth / starColCount;
|
|
5238
|
+
this._columnWidths[i] = Math.max(starSize, col.minWidth);
|
|
5239
|
+
if (col.maxWidth > 0) {
|
|
5240
|
+
this._columnWidths[i] = Math.min(this._columnWidths[i], col.maxWidth);
|
|
5241
|
+
}
|
|
5242
|
+
unclaimedWidth -= this._columnWidths[i];
|
|
5243
|
+
starColCount--;
|
|
5244
|
+
});
|
|
5245
|
+
}
|
|
5246
|
+
let tempX = this._position.x;
|
|
5247
|
+
this._columnXPos = Array.from(this._columnWidths, v => {
|
|
5248
|
+
const t = tempX;
|
|
5249
|
+
tempX += v;
|
|
5250
|
+
return t;
|
|
5251
|
+
});
|
|
5252
|
+
}
|
|
5253
|
+
function measure(row, rowIndex) {
|
|
5254
|
+
row.forEach(cell => this._rowBuffer.add(cell));
|
|
5255
|
+
if (rowIndex > 0) {
|
|
5256
|
+
this._rowYPos[rowIndex] = this._rowYPos[rowIndex - 1] + this._rowHeights[rowIndex - 1];
|
|
5257
|
+
}
|
|
5258
|
+
const rowStyle = this._rowStyle(rowIndex);
|
|
5259
|
+
let toRender = [];
|
|
5260
|
+
this._rowBuffer.forEach(cell => {
|
|
5261
|
+
if (cell.rowIndex + cell.rowSpan - 1 === rowIndex) {
|
|
5262
|
+
toRender.push(measureCell.call(this, cell, rowStyle.height));
|
|
5263
|
+
this._rowBuffer.delete(cell);
|
|
5264
|
+
}
|
|
5265
|
+
});
|
|
5266
|
+
let rowHeight = rowStyle.height;
|
|
5267
|
+
if (rowHeight === 'auto') {
|
|
5268
|
+
rowHeight = toRender.reduce((acc, cell) => {
|
|
5269
|
+
let minHeight = cell.textBounds.height + cell.padding.top + cell.padding.bottom;
|
|
5270
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5271
|
+
minHeight -= this._rowHeights[cell.rowIndex + i];
|
|
5272
|
+
}
|
|
5273
|
+
return Math.max(acc, minHeight);
|
|
5274
|
+
}, 0);
|
|
5275
|
+
}
|
|
5276
|
+
rowHeight = Math.max(rowHeight, rowStyle.minHeight);
|
|
5277
|
+
if (rowStyle.maxHeight > 0) {
|
|
5278
|
+
rowHeight = Math.min(rowHeight, rowStyle.maxHeight);
|
|
5279
|
+
}
|
|
5280
|
+
this._rowHeights[rowIndex] = rowHeight;
|
|
5281
|
+
let newPage = false;
|
|
5282
|
+
if (rowHeight > this.document.page.contentHeight) {
|
|
5283
|
+
console.warn(new Error(`Row ${rowIndex} requested more than the safe page height, row has been clamped`).stack.slice(7));
|
|
5284
|
+
this._rowHeights[rowIndex] = this.document.page.maxY() - this._rowYPos[rowIndex];
|
|
5285
|
+
} else if (this._rowYPos[rowIndex] + rowHeight >= this.document.page.maxY()) {
|
|
5286
|
+
this._rowYPos[rowIndex] = this.document.page.margins.top;
|
|
5287
|
+
newPage = true;
|
|
5288
|
+
}
|
|
5289
|
+
return {
|
|
5290
|
+
newPage,
|
|
5291
|
+
toRender: toRender.map(cell => measureCell.call(this, cell, rowHeight))
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5294
|
+
function measureCell(cell, rowHeight) {
|
|
5295
|
+
let cellWidth = 0;
|
|
5296
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5297
|
+
cellWidth += this._columnWidths[cell.colIndex + i];
|
|
5298
|
+
}
|
|
5299
|
+
let cellHeight = rowHeight;
|
|
5300
|
+
if (cellHeight === 'auto') {
|
|
5301
|
+
cellHeight = this.document.page.contentHeight;
|
|
5302
|
+
} else {
|
|
5303
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5304
|
+
cellHeight += this._rowHeights[cell.rowIndex + i];
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
5307
|
+
const textAllocatedWidth = cellWidth - cell.padding.left - cell.padding.right;
|
|
5308
|
+
const textAllocatedHeight = cellHeight - cell.padding.top - cell.padding.bottom;
|
|
5309
|
+
const rotation = cell.textOptions.rotation ?? 0;
|
|
5310
|
+
const {
|
|
5311
|
+
width: textMaxWidth,
|
|
5312
|
+
height: textMaxHeight
|
|
5313
|
+
} = computeBounds(rotation, textAllocatedWidth, textAllocatedHeight);
|
|
5314
|
+
const textOptions = {
|
|
5315
|
+
align: cell.align.x,
|
|
5316
|
+
ellipsis: true,
|
|
5317
|
+
stroke: cell.textStroke > 0,
|
|
5318
|
+
fill: true,
|
|
5319
|
+
width: textMaxWidth,
|
|
5320
|
+
height: textMaxHeight,
|
|
5321
|
+
rotation,
|
|
5322
|
+
...cell.textOptions
|
|
5323
|
+
};
|
|
5324
|
+
let textBounds = {
|
|
5325
|
+
x: 0,
|
|
5326
|
+
y: 0,
|
|
5327
|
+
width: 0,
|
|
5328
|
+
height: 0
|
|
5329
|
+
};
|
|
5330
|
+
if (cell.text) {
|
|
5331
|
+
const rollbackFont = this.document._fontSource;
|
|
5332
|
+
const rollbackFontSize = this.document._fontSize;
|
|
5333
|
+
const rollbackFontFamily = this.document._fontFamily;
|
|
5334
|
+
if (cell.font?.src) this.document.font(cell.font.src, cell.font?.family);
|
|
5335
|
+
if (cell.font?.size) this.document.fontSize(cell.font.size);
|
|
5336
|
+
const unRotatedTextBounds = this.document.boundsOfString(cell.text, 0, 0, {
|
|
5337
|
+
...textOptions,
|
|
5338
|
+
rotation: 0
|
|
5339
|
+
});
|
|
5340
|
+
textOptions.width = unRotatedTextBounds.width;
|
|
5341
|
+
textOptions.height = unRotatedTextBounds.height;
|
|
5342
|
+
textBounds = this.document.boundsOfString(cell.text, 0, 0, textOptions);
|
|
5343
|
+
this.document.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5344
|
+
}
|
|
5345
|
+
return {
|
|
5346
|
+
...cell,
|
|
5347
|
+
textOptions,
|
|
5348
|
+
x: this._columnXPos[cell.colIndex],
|
|
5349
|
+
y: this._rowYPos[cell.rowIndex],
|
|
5350
|
+
textX: this._columnXPos[cell.colIndex] + cell.padding.left,
|
|
5351
|
+
textY: this._rowYPos[cell.rowIndex] + cell.padding.top,
|
|
5352
|
+
width: cellWidth,
|
|
5353
|
+
height: cellHeight,
|
|
5354
|
+
textAllocatedHeight,
|
|
5355
|
+
textAllocatedWidth,
|
|
5356
|
+
textBounds
|
|
5357
|
+
};
|
|
5358
|
+
}
|
|
5359
|
+
function computeBounds(rotation, allocWidth, allocHeight) {
|
|
5360
|
+
let textMaxWidth, textMaxHeight;
|
|
5361
|
+
const cos = cosine(rotation);
|
|
5362
|
+
const sin = sine(rotation);
|
|
5363
|
+
if (rotation === 0 || rotation === 180) {
|
|
5364
|
+
textMaxWidth = allocWidth;
|
|
5365
|
+
textMaxHeight = allocHeight;
|
|
5366
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5367
|
+
textMaxWidth = allocHeight;
|
|
5368
|
+
textMaxHeight = allocWidth;
|
|
5369
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5370
|
+
textMaxWidth = allocWidth / (2 * cos);
|
|
5371
|
+
textMaxHeight = allocWidth / (2 * sin);
|
|
5372
|
+
} else {
|
|
5373
|
+
textMaxHeight = allocWidth / (2 * cos);
|
|
5374
|
+
textMaxWidth = allocWidth / (2 * sin);
|
|
5375
|
+
}
|
|
5376
|
+
const EF = sin * textMaxWidth;
|
|
5377
|
+
const FG = cos * textMaxHeight;
|
|
5378
|
+
if (EF + FG > allocHeight) {
|
|
5379
|
+
const denominator = cos * cos - sin * sin;
|
|
5380
|
+
if (rotation === 0 || rotation === 180) {
|
|
5381
|
+
textMaxWidth = allocWidth;
|
|
5382
|
+
textMaxHeight = allocHeight;
|
|
5383
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5384
|
+
textMaxWidth = allocHeight;
|
|
5385
|
+
textMaxHeight = allocWidth;
|
|
5386
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5387
|
+
textMaxWidth = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5388
|
+
textMaxHeight = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5389
|
+
} else {
|
|
5390
|
+
textMaxHeight = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5391
|
+
textMaxWidth = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
return {
|
|
5395
|
+
width: Math.abs(textMaxWidth),
|
|
5396
|
+
height: Math.abs(textMaxHeight)
|
|
5397
|
+
};
|
|
5398
|
+
}
|
|
5399
|
+
|
|
5400
|
+
function accommodateTable() {
|
|
5401
|
+
const structParent = this.opts.structParent;
|
|
5402
|
+
if (structParent) {
|
|
5403
|
+
this._tableStruct = this.document.struct('Table');
|
|
5404
|
+
this._tableStruct.dictionary.data.ID = this._id;
|
|
5405
|
+
if (structParent instanceof PDFStructureElement) {
|
|
5406
|
+
structParent.add(this._tableStruct);
|
|
5407
|
+
} else if (structParent instanceof PDFDocument) {
|
|
5408
|
+
structParent.addStructure(this._tableStruct);
|
|
5409
|
+
}
|
|
5410
|
+
this._headerRowLookup = {};
|
|
5411
|
+
this._headerColumnLookup = {};
|
|
5412
|
+
}
|
|
5413
|
+
}
|
|
5414
|
+
function accommodateCleanup() {
|
|
5415
|
+
if (this._tableStruct) this._tableStruct.end();
|
|
5416
|
+
}
|
|
5417
|
+
function accessibleRow(row, rowIndex, renderCell) {
|
|
5418
|
+
const rowStruct = this.document.struct('TR');
|
|
5419
|
+
rowStruct.dictionary.data.ID = new String(`${this._id}-${rowIndex}`);
|
|
5420
|
+
this._tableStruct.add(rowStruct);
|
|
5421
|
+
row.forEach(cell => renderCell(cell, rowStruct));
|
|
5422
|
+
rowStruct.end();
|
|
5423
|
+
}
|
|
5424
|
+
function accessibleCell(cell, rowStruct, callback) {
|
|
5425
|
+
const doc = this.document;
|
|
5426
|
+
const cellStruct = doc.struct(cell.type, {
|
|
5427
|
+
title: cell.title
|
|
5428
|
+
});
|
|
5429
|
+
cellStruct.dictionary.data.ID = cell.id;
|
|
5430
|
+
rowStruct.add(cellStruct);
|
|
5431
|
+
const padding = cell.padding;
|
|
5432
|
+
const border = cell.border;
|
|
5433
|
+
const attributes = {
|
|
5434
|
+
O: 'Table',
|
|
5435
|
+
Width: cell.width,
|
|
5436
|
+
Height: cell.height,
|
|
5437
|
+
Padding: [padding.top, padding.bottom, padding.left, padding.right],
|
|
5438
|
+
RowSpan: cell.rowSpan > 1 ? cell.rowSpan : undefined,
|
|
5439
|
+
ColSpan: cell.colSpan > 1 ? cell.colSpan : undefined,
|
|
5440
|
+
BorderThickness: [border.top, border.bottom, border.left, border.right]
|
|
5441
|
+
};
|
|
5442
|
+
if (cell.type === 'TH') {
|
|
5443
|
+
if (cell.scope === 'Row' || cell.scope === 'Both') {
|
|
5444
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5445
|
+
if (!this._headerRowLookup[cell.rowIndex + i]) {
|
|
5446
|
+
this._headerRowLookup[cell.rowIndex + i] = [];
|
|
5447
|
+
}
|
|
5448
|
+
this._headerRowLookup[cell.rowIndex + i].push(cell.id);
|
|
5449
|
+
}
|
|
5450
|
+
attributes.Scope = cell.scope;
|
|
5451
|
+
}
|
|
5452
|
+
if (cell.scope === 'Column' || cell.scope === 'Both') {
|
|
5453
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5454
|
+
if (!this._headerColumnLookup[cell.colIndex + i]) {
|
|
5455
|
+
this._headerColumnLookup[cell.colIndex + i] = [];
|
|
5456
|
+
}
|
|
5457
|
+
this._headerColumnLookup[cell.colIndex + i].push(cell.id);
|
|
5458
|
+
}
|
|
5459
|
+
attributes.Scope = cell.scope;
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
const Headers = new Set([...Array.from({
|
|
5463
|
+
length: cell.colSpan
|
|
5464
|
+
}, (_, i) => this._headerColumnLookup[cell.colIndex + i]).flat(), ...Array.from({
|
|
5465
|
+
length: cell.rowSpan
|
|
5466
|
+
}, (_, i) => this._headerRowLookup[cell.rowIndex + i]).flat()].filter(Boolean));
|
|
5467
|
+
if (Headers.size) attributes.Headers = Array.from(Headers);
|
|
5468
|
+
const normalizeColor = doc._normalizeColor;
|
|
5469
|
+
if (cell.backgroundColor != null) {
|
|
5470
|
+
attributes.BackgroundColor = normalizeColor(cell.backgroundColor);
|
|
5471
|
+
}
|
|
5472
|
+
const hasBorder = [border.top, border.bottom, border.left, border.right];
|
|
5473
|
+
if (hasBorder.some(x => x)) {
|
|
5474
|
+
const borderColor = cell.borderColor;
|
|
5475
|
+
attributes.BorderColor = [hasBorder[0] ? normalizeColor(borderColor.top) : null, hasBorder[1] ? normalizeColor(borderColor.bottom) : null, hasBorder[2] ? normalizeColor(borderColor.left) : null, hasBorder[3] ? normalizeColor(borderColor.right) : null];
|
|
5476
|
+
}
|
|
5477
|
+
Object.keys(attributes).forEach(key => attributes[key] === undefined && delete attributes[key]);
|
|
5478
|
+
cellStruct.dictionary.data.A = doc.ref(attributes);
|
|
5479
|
+
cellStruct.add(callback);
|
|
5480
|
+
cellStruct.end();
|
|
5481
|
+
cellStruct.dictionary.data.A.end();
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5484
|
+
function renderRow(row, rowIndex) {
|
|
5485
|
+
if (this._tableStruct) {
|
|
5486
|
+
accessibleRow.call(this, row, rowIndex, renderCell.bind(this));
|
|
5487
|
+
} else {
|
|
5488
|
+
row.forEach(cell => renderCell.call(this, cell));
|
|
5489
|
+
}
|
|
5490
|
+
return this._rowYPos[rowIndex] + this._rowHeights[rowIndex];
|
|
5491
|
+
}
|
|
5492
|
+
function renderCell(cell, rowStruct) {
|
|
5493
|
+
const cellRenderer = () => {
|
|
5494
|
+
if (cell.backgroundColor != null) {
|
|
5495
|
+
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(cell.backgroundColor).restore();
|
|
5496
|
+
}
|
|
5497
|
+
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5498
|
+
if (cell.debug) {
|
|
5499
|
+
this.document.save();
|
|
5500
|
+
this.document.dash(1, {
|
|
5501
|
+
space: 1
|
|
5502
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5503
|
+
this.document.rect(cell.x, cell.y, cell.width, cell.height).stroke('green');
|
|
5504
|
+
this.document.restore();
|
|
5505
|
+
}
|
|
5506
|
+
if (cell.text) renderCellText.call(this, cell);
|
|
5507
|
+
};
|
|
5508
|
+
if (rowStruct) accessibleCell.call(this, cell, rowStruct, cellRenderer);else cellRenderer();
|
|
5509
|
+
}
|
|
5510
|
+
function renderCellText(cell) {
|
|
5511
|
+
const doc = this.document;
|
|
5512
|
+
const rollbackFont = doc._fontSource;
|
|
5513
|
+
const rollbackFontSize = doc._fontSize;
|
|
5514
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5515
|
+
if (cell.customFont) {
|
|
5516
|
+
if (cell.font.src) doc.font(cell.font.src, cell.font.family);
|
|
5517
|
+
if (cell.font.size) doc.fontSize(cell.font.size);
|
|
5518
|
+
}
|
|
5519
|
+
const x = cell.textX;
|
|
5520
|
+
const y = cell.textY;
|
|
5521
|
+
const Ah = cell.textAllocatedHeight;
|
|
5522
|
+
const Aw = cell.textAllocatedWidth;
|
|
5523
|
+
const Cw = cell.textBounds.width;
|
|
5524
|
+
const Ch = cell.textBounds.height;
|
|
5525
|
+
const Ox = -cell.textBounds.x;
|
|
5526
|
+
const Oy = -cell.textBounds.y;
|
|
5527
|
+
const PxScale = cell.align.x === 'right' ? 1 : cell.align.x === 'center' ? 0.5 : 0;
|
|
5528
|
+
const Px = (Aw - Cw) * PxScale;
|
|
5529
|
+
const PyScale = cell.align.y === 'bottom' ? 1 : cell.align.y === 'center' ? 0.5 : 0;
|
|
5530
|
+
const Py = (Ah - Ch) * PyScale;
|
|
5531
|
+
const dx = Px + Ox;
|
|
5532
|
+
const dy = Py + Oy;
|
|
5533
|
+
if (cell.debug) {
|
|
5534
|
+
doc.save();
|
|
5535
|
+
doc.dash(1, {
|
|
5536
|
+
space: 1
|
|
5537
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5538
|
+
if (cell.text) {
|
|
5539
|
+
doc.moveTo(x + Px, y).lineTo(x + Px, y + Ah).moveTo(x + Px + Cw, y).lineTo(x + Px + Cw, y + Ah).stroke('blue').moveTo(x, y + Py).lineTo(x + Aw, y + Py).moveTo(x, y + Py + Ch).lineTo(x + Aw, y + Py + Ch).stroke('green');
|
|
5540
|
+
}
|
|
5541
|
+
doc.rect(x, y, Aw, Ah).stroke('orange');
|
|
5542
|
+
doc.restore();
|
|
5543
|
+
}
|
|
5544
|
+
doc.save().rect(x, y, Aw, Ah).clip();
|
|
5545
|
+
doc.fillColor(cell.textColor).strokeColor(cell.textStrokeColor);
|
|
5546
|
+
if (cell.textStroke > 0) doc.lineWidth(cell.textStroke);
|
|
5547
|
+
doc.text(cell.text, x + dx, y + dy, cell.textOptions);
|
|
5548
|
+
doc.restore();
|
|
5549
|
+
if (cell.font) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5550
|
+
}
|
|
5551
|
+
function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
5552
|
+
border = Object.fromEntries(Object.entries(border).map(([k, v]) => [k, mask && !mask[k] ? 0 : v]));
|
|
5553
|
+
const doc = this.document;
|
|
5554
|
+
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5555
|
+
if (border.top > 0) {
|
|
5556
|
+
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(borderColor.top).restore();
|
|
5557
|
+
}
|
|
5558
|
+
} else {
|
|
5559
|
+
if (border.top > 0) {
|
|
5560
|
+
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(borderColor.top).restore();
|
|
5561
|
+
}
|
|
5562
|
+
if (border.right > 0) {
|
|
5563
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(borderColor.right).restore();
|
|
5564
|
+
}
|
|
5565
|
+
if (border.bottom > 0) {
|
|
5566
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(borderColor.bottom).restore();
|
|
5567
|
+
}
|
|
5568
|
+
if (border.left > 0) {
|
|
5569
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(borderColor.left).restore();
|
|
5570
|
+
}
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
|
|
5574
|
+
class PDFTable {
|
|
5575
|
+
constructor(document, opts = {}) {
|
|
5576
|
+
this.document = document;
|
|
5577
|
+
this.opts = Object.freeze(opts);
|
|
5578
|
+
normalizeTable.call(this);
|
|
5579
|
+
accommodateTable.call(this);
|
|
5580
|
+
this._currRowIndex = 0;
|
|
5581
|
+
this._ended = false;
|
|
5582
|
+
if (opts.data) {
|
|
5583
|
+
for (const row of opts.data) this.row(row);
|
|
5584
|
+
return this.end();
|
|
5585
|
+
}
|
|
5586
|
+
}
|
|
5587
|
+
row(row, lastRow = false) {
|
|
5588
|
+
if (this._ended) {
|
|
5589
|
+
throw new Error(`Table was marked as ended on row ${this._currRowIndex}`);
|
|
5590
|
+
}
|
|
5591
|
+
row = Array.from(row);
|
|
5592
|
+
row = normalizeRow.call(this, row, this._currRowIndex);
|
|
5593
|
+
if (this._currRowIndex === 0) ensure.call(this, row);
|
|
5594
|
+
const {
|
|
5595
|
+
newPage,
|
|
5596
|
+
toRender
|
|
5597
|
+
} = measure.call(this, row, this._currRowIndex);
|
|
5598
|
+
if (newPage) this.document.continueOnNewPage();
|
|
5599
|
+
const yPos = renderRow.call(this, toRender, this._currRowIndex);
|
|
5600
|
+
this.document.x = this._position.x;
|
|
5601
|
+
this.document.y = yPos;
|
|
5602
|
+
if (lastRow) return this.end();
|
|
5603
|
+
this._currRowIndex++;
|
|
5604
|
+
return this;
|
|
5605
|
+
}
|
|
5606
|
+
end() {
|
|
5607
|
+
while (this._rowBuffer?.size) this.row([]);
|
|
5608
|
+
this._ended = true;
|
|
5609
|
+
accommodateCleanup.call(this);
|
|
5610
|
+
return this.document;
|
|
5611
|
+
}
|
|
5612
|
+
}
|
|
5613
|
+
|
|
5614
|
+
var TableMixin = {
|
|
5615
|
+
initTables() {
|
|
5616
|
+
this._tableIndex = 0;
|
|
5617
|
+
},
|
|
5618
|
+
table(opts) {
|
|
5619
|
+
return new PDFTable(this, opts);
|
|
5620
|
+
}
|
|
5621
|
+
};
|
|
5622
|
+
|
|
5383
5623
|
class PDFMetadata {
|
|
5384
5624
|
constructor() {
|
|
5385
5625
|
this._metadata = `
|
|
@@ -5421,7 +5661,7 @@ var MetadataMixin = {
|
|
|
5421
5661
|
_addInfo() {
|
|
5422
5662
|
this.appendXML(`
|
|
5423
5663
|
<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
|
|
5424
|
-
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] +
|
|
5664
|
+
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] + 'Z'}</xmp:CreateDate>
|
|
5425
5665
|
<xmp:CreatorTool>${this.info.Creator}</xmp:CreatorTool>
|
|
5426
5666
|
</rdf:Description>
|
|
5427
5667
|
`);
|
|
@@ -5474,11 +5714,6 @@ var MetadataMixin = {
|
|
|
5474
5714
|
endMetadata() {
|
|
5475
5715
|
this._addInfo();
|
|
5476
5716
|
this.metadata.end();
|
|
5477
|
-
|
|
5478
|
-
/*
|
|
5479
|
-
Metadata was introduced in PDF 1.4, so adding it to 1.3
|
|
5480
|
-
will likely only take up more space.
|
|
5481
|
-
*/
|
|
5482
5717
|
if (this.version != 1.3) {
|
|
5483
5718
|
this.metadataRef = this.ref({
|
|
5484
5719
|
length: this.metadata.getLength(),
|
|
@@ -5493,16 +5728,10 @@ var MetadataMixin = {
|
|
|
5493
5728
|
}
|
|
5494
5729
|
};
|
|
5495
5730
|
|
|
5496
|
-
/*
|
|
5497
|
-
PDFDocument - represents an entire PDF document
|
|
5498
|
-
By Devon Govett
|
|
5499
|
-
*/
|
|
5500
5731
|
class PDFDocument extends stream.Readable {
|
|
5501
5732
|
constructor(options = {}) {
|
|
5502
5733
|
super(options);
|
|
5503
5734
|
this.options = options;
|
|
5504
|
-
|
|
5505
|
-
// PDF version
|
|
5506
5735
|
switch (options.pdfVersion) {
|
|
5507
5736
|
case '1.4':
|
|
5508
5737
|
this.version = 1.4;
|
|
@@ -5521,13 +5750,9 @@ class PDFDocument extends stream.Readable {
|
|
|
5521
5750
|
this.version = 1.3;
|
|
5522
5751
|
break;
|
|
5523
5752
|
}
|
|
5524
|
-
|
|
5525
|
-
// Whether streams should be compressed
|
|
5526
5753
|
this.compress = this.options.compress != null ? this.options.compress : true;
|
|
5527
5754
|
this._pageBuffer = [];
|
|
5528
5755
|
this._pageBufferStart = 0;
|
|
5529
|
-
|
|
5530
|
-
// The PDF object store
|
|
5531
5756
|
this._offsets = [];
|
|
5532
5757
|
this._waiting = 0;
|
|
5533
5758
|
this._ended = false;
|
|
@@ -5548,11 +5773,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5548
5773
|
if (this.options.lang) {
|
|
5549
5774
|
this._root.data.Lang = new String(this.options.lang);
|
|
5550
5775
|
}
|
|
5551
|
-
|
|
5552
|
-
// The current page
|
|
5553
5776
|
this.page = null;
|
|
5554
|
-
|
|
5555
|
-
// Initialize mixins
|
|
5556
5777
|
this.initMetadata();
|
|
5557
5778
|
this.initColor();
|
|
5558
5779
|
this.initVector();
|
|
@@ -5561,9 +5782,8 @@ class PDFDocument extends stream.Readable {
|
|
|
5561
5782
|
this.initImages();
|
|
5562
5783
|
this.initOutline();
|
|
5563
5784
|
this.initMarkings(options);
|
|
5785
|
+
this.initTables();
|
|
5564
5786
|
this.initSubset(options);
|
|
5565
|
-
|
|
5566
|
-
// Initialize the metadata
|
|
5567
5787
|
this.info = {
|
|
5568
5788
|
Producer: 'PDFKit',
|
|
5569
5789
|
Creator: 'PDFKit',
|
|
@@ -5580,21 +5800,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5580
5800
|
DisplayDocTitle: true
|
|
5581
5801
|
});
|
|
5582
5802
|
}
|
|
5583
|
-
|
|
5584
|
-
// Generate file ID
|
|
5585
5803
|
this._id = PDFSecurity.generateFileID(this.info);
|
|
5586
|
-
|
|
5587
|
-
// Initialize security settings
|
|
5588
5804
|
this._security = PDFSecurity.create(this, options);
|
|
5589
|
-
|
|
5590
|
-
// Write the header
|
|
5591
|
-
// PDF version
|
|
5592
5805
|
this._write(`%PDF-${this.version}`);
|
|
5593
|
-
|
|
5594
|
-
// 4 binary chars, as recommended by the spec
|
|
5595
5806
|
this._write('%\xFF\xFF\xFF\xFF');
|
|
5596
|
-
|
|
5597
|
-
// Add the first page
|
|
5598
5807
|
if (this.options.autoFirstPage !== false) {
|
|
5599
5808
|
this.addPage();
|
|
5600
5809
|
}
|
|
@@ -5605,27 +5814,16 @@ class PDFDocument extends stream.Readable {
|
|
|
5605
5814
|
options
|
|
5606
5815
|
} = this);
|
|
5607
5816
|
}
|
|
5608
|
-
|
|
5609
|
-
// end the current page if needed
|
|
5610
5817
|
if (!this.options.bufferPages) {
|
|
5611
5818
|
this.flushPages();
|
|
5612
5819
|
}
|
|
5613
|
-
|
|
5614
|
-
// create a page object
|
|
5615
5820
|
this.page = new PDFPage(this, options);
|
|
5616
5821
|
this._pageBuffer.push(this.page);
|
|
5617
|
-
|
|
5618
|
-
// add the page to the object store
|
|
5619
5822
|
const pages = this._root.data.Pages.data;
|
|
5620
5823
|
pages.Kids.push(this.page.dictionary);
|
|
5621
5824
|
pages.Count++;
|
|
5622
|
-
|
|
5623
|
-
// reset x and y coordinates
|
|
5624
5825
|
this.x = this.page.margins.left;
|
|
5625
5826
|
this.y = this.page.margins.top;
|
|
5626
|
-
|
|
5627
|
-
// flip PDF coordinate system so that the origin is in
|
|
5628
|
-
// the top left rather than the bottom left
|
|
5629
5827
|
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
5630
5828
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
5631
5829
|
this.emit('pageAdded');
|
|
@@ -5633,7 +5831,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5633
5831
|
}
|
|
5634
5832
|
continueOnNewPage(options) {
|
|
5635
5833
|
const pageMarkings = this.endPageMarkings(this.page);
|
|
5636
|
-
this.addPage(options);
|
|
5834
|
+
this.addPage(options ?? this.page._options);
|
|
5637
5835
|
this.initPageMarkings(pageMarkings);
|
|
5638
5836
|
return this;
|
|
5639
5837
|
}
|
|
@@ -5651,8 +5849,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5651
5849
|
return this.page = page;
|
|
5652
5850
|
}
|
|
5653
5851
|
flushPages() {
|
|
5654
|
-
// this local variable exists so we're future-proof against
|
|
5655
|
-
// reentrant calls to flushPages.
|
|
5656
5852
|
const pages = this._pageBuffer;
|
|
5657
5853
|
this._pageBuffer = [];
|
|
5658
5854
|
this._pageBufferStart += pages.length;
|
|
@@ -5673,13 +5869,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5673
5869
|
}
|
|
5674
5870
|
addNamedEmbeddedFile(name, ref) {
|
|
5675
5871
|
if (!this._root.data.Names.data.EmbeddedFiles) {
|
|
5676
|
-
// disabling /Limits for this tree fixes attachments not showing in Adobe Reader
|
|
5677
5872
|
this._root.data.Names.data.EmbeddedFiles = new PDFNameTree({
|
|
5678
5873
|
limits: false
|
|
5679
5874
|
});
|
|
5680
5875
|
}
|
|
5681
|
-
|
|
5682
|
-
// add filespec to EmbeddedFiles
|
|
5683
5876
|
this._root.data.Names.data.EmbeddedFiles.add(name, ref);
|
|
5684
5877
|
}
|
|
5685
5878
|
addNamedJavaScript(name, js) {
|
|
@@ -5694,19 +5887,17 @@ class PDFDocument extends stream.Readable {
|
|
|
5694
5887
|
}
|
|
5695
5888
|
ref(data) {
|
|
5696
5889
|
const ref = new PDFReference(this, this._offsets.length + 1, data);
|
|
5697
|
-
this._offsets.push(null);
|
|
5890
|
+
this._offsets.push(null);
|
|
5698
5891
|
this._waiting++;
|
|
5699
5892
|
return ref;
|
|
5700
5893
|
}
|
|
5701
5894
|
_read() {}
|
|
5702
|
-
// do nothing, but this method is required by node
|
|
5703
|
-
|
|
5704
5895
|
_write(data) {
|
|
5705
5896
|
if (!Buffer.isBuffer(data)) {
|
|
5706
5897
|
data = Buffer.from(data + '\n', 'binary');
|
|
5707
5898
|
}
|
|
5708
5899
|
this.push(data);
|
|
5709
|
-
|
|
5900
|
+
this._offset += data.length;
|
|
5710
5901
|
}
|
|
5711
5902
|
addContent(data) {
|
|
5712
5903
|
this.page.write(data);
|
|
@@ -5716,7 +5907,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5716
5907
|
this._offsets[ref.id - 1] = ref.offset;
|
|
5717
5908
|
if (--this._waiting === 0 && this._ended) {
|
|
5718
5909
|
this._finalize();
|
|
5719
|
-
|
|
5910
|
+
this._ended = false;
|
|
5720
5911
|
}
|
|
5721
5912
|
}
|
|
5722
5913
|
end() {
|
|
@@ -5753,13 +5944,12 @@ class PDFDocument extends stream.Readable {
|
|
|
5753
5944
|
this._security.end();
|
|
5754
5945
|
}
|
|
5755
5946
|
if (this._waiting === 0) {
|
|
5756
|
-
|
|
5947
|
+
this._finalize();
|
|
5757
5948
|
} else {
|
|
5758
|
-
|
|
5949
|
+
this._ended = true;
|
|
5759
5950
|
}
|
|
5760
5951
|
}
|
|
5761
5952
|
_finalize() {
|
|
5762
|
-
// generate xref
|
|
5763
5953
|
const xRefOffset = this._offset;
|
|
5764
5954
|
this._write('xref');
|
|
5765
5955
|
this._write(`0 ${this._offsets.length + 1}`);
|
|
@@ -5768,8 +5958,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5768
5958
|
offset = `0000000000${offset}`.slice(-10);
|
|
5769
5959
|
this._write(offset + ' 00000 n ');
|
|
5770
5960
|
}
|
|
5771
|
-
|
|
5772
|
-
// trailer
|
|
5773
5961
|
const trailer = {
|
|
5774
5962
|
Size: this._offsets.length + 1,
|
|
5775
5963
|
Root: this._root,
|
|
@@ -5784,9 +5972,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5784
5972
|
this._write('startxref');
|
|
5785
5973
|
this._write(`${xRefOffset}`);
|
|
5786
5974
|
this._write('%%EOF');
|
|
5787
|
-
|
|
5788
|
-
// end the stream
|
|
5789
|
-
return this.push(null);
|
|
5975
|
+
this.push(null);
|
|
5790
5976
|
}
|
|
5791
5977
|
toString() {
|
|
5792
5978
|
return '[object PDFDocument]';
|
|
@@ -5807,6 +5993,7 @@ mixin(MarkingsMixin);
|
|
|
5807
5993
|
mixin(AcroFormMixin);
|
|
5808
5994
|
mixin(AttachmentsMixin);
|
|
5809
5995
|
mixin(SubsetMixin);
|
|
5996
|
+
mixin(TableMixin);
|
|
5810
5997
|
PDFDocument.LineWrapper = LineWrapper;
|
|
5811
5998
|
|
|
5812
5999
|
module.exports = PDFDocument;
|