pdfkit 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.git-blame-ignore-revs +1 -0
- package/CHANGELOG.md +13 -0
- package/js/pdfkit.es.js +989 -782
- 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 +968 -783
- package/js/pdfkit.js.map +1 -1
- package/js/pdfkit.standalone.js +968 -783
- package/package.json +3 -3
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,69 @@ class PDFReference extends PDFAbstractReference {
|
|
|
258
221
|
}
|
|
259
222
|
}
|
|
260
223
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
224
|
+
function PDFNumber(n) {
|
|
225
|
+
return Math.fround(n);
|
|
226
|
+
}
|
|
227
|
+
function normalizeSides(sides, defaultDefinition = undefined, transformer = v => v) {
|
|
228
|
+
if (sides == null || typeof sides === 'object' && Object.keys(sides).length === 0) {
|
|
229
|
+
sides = defaultDefinition;
|
|
230
|
+
}
|
|
231
|
+
if (sides == null || typeof sides !== 'object') {
|
|
232
|
+
sides = {
|
|
233
|
+
top: sides,
|
|
234
|
+
right: sides,
|
|
235
|
+
bottom: sides,
|
|
236
|
+
left: sides
|
|
237
|
+
};
|
|
238
|
+
} else if (Array.isArray(sides)) {
|
|
239
|
+
if (sides.length === 2) {
|
|
240
|
+
sides = {
|
|
241
|
+
vertical: sides[0],
|
|
242
|
+
horizontal: sides[1]
|
|
243
|
+
};
|
|
244
|
+
} else {
|
|
245
|
+
sides = {
|
|
246
|
+
top: sides[0],
|
|
247
|
+
right: sides[1],
|
|
248
|
+
bottom: sides[2],
|
|
249
|
+
left: sides[3]
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if ('vertical' in sides || 'horizontal' in sides) {
|
|
254
|
+
sides = {
|
|
255
|
+
top: sides.vertical,
|
|
256
|
+
right: sides.horizontal,
|
|
257
|
+
bottom: sides.vertical,
|
|
258
|
+
left: sides.horizontal
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
top: transformer(sides.top),
|
|
263
|
+
right: transformer(sides.right),
|
|
264
|
+
bottom: transformer(sides.bottom),
|
|
265
|
+
left: transformer(sides.left)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const MM_TO_CM = 1 / 10;
|
|
269
|
+
const CM_TO_IN = 1 / 2.54;
|
|
270
|
+
const PX_TO_IN = 1 / 96;
|
|
271
|
+
const IN_TO_PT = 72;
|
|
272
|
+
const PC_TO_PT = 12;
|
|
273
|
+
function cosine(a) {
|
|
274
|
+
if (a === 0) return 1;
|
|
275
|
+
if (a === 90) return 0;
|
|
276
|
+
if (a === 180) return -1;
|
|
277
|
+
if (a === 270) return 0;
|
|
278
|
+
return Math.cos(a * Math.PI / 180);
|
|
279
|
+
}
|
|
280
|
+
function sine(a) {
|
|
281
|
+
if (a === 0) return 0;
|
|
282
|
+
if (a === 90) return 1;
|
|
283
|
+
if (a === 180) return 0;
|
|
284
|
+
if (a === 270) return -1;
|
|
285
|
+
return Math.sin(a * Math.PI / 180);
|
|
286
|
+
}
|
|
265
287
|
|
|
266
288
|
const DEFAULT_MARGINS = {
|
|
267
289
|
top: 72,
|
|
@@ -324,35 +346,19 @@ const SIZES = {
|
|
|
324
346
|
class PDFPage {
|
|
325
347
|
constructor(document, options = {}) {
|
|
326
348
|
this.document = document;
|
|
349
|
+
this._options = options;
|
|
327
350
|
this.size = options.size || 'letter';
|
|
328
351
|
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
352
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
346
353
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
347
354
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
348
355
|
this.content = this.document.ref();
|
|
349
|
-
|
|
350
|
-
|
|
356
|
+
if (options.font) document.font(options.font, options.fontFamily);
|
|
357
|
+
if (options.fontSize) document.fontSize(options.fontSize);
|
|
358
|
+
this.margins = normalizeSides(options.margin ?? options.margins, DEFAULT_MARGINS, x => document.sizeToPoint(x, 0, this));
|
|
351
359
|
this.resources = this.document.ref({
|
|
352
360
|
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI']
|
|
353
361
|
});
|
|
354
|
-
|
|
355
|
-
// The page dictionary
|
|
356
362
|
this.dictionary = this.document.ref({
|
|
357
363
|
Type: 'Page',
|
|
358
364
|
Parent: this.document._root.data.Pages,
|
|
@@ -362,8 +368,6 @@ class PDFPage {
|
|
|
362
368
|
});
|
|
363
369
|
this.markings = [];
|
|
364
370
|
}
|
|
365
|
-
|
|
366
|
-
// Lazily create these objects
|
|
367
371
|
get fonts() {
|
|
368
372
|
const data = this.resources.data;
|
|
369
373
|
return data.Font != null ? data.Font : data.Font = {};
|
|
@@ -392,14 +396,18 @@ class PDFPage {
|
|
|
392
396
|
const data = this.dictionary.data;
|
|
393
397
|
return data.StructParents != null ? data.StructParents : data.StructParents = this.document.createStructParentTreeNextKey();
|
|
394
398
|
}
|
|
399
|
+
get contentWidth() {
|
|
400
|
+
return this.width - this.margins.left - this.margins.right;
|
|
401
|
+
}
|
|
402
|
+
get contentHeight() {
|
|
403
|
+
return this.height - this.margins.top - this.margins.bottom;
|
|
404
|
+
}
|
|
395
405
|
maxY() {
|
|
396
406
|
return this.height - this.margins.bottom;
|
|
397
407
|
}
|
|
398
408
|
write(chunk) {
|
|
399
409
|
return this.content.write(chunk);
|
|
400
410
|
}
|
|
401
|
-
|
|
402
|
-
// Set tab order if document is tagged for accessibility.
|
|
403
411
|
_setTabOrder() {
|
|
404
412
|
if (!this.dictionary.Tabs && this.document.hasMarkInfoDictionary()) {
|
|
405
413
|
this.dictionary.data.Tabs = 'S';
|
|
@@ -417,191 +425,57 @@ class PDFPage {
|
|
|
417
425
|
}
|
|
418
426
|
}
|
|
419
427
|
|
|
420
|
-
/*
|
|
421
|
-
PDFNameTree - represents a name tree object
|
|
422
|
-
*/
|
|
423
428
|
class PDFNameTree extends PDFTree {
|
|
424
429
|
_compareKeys(a, b) {
|
|
425
430
|
return a.localeCompare(b);
|
|
426
431
|
}
|
|
427
432
|
_keysName() {
|
|
428
|
-
return
|
|
433
|
+
return 'Names';
|
|
429
434
|
}
|
|
430
435
|
_dataForKey(k) {
|
|
431
436
|
return new String(k);
|
|
432
437
|
}
|
|
433
438
|
}
|
|
434
439
|
|
|
435
|
-
/**
|
|
436
|
-
* Check if value is in a range group.
|
|
437
|
-
* @param {number} value
|
|
438
|
-
* @param {number[]} rangeGroup
|
|
439
|
-
* @returns {boolean}
|
|
440
|
-
*/
|
|
441
440
|
function inRange(value, rangeGroup) {
|
|
442
441
|
if (value < rangeGroup[0]) return false;
|
|
443
442
|
let startRange = 0;
|
|
444
443
|
let endRange = rangeGroup.length / 2;
|
|
445
444
|
while (startRange <= endRange) {
|
|
446
445
|
const middleRange = Math.floor((startRange + endRange) / 2);
|
|
447
|
-
|
|
448
|
-
// actual array index
|
|
449
446
|
const arrayIndex = middleRange * 2;
|
|
450
|
-
|
|
451
|
-
// Check if value is in range pointed by actual index
|
|
452
447
|
if (value >= rangeGroup[arrayIndex] && value <= rangeGroup[arrayIndex + 1]) {
|
|
453
448
|
return true;
|
|
454
449
|
}
|
|
455
450
|
if (value > rangeGroup[arrayIndex + 1]) {
|
|
456
|
-
// Search Right Side Of Array
|
|
457
451
|
startRange = middleRange + 1;
|
|
458
452
|
} else {
|
|
459
|
-
// Search Left Side Of Array
|
|
460
453
|
endRange = middleRange - 1;
|
|
461
454
|
}
|
|
462
455
|
}
|
|
463
456
|
return false;
|
|
464
457
|
}
|
|
465
458
|
|
|
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
459
|
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
460
|
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
461
|
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
462
|
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
|
-
|
|
463
|
+
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
464
|
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
|
-
|
|
465
|
+
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];
|
|
466
|
+
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];
|
|
467
|
+
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
468
|
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
469
|
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
470
|
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
471
|
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
472
|
const isBidirectionalL = character => inRange(character, bidirectional_l);
|
|
578
473
|
|
|
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
474
|
const mapping2space = isNonASCIISpaceCharacter;
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* the "commonly mapped to nothing" characters [StringPrep, B.1]
|
|
589
|
-
* that can be mapped to nothing.
|
|
590
|
-
*/
|
|
591
475
|
const mapping2nothing = isCommonlyMappedToNothing;
|
|
592
|
-
|
|
593
|
-
// utils
|
|
594
476
|
const getCodePoint = character => character.codePointAt(0);
|
|
595
477
|
const first = x => x[0];
|
|
596
478
|
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
479
|
function toCodePoints(input) {
|
|
606
480
|
const codepoints = [];
|
|
607
481
|
const size = input.length;
|
|
@@ -619,14 +493,6 @@ function toCodePoints(input) {
|
|
|
619
493
|
}
|
|
620
494
|
return codepoints;
|
|
621
495
|
}
|
|
622
|
-
|
|
623
|
-
/**
|
|
624
|
-
* SASLprep.
|
|
625
|
-
* @param {string} input
|
|
626
|
-
* @param {Object} opts
|
|
627
|
-
* @param {boolean} opts.allowUnassigned
|
|
628
|
-
* @returns {string}
|
|
629
|
-
*/
|
|
630
496
|
function saslprep(input, opts = {}) {
|
|
631
497
|
if (typeof input !== 'string') {
|
|
632
498
|
throw new TypeError('Expected string.');
|
|
@@ -634,49 +500,24 @@ function saslprep(input, opts = {}) {
|
|
|
634
500
|
if (input.length === 0) {
|
|
635
501
|
return '';
|
|
636
502
|
}
|
|
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
|
|
503
|
+
const mapped_input = toCodePoints(input).map(character => mapping2space(character) ? 0x20 : character).filter(character => !mapping2nothing(character));
|
|
646
504
|
const normalized_input = String.fromCodePoint.apply(null, mapped_input).normalize('NFKC');
|
|
647
505
|
const normalized_map = toCodePoints(normalized_input);
|
|
648
|
-
|
|
649
|
-
// 3. Prohibit
|
|
650
506
|
const hasProhibited = normalized_map.some(isProhibitedCharacter);
|
|
651
507
|
if (hasProhibited) {
|
|
652
508
|
throw new Error('Prohibited character, see https://tools.ietf.org/html/rfc4013#section-2.3');
|
|
653
509
|
}
|
|
654
|
-
|
|
655
|
-
// Unassigned Code Points
|
|
656
510
|
if (opts.allowUnassigned !== true) {
|
|
657
511
|
const hasUnassigned = normalized_map.some(isUnassignedCodePoint);
|
|
658
512
|
if (hasUnassigned) {
|
|
659
513
|
throw new Error('Unassigned code point, see https://tools.ietf.org/html/rfc4013#section-2.5');
|
|
660
514
|
}
|
|
661
515
|
}
|
|
662
|
-
|
|
663
|
-
// 4. check bidi
|
|
664
|
-
|
|
665
516
|
const hasBidiRAL = normalized_map.some(isBidirectionalRAL);
|
|
666
517
|
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
518
|
if (hasBidiRAL && hasBidiL) {
|
|
671
519
|
throw new Error('String must not contain RandALCat and LCat at the same time,' + ' see https://tools.ietf.org/html/rfc3454#section-6');
|
|
672
520
|
}
|
|
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
521
|
const isFirstBidiRAL = isBidirectionalRAL(getCodePoint(first(normalized_input)));
|
|
681
522
|
const isLastBidiRAL = isBidirectionalRAL(getCodePoint(last(normalized_input)));
|
|
682
523
|
if (hasBidiRAL && !(isFirstBidiRAL && isLastBidiRAL)) {
|
|
@@ -685,15 +526,10 @@ function saslprep(input, opts = {}) {
|
|
|
685
526
|
return normalized_input;
|
|
686
527
|
}
|
|
687
528
|
|
|
688
|
-
/*
|
|
689
|
-
PDFSecurity - represents PDF security settings
|
|
690
|
-
By Yang Liu <hi@zesik.com>
|
|
691
|
-
*/
|
|
692
529
|
class PDFSecurity {
|
|
693
530
|
static generateFileID(info = {}) {
|
|
694
531
|
let infoStr = `${info.CreationDate.getTime()}\n`;
|
|
695
532
|
for (let key in info) {
|
|
696
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
697
533
|
if (!info.hasOwnProperty(key)) {
|
|
698
534
|
continue;
|
|
699
535
|
}
|
|
@@ -1067,8 +903,6 @@ class PDFGradient$1 {
|
|
|
1067
903
|
}
|
|
1068
904
|
this.embedded = true;
|
|
1069
905
|
this.matrix = m;
|
|
1070
|
-
|
|
1071
|
-
// if the last stop comes before 100%, add a copy at 100%
|
|
1072
906
|
const last = this.stops[stopsLength - 1];
|
|
1073
907
|
if (last[0] < 1) {
|
|
1074
908
|
this.stops.push([1, last[1], last[2]]);
|
|
@@ -1091,14 +925,11 @@ class PDFGradient$1 {
|
|
|
1091
925
|
stops.push(fn);
|
|
1092
926
|
fn.end();
|
|
1093
927
|
}
|
|
1094
|
-
|
|
1095
|
-
// if there are only two stops, we don't need a stitching function
|
|
1096
928
|
if (stopsLength === 1) {
|
|
1097
929
|
fn = stops[0];
|
|
1098
930
|
} else {
|
|
1099
931
|
fn = this.doc.ref({
|
|
1100
932
|
FunctionType: 3,
|
|
1101
|
-
// stitching function
|
|
1102
933
|
Domain: [0, 1],
|
|
1103
934
|
Functions: stops,
|
|
1104
935
|
Bounds: bounds,
|
|
@@ -1179,7 +1010,6 @@ class PDFGradient$1 {
|
|
|
1179
1010
|
return pattern;
|
|
1180
1011
|
}
|
|
1181
1012
|
apply(stroke) {
|
|
1182
|
-
// apply gradient transform to existing document ctm
|
|
1183
1013
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1184
1014
|
const [m11, m12, m21, m22, dx, dy] = this.transform;
|
|
1185
1015
|
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 +1072,6 @@ var Gradient = {
|
|
|
1242
1072
|
PDFRadialGradient: PDFRadialGradient$1
|
|
1243
1073
|
};
|
|
1244
1074
|
|
|
1245
|
-
/*
|
|
1246
|
-
PDF tiling pattern support. Uncolored only.
|
|
1247
|
-
*/
|
|
1248
|
-
|
|
1249
1075
|
const underlyingColorSpaces = ['DeviceCMYK', 'DeviceRGB'];
|
|
1250
1076
|
class PDFTilingPattern$1 {
|
|
1251
1077
|
constructor(doc, bBox, xStep, yStep, stream) {
|
|
@@ -1256,23 +1082,16 @@ class PDFTilingPattern$1 {
|
|
|
1256
1082
|
this.stream = stream;
|
|
1257
1083
|
}
|
|
1258
1084
|
createPattern() {
|
|
1259
|
-
// no resources needed for our current usage
|
|
1260
|
-
// required entry
|
|
1261
1085
|
const resources = this.doc.ref();
|
|
1262
1086
|
resources.end();
|
|
1263
|
-
// apply default transform matrix (flipped in the default doc._ctm)
|
|
1264
|
-
// see document.js & gradient.js
|
|
1265
1087
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1266
1088
|
const [m11, m12, m21, m22, dx, dy] = [1, 0, 0, 1, 0, 0];
|
|
1267
1089
|
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
1090
|
const pattern = this.doc.ref({
|
|
1269
1091
|
Type: 'Pattern',
|
|
1270
1092
|
PatternType: 1,
|
|
1271
|
-
// tiling
|
|
1272
1093
|
PaintType: 2,
|
|
1273
|
-
// 1-colored, 2-uncolored
|
|
1274
1094
|
TilingType: 2,
|
|
1275
|
-
// 2-no distortion
|
|
1276
1095
|
BBox: this.bBox,
|
|
1277
1096
|
XStep: this.xStep,
|
|
1278
1097
|
YStep: this.yStep,
|
|
@@ -1283,8 +1102,6 @@ class PDFTilingPattern$1 {
|
|
|
1283
1102
|
return pattern;
|
|
1284
1103
|
}
|
|
1285
1104
|
embedPatternColorSpaces() {
|
|
1286
|
-
// map each pattern to an underlying color space
|
|
1287
|
-
// and embed on each page
|
|
1288
1105
|
underlyingColorSpaces.forEach(csName => {
|
|
1289
1106
|
const csId = this.getPatternColorSpaceId(csName);
|
|
1290
1107
|
if (this.doc.page.colorSpaces[csId]) return;
|
|
@@ -1302,24 +1119,17 @@ class PDFTilingPattern$1 {
|
|
|
1302
1119
|
this.id = 'P' + this.doc._patternCount;
|
|
1303
1120
|
this.pattern = this.createPattern();
|
|
1304
1121
|
}
|
|
1305
|
-
|
|
1306
|
-
// patterns are embedded in each page
|
|
1307
1122
|
if (!this.doc.page.patterns[this.id]) {
|
|
1308
1123
|
this.doc.page.patterns[this.id] = this.pattern;
|
|
1309
1124
|
}
|
|
1310
1125
|
}
|
|
1311
1126
|
apply(stroke, patternColor) {
|
|
1312
|
-
// do any embedding/creating that might be needed
|
|
1313
1127
|
this.embedPatternColorSpaces();
|
|
1314
1128
|
this.embed();
|
|
1315
1129
|
const normalizedColor = this.doc._normalizeColor(patternColor);
|
|
1316
1130
|
if (!normalizedColor) throw Error(`invalid pattern color. (value: ${patternColor})`);
|
|
1317
|
-
|
|
1318
|
-
// select one of the pattern color spaces
|
|
1319
1131
|
const csId = this.getPatternColorSpaceId(this.doc._getColorSpace(normalizedColor));
|
|
1320
1132
|
this.doc._setColorSpace(csId, stroke);
|
|
1321
|
-
|
|
1322
|
-
// stroke/fill using the pattern and color (in the above underlying color space)
|
|
1323
1133
|
const op = stroke ? 'SCN' : 'scn';
|
|
1324
1134
|
return this.doc.addContent(`${normalizedColor.join(' ')} /${this.id} ${op}`);
|
|
1325
1135
|
}
|
|
@@ -1339,11 +1149,10 @@ const {
|
|
|
1339
1149
|
var ColorMixin = {
|
|
1340
1150
|
initColor() {
|
|
1341
1151
|
this.spotColors = {};
|
|
1342
|
-
// The opacity dictionaries
|
|
1343
1152
|
this._opacityRegistry = {};
|
|
1344
1153
|
this._opacityCount = 0;
|
|
1345
1154
|
this._patternCount = 0;
|
|
1346
|
-
|
|
1155
|
+
this._gradCount = 0;
|
|
1347
1156
|
},
|
|
1348
1157
|
_normalizeColor(color) {
|
|
1349
1158
|
if (typeof color === 'string') {
|
|
@@ -1360,10 +1169,8 @@ var ColorMixin = {
|
|
|
1360
1169
|
}
|
|
1361
1170
|
}
|
|
1362
1171
|
if (Array.isArray(color)) {
|
|
1363
|
-
// RGB
|
|
1364
1172
|
if (color.length === 3) {
|
|
1365
1173
|
color = color.map(part => part / 255);
|
|
1366
|
-
// CMYK
|
|
1367
1174
|
} else if (color.length === 4) {
|
|
1368
1175
|
color = color.map(part => part / 100);
|
|
1369
1176
|
}
|
|
@@ -1375,12 +1182,10 @@ var ColorMixin = {
|
|
|
1375
1182
|
if (color instanceof PDFGradient) {
|
|
1376
1183
|
color.apply(stroke);
|
|
1377
1184
|
return true;
|
|
1378
|
-
// see if tiling pattern, decode & apply it it
|
|
1379
1185
|
} else if (Array.isArray(color) && color[0] instanceof PDFTilingPattern) {
|
|
1380
1186
|
color[0].apply(stroke, color[1]);
|
|
1381
1187
|
return true;
|
|
1382
1188
|
}
|
|
1383
|
-
// any other case should be a normal color and not a pattern
|
|
1384
1189
|
return this._setColorCore(color, stroke);
|
|
1385
1190
|
},
|
|
1386
1191
|
_setColorCore(color, stroke) {
|
|
@@ -1414,9 +1219,6 @@ var ColorMixin = {
|
|
|
1414
1219
|
if (set) {
|
|
1415
1220
|
this.fillOpacity(opacity);
|
|
1416
1221
|
}
|
|
1417
|
-
|
|
1418
|
-
// save this for text wrapper, which needs to reset
|
|
1419
|
-
// the fill color on new pages
|
|
1420
1222
|
this._fillColor = [color, opacity];
|
|
1421
1223
|
return this;
|
|
1422
1224
|
},
|
|
@@ -1672,7 +1474,6 @@ const parse = function (path) {
|
|
|
1672
1474
|
if (parameters[c] != null) {
|
|
1673
1475
|
params = parameters[c];
|
|
1674
1476
|
if (cmd) {
|
|
1675
|
-
// save existing command
|
|
1676
1477
|
if (curArg.length > 0) {
|
|
1677
1478
|
args[args.length] = +curArg;
|
|
1678
1479
|
}
|
|
@@ -1690,14 +1491,11 @@ const parse = function (path) {
|
|
|
1690
1491
|
continue;
|
|
1691
1492
|
}
|
|
1692
1493
|
if (args.length === params) {
|
|
1693
|
-
// handle reused commands
|
|
1694
1494
|
ret[ret.length] = {
|
|
1695
1495
|
cmd,
|
|
1696
1496
|
args
|
|
1697
1497
|
};
|
|
1698
1498
|
args = [+curArg];
|
|
1699
|
-
|
|
1700
|
-
// handle assumed commands
|
|
1701
1499
|
if (cmd === 'M') {
|
|
1702
1500
|
cmd = 'L';
|
|
1703
1501
|
}
|
|
@@ -1708,8 +1506,6 @@ const parse = function (path) {
|
|
|
1708
1506
|
args[args.length] = +curArg;
|
|
1709
1507
|
}
|
|
1710
1508
|
foundDecimal = c === '.';
|
|
1711
|
-
|
|
1712
|
-
// fix for negative numbers or repeated decimals with no delimeter between commands
|
|
1713
1509
|
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1714
1510
|
} else {
|
|
1715
1511
|
curArg += c;
|
|
@@ -1718,18 +1514,13 @@ const parse = function (path) {
|
|
|
1718
1514
|
}
|
|
1719
1515
|
}
|
|
1720
1516
|
}
|
|
1721
|
-
|
|
1722
|
-
// add the last command
|
|
1723
1517
|
if (curArg.length > 0) {
|
|
1724
1518
|
if (args.length === params) {
|
|
1725
|
-
// handle reused commands
|
|
1726
1519
|
ret[ret.length] = {
|
|
1727
1520
|
cmd,
|
|
1728
1521
|
args
|
|
1729
1522
|
};
|
|
1730
1523
|
args = [+curArg];
|
|
1731
|
-
|
|
1732
|
-
// handle assumed commands
|
|
1733
1524
|
if (cmd === 'M') {
|
|
1734
1525
|
cmd = 'L';
|
|
1735
1526
|
}
|
|
@@ -1747,10 +1538,7 @@ const parse = function (path) {
|
|
|
1747
1538
|
return ret;
|
|
1748
1539
|
};
|
|
1749
1540
|
const apply = function (commands, doc) {
|
|
1750
|
-
// current point, control point, and subpath starting point
|
|
1751
1541
|
cx = cy = px = py = sx = sy = 0;
|
|
1752
|
-
|
|
1753
|
-
// run the commands
|
|
1754
1542
|
for (let i = 0; i < commands.length; i++) {
|
|
1755
1543
|
const c = commands[i];
|
|
1756
1544
|
if (typeof runners[c.cmd] === 'function') {
|
|
@@ -1914,8 +1702,6 @@ const solveArc = function (doc, x, y, coords) {
|
|
|
1914
1702
|
doc.bezierCurveTo(...bez);
|
|
1915
1703
|
}
|
|
1916
1704
|
};
|
|
1917
|
-
|
|
1918
|
-
// from Inkscape svgtopdf, thanks!
|
|
1919
1705
|
const arcToSegments = function (x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
|
1920
1706
|
const th = rotateX * (Math.PI / 180);
|
|
1921
1707
|
const sin_th = Math.sin(th);
|
|
@@ -1991,18 +1777,14 @@ class SVGPath {
|
|
|
1991
1777
|
const {
|
|
1992
1778
|
number: number$1
|
|
1993
1779
|
} = PDFObject;
|
|
1994
|
-
|
|
1995
|
-
// This constant is used to approximate a symmetrical arc using a cubic
|
|
1996
|
-
// Bezier curve.
|
|
1997
1780
|
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
|
|
1998
1781
|
var VectorMixin = {
|
|
1999
1782
|
initVector() {
|
|
2000
|
-
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
2001
|
-
|
|
1783
|
+
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
1784
|
+
this._ctmStack = [];
|
|
2002
1785
|
},
|
|
2003
1786
|
save() {
|
|
2004
1787
|
this._ctmStack.push(this._ctm.slice());
|
|
2005
|
-
// TODO: save/restore colorspace and styles so not setting it unnessesarily all the time?
|
|
2006
1788
|
return this.addContent('q');
|
|
2007
1789
|
},
|
|
2008
1790
|
restore() {
|
|
@@ -2075,8 +1857,6 @@ var VectorMixin = {
|
|
|
2075
1857
|
r = 0;
|
|
2076
1858
|
}
|
|
2077
1859
|
r = Math.min(r, 0.5 * w, 0.5 * h);
|
|
2078
|
-
|
|
2079
|
-
// amount to inset control points from corners (see `ellipse`)
|
|
2080
1860
|
const c = r * (1.0 - KAPPA);
|
|
2081
1861
|
this.moveTo(x + r, y);
|
|
2082
1862
|
this.lineTo(x + w - r, y);
|
|
@@ -2090,7 +1870,6 @@ var VectorMixin = {
|
|
|
2090
1870
|
return this.closePath();
|
|
2091
1871
|
},
|
|
2092
1872
|
ellipse(x, y, r1, r2) {
|
|
2093
|
-
// based on http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas/2173084#2173084
|
|
2094
1873
|
if (r2 == null) {
|
|
2095
1874
|
r2 = r1;
|
|
2096
1875
|
}
|
|
@@ -2120,10 +1899,8 @@ var VectorMixin = {
|
|
|
2120
1899
|
const HALF_PI = 0.5 * Math.PI;
|
|
2121
1900
|
let deltaAng = endAngle - startAngle;
|
|
2122
1901
|
if (Math.abs(deltaAng) > TWO_PI) {
|
|
2123
|
-
// draw only full circle if more than that is specified
|
|
2124
1902
|
deltaAng = TWO_PI;
|
|
2125
1903
|
} else if (deltaAng !== 0 && anticlockwise !== deltaAng < 0) {
|
|
2126
|
-
// necessary to flip direction of rendering
|
|
2127
1904
|
const dir = anticlockwise ? -1 : 1;
|
|
2128
1905
|
deltaAng = dir * TWO_PI + deltaAng;
|
|
2129
1906
|
}
|
|
@@ -2131,38 +1908,21 @@ var VectorMixin = {
|
|
|
2131
1908
|
const segAng = deltaAng / numSegs;
|
|
2132
1909
|
const handleLen = segAng / HALF_PI * KAPPA * radius;
|
|
2133
1910
|
let curAng = startAngle;
|
|
2134
|
-
|
|
2135
|
-
// component distances between anchor point and control point
|
|
2136
1911
|
let deltaCx = -Math.sin(curAng) * handleLen;
|
|
2137
1912
|
let deltaCy = Math.cos(curAng) * handleLen;
|
|
2138
|
-
|
|
2139
|
-
// anchor point
|
|
2140
1913
|
let ax = x + Math.cos(curAng) * radius;
|
|
2141
1914
|
let ay = y + Math.sin(curAng) * radius;
|
|
2142
|
-
|
|
2143
|
-
// calculate and render segments
|
|
2144
1915
|
this.moveTo(ax, ay);
|
|
2145
1916
|
for (let segIdx = 0; segIdx < numSegs; segIdx++) {
|
|
2146
|
-
// starting control point
|
|
2147
1917
|
const cp1x = ax + deltaCx;
|
|
2148
1918
|
const cp1y = ay + deltaCy;
|
|
2149
|
-
|
|
2150
|
-
// step angle
|
|
2151
1919
|
curAng += segAng;
|
|
2152
|
-
|
|
2153
|
-
// next anchor point
|
|
2154
1920
|
ax = x + Math.cos(curAng) * radius;
|
|
2155
1921
|
ay = y + Math.sin(curAng) * radius;
|
|
2156
|
-
|
|
2157
|
-
// next control point delta
|
|
2158
1922
|
deltaCx = -Math.sin(curAng) * handleLen;
|
|
2159
1923
|
deltaCy = Math.cos(curAng) * handleLen;
|
|
2160
|
-
|
|
2161
|
-
// ending control point
|
|
2162
1924
|
const cp2x = ax - deltaCx;
|
|
2163
1925
|
const cp2y = ay - deltaCy;
|
|
2164
|
-
|
|
2165
|
-
// render segment
|
|
2166
1926
|
this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, ax, ay);
|
|
2167
1927
|
}
|
|
2168
1928
|
return this;
|
|
@@ -2223,9 +1983,7 @@ var VectorMixin = {
|
|
|
2223
1983
|
return this.addContent(`W${this._windingRule(rule)} n`);
|
|
2224
1984
|
},
|
|
2225
1985
|
transform(m11, m12, m21, m22, dx, dy) {
|
|
2226
|
-
// keep track of the current transformation matrix
|
|
2227
1986
|
if (m11 === 1 && m12 === 0 && m21 === 0 && m22 === 1 && dx === 0 && dy === 0) {
|
|
2228
|
-
// Ignore identity transforms
|
|
2229
1987
|
return this;
|
|
2230
1988
|
}
|
|
2231
1989
|
const m = this._ctm;
|
|
@@ -2389,7 +2147,6 @@ class AFMFont {
|
|
|
2389
2147
|
this.boundingBoxes = {};
|
|
2390
2148
|
this.kernPairs = {};
|
|
2391
2149
|
this.parse();
|
|
2392
|
-
// todo: remove charWidths since appears to not be used
|
|
2393
2150
|
this.charWidths = new Array(256);
|
|
2394
2151
|
for (let char = 0; char <= 255; char++) {
|
|
2395
2152
|
this.charWidths[char] = this.glyphWidths[characters[char]];
|
|
@@ -2496,21 +2253,17 @@ class PDFFont {
|
|
|
2496
2253
|
return;
|
|
2497
2254
|
}
|
|
2498
2255
|
this.embed();
|
|
2499
|
-
|
|
2256
|
+
this.embedded = true;
|
|
2500
2257
|
}
|
|
2501
2258
|
embed() {
|
|
2502
2259
|
throw new Error('Must be implemented by subclasses');
|
|
2503
2260
|
}
|
|
2504
|
-
lineHeight(size, includeGap) {
|
|
2505
|
-
if (includeGap == null) {
|
|
2506
|
-
includeGap = false;
|
|
2507
|
-
}
|
|
2261
|
+
lineHeight(size, includeGap = false) {
|
|
2508
2262
|
const gap = includeGap ? this.lineGap : 0;
|
|
2509
2263
|
return (this.ascender + gap - this.descender) / 1000 * size;
|
|
2510
2264
|
}
|
|
2511
2265
|
}
|
|
2512
2266
|
|
|
2513
|
-
// This insanity is so bundlers can inline the font files
|
|
2514
2267
|
const STANDARD_FONTS = {
|
|
2515
2268
|
Courier() {
|
|
2516
2269
|
return fs.readFileSync(__dirname + '/data/Courier.afm', 'utf8');
|
|
@@ -2638,8 +2391,6 @@ class EmbeddedFont extends PDFFont {
|
|
|
2638
2391
|
}
|
|
2639
2392
|
layoutRun(text, features) {
|
|
2640
2393
|
const run = this.font.layout(text, features);
|
|
2641
|
-
|
|
2642
|
-
// Normalize position values
|
|
2643
2394
|
for (let i = 0; i < run.positions.length; i++) {
|
|
2644
2395
|
const position = run.positions[i];
|
|
2645
2396
|
for (let key in position) {
|
|
@@ -2662,16 +2413,12 @@ class EmbeddedFont extends PDFFont {
|
|
|
2662
2413
|
return run;
|
|
2663
2414
|
}
|
|
2664
2415
|
layout(text, features, onlyWidth) {
|
|
2665
|
-
// Skip the cache if any user defined features are applied
|
|
2666
2416
|
if (features) {
|
|
2667
2417
|
return this.layoutRun(text, features);
|
|
2668
2418
|
}
|
|
2669
2419
|
let glyphs = onlyWidth ? null : [];
|
|
2670
2420
|
let positions = onlyWidth ? null : [];
|
|
2671
2421
|
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
2422
|
let last = 0;
|
|
2676
2423
|
let index = 0;
|
|
2677
2424
|
while (index <= text.length) {
|
|
@@ -2733,17 +2480,15 @@ class EmbeddedFont extends PDFFont {
|
|
|
2733
2480
|
if (1 <= familyClass && familyClass <= 7) {
|
|
2734
2481
|
flags |= 1 << 1;
|
|
2735
2482
|
}
|
|
2736
|
-
flags |= 1 << 2;
|
|
2483
|
+
flags |= 1 << 2;
|
|
2737
2484
|
if (familyClass === 10) {
|
|
2738
2485
|
flags |= 1 << 3;
|
|
2739
2486
|
}
|
|
2740
2487
|
if (this.font.head.macStyle.italic) {
|
|
2741
2488
|
flags |= 1 << 6;
|
|
2742
2489
|
}
|
|
2743
|
-
|
|
2744
|
-
// generate a tag (6 uppercase letters. 17 is the char code offset from '0' to 'A'. 73 will map to 'Z')
|
|
2745
2490
|
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
|
|
2491
|
+
const name = tag + '+' + this.font.postscriptName?.replaceAll(' ', '_');
|
|
2747
2492
|
const {
|
|
2748
2493
|
bbox
|
|
2749
2494
|
} = this.font;
|
|
@@ -2758,8 +2503,7 @@ class EmbeddedFont extends PDFFont {
|
|
|
2758
2503
|
CapHeight: (this.font.capHeight || this.font.ascent) * this.scale,
|
|
2759
2504
|
XHeight: (this.font.xHeight || 0) * this.scale,
|
|
2760
2505
|
StemV: 0
|
|
2761
|
-
});
|
|
2762
|
-
|
|
2506
|
+
});
|
|
2763
2507
|
if (isCFF) {
|
|
2764
2508
|
descriptor.data.FontFile3 = fontFile;
|
|
2765
2509
|
} else {
|
|
@@ -2801,17 +2545,11 @@ class EmbeddedFont extends PDFFont {
|
|
|
2801
2545
|
};
|
|
2802
2546
|
return this.dictionary.end();
|
|
2803
2547
|
}
|
|
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
2548
|
toUnicodeCmap() {
|
|
2809
2549
|
const cmap = this.document.ref();
|
|
2810
2550
|
const entries = [];
|
|
2811
2551
|
for (let codePoints of this.unicode) {
|
|
2812
2552
|
const encoded = [];
|
|
2813
|
-
|
|
2814
|
-
// encode codePoints to utf16
|
|
2815
2553
|
for (let value of codePoints) {
|
|
2816
2554
|
if (value > 0xffff) {
|
|
2817
2555
|
value -= 0x10000;
|
|
@@ -2878,31 +2616,26 @@ class PDFFontFactory {
|
|
|
2878
2616
|
}
|
|
2879
2617
|
|
|
2880
2618
|
const isEqualFont = (font1, font2) => {
|
|
2881
|
-
// compare font checksum
|
|
2882
2619
|
if (font1.font._tables?.head?.checkSumAdjustment !== font2.font._tables?.head?.checkSumAdjustment) {
|
|
2883
2620
|
return false;
|
|
2884
2621
|
}
|
|
2885
|
-
|
|
2886
|
-
// compare font name table
|
|
2887
2622
|
if (JSON.stringify(font1.font._tables?.name?.records) !== JSON.stringify(font2.font._tables?.name?.records)) {
|
|
2888
2623
|
return false;
|
|
2889
2624
|
}
|
|
2890
2625
|
return true;
|
|
2891
2626
|
};
|
|
2892
2627
|
var FontsMixin = {
|
|
2893
|
-
initFonts(defaultFont = 'Helvetica') {
|
|
2894
|
-
// Lookup table for embedded fonts
|
|
2628
|
+
initFonts(defaultFont = 'Helvetica', defaultFontFamily = null, defaultFontSize = 12) {
|
|
2895
2629
|
this._fontFamilies = {};
|
|
2896
2630
|
this._fontCount = 0;
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
this._fontSize =
|
|
2631
|
+
this._fontSource = defaultFont;
|
|
2632
|
+
this._fontFamily = defaultFontFamily;
|
|
2633
|
+
this._fontSize = defaultFontSize;
|
|
2900
2634
|
this._font = null;
|
|
2635
|
+
this._remSize = defaultFontSize;
|
|
2901
2636
|
this._registeredFonts = {};
|
|
2902
|
-
|
|
2903
|
-
// Set the default font
|
|
2904
2637
|
if (defaultFont) {
|
|
2905
|
-
this.font(defaultFont);
|
|
2638
|
+
this.font(defaultFont, defaultFontFamily);
|
|
2906
2639
|
}
|
|
2907
2640
|
},
|
|
2908
2641
|
font(src, family, size) {
|
|
@@ -2911,8 +2644,6 @@ var FontsMixin = {
|
|
|
2911
2644
|
size = family;
|
|
2912
2645
|
family = null;
|
|
2913
2646
|
}
|
|
2914
|
-
|
|
2915
|
-
// check registered fonts if src is a string
|
|
2916
2647
|
if (typeof src === 'string' && this._registeredFonts[src]) {
|
|
2917
2648
|
cacheKey = src;
|
|
2918
2649
|
({
|
|
@@ -2925,28 +2656,21 @@ var FontsMixin = {
|
|
|
2925
2656
|
cacheKey = null;
|
|
2926
2657
|
}
|
|
2927
2658
|
}
|
|
2659
|
+
this._fontSource = src;
|
|
2660
|
+
this._fontFamily = family;
|
|
2928
2661
|
if (size != null) {
|
|
2929
2662
|
this.fontSize(size);
|
|
2930
2663
|
}
|
|
2931
|
-
|
|
2932
|
-
// fast path: check if the font is already in the PDF
|
|
2933
2664
|
if (font = this._fontFamilies[cacheKey]) {
|
|
2934
2665
|
this._font = font;
|
|
2935
2666
|
return this;
|
|
2936
2667
|
}
|
|
2937
|
-
|
|
2938
|
-
// load the font
|
|
2939
2668
|
const id = `F${++this._fontCount}`;
|
|
2940
2669
|
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
2670
|
if ((font = this._fontFamilies[this._font.name]) && isEqualFont(this._font, font)) {
|
|
2945
2671
|
this._font = font;
|
|
2946
2672
|
return this;
|
|
2947
2673
|
}
|
|
2948
|
-
|
|
2949
|
-
// save the font for reuse later
|
|
2950
2674
|
if (cacheKey) {
|
|
2951
2675
|
this._fontFamilies[cacheKey] = this._font;
|
|
2952
2676
|
}
|
|
@@ -2956,13 +2680,10 @@ var FontsMixin = {
|
|
|
2956
2680
|
return this;
|
|
2957
2681
|
},
|
|
2958
2682
|
fontSize(_fontSize) {
|
|
2959
|
-
this._fontSize = _fontSize;
|
|
2683
|
+
this._fontSize = this.sizeToPoint(_fontSize);
|
|
2960
2684
|
return this;
|
|
2961
2685
|
},
|
|
2962
2686
|
currentLineHeight(includeGap) {
|
|
2963
|
-
if (includeGap == null) {
|
|
2964
|
-
includeGap = false;
|
|
2965
|
-
}
|
|
2966
2687
|
return this._font.lineHeight(this._fontSize, includeGap);
|
|
2967
2688
|
},
|
|
2968
2689
|
registerFont(name, src, family) {
|
|
@@ -2971,6 +2692,64 @@ var FontsMixin = {
|
|
|
2971
2692
|
family
|
|
2972
2693
|
};
|
|
2973
2694
|
return this;
|
|
2695
|
+
},
|
|
2696
|
+
sizeToPoint(size, defaultValue = 0, page = this.page, percentageWidth = undefined) {
|
|
2697
|
+
if (!percentageWidth) percentageWidth = this._fontSize;
|
|
2698
|
+
if (typeof defaultValue !== 'number') defaultValue = this.sizeToPoint(defaultValue);
|
|
2699
|
+
if (size === undefined) return defaultValue;
|
|
2700
|
+
if (typeof size === 'number') return size;
|
|
2701
|
+
if (typeof size === 'boolean') return Number(size);
|
|
2702
|
+
const match = String(size).match(/((\d+)?(\.\d+)?)(em|in|px|cm|mm|pc|ex|ch|rem|vw|vh|vmin|vmax|%|pt)?/);
|
|
2703
|
+
if (!match) throw new Error(`Unsupported size '${size}'`);
|
|
2704
|
+
let multiplier;
|
|
2705
|
+
switch (match[4]) {
|
|
2706
|
+
case 'em':
|
|
2707
|
+
multiplier = this._fontSize;
|
|
2708
|
+
break;
|
|
2709
|
+
case 'in':
|
|
2710
|
+
multiplier = IN_TO_PT;
|
|
2711
|
+
break;
|
|
2712
|
+
case 'px':
|
|
2713
|
+
multiplier = PX_TO_IN * IN_TO_PT;
|
|
2714
|
+
break;
|
|
2715
|
+
case 'cm':
|
|
2716
|
+
multiplier = CM_TO_IN * IN_TO_PT;
|
|
2717
|
+
break;
|
|
2718
|
+
case 'mm':
|
|
2719
|
+
multiplier = MM_TO_CM * CM_TO_IN * IN_TO_PT;
|
|
2720
|
+
break;
|
|
2721
|
+
case 'pc':
|
|
2722
|
+
multiplier = PC_TO_PT;
|
|
2723
|
+
break;
|
|
2724
|
+
case 'ex':
|
|
2725
|
+
multiplier = this.currentLineHeight();
|
|
2726
|
+
break;
|
|
2727
|
+
case 'ch':
|
|
2728
|
+
multiplier = this.widthOfString('0');
|
|
2729
|
+
break;
|
|
2730
|
+
case 'rem':
|
|
2731
|
+
multiplier = this._remSize;
|
|
2732
|
+
break;
|
|
2733
|
+
case 'vw':
|
|
2734
|
+
multiplier = page.width / 100;
|
|
2735
|
+
break;
|
|
2736
|
+
case 'vh':
|
|
2737
|
+
multiplier = page.height / 100;
|
|
2738
|
+
break;
|
|
2739
|
+
case 'vmin':
|
|
2740
|
+
multiplier = Math.min(page.width, page.height) / 100;
|
|
2741
|
+
break;
|
|
2742
|
+
case 'vmax':
|
|
2743
|
+
multiplier = Math.max(page.width, page.height) / 100;
|
|
2744
|
+
break;
|
|
2745
|
+
case '%':
|
|
2746
|
+
multiplier = percentageWidth / 100;
|
|
2747
|
+
break;
|
|
2748
|
+
case 'pt':
|
|
2749
|
+
default:
|
|
2750
|
+
multiplier = 1;
|
|
2751
|
+
}
|
|
2752
|
+
return multiplier * Number(match[1]);
|
|
2974
2753
|
}
|
|
2975
2754
|
};
|
|
2976
2755
|
|
|
@@ -2985,7 +2764,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2985
2764
|
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
2986
2765
|
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
2987
2766
|
this.columns = options.columns || 1;
|
|
2988
|
-
this.columnGap = (options.columnGap != null ? options.columnGap : 18) * this.horizontalScaling / 100;
|
|
2767
|
+
this.columnGap = (options.columnGap != null ? options.columnGap : 18) * this.horizontalScaling / 100;
|
|
2989
2768
|
this.lineWidth = (options.width * this.horizontalScaling / 100 - this.columnGap * (this.columns - 1)) / this.columns;
|
|
2990
2769
|
this.spaceLeft = this.lineWidth;
|
|
2991
2770
|
this.startX = this.document.x;
|
|
@@ -2994,44 +2773,30 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2994
2773
|
this.ellipsis = options.ellipsis;
|
|
2995
2774
|
this.continuedX = 0;
|
|
2996
2775
|
this.features = options.features;
|
|
2997
|
-
|
|
2998
|
-
// calculate the maximum Y position the text can appear at
|
|
2999
2776
|
if (options.height != null) {
|
|
3000
2777
|
this.height = options.height;
|
|
3001
|
-
this.maxY = this.startY + options.height;
|
|
2778
|
+
this.maxY = PDFNumber(this.startY + options.height);
|
|
3002
2779
|
} else {
|
|
3003
|
-
this.maxY = this.document.page.maxY();
|
|
2780
|
+
this.maxY = PDFNumber(this.document.page.maxY());
|
|
3004
2781
|
}
|
|
3005
|
-
|
|
3006
|
-
// handle paragraph indents
|
|
3007
2782
|
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
2783
|
const indent = this.continuedX || this.indent;
|
|
3012
2784
|
this.document.x += indent;
|
|
3013
2785
|
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
2786
|
if (options.indentAllLines) {
|
|
3018
2787
|
return;
|
|
3019
2788
|
}
|
|
3020
|
-
|
|
3021
|
-
// otherwise we start the next line without indent
|
|
3022
|
-
return this.once('line', () => {
|
|
2789
|
+
this.once('line', () => {
|
|
3023
2790
|
this.document.x -= indent;
|
|
3024
2791
|
this.lineWidth += indent;
|
|
3025
2792
|
if (options.continued && !this.continuedX) {
|
|
3026
2793
|
this.continuedX = this.indent;
|
|
3027
2794
|
}
|
|
3028
2795
|
if (!options.continued) {
|
|
3029
|
-
|
|
2796
|
+
this.continuedX = 0;
|
|
3030
2797
|
}
|
|
3031
2798
|
});
|
|
3032
2799
|
});
|
|
3033
|
-
|
|
3034
|
-
// handle left aligning last lines of paragraphs
|
|
3035
2800
|
this.on('lastLine', options => {
|
|
3036
2801
|
const {
|
|
3037
2802
|
align
|
|
@@ -3040,7 +2805,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3040
2805
|
options.align = 'left';
|
|
3041
2806
|
}
|
|
3042
2807
|
this.lastLine = true;
|
|
3043
|
-
|
|
2808
|
+
this.once('line', () => {
|
|
3044
2809
|
this.document.y += options.paragraphGap || 0;
|
|
3045
2810
|
options.align = align;
|
|
3046
2811
|
return this.lastLine = false;
|
|
@@ -3057,7 +2822,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3057
2822
|
return w + this.wordWidth(HYPHEN) <= this.spaceLeft;
|
|
3058
2823
|
}
|
|
3059
2824
|
eachWord(text, fn) {
|
|
3060
|
-
// setup a unicode line breaker
|
|
3061
2825
|
let bk;
|
|
3062
2826
|
const breaker = new LineBreaker(text);
|
|
3063
2827
|
let last = null;
|
|
@@ -3066,19 +2830,12 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3066
2830
|
var shouldContinue;
|
|
3067
2831
|
let word = text.slice((last != null ? last.position : undefined) || 0, bk.position);
|
|
3068
2832
|
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
2833
|
if (w > this.lineWidth + this.continuedX) {
|
|
3073
|
-
// make some fake break objects
|
|
3074
2834
|
let lbk = last;
|
|
3075
2835
|
const fbk = {};
|
|
3076
2836
|
while (word.length) {
|
|
3077
|
-
// fit as much of the word as possible into the space we have
|
|
3078
2837
|
var l, mightGrow;
|
|
3079
2838
|
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
2839
|
l = Math.ceil(this.spaceLeft / (w / word.length));
|
|
3083
2840
|
w = this.wordWidth(word.slice(0, l));
|
|
3084
2841
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
@@ -3086,7 +2843,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3086
2843
|
l = word.length;
|
|
3087
2844
|
}
|
|
3088
2845
|
let mustShrink = w > this.spaceLeft && l > 0;
|
|
3089
|
-
// shrink or grow word as necessary after our near-guess above
|
|
3090
2846
|
while (mustShrink || mightGrow) {
|
|
3091
2847
|
if (mustShrink) {
|
|
3092
2848
|
w = this.wordWidth(word.slice(0, --l));
|
|
@@ -3097,20 +2853,14 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3097
2853
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
3098
2854
|
}
|
|
3099
2855
|
}
|
|
3100
|
-
|
|
3101
|
-
// check for the edge case where a single character cannot fit into a line.
|
|
3102
2856
|
if (l === 0 && this.spaceLeft === this.lineWidth) {
|
|
3103
2857
|
l = 1;
|
|
3104
2858
|
}
|
|
3105
|
-
|
|
3106
|
-
// send a required break unless this is the last piece and a linebreak is not specified
|
|
3107
2859
|
fbk.required = bk.required || l < word.length;
|
|
3108
2860
|
shouldContinue = fn(word.slice(0, l), w, fbk, lbk);
|
|
3109
2861
|
lbk = {
|
|
3110
2862
|
required: false
|
|
3111
2863
|
};
|
|
3112
|
-
|
|
3113
|
-
// get the remaining piece of the word
|
|
3114
2864
|
word = word.slice(l);
|
|
3115
2865
|
w = this.wordWidth(word);
|
|
3116
2866
|
if (shouldContinue === false) {
|
|
@@ -3118,7 +2868,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3118
2868
|
}
|
|
3119
2869
|
}
|
|
3120
2870
|
} else {
|
|
3121
|
-
// otherwise just emit the break as it was given to us
|
|
3122
2871
|
shouldContinue = fn(word, w, bk, last);
|
|
3123
2872
|
}
|
|
3124
2873
|
if (shouldContinue === false) {
|
|
@@ -3128,7 +2877,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3128
2877
|
}
|
|
3129
2878
|
}
|
|
3130
2879
|
wrap(text, options) {
|
|
3131
|
-
// override options from previous continued fragments
|
|
3132
2880
|
this.horizontalScaling = options.horizontalScaling || 100;
|
|
3133
2881
|
if (options.indent != null) {
|
|
3134
2882
|
this.indent = options.indent * this.horizontalScaling / 100;
|
|
@@ -3142,10 +2890,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3142
2890
|
if (options.ellipsis != null) {
|
|
3143
2891
|
this.ellipsis = options.ellipsis;
|
|
3144
2892
|
}
|
|
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
2893
|
const nextY = this.document.y + this.document.currentLineHeight(true);
|
|
3150
2894
|
if (this.document.y > this.maxY || nextY > this.maxY) {
|
|
3151
2895
|
this.nextSection();
|
|
@@ -3156,7 +2900,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3156
2900
|
let lc = 0;
|
|
3157
2901
|
let {
|
|
3158
2902
|
y
|
|
3159
|
-
} = this.document;
|
|
2903
|
+
} = this.document;
|
|
3160
2904
|
const emitLine = () => {
|
|
3161
2905
|
options.textWidth = textWidth + this.wordSpacing * (wc - 1);
|
|
3162
2906
|
options.wordCount = wc;
|
|
@@ -3179,23 +2923,17 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3179
2923
|
wc++;
|
|
3180
2924
|
}
|
|
3181
2925
|
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
2926
|
const lh = this.document.currentLineHeight(true);
|
|
3185
|
-
if (this.height != null && this.ellipsis && this.document.y + lh * 2 > this.maxY && this.column >= this.columns) {
|
|
2927
|
+
if (this.height != null && this.ellipsis && PDFNumber(this.document.y + lh * 2) > this.maxY && this.column >= this.columns) {
|
|
3186
2928
|
if (this.ellipsis === true) {
|
|
3187
2929
|
this.ellipsis = '…';
|
|
3188
|
-
}
|
|
2930
|
+
}
|
|
3189
2931
|
buffer = buffer.replace(/\s+$/, '');
|
|
3190
2932
|
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
2933
|
while (buffer && textWidth > this.lineWidth) {
|
|
3195
2934
|
buffer = buffer.slice(0, -1).replace(/\s+$/, '');
|
|
3196
2935
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3197
2936
|
}
|
|
3198
|
-
// need to add ellipsis only if there is enough space for it
|
|
3199
2937
|
if (textWidth <= this.lineWidth) {
|
|
3200
2938
|
buffer = buffer + this.ellipsis;
|
|
3201
2939
|
}
|
|
@@ -3210,35 +2948,25 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3210
2948
|
}
|
|
3211
2949
|
this.emit('lastLine', options, this);
|
|
3212
2950
|
}
|
|
3213
|
-
|
|
3214
|
-
// Previous entry is a soft hyphen - add visible hyphen.
|
|
3215
2951
|
if (buffer[buffer.length - 1] == SOFT_HYPHEN) {
|
|
3216
2952
|
buffer = buffer.slice(0, -1) + HYPHEN;
|
|
3217
2953
|
this.spaceLeft -= this.wordWidth(HYPHEN);
|
|
3218
2954
|
}
|
|
3219
2955
|
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) {
|
|
2956
|
+
if (PDFNumber(this.document.y + lh) > this.maxY) {
|
|
3224
2957
|
const shouldContinue = this.nextSection();
|
|
3225
|
-
|
|
3226
|
-
// stop if we reached the maximum height
|
|
3227
2958
|
if (!shouldContinue) {
|
|
3228
2959
|
wc = 0;
|
|
3229
2960
|
buffer = '';
|
|
3230
2961
|
return false;
|
|
3231
2962
|
}
|
|
3232
2963
|
}
|
|
3233
|
-
|
|
3234
|
-
// reset the space left and buffer
|
|
3235
2964
|
if (bk.required) {
|
|
3236
2965
|
this.spaceLeft = this.lineWidth;
|
|
3237
2966
|
buffer = '';
|
|
3238
2967
|
textWidth = 0;
|
|
3239
2968
|
return wc = 0;
|
|
3240
2969
|
} else {
|
|
3241
|
-
// reset the space left and buffer
|
|
3242
2970
|
this.spaceLeft = this.lineWidth - w;
|
|
3243
2971
|
buffer = word;
|
|
3244
2972
|
textWidth = w;
|
|
@@ -3253,25 +2981,19 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3253
2981
|
emitLine();
|
|
3254
2982
|
}
|
|
3255
2983
|
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
2984
|
if (options.continued === true) {
|
|
3261
2985
|
if (lc > 1) {
|
|
3262
2986
|
this.continuedX = 0;
|
|
3263
2987
|
}
|
|
3264
2988
|
this.continuedX += options.textWidth || 0;
|
|
3265
|
-
|
|
2989
|
+
this.document.y = y;
|
|
3266
2990
|
} else {
|
|
3267
|
-
|
|
2991
|
+
this.document.x = this.startX;
|
|
3268
2992
|
}
|
|
3269
2993
|
}
|
|
3270
2994
|
nextSection(options) {
|
|
3271
2995
|
this.emit('sectionEnd', options, this);
|
|
3272
2996
|
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
2997
|
if (this.height != null) {
|
|
3276
2998
|
return false;
|
|
3277
2999
|
}
|
|
@@ -3300,10 +3022,9 @@ const {
|
|
|
3300
3022
|
var TextMixin = {
|
|
3301
3023
|
initText() {
|
|
3302
3024
|
this._line = this._line.bind(this);
|
|
3303
|
-
// Current coordinates
|
|
3304
3025
|
this.x = 0;
|
|
3305
3026
|
this.y = 0;
|
|
3306
|
-
|
|
3027
|
+
this._lineGap = 0;
|
|
3307
3028
|
},
|
|
3308
3029
|
lineGap(_lineGap) {
|
|
3309
3030
|
this._lineGap = _lineGap;
|
|
@@ -3325,11 +3046,7 @@ var TextMixin = {
|
|
|
3325
3046
|
},
|
|
3326
3047
|
_text(text, x, y, options, lineCallback) {
|
|
3327
3048
|
options = this._initOptions(x, y, options);
|
|
3328
|
-
|
|
3329
|
-
// Convert text to a string
|
|
3330
3049
|
text = text == null ? '' : `${text}`;
|
|
3331
|
-
|
|
3332
|
-
// if the wordSpacing option is specified, remove multiple consecutive spaces
|
|
3333
3050
|
if (options.wordSpacing) {
|
|
3334
3051
|
text = text.replace(/\s{2,}/g, ' ');
|
|
3335
3052
|
}
|
|
@@ -3338,8 +3055,12 @@ var TextMixin = {
|
|
|
3338
3055
|
options.structParent.add(this.struct(options.structType || 'P', [this.markStructureContent(options.structType || 'P')]));
|
|
3339
3056
|
}
|
|
3340
3057
|
};
|
|
3341
|
-
|
|
3342
|
-
|
|
3058
|
+
if (options.rotation !== 0) {
|
|
3059
|
+
this.save();
|
|
3060
|
+
this.rotate(-options.rotation, {
|
|
3061
|
+
origin: [this.x, this.y]
|
|
3062
|
+
});
|
|
3063
|
+
}
|
|
3343
3064
|
if (options.width) {
|
|
3344
3065
|
let wrapper = this._wrapper;
|
|
3345
3066
|
if (!wrapper) {
|
|
@@ -3350,14 +3071,13 @@ var TextMixin = {
|
|
|
3350
3071
|
this._wrapper = options.continued ? wrapper : null;
|
|
3351
3072
|
this._textOptions = options.continued ? options : null;
|
|
3352
3073
|
wrapper.wrap(text, options);
|
|
3353
|
-
|
|
3354
|
-
// render paragraphs as single lines
|
|
3355
3074
|
} else {
|
|
3356
3075
|
for (let line of text.split('\n')) {
|
|
3357
3076
|
addStructure();
|
|
3358
3077
|
lineCallback(line, options);
|
|
3359
3078
|
}
|
|
3360
3079
|
}
|
|
3080
|
+
if (options.rotation !== 0) this.restore();
|
|
3361
3081
|
return this;
|
|
3362
3082
|
},
|
|
3363
3083
|
text(text, x, y, options) {
|
|
@@ -3367,17 +3087,108 @@ var TextMixin = {
|
|
|
3367
3087
|
const horizontalScaling = options.horizontalScaling || 100;
|
|
3368
3088
|
return (this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1)) * horizontalScaling / 100;
|
|
3369
3089
|
},
|
|
3090
|
+
boundsOfString(string, x, y, options) {
|
|
3091
|
+
options = this._initOptions(x, y, options);
|
|
3092
|
+
({
|
|
3093
|
+
x,
|
|
3094
|
+
y
|
|
3095
|
+
} = this);
|
|
3096
|
+
const lineGap = options.lineGap ?? this._lineGap ?? 0;
|
|
3097
|
+
const lineHeight = this.currentLineHeight(true) + lineGap;
|
|
3098
|
+
let contentWidth = 0;
|
|
3099
|
+
string = String(string ?? '');
|
|
3100
|
+
if (options.wordSpacing) {
|
|
3101
|
+
string = string.replace(/\s{2,}/g, ' ');
|
|
3102
|
+
}
|
|
3103
|
+
if (options.width) {
|
|
3104
|
+
let wrapper = new LineWrapper(this, options);
|
|
3105
|
+
wrapper.on('line', (text, options) => {
|
|
3106
|
+
this.y += lineHeight;
|
|
3107
|
+
text = text.replace(/\n/g, '');
|
|
3108
|
+
if (text.length) {
|
|
3109
|
+
let wordSpacing = options.wordSpacing ?? 0;
|
|
3110
|
+
const characterSpacing = options.characterSpacing ?? 0;
|
|
3111
|
+
if (options.width && options.align === 'justify') {
|
|
3112
|
+
const words = text.trim().split(/\s+/);
|
|
3113
|
+
const textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3114
|
+
const spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
3115
|
+
wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth);
|
|
3116
|
+
}
|
|
3117
|
+
contentWidth = Math.max(contentWidth, options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1));
|
|
3118
|
+
}
|
|
3119
|
+
});
|
|
3120
|
+
wrapper.wrap(string, options);
|
|
3121
|
+
} else {
|
|
3122
|
+
for (let line of string.split('\n')) {
|
|
3123
|
+
const lineWidth = this.widthOfString(line, options);
|
|
3124
|
+
this.y += lineHeight;
|
|
3125
|
+
contentWidth = Math.max(contentWidth, lineWidth);
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
let contentHeight = this.y - y;
|
|
3129
|
+
if (options.height) contentHeight = Math.min(contentHeight, options.height);
|
|
3130
|
+
this.x = x;
|
|
3131
|
+
this.y = y;
|
|
3132
|
+
if (options.rotation === 0) {
|
|
3133
|
+
return {
|
|
3134
|
+
x,
|
|
3135
|
+
y,
|
|
3136
|
+
width: contentWidth,
|
|
3137
|
+
height: contentHeight
|
|
3138
|
+
};
|
|
3139
|
+
} else if (options.rotation === 90) {
|
|
3140
|
+
return {
|
|
3141
|
+
x: x,
|
|
3142
|
+
y: y - contentWidth,
|
|
3143
|
+
width: contentHeight,
|
|
3144
|
+
height: contentWidth
|
|
3145
|
+
};
|
|
3146
|
+
} else if (options.rotation === 180) {
|
|
3147
|
+
return {
|
|
3148
|
+
x: x - contentWidth,
|
|
3149
|
+
y: y - contentHeight,
|
|
3150
|
+
width: contentWidth,
|
|
3151
|
+
height: contentHeight
|
|
3152
|
+
};
|
|
3153
|
+
} else if (options.rotation === 270) {
|
|
3154
|
+
return {
|
|
3155
|
+
x: x - contentHeight,
|
|
3156
|
+
y: y,
|
|
3157
|
+
width: contentHeight,
|
|
3158
|
+
height: contentWidth
|
|
3159
|
+
};
|
|
3160
|
+
}
|
|
3161
|
+
const cos = cosine(options.rotation);
|
|
3162
|
+
const sin = sine(options.rotation);
|
|
3163
|
+
const x1 = x;
|
|
3164
|
+
const y1 = y;
|
|
3165
|
+
const x2 = x + contentWidth * cos;
|
|
3166
|
+
const y2 = y - contentWidth * sin;
|
|
3167
|
+
const x3 = x + contentWidth * cos + contentHeight * sin;
|
|
3168
|
+
const y3 = y - contentWidth * sin + contentHeight * cos;
|
|
3169
|
+
const x4 = x + contentHeight * sin;
|
|
3170
|
+
const y4 = y + contentHeight * cos;
|
|
3171
|
+
const xMin = Math.min(x1, x2, x3, x4);
|
|
3172
|
+
const xMax = Math.max(x1, x2, x3, x4);
|
|
3173
|
+
const yMin = Math.min(y1, y2, y3, y4);
|
|
3174
|
+
const yMax = Math.max(y1, y2, y3, y4);
|
|
3175
|
+
return {
|
|
3176
|
+
x: xMin,
|
|
3177
|
+
y: yMin,
|
|
3178
|
+
width: xMax - xMin,
|
|
3179
|
+
height: yMax - yMin
|
|
3180
|
+
};
|
|
3181
|
+
},
|
|
3370
3182
|
heightOfString(text, options) {
|
|
3371
3183
|
const {
|
|
3372
3184
|
x,
|
|
3373
3185
|
y
|
|
3374
3186
|
} = this;
|
|
3375
3187
|
options = this._initOptions(options);
|
|
3376
|
-
options.height = Infinity;
|
|
3377
|
-
|
|
3188
|
+
options.height = Infinity;
|
|
3378
3189
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3379
3190
|
this._text(text, this.x, this.y, options, () => {
|
|
3380
|
-
|
|
3191
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3381
3192
|
});
|
|
3382
3193
|
const height = this.y - y;
|
|
3383
3194
|
this.x = x;
|
|
@@ -3475,12 +3286,12 @@ var TextMixin = {
|
|
|
3475
3286
|
wrapper.on('sectionStart', () => {
|
|
3476
3287
|
const pos = indent + itemIndent * (level - 1);
|
|
3477
3288
|
this.x += pos;
|
|
3478
|
-
|
|
3289
|
+
wrapper.lineWidth -= pos;
|
|
3479
3290
|
});
|
|
3480
3291
|
wrapper.on('sectionEnd', () => {
|
|
3481
3292
|
const pos = indent + itemIndent * (level - 1);
|
|
3482
3293
|
this.x -= pos;
|
|
3483
|
-
|
|
3294
|
+
wrapper.lineWidth += pos;
|
|
3484
3295
|
});
|
|
3485
3296
|
wrapper.wrap(listItem, options);
|
|
3486
3297
|
};
|
|
@@ -3494,11 +3305,7 @@ var TextMixin = {
|
|
|
3494
3305
|
options = x;
|
|
3495
3306
|
x = null;
|
|
3496
3307
|
}
|
|
3497
|
-
|
|
3498
|
-
// clone options object
|
|
3499
3308
|
const result = Object.assign({}, options);
|
|
3500
|
-
|
|
3501
|
-
// extend options with previous values for continued text
|
|
3502
3309
|
if (this._textOptions) {
|
|
3503
3310
|
for (let key in this._textOptions) {
|
|
3504
3311
|
const val = this._textOptions[key];
|
|
@@ -3509,16 +3316,12 @@ var TextMixin = {
|
|
|
3509
3316
|
}
|
|
3510
3317
|
}
|
|
3511
3318
|
}
|
|
3512
|
-
|
|
3513
|
-
// Update the current position
|
|
3514
3319
|
if (x != null) {
|
|
3515
3320
|
this.x = x;
|
|
3516
3321
|
}
|
|
3517
3322
|
if (y != null) {
|
|
3518
3323
|
this.y = y;
|
|
3519
3324
|
}
|
|
3520
|
-
|
|
3521
|
-
// wrap to margins if no x or y position passed
|
|
3522
3325
|
if (result.lineBreak !== false) {
|
|
3523
3326
|
if (result.width == null) {
|
|
3524
3327
|
result.width = this.page.width - this.x - this.page.margins.right;
|
|
@@ -3530,17 +3333,18 @@ var TextMixin = {
|
|
|
3530
3333
|
}
|
|
3531
3334
|
if (result.columnGap == null) {
|
|
3532
3335
|
result.columnGap = 18;
|
|
3533
|
-
}
|
|
3534
|
-
|
|
3336
|
+
}
|
|
3337
|
+
result.rotation = Number(options.rotation ?? 0) % 360;
|
|
3338
|
+
if (result.rotation < 0) result.rotation += 360;
|
|
3535
3339
|
return result;
|
|
3536
3340
|
},
|
|
3537
3341
|
_line(text, options = {}, wrapper) {
|
|
3538
3342
|
this._fragment(text, this.x, this.y, options);
|
|
3539
3343
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3540
3344
|
if (!wrapper) {
|
|
3541
|
-
|
|
3345
|
+
this.x += this.widthOfString(text, options);
|
|
3542
3346
|
} else {
|
|
3543
|
-
|
|
3347
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3544
3348
|
}
|
|
3545
3349
|
},
|
|
3546
3350
|
_fragment(text, x, y, options) {
|
|
@@ -3549,14 +3353,10 @@ var TextMixin = {
|
|
|
3549
3353
|
if (text.length === 0) {
|
|
3550
3354
|
return;
|
|
3551
3355
|
}
|
|
3552
|
-
|
|
3553
|
-
// handle options
|
|
3554
3356
|
const align = options.align || 'left';
|
|
3555
3357
|
let wordSpacing = options.wordSpacing || 0;
|
|
3556
3358
|
const characterSpacing = options.characterSpacing || 0;
|
|
3557
3359
|
const horizontalScaling = options.horizontalScaling || 100;
|
|
3558
|
-
|
|
3559
|
-
// text alignments
|
|
3560
3360
|
if (options.width) {
|
|
3561
3361
|
switch (align) {
|
|
3562
3362
|
case 'right':
|
|
@@ -3567,7 +3367,6 @@ var TextMixin = {
|
|
|
3567
3367
|
x += options.lineWidth / 2 - options.textWidth / 2;
|
|
3568
3368
|
break;
|
|
3569
3369
|
case 'justify':
|
|
3570
|
-
// calculate the word spacing value
|
|
3571
3370
|
words = text.trim().split(/\s+/);
|
|
3572
3371
|
textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3573
3372
|
var spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
@@ -3575,8 +3374,6 @@ var TextMixin = {
|
|
|
3575
3374
|
break;
|
|
3576
3375
|
}
|
|
3577
3376
|
}
|
|
3578
|
-
|
|
3579
|
-
// text baseline alignments based on http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
|
|
3580
3377
|
if (typeof options.baseline === 'number') {
|
|
3581
3378
|
dy = -options.baseline;
|
|
3582
3379
|
} else {
|
|
@@ -3609,11 +3406,7 @@ var TextMixin = {
|
|
|
3609
3406
|
}
|
|
3610
3407
|
dy = dy / 1000 * this._fontSize;
|
|
3611
3408
|
}
|
|
3612
|
-
|
|
3613
|
-
// calculate the actual rendered width of the string after word and character spacing
|
|
3614
3409
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3615
|
-
|
|
3616
|
-
// create link annotations if the link option is given
|
|
3617
3410
|
if (options.link != null) {
|
|
3618
3411
|
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);
|
|
3619
3412
|
}
|
|
@@ -3623,8 +3416,6 @@ var TextMixin = {
|
|
|
3623
3416
|
if (options.destination != null) {
|
|
3624
3417
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
3625
3418
|
}
|
|
3626
|
-
|
|
3627
|
-
// create underline
|
|
3628
3419
|
if (options.underline) {
|
|
3629
3420
|
this.save();
|
|
3630
3421
|
if (!options.stroke) {
|
|
@@ -3638,8 +3429,6 @@ var TextMixin = {
|
|
|
3638
3429
|
this.stroke();
|
|
3639
3430
|
this.restore();
|
|
3640
3431
|
}
|
|
3641
|
-
|
|
3642
|
-
// create strikethrough line
|
|
3643
3432
|
if (options.strike) {
|
|
3644
3433
|
this.save();
|
|
3645
3434
|
if (!options.stroke) {
|
|
@@ -3654,8 +3443,6 @@ var TextMixin = {
|
|
|
3654
3443
|
this.restore();
|
|
3655
3444
|
}
|
|
3656
3445
|
this.save();
|
|
3657
|
-
|
|
3658
|
-
// oblique (angle in degrees or boolean)
|
|
3659
3446
|
if (options.oblique) {
|
|
3660
3447
|
let skew;
|
|
3661
3448
|
if (typeof options.oblique === 'number') {
|
|
@@ -3667,45 +3454,24 @@ var TextMixin = {
|
|
|
3667
3454
|
this.transform(1, 0, skew, 1, -skew * dy, 0);
|
|
3668
3455
|
this.transform(1, 0, 0, 1, -x, -y);
|
|
3669
3456
|
}
|
|
3670
|
-
|
|
3671
|
-
// flip coordinate system
|
|
3672
3457
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
3673
3458
|
y = this.page.height - y - dy;
|
|
3674
|
-
|
|
3675
|
-
// add current font to page if necessary
|
|
3676
3459
|
if (this.page.fonts[this._font.id] == null) {
|
|
3677
3460
|
this.page.fonts[this._font.id] = this._font.ref();
|
|
3678
3461
|
}
|
|
3679
|
-
|
|
3680
|
-
// begin the text object
|
|
3681
3462
|
this.addContent('BT');
|
|
3682
|
-
|
|
3683
|
-
// text position
|
|
3684
3463
|
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3685
|
-
|
|
3686
|
-
// font and font size
|
|
3687
3464
|
this.addContent(`/${this._font.id} ${number(this._fontSize)} Tf`);
|
|
3688
|
-
|
|
3689
|
-
// rendering mode
|
|
3690
3465
|
const mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;
|
|
3691
3466
|
if (mode) {
|
|
3692
3467
|
this.addContent(`${mode} Tr`);
|
|
3693
3468
|
}
|
|
3694
|
-
|
|
3695
|
-
// Character spacing
|
|
3696
3469
|
if (characterSpacing) {
|
|
3697
3470
|
this.addContent(`${number(characterSpacing)} Tc`);
|
|
3698
3471
|
}
|
|
3699
|
-
|
|
3700
|
-
// Horizontal scaling
|
|
3701
3472
|
if (horizontalScaling !== 100) {
|
|
3702
3473
|
this.addContent(`${horizontalScaling} Tz`);
|
|
3703
3474
|
}
|
|
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
3475
|
if (wordSpacing) {
|
|
3710
3476
|
words = text.trim().split(/\s+/);
|
|
3711
3477
|
wordSpacing += this.widthOfString(' ') + characterSpacing;
|
|
@@ -3716,9 +3482,6 @@ var TextMixin = {
|
|
|
3716
3482
|
const [encodedWord, positionsWord] = this._font.encode(word, options.features);
|
|
3717
3483
|
encoded = encoded.concat(encodedWord);
|
|
3718
3484
|
positions = positions.concat(positionsWord);
|
|
3719
|
-
|
|
3720
|
-
// add the word spacing to the end of the word
|
|
3721
|
-
// clone object because of cache
|
|
3722
3485
|
const space = {};
|
|
3723
3486
|
const object = positions[positions.length - 1];
|
|
3724
3487
|
for (let key in object) {
|
|
@@ -3735,60 +3498,42 @@ var TextMixin = {
|
|
|
3735
3498
|
const commands = [];
|
|
3736
3499
|
let last = 0;
|
|
3737
3500
|
let hadOffset = false;
|
|
3738
|
-
|
|
3739
|
-
// Adds a segment of text to the TJ command buffer
|
|
3740
3501
|
const addSegment = cur => {
|
|
3741
3502
|
if (last < cur) {
|
|
3742
3503
|
const hex = encoded.slice(last, cur).join('');
|
|
3743
3504
|
const advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;
|
|
3744
3505
|
commands.push(`<${hex}> ${number(-advance)}`);
|
|
3745
3506
|
}
|
|
3746
|
-
|
|
3507
|
+
last = cur;
|
|
3747
3508
|
};
|
|
3748
|
-
|
|
3749
|
-
// Flushes the current TJ commands to the output stream
|
|
3750
3509
|
const flush = i => {
|
|
3751
3510
|
addSegment(i);
|
|
3752
3511
|
if (commands.length > 0) {
|
|
3753
3512
|
this.addContent(`[${commands.join(' ')}] TJ`);
|
|
3754
|
-
|
|
3513
|
+
commands.length = 0;
|
|
3755
3514
|
}
|
|
3756
3515
|
};
|
|
3757
3516
|
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
3517
|
const pos = positions[i];
|
|
3761
3518
|
if (pos.xOffset || pos.yOffset) {
|
|
3762
|
-
// Flush the current buffer
|
|
3763
3519
|
flush(i);
|
|
3764
|
-
|
|
3765
|
-
// Move the text position and flush just the current character
|
|
3766
3520
|
this.addContent(`1 0 0 1 ${number(x + pos.xOffset * scale)} ${number(y + pos.yOffset * scale)} Tm`);
|
|
3767
3521
|
flush(i + 1);
|
|
3768
3522
|
hadOffset = true;
|
|
3769
3523
|
} else {
|
|
3770
|
-
// If the last character had an offset, reset the text position
|
|
3771
3524
|
if (hadOffset) {
|
|
3772
3525
|
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3773
3526
|
hadOffset = false;
|
|
3774
3527
|
}
|
|
3775
|
-
|
|
3776
|
-
// Group segments that don't have any advance adjustments
|
|
3777
3528
|
if (pos.xAdvance - pos.advanceWidth !== 0) {
|
|
3778
3529
|
addSegment(i + 1);
|
|
3779
3530
|
}
|
|
3780
3531
|
}
|
|
3781
3532
|
x += pos.xAdvance * scale;
|
|
3782
3533
|
}
|
|
3783
|
-
|
|
3784
|
-
// Flush any remaining commands
|
|
3785
3534
|
flush(i);
|
|
3786
|
-
|
|
3787
|
-
// end the text object
|
|
3788
3535
|
this.addContent('ET');
|
|
3789
|
-
|
|
3790
|
-
// restore flipped coordinate system
|
|
3791
|
-
return this.restore();
|
|
3536
|
+
this.restore();
|
|
3792
3537
|
}
|
|
3793
3538
|
};
|
|
3794
3539
|
|
|
@@ -3806,8 +3551,6 @@ class JPEG {
|
|
|
3806
3551
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3807
3552
|
throw 'SOI not found in JPEG';
|
|
3808
3553
|
}
|
|
3809
|
-
|
|
3810
|
-
// Parse the EXIF orientation
|
|
3811
3554
|
this.orientation = exif.fromBuffer(this.data).Orientation || 1;
|
|
3812
3555
|
let pos = 2;
|
|
3813
3556
|
while (pos < this.data.length) {
|
|
@@ -3844,16 +3587,10 @@ class JPEG {
|
|
|
3844
3587
|
ColorSpace: this.colorSpace,
|
|
3845
3588
|
Filter: 'DCTDecode'
|
|
3846
3589
|
});
|
|
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
3590
|
if (this.colorSpace === 'DeviceCMYK') {
|
|
3852
3591
|
this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];
|
|
3853
3592
|
}
|
|
3854
3593
|
this.obj.end(this.data);
|
|
3855
|
-
|
|
3856
|
-
// free memory
|
|
3857
3594
|
return this.data = null;
|
|
3858
3595
|
}
|
|
3859
3596
|
}
|
|
@@ -3896,24 +3633,14 @@ class PNGImage {
|
|
|
3896
3633
|
if (this.image.palette.length === 0) {
|
|
3897
3634
|
this.obj.data['ColorSpace'] = this.image.colorSpace;
|
|
3898
3635
|
} else {
|
|
3899
|
-
// embed the color palette in the PDF as an object stream
|
|
3900
3636
|
const palette = this.document.ref();
|
|
3901
3637
|
palette.end(Buffer.from(this.image.palette));
|
|
3902
|
-
|
|
3903
|
-
// build the color space array for the image
|
|
3904
3638
|
this.obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', this.image.palette.length / 3 - 1, palette];
|
|
3905
3639
|
}
|
|
3906
|
-
|
|
3907
|
-
// For PNG color types 0, 2 and 3, the transparency data is stored in
|
|
3908
|
-
// a dedicated PNG chunk.
|
|
3909
3640
|
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
3641
|
const val = this.image.transparency.grayscale;
|
|
3913
3642
|
this.obj.data['Mask'] = [val, val];
|
|
3914
3643
|
} 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
3644
|
const {
|
|
3918
3645
|
rgb
|
|
3919
3646
|
} = this.image.transparency;
|
|
@@ -3923,14 +3650,9 @@ class PNGImage {
|
|
|
3923
3650
|
}
|
|
3924
3651
|
this.obj.data['Mask'] = mask;
|
|
3925
3652
|
} 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
3653
|
dataDecoded = true;
|
|
3929
3654
|
return this.loadIndexedAlphaChannel();
|
|
3930
3655
|
} 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
3656
|
dataDecoded = true;
|
|
3935
3657
|
return this.splitAlphaChannel();
|
|
3936
3658
|
}
|
|
@@ -3954,11 +3676,7 @@ class PNGImage {
|
|
|
3954
3676
|
sMask.end(this.alphaChannel);
|
|
3955
3677
|
this.obj.data['SMask'] = sMask;
|
|
3956
3678
|
}
|
|
3957
|
-
|
|
3958
|
-
// add the actual image data
|
|
3959
3679
|
this.obj.end(this.imgData);
|
|
3960
|
-
|
|
3961
|
-
// free memory
|
|
3962
3680
|
this.image = null;
|
|
3963
3681
|
return this.imgData = null;
|
|
3964
3682
|
}
|
|
@@ -3971,7 +3689,6 @@ class PNGImage {
|
|
|
3971
3689
|
const alphaChannel = Buffer.alloc(pixelCount);
|
|
3972
3690
|
let i = p = a = 0;
|
|
3973
3691
|
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
3692
|
const skipByteCount = this.image.bits === 16 ? 1 : 0;
|
|
3976
3693
|
while (i < len) {
|
|
3977
3694
|
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
|
|
@@ -4006,10 +3723,6 @@ class PNGImage {
|
|
|
4006
3723
|
}
|
|
4007
3724
|
}
|
|
4008
3725
|
|
|
4009
|
-
/*
|
|
4010
|
-
PDFImage - embeds images in PDF documents
|
|
4011
|
-
By Devon Govett
|
|
4012
|
-
*/
|
|
4013
3726
|
class PDFImage {
|
|
4014
3727
|
static open(src, label) {
|
|
4015
3728
|
let data;
|
|
@@ -4041,17 +3754,16 @@ class PDFImage {
|
|
|
4041
3754
|
var ImagesMixin = {
|
|
4042
3755
|
initImages() {
|
|
4043
3756
|
this._imageRegistry = {};
|
|
4044
|
-
|
|
3757
|
+
this._imageCount = 0;
|
|
4045
3758
|
},
|
|
4046
3759
|
image(src, x, y, options = {}) {
|
|
4047
|
-
let bh, bp, bw, image, ip, left, left1,
|
|
3760
|
+
let bh, bp, bw, image, ip, left, left1, originX, originY;
|
|
4048
3761
|
if (typeof x === 'object') {
|
|
4049
3762
|
options = x;
|
|
4050
3763
|
x = null;
|
|
4051
3764
|
}
|
|
4052
|
-
|
|
4053
|
-
// Ignore orientation based on document options or image options
|
|
4054
3765
|
const ignoreOrientation = options.ignoreOrientation || options.ignoreOrientation !== false && this.options.ignoreOrientation;
|
|
3766
|
+
const inDocumentFlow = typeof y !== 'number';
|
|
4055
3767
|
x = (left = x != null ? x : options.x) != null ? left : this.x;
|
|
4056
3768
|
y = (left1 = y != null ? y : options.y) != null ? left1 : this.y;
|
|
4057
3769
|
if (typeof src === 'string') {
|
|
@@ -4074,8 +3786,6 @@ var ImagesMixin = {
|
|
|
4074
3786
|
width,
|
|
4075
3787
|
height
|
|
4076
3788
|
} = image;
|
|
4077
|
-
|
|
4078
|
-
// If EXIF orientation calls for it, swap width and height
|
|
4079
3789
|
if (!ignoreOrientation && image.orientation > 4) {
|
|
4080
3790
|
[width, height] = [height, width];
|
|
4081
3791
|
}
|
|
@@ -4127,80 +3837,70 @@ var ImagesMixin = {
|
|
|
4127
3837
|
y = y + bh - h;
|
|
4128
3838
|
}
|
|
4129
3839
|
}
|
|
3840
|
+
let rotateAngle = 0;
|
|
3841
|
+
let xTransform = x;
|
|
3842
|
+
let yTransform = y;
|
|
3843
|
+
let hTransform = h;
|
|
3844
|
+
let wTransform = w;
|
|
4130
3845
|
if (!ignoreOrientation) {
|
|
4131
3846
|
switch (image.orientation) {
|
|
4132
|
-
// No orientation (need to flip image, though, because of the default transform matrix on the document)
|
|
4133
3847
|
default:
|
|
4134
3848
|
case 1:
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
rotateAngle = 0;
|
|
3849
|
+
hTransform = -h;
|
|
3850
|
+
yTransform += h;
|
|
4138
3851
|
break;
|
|
4139
|
-
// Flip Horizontal
|
|
4140
3852
|
case 2:
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
rotateAngle = 0;
|
|
3853
|
+
wTransform = -w;
|
|
3854
|
+
hTransform = -h;
|
|
3855
|
+
xTransform += w;
|
|
3856
|
+
yTransform += h;
|
|
4146
3857
|
break;
|
|
4147
|
-
// Rotate 180 degrees
|
|
4148
3858
|
case 3:
|
|
4149
3859
|
originX = x;
|
|
4150
3860
|
originY = y;
|
|
4151
|
-
|
|
4152
|
-
|
|
3861
|
+
hTransform = -h;
|
|
3862
|
+
xTransform -= w;
|
|
4153
3863
|
rotateAngle = 180;
|
|
4154
3864
|
break;
|
|
4155
|
-
// Flip vertical
|
|
4156
3865
|
case 4:
|
|
4157
|
-
// Do nothing, image will be flipped
|
|
4158
|
-
|
|
4159
3866
|
break;
|
|
4160
|
-
// Flip horizontally and rotate 270 degrees CW
|
|
4161
3867
|
case 5:
|
|
4162
3868
|
originX = x;
|
|
4163
3869
|
originY = y;
|
|
4164
|
-
|
|
4165
|
-
|
|
3870
|
+
wTransform = h;
|
|
3871
|
+
hTransform = w;
|
|
3872
|
+
yTransform -= hTransform;
|
|
4166
3873
|
rotateAngle = 90;
|
|
4167
3874
|
break;
|
|
4168
|
-
// Rotate 90 degrees CW
|
|
4169
3875
|
case 6:
|
|
4170
3876
|
originX = x;
|
|
4171
3877
|
originY = y;
|
|
4172
|
-
|
|
4173
|
-
|
|
3878
|
+
wTransform = h;
|
|
3879
|
+
hTransform = -w;
|
|
4174
3880
|
rotateAngle = 90;
|
|
4175
3881
|
break;
|
|
4176
|
-
// Flip horizontally and rotate 90 degrees CW
|
|
4177
3882
|
case 7:
|
|
4178
3883
|
originX = x;
|
|
4179
3884
|
originY = y;
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
x -= w;
|
|
3885
|
+
hTransform = -w;
|
|
3886
|
+
wTransform = -h;
|
|
3887
|
+
xTransform += h;
|
|
4184
3888
|
rotateAngle = 90;
|
|
4185
3889
|
break;
|
|
4186
|
-
// Rotate 270 degrees CW
|
|
4187
3890
|
case 8:
|
|
4188
3891
|
originX = x;
|
|
4189
3892
|
originY = y;
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
3893
|
+
wTransform = h;
|
|
3894
|
+
hTransform = -w;
|
|
3895
|
+
xTransform -= h;
|
|
3896
|
+
yTransform += w;
|
|
4194
3897
|
rotateAngle = -90;
|
|
4195
3898
|
break;
|
|
4196
3899
|
}
|
|
4197
3900
|
} else {
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
rotateAngle = 0;
|
|
3901
|
+
hTransform = -h;
|
|
3902
|
+
yTransform += h;
|
|
4201
3903
|
}
|
|
4202
|
-
|
|
4203
|
-
// create link annotations if the link option is given
|
|
4204
3904
|
if (options.link != null) {
|
|
4205
3905
|
this.link(x, y, w, h, options.link);
|
|
4206
3906
|
}
|
|
@@ -4210,9 +3910,7 @@ var ImagesMixin = {
|
|
|
4210
3910
|
if (options.destination != null) {
|
|
4211
3911
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
4212
3912
|
}
|
|
4213
|
-
|
|
4214
|
-
// Set the current y position to below the image if it is in the document flow
|
|
4215
|
-
if (this.y === y) {
|
|
3913
|
+
if (inDocumentFlow) {
|
|
4216
3914
|
this.y += h;
|
|
4217
3915
|
}
|
|
4218
3916
|
this.save();
|
|
@@ -4221,7 +3919,7 @@ var ImagesMixin = {
|
|
|
4221
3919
|
origin: [originX, originY]
|
|
4222
3920
|
});
|
|
4223
3921
|
}
|
|
4224
|
-
this.transform(
|
|
3922
|
+
this.transform(wTransform, 0, 0, hTransform, xTransform, yTransform);
|
|
4225
3923
|
this.addContent(`/${image.label} Do`);
|
|
4226
3924
|
this.restore();
|
|
4227
3925
|
return this;
|
|
@@ -4247,19 +3945,17 @@ var AnnotationsMixin = {
|
|
|
4247
3945
|
options.Rect = this._convertRect(x, y, w, h);
|
|
4248
3946
|
options.Border = [0, 0, 0];
|
|
4249
3947
|
if (options.Subtype === 'Link' && typeof options.F === 'undefined') {
|
|
4250
|
-
options.F = 1 << 2;
|
|
3948
|
+
options.F = 1 << 2;
|
|
4251
3949
|
}
|
|
4252
3950
|
if (options.Subtype !== 'Link') {
|
|
4253
3951
|
if (options.C == null) {
|
|
4254
3952
|
options.C = this._normalizeColor(options.color || [0, 0, 0]);
|
|
4255
3953
|
}
|
|
4256
|
-
}
|
|
3954
|
+
}
|
|
4257
3955
|
delete options.color;
|
|
4258
3956
|
if (typeof options.Dest === 'string') {
|
|
4259
3957
|
options.Dest = new String(options.Dest);
|
|
4260
3958
|
}
|
|
4261
|
-
|
|
4262
|
-
// Capitalize keys
|
|
4263
3959
|
for (let key in options) {
|
|
4264
3960
|
const val = options[key];
|
|
4265
3961
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
@@ -4292,7 +3988,6 @@ var AnnotationsMixin = {
|
|
|
4292
3988
|
link(x, y, w, h, url, options = {}) {
|
|
4293
3989
|
options.Subtype = 'Link';
|
|
4294
3990
|
if (typeof url === 'number') {
|
|
4295
|
-
// Link to a page in the document (the page must already exist)
|
|
4296
3991
|
const pages = this._root.data.Pages.data;
|
|
4297
3992
|
if (url >= 0 && url < pages.Kids.length) {
|
|
4298
3993
|
options.A = this.ref({
|
|
@@ -4304,7 +3999,6 @@ var AnnotationsMixin = {
|
|
|
4304
3999
|
throw new Error(`The document has no page ${url}`);
|
|
4305
4000
|
}
|
|
4306
4001
|
} else {
|
|
4307
|
-
// Link to an external url
|
|
4308
4002
|
options.A = this.ref({
|
|
4309
4003
|
S: 'URI',
|
|
4310
4004
|
URI: new String(url)
|
|
@@ -4357,14 +4051,11 @@ var AnnotationsMixin = {
|
|
|
4357
4051
|
return this.annotate(x, y, w, h, options);
|
|
4358
4052
|
},
|
|
4359
4053
|
fileAnnotation(x, y, w, h, file = {}, options = {}) {
|
|
4360
|
-
// create hidden file
|
|
4361
4054
|
const filespec = this.file(file.src, Object.assign({
|
|
4362
4055
|
hidden: true
|
|
4363
4056
|
}, file));
|
|
4364
4057
|
options.Subtype = 'FileAttachment';
|
|
4365
4058
|
options.FS = filespec;
|
|
4366
|
-
|
|
4367
|
-
// add description from filespec unless description (Contents) has already been set
|
|
4368
4059
|
if (options.Contents) {
|
|
4369
4060
|
options.Contents = new String(options.Contents);
|
|
4370
4061
|
} else if (filespec.data.Desc) {
|
|
@@ -4373,14 +4064,9 @@ var AnnotationsMixin = {
|
|
|
4373
4064
|
return this.annotate(x, y, w, h, options);
|
|
4374
4065
|
},
|
|
4375
4066
|
_convertRect(x1, y1, w, h) {
|
|
4376
|
-
// flip y1 and y2
|
|
4377
4067
|
let y2 = y1;
|
|
4378
4068
|
y1 += h;
|
|
4379
|
-
|
|
4380
|
-
// make x2
|
|
4381
4069
|
let x2 = x1 + w;
|
|
4382
|
-
|
|
4383
|
-
// apply current transformation matrix to points
|
|
4384
4070
|
const [m0, m1, m2, m3, m4, m5] = this._ctm;
|
|
4385
4071
|
x1 = m0 * x1 + m2 * y1 + m4;
|
|
4386
4072
|
y1 = m1 * x1 + m3 * y1 + m5;
|
|
@@ -4442,7 +4128,7 @@ class PDFOutline {
|
|
|
4442
4128
|
|
|
4443
4129
|
var OutlineMixin = {
|
|
4444
4130
|
initOutline() {
|
|
4445
|
-
|
|
4131
|
+
this.outline = new PDFOutline(this, null, null, null);
|
|
4446
4132
|
},
|
|
4447
4133
|
endOutline() {
|
|
4448
4134
|
this.outline.endOutline();
|
|
@@ -4453,11 +4139,6 @@ var OutlineMixin = {
|
|
|
4453
4139
|
}
|
|
4454
4140
|
};
|
|
4455
4141
|
|
|
4456
|
-
/*
|
|
4457
|
-
PDFStructureContent - a reference to a marked structure content
|
|
4458
|
-
By Ben Schmidt
|
|
4459
|
-
*/
|
|
4460
|
-
|
|
4461
4142
|
class PDFStructureContent {
|
|
4462
4143
|
constructor(pageRef, mcid) {
|
|
4463
4144
|
this.refs = [{
|
|
@@ -4470,10 +4151,6 @@ class PDFStructureContent {
|
|
|
4470
4151
|
}
|
|
4471
4152
|
}
|
|
4472
4153
|
|
|
4473
|
-
/*
|
|
4474
|
-
PDFStructureElement - represents an element in the PDF logical structure tree
|
|
4475
|
-
By Ben Schmidt
|
|
4476
|
-
*/
|
|
4477
4154
|
class PDFStructureElement {
|
|
4478
4155
|
constructor(document, type, options = {}, children = null) {
|
|
4479
4156
|
this.document = document;
|
|
@@ -4481,7 +4158,6 @@ class PDFStructureElement {
|
|
|
4481
4158
|
this._ended = false;
|
|
4482
4159
|
this._flushed = false;
|
|
4483
4160
|
this.dictionary = document.ref({
|
|
4484
|
-
// Type: "StructElem",
|
|
4485
4161
|
S: type
|
|
4486
4162
|
});
|
|
4487
4163
|
const data = this.dictionary.data;
|
|
@@ -4530,7 +4206,6 @@ class PDFStructureElement {
|
|
|
4530
4206
|
this._addContentToParentTree(child);
|
|
4531
4207
|
}
|
|
4532
4208
|
if (typeof child === 'function' && this._attached) {
|
|
4533
|
-
// _contentForClosure() adds the content to the parent tree
|
|
4534
4209
|
child = this._contentForClosure(child);
|
|
4535
4210
|
}
|
|
4536
4211
|
this._children.push(child);
|
|
@@ -4606,10 +4281,6 @@ class PDFStructureElement {
|
|
|
4606
4281
|
this.dictionary.data.K = [];
|
|
4607
4282
|
this._children.forEach(child => this._flushChild(child));
|
|
4608
4283
|
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
4284
|
this._children = [];
|
|
4614
4285
|
this.dictionary.data.K = null;
|
|
4615
4286
|
this._flushed = true;
|
|
@@ -4630,7 +4301,7 @@ class PDFStructureElement {
|
|
|
4630
4301
|
this.dictionary.data.K.push(mcid);
|
|
4631
4302
|
} else {
|
|
4632
4303
|
this.dictionary.data.K.push({
|
|
4633
|
-
Type:
|
|
4304
|
+
Type: 'MCR',
|
|
4634
4305
|
Pg: pageRef,
|
|
4635
4306
|
MCID: mcid
|
|
4636
4307
|
});
|
|
@@ -4640,25 +4311,18 @@ class PDFStructureElement {
|
|
|
4640
4311
|
}
|
|
4641
4312
|
}
|
|
4642
4313
|
|
|
4643
|
-
/*
|
|
4644
|
-
PDFNumberTree - represents a number tree object
|
|
4645
|
-
*/
|
|
4646
4314
|
class PDFNumberTree extends PDFTree {
|
|
4647
4315
|
_compareKeys(a, b) {
|
|
4648
4316
|
return parseInt(a) - parseInt(b);
|
|
4649
4317
|
}
|
|
4650
4318
|
_keysName() {
|
|
4651
|
-
return
|
|
4319
|
+
return 'Nums';
|
|
4652
4320
|
}
|
|
4653
4321
|
_dataForKey(k) {
|
|
4654
4322
|
return parseInt(k);
|
|
4655
4323
|
}
|
|
4656
4324
|
}
|
|
4657
4325
|
|
|
4658
|
-
/*
|
|
4659
|
-
Markings mixin - support marked content sequences in content streams
|
|
4660
|
-
By Ben Schmidt
|
|
4661
|
-
*/
|
|
4662
4326
|
var MarkingsMixin = {
|
|
4663
4327
|
initMarkings(options) {
|
|
4664
4328
|
this.structChildren = [];
|
|
@@ -4794,7 +4458,6 @@ var MarkingsMixin = {
|
|
|
4794
4458
|
return this.getStructTreeRoot().data.ParentTree;
|
|
4795
4459
|
},
|
|
4796
4460
|
createStructParentTreeNextKey() {
|
|
4797
|
-
// initialise the MarkInfo dictionary
|
|
4798
4461
|
this.getMarkInfoDictionary();
|
|
4799
4462
|
const structTreeRoot = this.getStructTreeRoot();
|
|
4800
4463
|
const key = structTreeRoot.data.ParentTreeNextKey++;
|
|
@@ -4858,10 +4521,6 @@ const FORMAT_DEFAULT = {
|
|
|
4858
4521
|
}
|
|
4859
4522
|
};
|
|
4860
4523
|
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
4524
|
initForm() {
|
|
4866
4525
|
if (!this._font) {
|
|
4867
4526
|
throw new Error('Must set a font before calling initForm method');
|
|
@@ -4884,9 +4543,6 @@ var AcroFormMixin = {
|
|
|
4884
4543
|
this._root.data.AcroForm = AcroForm;
|
|
4885
4544
|
return this;
|
|
4886
4545
|
},
|
|
4887
|
-
/**
|
|
4888
|
-
* Called automatically by document.js
|
|
4889
|
-
*/
|
|
4890
4546
|
endAcroForm() {
|
|
4891
4547
|
if (this._root.data.AcroForm) {
|
|
4892
4548
|
if (!Object.keys(this._acroform.fonts).length && !this._acroform.defaultFont) {
|
|
@@ -4912,38 +4568,18 @@ var AcroFormMixin = {
|
|
|
4912
4568
|
}
|
|
4913
4569
|
return this;
|
|
4914
4570
|
},
|
|
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
4571
|
formField(name, options = {}) {
|
|
4923
4572
|
let fieldDict = this._fieldDict(name, null, options);
|
|
4924
4573
|
let fieldRef = this.ref(fieldDict);
|
|
4925
4574
|
this._addToParent(fieldRef);
|
|
4926
4575
|
return fieldRef;
|
|
4927
4576
|
},
|
|
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
4577
|
formAnnotation(name, type, x, y, w, h, options = {}) {
|
|
4940
4578
|
let fieldDict = this._fieldDict(name, type, options);
|
|
4941
4579
|
fieldDict.Subtype = 'Widget';
|
|
4942
4580
|
if (fieldDict.F === undefined) {
|
|
4943
|
-
fieldDict.F = 4;
|
|
4581
|
+
fieldDict.F = 4;
|
|
4944
4582
|
}
|
|
4945
|
-
|
|
4946
|
-
// Add Field annot to page, and get it's ref
|
|
4947
4583
|
this.annotate(x, y, w, h, fieldDict);
|
|
4948
4584
|
let annotRef = this.page.annotations[this.page.annotations.length - 1];
|
|
4949
4585
|
return this._addToParent(annotRef);
|
|
@@ -5104,23 +4740,18 @@ var AcroFormMixin = {
|
|
|
5104
4740
|
delete options.align;
|
|
5105
4741
|
}
|
|
5106
4742
|
if (result !== 0) {
|
|
5107
|
-
options.Q = result;
|
|
4743
|
+
options.Q = result;
|
|
5108
4744
|
}
|
|
5109
4745
|
return options;
|
|
5110
4746
|
},
|
|
5111
4747
|
_resolveFont(options) {
|
|
5112
|
-
// add current font to document-level AcroForm dict if necessary
|
|
5113
4748
|
if (this._acroform.fonts[this._font.id] == null) {
|
|
5114
4749
|
this._acroform.fonts[this._font.id] = this._font.ref();
|
|
5115
4750
|
}
|
|
5116
|
-
|
|
5117
|
-
// add current font to field's resource dict (RD) if not the default acroform font
|
|
5118
4751
|
if (this._acroform.defaultFont !== this._font.name) {
|
|
5119
4752
|
options.DR = {
|
|
5120
4753
|
Font: {}
|
|
5121
4754
|
};
|
|
5122
|
-
|
|
5123
|
-
// Get the fontSize option. If not set use auto sizing
|
|
5124
4755
|
const fontSize = options.fontSize || 0;
|
|
5125
4756
|
options.DR.Font[this._font.id] = this._font.ref();
|
|
5126
4757
|
options.DA = new String(`/${this._font.id} ${fontSize} Tf 0 g`);
|
|
@@ -5172,19 +4803,6 @@ var AcroFormMixin = {
|
|
|
5172
4803
|
};
|
|
5173
4804
|
|
|
5174
4805
|
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
4806
|
file(src, options = {}) {
|
|
5189
4807
|
options.name = options.name || src;
|
|
5190
4808
|
options.relationship = options.relationship || 'Unspecified';
|
|
@@ -5212,8 +4830,6 @@ var AttachmentsMixin = {
|
|
|
5212
4830
|
if (!data) {
|
|
5213
4831
|
throw new Error(`Could not read contents of file at filepath ${src}`);
|
|
5214
4832
|
}
|
|
5215
|
-
|
|
5216
|
-
// update CreationDate and ModDate
|
|
5217
4833
|
const {
|
|
5218
4834
|
birthtime,
|
|
5219
4835
|
ctime
|
|
@@ -5222,26 +4838,18 @@ var AttachmentsMixin = {
|
|
|
5222
4838
|
refBody.Params.ModDate = ctime;
|
|
5223
4839
|
}
|
|
5224
4840
|
}
|
|
5225
|
-
|
|
5226
|
-
// override creation date and modified date
|
|
5227
4841
|
if (options.creationDate instanceof Date) {
|
|
5228
4842
|
refBody.Params.CreationDate = options.creationDate;
|
|
5229
4843
|
}
|
|
5230
4844
|
if (options.modifiedDate instanceof Date) {
|
|
5231
4845
|
refBody.Params.ModDate = options.modifiedDate;
|
|
5232
4846
|
}
|
|
5233
|
-
// add optional subtype
|
|
5234
4847
|
if (options.type) {
|
|
5235
4848
|
refBody.Subtype = options.type.replace('/', '#2F');
|
|
5236
4849
|
}
|
|
5237
|
-
|
|
5238
|
-
// add checksum and size information
|
|
5239
4850
|
const checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(new Uint8Array(data)));
|
|
5240
4851
|
refBody.Params.CheckSum = new String(checksum);
|
|
5241
4852
|
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
4853
|
let ref;
|
|
5246
4854
|
if (!this._fileRegistry) this._fileRegistry = {};
|
|
5247
4855
|
let file = this._fileRegistry[options.name];
|
|
@@ -5255,7 +4863,6 @@ var AttachmentsMixin = {
|
|
|
5255
4863
|
ref
|
|
5256
4864
|
};
|
|
5257
4865
|
}
|
|
5258
|
-
// add filespec for embedded file
|
|
5259
4866
|
const fileSpecBody = {
|
|
5260
4867
|
Type: 'Filespec',
|
|
5261
4868
|
AFRelationship: options.relationship,
|
|
@@ -5273,8 +4880,6 @@ var AttachmentsMixin = {
|
|
|
5273
4880
|
if (!options.hidden) {
|
|
5274
4881
|
this.addNamedEmbeddedFile(options.name, filespec);
|
|
5275
4882
|
}
|
|
5276
|
-
|
|
5277
|
-
// Add file to the catalogue to be PDF/A3 compliant
|
|
5278
4883
|
if (this._root.data.AF) {
|
|
5279
4884
|
this._root.data.AF.push(filespec);
|
|
5280
4885
|
} else {
|
|
@@ -5283,8 +4888,6 @@ var AttachmentsMixin = {
|
|
|
5283
4888
|
return filespec;
|
|
5284
4889
|
}
|
|
5285
4890
|
};
|
|
5286
|
-
|
|
5287
|
-
/** check two embedded file metadata objects for equality */
|
|
5288
4891
|
function isEqual(a, b) {
|
|
5289
4892
|
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
4893
|
}
|
|
@@ -5295,7 +4898,6 @@ var PDFA = {
|
|
|
5295
4898
|
this.subset_conformance = pSubset.charAt(pSubset.length - 1).toUpperCase();
|
|
5296
4899
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 2));
|
|
5297
4900
|
} else {
|
|
5298
|
-
// Default to Basic conformance when user doesn't specify
|
|
5299
4901
|
this.subset_conformance = 'B';
|
|
5300
4902
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 1));
|
|
5301
4903
|
}
|
|
@@ -5380,6 +4982,642 @@ var SubsetMixin = {
|
|
|
5380
4982
|
}
|
|
5381
4983
|
};
|
|
5382
4984
|
|
|
4985
|
+
const ROW_FIELDS = ['height', 'minHeight', 'maxHeight'];
|
|
4986
|
+
const COLUMN_FIELDS = ['width', 'minWidth', 'maxWidth'];
|
|
4987
|
+
function memoize(fn, maxSize) {
|
|
4988
|
+
const cache = new Map();
|
|
4989
|
+
return function (...args) {
|
|
4990
|
+
const key = args[0];
|
|
4991
|
+
if (!cache.has(key)) {
|
|
4992
|
+
cache.set(key, fn(...args));
|
|
4993
|
+
if (cache.size > maxSize) cache.delete(cache.keys().next());
|
|
4994
|
+
}
|
|
4995
|
+
return cache.get(key);
|
|
4996
|
+
};
|
|
4997
|
+
}
|
|
4998
|
+
function isObject(item) {
|
|
4999
|
+
return item && typeof item === 'object' && !Array.isArray(item);
|
|
5000
|
+
}
|
|
5001
|
+
function deepMerge(target, ...sources) {
|
|
5002
|
+
if (!isObject(target)) return target;
|
|
5003
|
+
target = deepClone(target);
|
|
5004
|
+
for (const source of sources) {
|
|
5005
|
+
if (isObject(source)) {
|
|
5006
|
+
for (const key in source) {
|
|
5007
|
+
if (isObject(source[key])) {
|
|
5008
|
+
if (!(key in target)) target[key] = {};
|
|
5009
|
+
target[key] = deepMerge(target[key], source[key]);
|
|
5010
|
+
} else if (source[key] !== undefined) {
|
|
5011
|
+
target[key] = deepClone(source[key]);
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
return target;
|
|
5017
|
+
}
|
|
5018
|
+
function deepClone(obj) {
|
|
5019
|
+
let result = obj;
|
|
5020
|
+
if (typeof obj == 'object') {
|
|
5021
|
+
result = Array.isArray(obj) ? [] : {};
|
|
5022
|
+
for (const key in obj) result[key] = deepClone(obj[key]);
|
|
5023
|
+
}
|
|
5024
|
+
return result;
|
|
5025
|
+
}
|
|
5026
|
+
|
|
5027
|
+
function normalizedDefaultStyle(defaultStyleInternal) {
|
|
5028
|
+
let defaultStyle = defaultStyleInternal;
|
|
5029
|
+
if (typeof defaultStyle !== 'object') defaultStyle = {
|
|
5030
|
+
text: defaultStyle
|
|
5031
|
+
};
|
|
5032
|
+
const defaultRowStyle = Object.fromEntries(Object.entries(defaultStyle).filter(([k]) => ROW_FIELDS.includes(k)));
|
|
5033
|
+
const defaultColStyle = Object.fromEntries(Object.entries(defaultStyle).filter(([k]) => COLUMN_FIELDS.includes(k)));
|
|
5034
|
+
defaultStyle.padding = normalizeSides(defaultStyle.padding);
|
|
5035
|
+
defaultStyle.border = normalizeSides(defaultStyle.border);
|
|
5036
|
+
defaultStyle.borderColor = normalizeSides(defaultStyle.borderColor);
|
|
5037
|
+
defaultStyle.align = normalizeAlignment(defaultStyle.align);
|
|
5038
|
+
return {
|
|
5039
|
+
defaultStyle,
|
|
5040
|
+
defaultRowStyle,
|
|
5041
|
+
defaultColStyle
|
|
5042
|
+
};
|
|
5043
|
+
}
|
|
5044
|
+
function normalizedRowStyle(defaultRowStyle, rowStyleInternal, i) {
|
|
5045
|
+
let rowStyle = rowStyleInternal(i);
|
|
5046
|
+
if (rowStyle == null || typeof rowStyle !== 'object') {
|
|
5047
|
+
rowStyle = {
|
|
5048
|
+
height: rowStyle
|
|
5049
|
+
};
|
|
5050
|
+
}
|
|
5051
|
+
rowStyle.padding = normalizeSides(rowStyle.padding);
|
|
5052
|
+
rowStyle.border = normalizeSides(rowStyle.border);
|
|
5053
|
+
rowStyle.borderColor = normalizeSides(rowStyle.borderColor);
|
|
5054
|
+
rowStyle.align = normalizeAlignment(rowStyle.align);
|
|
5055
|
+
rowStyle = deepMerge(defaultRowStyle, rowStyle);
|
|
5056
|
+
const document = this.document;
|
|
5057
|
+
const page = document.page;
|
|
5058
|
+
const contentHeight = page.contentHeight;
|
|
5059
|
+
if (rowStyle.height == null || rowStyle.height === 'auto') {
|
|
5060
|
+
rowStyle.height = 'auto';
|
|
5061
|
+
} else {
|
|
5062
|
+
rowStyle.height = document.sizeToPoint(rowStyle.height, 0, page, contentHeight);
|
|
5063
|
+
}
|
|
5064
|
+
rowStyle.minHeight = document.sizeToPoint(rowStyle.minHeight, 0, page, contentHeight);
|
|
5065
|
+
rowStyle.maxHeight = document.sizeToPoint(rowStyle.maxHeight, 0, page, contentHeight);
|
|
5066
|
+
return rowStyle;
|
|
5067
|
+
}
|
|
5068
|
+
function normalizedColumnStyle(defaultColStyle, colStyleInternal, i) {
|
|
5069
|
+
let colStyle = colStyleInternal(i);
|
|
5070
|
+
if (colStyle == null || typeof colStyle !== 'object') {
|
|
5071
|
+
colStyle = {
|
|
5072
|
+
width: colStyle
|
|
5073
|
+
};
|
|
5074
|
+
}
|
|
5075
|
+
colStyle.padding = normalizeSides(colStyle.padding);
|
|
5076
|
+
colStyle.border = normalizeSides(colStyle.border);
|
|
5077
|
+
colStyle.borderColor = normalizeSides(colStyle.borderColor);
|
|
5078
|
+
colStyle.align = normalizeAlignment(colStyle.align);
|
|
5079
|
+
colStyle = deepMerge(defaultColStyle, colStyle);
|
|
5080
|
+
if (colStyle.width == null || colStyle.width === '*') {
|
|
5081
|
+
colStyle.width = '*';
|
|
5082
|
+
} else {
|
|
5083
|
+
colStyle.width = this.document.sizeToPoint(colStyle.width, 0, this.document.page, this._maxWidth);
|
|
5084
|
+
}
|
|
5085
|
+
colStyle.minWidth = this.document.sizeToPoint(colStyle.minWidth, 0, this.document.page, this._maxWidth);
|
|
5086
|
+
colStyle.maxWidth = this.document.sizeToPoint(colStyle.maxWidth, 0, this.document.page, this._maxWidth);
|
|
5087
|
+
return colStyle;
|
|
5088
|
+
}
|
|
5089
|
+
function normalizeAlignment(align) {
|
|
5090
|
+
return align == null || typeof align === 'string' ? {
|
|
5091
|
+
x: align,
|
|
5092
|
+
y: align
|
|
5093
|
+
} : align;
|
|
5094
|
+
}
|
|
5095
|
+
|
|
5096
|
+
function normalizeTable() {
|
|
5097
|
+
const doc = this.document;
|
|
5098
|
+
const opts = this.opts;
|
|
5099
|
+
let index = doc._tableIndex++;
|
|
5100
|
+
this._id = new String(opts.id ?? `table-${index}`);
|
|
5101
|
+
this._position = {
|
|
5102
|
+
x: doc.sizeToPoint(opts.position?.x, doc.x),
|
|
5103
|
+
y: doc.sizeToPoint(opts.position?.y, doc.y)
|
|
5104
|
+
};
|
|
5105
|
+
this._maxWidth = doc.sizeToPoint(opts.maxWidth, doc.page.width - doc.page.margins.right - this._position.x);
|
|
5106
|
+
const {
|
|
5107
|
+
defaultStyle,
|
|
5108
|
+
defaultColStyle,
|
|
5109
|
+
defaultRowStyle
|
|
5110
|
+
} = normalizedDefaultStyle(opts.defaultStyle);
|
|
5111
|
+
this._defaultStyle = defaultStyle;
|
|
5112
|
+
let colStyle;
|
|
5113
|
+
if (opts.columnStyles) {
|
|
5114
|
+
if (Array.isArray(opts.columnStyles)) {
|
|
5115
|
+
colStyle = i => opts.columnStyles[i];
|
|
5116
|
+
} else if (typeof opts.columnStyles === 'function') {
|
|
5117
|
+
colStyle = memoize(i => opts.columnStyles(i), Infinity);
|
|
5118
|
+
} else if (typeof opts.columnStyles === 'object') {
|
|
5119
|
+
colStyle = () => opts.columnStyles;
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
if (!colStyle) colStyle = () => ({});
|
|
5123
|
+
this._colStyle = normalizedColumnStyle.bind(this, defaultColStyle, colStyle);
|
|
5124
|
+
let rowStyle;
|
|
5125
|
+
if (opts.rowStyles) {
|
|
5126
|
+
if (Array.isArray(opts.rowStyles)) {
|
|
5127
|
+
rowStyle = i => opts.rowStyles[i];
|
|
5128
|
+
} else if (typeof opts.rowStyles === 'function') {
|
|
5129
|
+
rowStyle = memoize(i => opts.rowStyles(i), 10);
|
|
5130
|
+
} else if (typeof opts.rowStyles === 'object') {
|
|
5131
|
+
rowStyle = () => opts.rowStyles;
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
if (!rowStyle) rowStyle = () => ({});
|
|
5135
|
+
this._rowStyle = normalizedRowStyle.bind(this, defaultRowStyle, rowStyle);
|
|
5136
|
+
}
|
|
5137
|
+
function normalizeText(text) {
|
|
5138
|
+
if (text != null) text = `${text}`;
|
|
5139
|
+
return text;
|
|
5140
|
+
}
|
|
5141
|
+
function normalizeCell(cell, rowIndex, colIndex) {
|
|
5142
|
+
const colStyle = this._colStyle(colIndex);
|
|
5143
|
+
let rowStyle = this._rowStyle(rowIndex);
|
|
5144
|
+
const font = deepMerge({}, colStyle.font, rowStyle.font, cell.font);
|
|
5145
|
+
const customFont = Object.values(font).filter(v => v != null).length > 0;
|
|
5146
|
+
const doc = this.document;
|
|
5147
|
+
const rollbackFont = doc._fontSource;
|
|
5148
|
+
const rollbackFontSize = doc._fontSize;
|
|
5149
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5150
|
+
if (customFont) {
|
|
5151
|
+
if (font.src) doc.font(font.src, font.family);
|
|
5152
|
+
if (font.size) doc.fontSize(font.size);
|
|
5153
|
+
rowStyle = this._rowStyle(rowIndex);
|
|
5154
|
+
}
|
|
5155
|
+
cell.padding = normalizeSides(cell.padding);
|
|
5156
|
+
cell.border = normalizeSides(cell.border);
|
|
5157
|
+
cell.borderColor = normalizeSides(cell.borderColor);
|
|
5158
|
+
const config = deepMerge(this._defaultStyle, colStyle, rowStyle, cell);
|
|
5159
|
+
config.rowIndex = rowIndex;
|
|
5160
|
+
config.colIndex = colIndex;
|
|
5161
|
+
config.font = font ?? {};
|
|
5162
|
+
config.customFont = customFont;
|
|
5163
|
+
config.text = normalizeText(config.text);
|
|
5164
|
+
config.rowSpan = config.rowSpan ?? 1;
|
|
5165
|
+
config.colSpan = config.colSpan ?? 1;
|
|
5166
|
+
config.padding = normalizeSides(config.padding, '0.25em', x => doc.sizeToPoint(x, '0.25em'));
|
|
5167
|
+
config.border = normalizeSides(config.border, 1, x => doc.sizeToPoint(x, 1));
|
|
5168
|
+
config.borderColor = normalizeSides(config.borderColor, 'black', x => x ?? 'black');
|
|
5169
|
+
config.align = normalizeAlignment(config.align);
|
|
5170
|
+
config.align.x = config.align.x ?? 'left';
|
|
5171
|
+
config.align.y = config.align.y ?? 'top';
|
|
5172
|
+
config.textStroke = doc.sizeToPoint(config.textStroke, 0);
|
|
5173
|
+
config.textStrokeColor = config.textStrokeColor ?? 'black';
|
|
5174
|
+
config.textColor = config.textColor ?? 'black';
|
|
5175
|
+
config.textOptions = config.textOptions ?? {};
|
|
5176
|
+
config.id = new String(config.id ?? `${this._id}-${rowIndex}-${colIndex}`);
|
|
5177
|
+
config.type = config.type?.toUpperCase() === 'TH' ? 'TH' : 'TD';
|
|
5178
|
+
if (config.scope) {
|
|
5179
|
+
config.scope = config.scope.toLowerCase();
|
|
5180
|
+
if (config.scope === 'row') config.scope = 'Row';else if (config.scope === 'both') config.scope = 'Both';else if (config.scope === 'column') config.scope = 'Column';
|
|
5181
|
+
}
|
|
5182
|
+
if (typeof this.opts.debug === 'boolean') config.debug = this.opts.debug;
|
|
5183
|
+
if (customFont) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5184
|
+
return config;
|
|
5185
|
+
}
|
|
5186
|
+
function normalizeRow(row, rowIndex) {
|
|
5187
|
+
if (!this._cellClaim) this._cellClaim = new Set();
|
|
5188
|
+
let colIndex = 0;
|
|
5189
|
+
return row.map(cell => {
|
|
5190
|
+
if (cell == null || typeof cell !== 'object') cell = {
|
|
5191
|
+
text: cell
|
|
5192
|
+
};
|
|
5193
|
+
while (this._cellClaim.has(`${rowIndex},${colIndex}`)) {
|
|
5194
|
+
colIndex++;
|
|
5195
|
+
}
|
|
5196
|
+
cell = normalizeCell.call(this, cell, rowIndex, colIndex);
|
|
5197
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5198
|
+
for (let j = 0; j < cell.colSpan; j++) {
|
|
5199
|
+
this._cellClaim.add(`${rowIndex + i},${colIndex + j}`);
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
colIndex += cell.colSpan;
|
|
5203
|
+
return cell;
|
|
5204
|
+
});
|
|
5205
|
+
}
|
|
5206
|
+
|
|
5207
|
+
function ensure(row) {
|
|
5208
|
+
this._columnWidths = [];
|
|
5209
|
+
ensureColumnWidths.call(this, row.reduce((a, cell) => a + cell.colSpan, 0));
|
|
5210
|
+
this._rowHeights = [];
|
|
5211
|
+
this._rowYPos = [this._position.y];
|
|
5212
|
+
this._rowBuffer = new Set();
|
|
5213
|
+
}
|
|
5214
|
+
function ensureColumnWidths(numCols) {
|
|
5215
|
+
let starColumnIndexes = [];
|
|
5216
|
+
let starMinAcc = 0;
|
|
5217
|
+
let unclaimedWidth = this._maxWidth;
|
|
5218
|
+
for (let i = 0; i < numCols; i++) {
|
|
5219
|
+
let col = this._colStyle(i);
|
|
5220
|
+
if (col.width === '*') {
|
|
5221
|
+
starColumnIndexes[i] = col;
|
|
5222
|
+
starMinAcc += col.minWidth;
|
|
5223
|
+
} else {
|
|
5224
|
+
unclaimedWidth -= col.width;
|
|
5225
|
+
this._columnWidths[i] = col.width;
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
let starColCount = starColumnIndexes.reduce(x => x + 1, 0);
|
|
5229
|
+
if (starMinAcc >= unclaimedWidth) {
|
|
5230
|
+
starColumnIndexes.forEach((cell, i) => {
|
|
5231
|
+
this._columnWidths[i] = cell.minWidth;
|
|
5232
|
+
});
|
|
5233
|
+
} else if (starColCount > 0) {
|
|
5234
|
+
starColumnIndexes.forEach((col, i) => {
|
|
5235
|
+
let starSize = unclaimedWidth / starColCount;
|
|
5236
|
+
this._columnWidths[i] = Math.max(starSize, col.minWidth);
|
|
5237
|
+
if (col.maxWidth > 0) {
|
|
5238
|
+
this._columnWidths[i] = Math.min(this._columnWidths[i], col.maxWidth);
|
|
5239
|
+
}
|
|
5240
|
+
unclaimedWidth -= this._columnWidths[i];
|
|
5241
|
+
starColCount--;
|
|
5242
|
+
});
|
|
5243
|
+
}
|
|
5244
|
+
let tempX = this._position.x;
|
|
5245
|
+
this._columnXPos = Array.from(this._columnWidths, v => {
|
|
5246
|
+
const t = tempX;
|
|
5247
|
+
tempX += v;
|
|
5248
|
+
return t;
|
|
5249
|
+
});
|
|
5250
|
+
}
|
|
5251
|
+
function measure(row, rowIndex) {
|
|
5252
|
+
row.forEach(cell => this._rowBuffer.add(cell));
|
|
5253
|
+
if (rowIndex > 0) {
|
|
5254
|
+
this._rowYPos[rowIndex] = this._rowYPos[rowIndex - 1] + this._rowHeights[rowIndex - 1];
|
|
5255
|
+
}
|
|
5256
|
+
const rowStyle = this._rowStyle(rowIndex);
|
|
5257
|
+
let toRender = [];
|
|
5258
|
+
this._rowBuffer.forEach(cell => {
|
|
5259
|
+
if (cell.rowIndex + cell.rowSpan - 1 === rowIndex) {
|
|
5260
|
+
toRender.push(measureCell.call(this, cell, rowStyle.height));
|
|
5261
|
+
this._rowBuffer.delete(cell);
|
|
5262
|
+
}
|
|
5263
|
+
});
|
|
5264
|
+
let rowHeight = rowStyle.height;
|
|
5265
|
+
if (rowHeight === 'auto') {
|
|
5266
|
+
rowHeight = toRender.reduce((acc, cell) => {
|
|
5267
|
+
let minHeight = cell.textBounds.height + cell.padding.top + cell.padding.bottom;
|
|
5268
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5269
|
+
minHeight -= this._rowHeights[cell.rowIndex + i];
|
|
5270
|
+
}
|
|
5271
|
+
return Math.max(acc, minHeight);
|
|
5272
|
+
}, 0);
|
|
5273
|
+
}
|
|
5274
|
+
rowHeight = Math.max(rowHeight, rowStyle.minHeight);
|
|
5275
|
+
if (rowStyle.maxHeight > 0) {
|
|
5276
|
+
rowHeight = Math.min(rowHeight, rowStyle.maxHeight);
|
|
5277
|
+
}
|
|
5278
|
+
this._rowHeights[rowIndex] = rowHeight;
|
|
5279
|
+
let newPage = false;
|
|
5280
|
+
if (rowHeight > this.document.page.contentHeight) {
|
|
5281
|
+
console.warn(new Error(`Row ${rowIndex} requested more than the safe page height, row has been clamped`).stack.slice(7));
|
|
5282
|
+
this._rowHeights[rowIndex] = this.document.page.maxY() - this._rowYPos[rowIndex];
|
|
5283
|
+
} else if (this._rowYPos[rowIndex] + rowHeight >= this.document.page.maxY()) {
|
|
5284
|
+
this._rowYPos[rowIndex] = this.document.page.margins.top;
|
|
5285
|
+
newPage = true;
|
|
5286
|
+
}
|
|
5287
|
+
return {
|
|
5288
|
+
newPage,
|
|
5289
|
+
toRender: toRender.map(cell => measureCell.call(this, cell, rowHeight))
|
|
5290
|
+
};
|
|
5291
|
+
}
|
|
5292
|
+
function measureCell(cell, rowHeight) {
|
|
5293
|
+
let cellWidth = 0;
|
|
5294
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5295
|
+
cellWidth += this._columnWidths[cell.colIndex + i];
|
|
5296
|
+
}
|
|
5297
|
+
let cellHeight = rowHeight;
|
|
5298
|
+
if (cellHeight === 'auto') {
|
|
5299
|
+
cellHeight = this.document.page.contentHeight;
|
|
5300
|
+
} else {
|
|
5301
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5302
|
+
cellHeight += this._rowHeights[cell.rowIndex + i];
|
|
5303
|
+
}
|
|
5304
|
+
}
|
|
5305
|
+
const textAllocatedWidth = cellWidth - cell.padding.left - cell.padding.right;
|
|
5306
|
+
const textAllocatedHeight = cellHeight - cell.padding.top - cell.padding.bottom;
|
|
5307
|
+
const rotation = cell.textOptions.rotation ?? 0;
|
|
5308
|
+
const {
|
|
5309
|
+
width: textMaxWidth,
|
|
5310
|
+
height: textMaxHeight
|
|
5311
|
+
} = computeBounds(rotation, textAllocatedWidth, textAllocatedHeight);
|
|
5312
|
+
const textOptions = {
|
|
5313
|
+
align: cell.align.x,
|
|
5314
|
+
ellipsis: true,
|
|
5315
|
+
stroke: cell.textStroke > 0,
|
|
5316
|
+
fill: true,
|
|
5317
|
+
width: textMaxWidth,
|
|
5318
|
+
height: textMaxHeight,
|
|
5319
|
+
rotation,
|
|
5320
|
+
...cell.textOptions
|
|
5321
|
+
};
|
|
5322
|
+
let textBounds = {
|
|
5323
|
+
x: 0,
|
|
5324
|
+
y: 0,
|
|
5325
|
+
width: 0,
|
|
5326
|
+
height: 0
|
|
5327
|
+
};
|
|
5328
|
+
if (cell.text) {
|
|
5329
|
+
const rollbackFont = this.document._fontSource;
|
|
5330
|
+
const rollbackFontSize = this.document._fontSize;
|
|
5331
|
+
const rollbackFontFamily = this.document._fontFamily;
|
|
5332
|
+
if (cell.font?.src) this.document.font(cell.font.src, cell.font?.family);
|
|
5333
|
+
if (cell.font?.size) this.document.fontSize(cell.font.size);
|
|
5334
|
+
const unRotatedTextBounds = this.document.boundsOfString(cell.text, 0, 0, {
|
|
5335
|
+
...textOptions,
|
|
5336
|
+
rotation: 0
|
|
5337
|
+
});
|
|
5338
|
+
textOptions.width = unRotatedTextBounds.width;
|
|
5339
|
+
textOptions.height = unRotatedTextBounds.height;
|
|
5340
|
+
textBounds = this.document.boundsOfString(cell.text, 0, 0, textOptions);
|
|
5341
|
+
this.document.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5342
|
+
}
|
|
5343
|
+
return {
|
|
5344
|
+
...cell,
|
|
5345
|
+
textOptions,
|
|
5346
|
+
x: this._columnXPos[cell.colIndex],
|
|
5347
|
+
y: this._rowYPos[cell.rowIndex],
|
|
5348
|
+
textX: this._columnXPos[cell.colIndex] + cell.padding.left,
|
|
5349
|
+
textY: this._rowYPos[cell.rowIndex] + cell.padding.top,
|
|
5350
|
+
width: cellWidth,
|
|
5351
|
+
height: cellHeight,
|
|
5352
|
+
textAllocatedHeight,
|
|
5353
|
+
textAllocatedWidth,
|
|
5354
|
+
textBounds
|
|
5355
|
+
};
|
|
5356
|
+
}
|
|
5357
|
+
function computeBounds(rotation, allocWidth, allocHeight) {
|
|
5358
|
+
let textMaxWidth, textMaxHeight;
|
|
5359
|
+
const cos = cosine(rotation);
|
|
5360
|
+
const sin = sine(rotation);
|
|
5361
|
+
if (rotation === 0 || rotation === 180) {
|
|
5362
|
+
textMaxWidth = allocWidth;
|
|
5363
|
+
textMaxHeight = allocHeight;
|
|
5364
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5365
|
+
textMaxWidth = allocHeight;
|
|
5366
|
+
textMaxHeight = allocWidth;
|
|
5367
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5368
|
+
textMaxWidth = allocWidth / (2 * cos);
|
|
5369
|
+
textMaxHeight = allocWidth / (2 * sin);
|
|
5370
|
+
} else {
|
|
5371
|
+
textMaxHeight = allocWidth / (2 * cos);
|
|
5372
|
+
textMaxWidth = allocWidth / (2 * sin);
|
|
5373
|
+
}
|
|
5374
|
+
const EF = sin * textMaxWidth;
|
|
5375
|
+
const FG = cos * textMaxHeight;
|
|
5376
|
+
if (EF + FG > allocHeight) {
|
|
5377
|
+
const denominator = cos * cos - sin * sin;
|
|
5378
|
+
if (rotation === 0 || rotation === 180) {
|
|
5379
|
+
textMaxWidth = allocWidth;
|
|
5380
|
+
textMaxHeight = allocHeight;
|
|
5381
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5382
|
+
textMaxWidth = allocHeight;
|
|
5383
|
+
textMaxHeight = allocWidth;
|
|
5384
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5385
|
+
textMaxWidth = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5386
|
+
textMaxHeight = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5387
|
+
} else {
|
|
5388
|
+
textMaxHeight = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5389
|
+
textMaxWidth = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
return {
|
|
5393
|
+
width: Math.abs(textMaxWidth),
|
|
5394
|
+
height: Math.abs(textMaxHeight)
|
|
5395
|
+
};
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5398
|
+
function accommodateTable() {
|
|
5399
|
+
const structParent = this.opts.structParent;
|
|
5400
|
+
if (structParent) {
|
|
5401
|
+
this._tableStruct = this.document.struct('Table');
|
|
5402
|
+
this._tableStruct.dictionary.data.ID = this._id;
|
|
5403
|
+
if (structParent instanceof PDFStructureElement) {
|
|
5404
|
+
structParent.add(this._tableStruct);
|
|
5405
|
+
} else if (structParent instanceof PDFDocument) {
|
|
5406
|
+
structParent.addStructure(this._tableStruct);
|
|
5407
|
+
}
|
|
5408
|
+
this._headerRowLookup = {};
|
|
5409
|
+
this._headerColumnLookup = {};
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
function accommodateCleanup() {
|
|
5413
|
+
if (this._tableStruct) this._tableStruct.end();
|
|
5414
|
+
}
|
|
5415
|
+
function accessibleRow(row, rowIndex, renderCell) {
|
|
5416
|
+
const rowStruct = this.document.struct('TR');
|
|
5417
|
+
rowStruct.dictionary.data.ID = new String(`${this._id}-${rowIndex}`);
|
|
5418
|
+
this._tableStruct.add(rowStruct);
|
|
5419
|
+
row.forEach(cell => renderCell(cell, rowStruct));
|
|
5420
|
+
rowStruct.end();
|
|
5421
|
+
}
|
|
5422
|
+
function accessibleCell(cell, rowStruct, callback) {
|
|
5423
|
+
const doc = this.document;
|
|
5424
|
+
const cellStruct = doc.struct(cell.type, {
|
|
5425
|
+
title: cell.title
|
|
5426
|
+
});
|
|
5427
|
+
cellStruct.dictionary.data.ID = cell.id;
|
|
5428
|
+
rowStruct.add(cellStruct);
|
|
5429
|
+
const padding = cell.padding;
|
|
5430
|
+
const border = cell.border;
|
|
5431
|
+
const attributes = {
|
|
5432
|
+
O: 'Table',
|
|
5433
|
+
Width: cell.width,
|
|
5434
|
+
Height: cell.height,
|
|
5435
|
+
Padding: [padding.top, padding.bottom, padding.left, padding.right],
|
|
5436
|
+
RowSpan: cell.rowSpan > 1 ? cell.rowSpan : undefined,
|
|
5437
|
+
ColSpan: cell.colSpan > 1 ? cell.colSpan : undefined,
|
|
5438
|
+
BorderThickness: [border.top, border.bottom, border.left, border.right]
|
|
5439
|
+
};
|
|
5440
|
+
if (cell.type === 'TH') {
|
|
5441
|
+
if (cell.scope === 'Row' || cell.scope === 'Both') {
|
|
5442
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5443
|
+
if (!this._headerRowLookup[cell.rowIndex + i]) {
|
|
5444
|
+
this._headerRowLookup[cell.rowIndex + i] = [];
|
|
5445
|
+
}
|
|
5446
|
+
this._headerRowLookup[cell.rowIndex + i].push(cell.id);
|
|
5447
|
+
}
|
|
5448
|
+
attributes.Scope = cell.scope;
|
|
5449
|
+
}
|
|
5450
|
+
if (cell.scope === 'Column' || cell.scope === 'Both') {
|
|
5451
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5452
|
+
if (!this._headerColumnLookup[cell.colIndex + i]) {
|
|
5453
|
+
this._headerColumnLookup[cell.colIndex + i] = [];
|
|
5454
|
+
}
|
|
5455
|
+
this._headerColumnLookup[cell.colIndex + i].push(cell.id);
|
|
5456
|
+
}
|
|
5457
|
+
attributes.Scope = cell.scope;
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5460
|
+
const Headers = new Set([...Array.from({
|
|
5461
|
+
length: cell.colSpan
|
|
5462
|
+
}, (_, i) => this._headerColumnLookup[cell.colIndex + i]).flat(), ...Array.from({
|
|
5463
|
+
length: cell.rowSpan
|
|
5464
|
+
}, (_, i) => this._headerRowLookup[cell.rowIndex + i]).flat()].filter(Boolean));
|
|
5465
|
+
if (Headers.size) attributes.Headers = Array.from(Headers);
|
|
5466
|
+
const normalizeColor = doc._normalizeColor;
|
|
5467
|
+
if (cell.backgroundColor != null) {
|
|
5468
|
+
attributes.BackgroundColor = normalizeColor(cell.backgroundColor);
|
|
5469
|
+
}
|
|
5470
|
+
const hasBorder = [border.top, border.bottom, border.left, border.right];
|
|
5471
|
+
if (hasBorder.some(x => x)) {
|
|
5472
|
+
const borderColor = cell.borderColor;
|
|
5473
|
+
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];
|
|
5474
|
+
}
|
|
5475
|
+
Object.keys(attributes).forEach(key => attributes[key] === undefined && delete attributes[key]);
|
|
5476
|
+
cellStruct.dictionary.data.A = doc.ref(attributes);
|
|
5477
|
+
cellStruct.add(callback);
|
|
5478
|
+
cellStruct.end();
|
|
5479
|
+
cellStruct.dictionary.data.A.end();
|
|
5480
|
+
}
|
|
5481
|
+
|
|
5482
|
+
function renderRow(row, rowIndex) {
|
|
5483
|
+
if (this._tableStruct) {
|
|
5484
|
+
accessibleRow.call(this, row, rowIndex, renderCell.bind(this));
|
|
5485
|
+
} else {
|
|
5486
|
+
row.forEach(cell => renderCell.call(this, cell));
|
|
5487
|
+
}
|
|
5488
|
+
return this._rowYPos[rowIndex] + this._rowHeights[rowIndex];
|
|
5489
|
+
}
|
|
5490
|
+
function renderCell(cell, rowStruct) {
|
|
5491
|
+
const cellRenderer = () => {
|
|
5492
|
+
if (cell.backgroundColor != null) {
|
|
5493
|
+
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(cell.backgroundColor).restore();
|
|
5494
|
+
}
|
|
5495
|
+
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5496
|
+
if (cell.debug) {
|
|
5497
|
+
this.document.save();
|
|
5498
|
+
this.document.dash(1, {
|
|
5499
|
+
space: 1
|
|
5500
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5501
|
+
this.document.rect(cell.x, cell.y, cell.width, cell.height).stroke('green');
|
|
5502
|
+
this.document.restore();
|
|
5503
|
+
}
|
|
5504
|
+
if (cell.text) renderCellText.call(this, cell);
|
|
5505
|
+
};
|
|
5506
|
+
if (rowStruct) accessibleCell.call(this, cell, rowStruct, cellRenderer);else cellRenderer();
|
|
5507
|
+
}
|
|
5508
|
+
function renderCellText(cell) {
|
|
5509
|
+
const doc = this.document;
|
|
5510
|
+
const rollbackFont = doc._fontSource;
|
|
5511
|
+
const rollbackFontSize = doc._fontSize;
|
|
5512
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5513
|
+
if (cell.customFont) {
|
|
5514
|
+
if (cell.font.src) doc.font(cell.font.src, cell.font.family);
|
|
5515
|
+
if (cell.font.size) doc.fontSize(cell.font.size);
|
|
5516
|
+
}
|
|
5517
|
+
const x = cell.textX;
|
|
5518
|
+
const y = cell.textY;
|
|
5519
|
+
const Ah = cell.textAllocatedHeight;
|
|
5520
|
+
const Aw = cell.textAllocatedWidth;
|
|
5521
|
+
const Cw = cell.textBounds.width;
|
|
5522
|
+
const Ch = cell.textBounds.height;
|
|
5523
|
+
const Ox = -cell.textBounds.x;
|
|
5524
|
+
const Oy = -cell.textBounds.y;
|
|
5525
|
+
const PxScale = cell.align.x === 'right' ? 1 : cell.align.x === 'center' ? 0.5 : 0;
|
|
5526
|
+
const Px = (Aw - Cw) * PxScale;
|
|
5527
|
+
const PyScale = cell.align.y === 'bottom' ? 1 : cell.align.y === 'center' ? 0.5 : 0;
|
|
5528
|
+
const Py = (Ah - Ch) * PyScale;
|
|
5529
|
+
const dx = Px + Ox;
|
|
5530
|
+
const dy = Py + Oy;
|
|
5531
|
+
if (cell.debug) {
|
|
5532
|
+
doc.save();
|
|
5533
|
+
doc.dash(1, {
|
|
5534
|
+
space: 1
|
|
5535
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5536
|
+
if (cell.text) {
|
|
5537
|
+
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');
|
|
5538
|
+
}
|
|
5539
|
+
doc.rect(x, y, Aw, Ah).stroke('orange');
|
|
5540
|
+
doc.restore();
|
|
5541
|
+
}
|
|
5542
|
+
doc.save().rect(x, y, Aw, Ah).clip();
|
|
5543
|
+
doc.fillColor(cell.textColor).strokeColor(cell.textStrokeColor);
|
|
5544
|
+
if (cell.textStroke > 0) doc.lineWidth(cell.textStroke);
|
|
5545
|
+
doc.text(cell.text, x + dx, y + dy, cell.textOptions);
|
|
5546
|
+
doc.restore();
|
|
5547
|
+
if (cell.font) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5548
|
+
}
|
|
5549
|
+
function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
5550
|
+
border = Object.fromEntries(Object.entries(border).map(([k, v]) => [k, mask && !mask[k] ? 0 : v]));
|
|
5551
|
+
const doc = this.document;
|
|
5552
|
+
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5553
|
+
if (border.top > 0) {
|
|
5554
|
+
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(borderColor.top).restore();
|
|
5555
|
+
}
|
|
5556
|
+
} else {
|
|
5557
|
+
if (border.top > 0) {
|
|
5558
|
+
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(borderColor.top).restore();
|
|
5559
|
+
}
|
|
5560
|
+
if (border.right > 0) {
|
|
5561
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(borderColor.right).restore();
|
|
5562
|
+
}
|
|
5563
|
+
if (border.bottom > 0) {
|
|
5564
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(borderColor.bottom).restore();
|
|
5565
|
+
}
|
|
5566
|
+
if (border.left > 0) {
|
|
5567
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(borderColor.left).restore();
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
|
|
5572
|
+
class PDFTable {
|
|
5573
|
+
constructor(document, opts = {}) {
|
|
5574
|
+
this.document = document;
|
|
5575
|
+
this.opts = Object.freeze(opts);
|
|
5576
|
+
normalizeTable.call(this);
|
|
5577
|
+
accommodateTable.call(this);
|
|
5578
|
+
this._currRowIndex = 0;
|
|
5579
|
+
this._ended = false;
|
|
5580
|
+
if (opts.data) {
|
|
5581
|
+
for (const row of opts.data) this.row(row);
|
|
5582
|
+
return this.end();
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5585
|
+
row(row, lastRow = false) {
|
|
5586
|
+
if (this._ended) {
|
|
5587
|
+
throw new Error(`Table was marked as ended on row ${this._currRowIndex}`);
|
|
5588
|
+
}
|
|
5589
|
+
row = Array.from(row);
|
|
5590
|
+
row = normalizeRow.call(this, row, this._currRowIndex);
|
|
5591
|
+
if (this._currRowIndex === 0) ensure.call(this, row);
|
|
5592
|
+
const {
|
|
5593
|
+
newPage,
|
|
5594
|
+
toRender
|
|
5595
|
+
} = measure.call(this, row, this._currRowIndex);
|
|
5596
|
+
if (newPage) this.document.continueOnNewPage();
|
|
5597
|
+
const yPos = renderRow.call(this, toRender, this._currRowIndex);
|
|
5598
|
+
this.document.x = this._position.x;
|
|
5599
|
+
this.document.y = yPos;
|
|
5600
|
+
if (lastRow) return this.end();
|
|
5601
|
+
this._currRowIndex++;
|
|
5602
|
+
return this;
|
|
5603
|
+
}
|
|
5604
|
+
end() {
|
|
5605
|
+
while (this._rowBuffer?.size) this.row([]);
|
|
5606
|
+
this._ended = true;
|
|
5607
|
+
accommodateCleanup.call(this);
|
|
5608
|
+
return this.document;
|
|
5609
|
+
}
|
|
5610
|
+
}
|
|
5611
|
+
|
|
5612
|
+
var TableMixin = {
|
|
5613
|
+
initTables() {
|
|
5614
|
+
this._tableIndex = 0;
|
|
5615
|
+
},
|
|
5616
|
+
table(opts) {
|
|
5617
|
+
return new PDFTable(this, opts);
|
|
5618
|
+
}
|
|
5619
|
+
};
|
|
5620
|
+
|
|
5383
5621
|
class PDFMetadata {
|
|
5384
5622
|
constructor() {
|
|
5385
5623
|
this._metadata = `
|
|
@@ -5421,7 +5659,7 @@ var MetadataMixin = {
|
|
|
5421
5659
|
_addInfo() {
|
|
5422
5660
|
this.appendXML(`
|
|
5423
5661
|
<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
|
|
5424
|
-
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] +
|
|
5662
|
+
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] + 'Z'}</xmp:CreateDate>
|
|
5425
5663
|
<xmp:CreatorTool>${this.info.Creator}</xmp:CreatorTool>
|
|
5426
5664
|
</rdf:Description>
|
|
5427
5665
|
`);
|
|
@@ -5474,11 +5712,6 @@ var MetadataMixin = {
|
|
|
5474
5712
|
endMetadata() {
|
|
5475
5713
|
this._addInfo();
|
|
5476
5714
|
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
5715
|
if (this.version != 1.3) {
|
|
5483
5716
|
this.metadataRef = this.ref({
|
|
5484
5717
|
length: this.metadata.getLength(),
|
|
@@ -5493,16 +5726,10 @@ var MetadataMixin = {
|
|
|
5493
5726
|
}
|
|
5494
5727
|
};
|
|
5495
5728
|
|
|
5496
|
-
/*
|
|
5497
|
-
PDFDocument - represents an entire PDF document
|
|
5498
|
-
By Devon Govett
|
|
5499
|
-
*/
|
|
5500
5729
|
class PDFDocument extends stream.Readable {
|
|
5501
5730
|
constructor(options = {}) {
|
|
5502
5731
|
super(options);
|
|
5503
5732
|
this.options = options;
|
|
5504
|
-
|
|
5505
|
-
// PDF version
|
|
5506
5733
|
switch (options.pdfVersion) {
|
|
5507
5734
|
case '1.4':
|
|
5508
5735
|
this.version = 1.4;
|
|
@@ -5521,13 +5748,9 @@ class PDFDocument extends stream.Readable {
|
|
|
5521
5748
|
this.version = 1.3;
|
|
5522
5749
|
break;
|
|
5523
5750
|
}
|
|
5524
|
-
|
|
5525
|
-
// Whether streams should be compressed
|
|
5526
5751
|
this.compress = this.options.compress != null ? this.options.compress : true;
|
|
5527
5752
|
this._pageBuffer = [];
|
|
5528
5753
|
this._pageBufferStart = 0;
|
|
5529
|
-
|
|
5530
|
-
// The PDF object store
|
|
5531
5754
|
this._offsets = [];
|
|
5532
5755
|
this._waiting = 0;
|
|
5533
5756
|
this._ended = false;
|
|
@@ -5548,11 +5771,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5548
5771
|
if (this.options.lang) {
|
|
5549
5772
|
this._root.data.Lang = new String(this.options.lang);
|
|
5550
5773
|
}
|
|
5551
|
-
|
|
5552
|
-
// The current page
|
|
5553
5774
|
this.page = null;
|
|
5554
|
-
|
|
5555
|
-
// Initialize mixins
|
|
5556
5775
|
this.initMetadata();
|
|
5557
5776
|
this.initColor();
|
|
5558
5777
|
this.initVector();
|
|
@@ -5561,9 +5780,8 @@ class PDFDocument extends stream.Readable {
|
|
|
5561
5780
|
this.initImages();
|
|
5562
5781
|
this.initOutline();
|
|
5563
5782
|
this.initMarkings(options);
|
|
5783
|
+
this.initTables();
|
|
5564
5784
|
this.initSubset(options);
|
|
5565
|
-
|
|
5566
|
-
// Initialize the metadata
|
|
5567
5785
|
this.info = {
|
|
5568
5786
|
Producer: 'PDFKit',
|
|
5569
5787
|
Creator: 'PDFKit',
|
|
@@ -5580,21 +5798,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5580
5798
|
DisplayDocTitle: true
|
|
5581
5799
|
});
|
|
5582
5800
|
}
|
|
5583
|
-
|
|
5584
|
-
// Generate file ID
|
|
5585
5801
|
this._id = PDFSecurity.generateFileID(this.info);
|
|
5586
|
-
|
|
5587
|
-
// Initialize security settings
|
|
5588
5802
|
this._security = PDFSecurity.create(this, options);
|
|
5589
|
-
|
|
5590
|
-
// Write the header
|
|
5591
|
-
// PDF version
|
|
5592
5803
|
this._write(`%PDF-${this.version}`);
|
|
5593
|
-
|
|
5594
|
-
// 4 binary chars, as recommended by the spec
|
|
5595
5804
|
this._write('%\xFF\xFF\xFF\xFF');
|
|
5596
|
-
|
|
5597
|
-
// Add the first page
|
|
5598
5805
|
if (this.options.autoFirstPage !== false) {
|
|
5599
5806
|
this.addPage();
|
|
5600
5807
|
}
|
|
@@ -5605,27 +5812,16 @@ class PDFDocument extends stream.Readable {
|
|
|
5605
5812
|
options
|
|
5606
5813
|
} = this);
|
|
5607
5814
|
}
|
|
5608
|
-
|
|
5609
|
-
// end the current page if needed
|
|
5610
5815
|
if (!this.options.bufferPages) {
|
|
5611
5816
|
this.flushPages();
|
|
5612
5817
|
}
|
|
5613
|
-
|
|
5614
|
-
// create a page object
|
|
5615
5818
|
this.page = new PDFPage(this, options);
|
|
5616
5819
|
this._pageBuffer.push(this.page);
|
|
5617
|
-
|
|
5618
|
-
// add the page to the object store
|
|
5619
5820
|
const pages = this._root.data.Pages.data;
|
|
5620
5821
|
pages.Kids.push(this.page.dictionary);
|
|
5621
5822
|
pages.Count++;
|
|
5622
|
-
|
|
5623
|
-
// reset x and y coordinates
|
|
5624
5823
|
this.x = this.page.margins.left;
|
|
5625
5824
|
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
5825
|
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
5630
5826
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
5631
5827
|
this.emit('pageAdded');
|
|
@@ -5633,7 +5829,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5633
5829
|
}
|
|
5634
5830
|
continueOnNewPage(options) {
|
|
5635
5831
|
const pageMarkings = this.endPageMarkings(this.page);
|
|
5636
|
-
this.addPage(options);
|
|
5832
|
+
this.addPage(options ?? this.page._options);
|
|
5637
5833
|
this.initPageMarkings(pageMarkings);
|
|
5638
5834
|
return this;
|
|
5639
5835
|
}
|
|
@@ -5651,8 +5847,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5651
5847
|
return this.page = page;
|
|
5652
5848
|
}
|
|
5653
5849
|
flushPages() {
|
|
5654
|
-
// this local variable exists so we're future-proof against
|
|
5655
|
-
// reentrant calls to flushPages.
|
|
5656
5850
|
const pages = this._pageBuffer;
|
|
5657
5851
|
this._pageBuffer = [];
|
|
5658
5852
|
this._pageBufferStart += pages.length;
|
|
@@ -5673,13 +5867,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5673
5867
|
}
|
|
5674
5868
|
addNamedEmbeddedFile(name, ref) {
|
|
5675
5869
|
if (!this._root.data.Names.data.EmbeddedFiles) {
|
|
5676
|
-
// disabling /Limits for this tree fixes attachments not showing in Adobe Reader
|
|
5677
5870
|
this._root.data.Names.data.EmbeddedFiles = new PDFNameTree({
|
|
5678
5871
|
limits: false
|
|
5679
5872
|
});
|
|
5680
5873
|
}
|
|
5681
|
-
|
|
5682
|
-
// add filespec to EmbeddedFiles
|
|
5683
5874
|
this._root.data.Names.data.EmbeddedFiles.add(name, ref);
|
|
5684
5875
|
}
|
|
5685
5876
|
addNamedJavaScript(name, js) {
|
|
@@ -5694,19 +5885,17 @@ class PDFDocument extends stream.Readable {
|
|
|
5694
5885
|
}
|
|
5695
5886
|
ref(data) {
|
|
5696
5887
|
const ref = new PDFReference(this, this._offsets.length + 1, data);
|
|
5697
|
-
this._offsets.push(null);
|
|
5888
|
+
this._offsets.push(null);
|
|
5698
5889
|
this._waiting++;
|
|
5699
5890
|
return ref;
|
|
5700
5891
|
}
|
|
5701
5892
|
_read() {}
|
|
5702
|
-
// do nothing, but this method is required by node
|
|
5703
|
-
|
|
5704
5893
|
_write(data) {
|
|
5705
5894
|
if (!Buffer.isBuffer(data)) {
|
|
5706
5895
|
data = Buffer.from(data + '\n', 'binary');
|
|
5707
5896
|
}
|
|
5708
5897
|
this.push(data);
|
|
5709
|
-
|
|
5898
|
+
this._offset += data.length;
|
|
5710
5899
|
}
|
|
5711
5900
|
addContent(data) {
|
|
5712
5901
|
this.page.write(data);
|
|
@@ -5716,7 +5905,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5716
5905
|
this._offsets[ref.id - 1] = ref.offset;
|
|
5717
5906
|
if (--this._waiting === 0 && this._ended) {
|
|
5718
5907
|
this._finalize();
|
|
5719
|
-
|
|
5908
|
+
this._ended = false;
|
|
5720
5909
|
}
|
|
5721
5910
|
}
|
|
5722
5911
|
end() {
|
|
@@ -5753,13 +5942,12 @@ class PDFDocument extends stream.Readable {
|
|
|
5753
5942
|
this._security.end();
|
|
5754
5943
|
}
|
|
5755
5944
|
if (this._waiting === 0) {
|
|
5756
|
-
|
|
5945
|
+
this._finalize();
|
|
5757
5946
|
} else {
|
|
5758
|
-
|
|
5947
|
+
this._ended = true;
|
|
5759
5948
|
}
|
|
5760
5949
|
}
|
|
5761
5950
|
_finalize() {
|
|
5762
|
-
// generate xref
|
|
5763
5951
|
const xRefOffset = this._offset;
|
|
5764
5952
|
this._write('xref');
|
|
5765
5953
|
this._write(`0 ${this._offsets.length + 1}`);
|
|
@@ -5768,8 +5956,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5768
5956
|
offset = `0000000000${offset}`.slice(-10);
|
|
5769
5957
|
this._write(offset + ' 00000 n ');
|
|
5770
5958
|
}
|
|
5771
|
-
|
|
5772
|
-
// trailer
|
|
5773
5959
|
const trailer = {
|
|
5774
5960
|
Size: this._offsets.length + 1,
|
|
5775
5961
|
Root: this._root,
|
|
@@ -5784,9 +5970,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5784
5970
|
this._write('startxref');
|
|
5785
5971
|
this._write(`${xRefOffset}`);
|
|
5786
5972
|
this._write('%%EOF');
|
|
5787
|
-
|
|
5788
|
-
// end the stream
|
|
5789
|
-
return this.push(null);
|
|
5973
|
+
this.push(null);
|
|
5790
5974
|
}
|
|
5791
5975
|
toString() {
|
|
5792
5976
|
return '[object PDFDocument]';
|
|
@@ -5807,6 +5991,7 @@ mixin(MarkingsMixin);
|
|
|
5807
5991
|
mixin(AcroFormMixin);
|
|
5808
5992
|
mixin(AttachmentsMixin);
|
|
5809
5993
|
mixin(SubsetMixin);
|
|
5994
|
+
mixin(TableMixin);
|
|
5810
5995
|
PDFDocument.LineWrapper = LineWrapper;
|
|
5811
5996
|
|
|
5812
5997
|
module.exports = PDFDocument;
|