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.es.js
CHANGED
|
@@ -8,24 +8,16 @@ import LineBreaker from 'linebreak';
|
|
|
8
8
|
import exif from 'jpeg-exif';
|
|
9
9
|
import PNG from 'png-js';
|
|
10
10
|
|
|
11
|
-
/*
|
|
12
|
-
PDFAbstractReference - abstract class for PDF reference
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
11
|
class PDFAbstractReference {
|
|
16
12
|
toString() {
|
|
17
13
|
throw new Error('Must be implemented by subclasses');
|
|
18
14
|
}
|
|
19
15
|
}
|
|
20
16
|
|
|
21
|
-
/*
|
|
22
|
-
PDFTree - abstract base class for name and number tree objects
|
|
23
|
-
*/
|
|
24
17
|
class PDFTree {
|
|
25
18
|
constructor() {
|
|
26
19
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
27
20
|
this._items = {};
|
|
28
|
-
// disable /Limits output for this tree
|
|
29
21
|
this.limits = typeof options.limits === 'boolean' ? options.limits : true;
|
|
30
22
|
}
|
|
31
23
|
add(key, val) {
|
|
@@ -35,7 +27,6 @@ class PDFTree {
|
|
|
35
27
|
return this._items[key];
|
|
36
28
|
}
|
|
37
29
|
toString() {
|
|
38
|
-
// Needs to be sorted by key
|
|
39
30
|
const sortedKeys = Object.keys(this._items).sort((a, b) => this._compareKeys(a, b));
|
|
40
31
|
const out = ['<<'];
|
|
41
32
|
if (this.limits && sortedKeys.length > 1) {
|
|
@@ -51,15 +42,13 @@ class PDFTree {
|
|
|
51
42
|
out.push('>>');
|
|
52
43
|
return out.join('\n');
|
|
53
44
|
}
|
|
54
|
-
_compareKeys(
|
|
55
|
-
) {
|
|
45
|
+
_compareKeys() {
|
|
56
46
|
throw new Error('Must be implemented by subclasses');
|
|
57
47
|
}
|
|
58
48
|
_keysName() {
|
|
59
49
|
throw new Error('Must be implemented by subclasses');
|
|
60
50
|
}
|
|
61
|
-
_dataForKey(
|
|
62
|
-
) {
|
|
51
|
+
_dataForKey() {
|
|
63
52
|
throw new Error('Must be implemented by subclasses');
|
|
64
53
|
}
|
|
65
54
|
}
|
|
@@ -84,10 +73,6 @@ class SpotColor {
|
|
|
84
73
|
}
|
|
85
74
|
}
|
|
86
75
|
|
|
87
|
-
/*
|
|
88
|
-
PDFObject - converts JavaScript types into their corresponding PDF types.
|
|
89
|
-
By Devon Govett
|
|
90
|
-
*/
|
|
91
76
|
const pad = (str, length) => (Array(length + 1).join('0') + str).slice(-length);
|
|
92
77
|
const escapableRe = /[\n\r\t\b\f()\\]/g;
|
|
93
78
|
const escapable = {
|
|
@@ -100,8 +85,6 @@ const escapable = {
|
|
|
100
85
|
'(': '\\(',
|
|
101
86
|
')': '\\)'
|
|
102
87
|
};
|
|
103
|
-
|
|
104
|
-
// Convert little endian UTF-16 to big endian
|
|
105
88
|
const swapBytes = function (buff) {
|
|
106
89
|
const l = buff.length;
|
|
107
90
|
if (l & 0x01) {
|
|
@@ -118,14 +101,10 @@ const swapBytes = function (buff) {
|
|
|
118
101
|
class PDFObject {
|
|
119
102
|
static convert(object) {
|
|
120
103
|
let encryptFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 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) {
|
|
203
166
|
let data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
@@ -221,14 +184,14 @@ class PDFReference extends PDFAbstractReference {
|
|
|
221
184
|
this.buffer.push(chunk);
|
|
222
185
|
this.data.Length += chunk.length;
|
|
223
186
|
if (this.compress) {
|
|
224
|
-
|
|
187
|
+
this.data.Filter = 'FlateDecode';
|
|
225
188
|
}
|
|
226
189
|
}
|
|
227
190
|
end(chunk) {
|
|
228
191
|
if (chunk) {
|
|
229
192
|
this.write(chunk);
|
|
230
193
|
}
|
|
231
|
-
|
|
194
|
+
this.finalize();
|
|
232
195
|
}
|
|
233
196
|
finalize() {
|
|
234
197
|
this.offset = this.document._offset;
|
|
@@ -248,7 +211,7 @@ class PDFReference extends PDFAbstractReference {
|
|
|
248
211
|
if (this.buffer.length) {
|
|
249
212
|
this.document._write('stream');
|
|
250
213
|
this.document._write(this.buffer);
|
|
251
|
-
this.buffer = [];
|
|
214
|
+
this.buffer = [];
|
|
252
215
|
this.document._write('\nendstream');
|
|
253
216
|
}
|
|
254
217
|
this.document._write('endobj');
|
|
@@ -259,10 +222,71 @@ class PDFReference extends PDFAbstractReference {
|
|
|
259
222
|
}
|
|
260
223
|
}
|
|
261
224
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
225
|
+
function PDFNumber(n) {
|
|
226
|
+
return Math.fround(n);
|
|
227
|
+
}
|
|
228
|
+
function normalizeSides(sides) {
|
|
229
|
+
let defaultDefinition = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
|
230
|
+
let transformer = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : v => v;
|
|
231
|
+
if (sides == null || typeof sides === 'object' && Object.keys(sides).length === 0) {
|
|
232
|
+
sides = defaultDefinition;
|
|
233
|
+
}
|
|
234
|
+
if (sides == null || typeof sides !== 'object') {
|
|
235
|
+
sides = {
|
|
236
|
+
top: sides,
|
|
237
|
+
right: sides,
|
|
238
|
+
bottom: sides,
|
|
239
|
+
left: sides
|
|
240
|
+
};
|
|
241
|
+
} else if (Array.isArray(sides)) {
|
|
242
|
+
if (sides.length === 2) {
|
|
243
|
+
sides = {
|
|
244
|
+
vertical: sides[0],
|
|
245
|
+
horizontal: sides[1]
|
|
246
|
+
};
|
|
247
|
+
} else {
|
|
248
|
+
sides = {
|
|
249
|
+
top: sides[0],
|
|
250
|
+
right: sides[1],
|
|
251
|
+
bottom: sides[2],
|
|
252
|
+
left: sides[3]
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if ('vertical' in sides || 'horizontal' in sides) {
|
|
257
|
+
sides = {
|
|
258
|
+
top: sides.vertical,
|
|
259
|
+
right: sides.horizontal,
|
|
260
|
+
bottom: sides.vertical,
|
|
261
|
+
left: sides.horizontal
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
top: transformer(sides.top),
|
|
266
|
+
right: transformer(sides.right),
|
|
267
|
+
bottom: transformer(sides.bottom),
|
|
268
|
+
left: transformer(sides.left)
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const MM_TO_CM = 1 / 10;
|
|
272
|
+
const CM_TO_IN = 1 / 2.54;
|
|
273
|
+
const PX_TO_IN = 1 / 96;
|
|
274
|
+
const IN_TO_PT = 72;
|
|
275
|
+
const PC_TO_PT = 12;
|
|
276
|
+
function cosine(a) {
|
|
277
|
+
if (a === 0) return 1;
|
|
278
|
+
if (a === 90) return 0;
|
|
279
|
+
if (a === 180) return -1;
|
|
280
|
+
if (a === 270) return 0;
|
|
281
|
+
return Math.cos(a * Math.PI / 180);
|
|
282
|
+
}
|
|
283
|
+
function sine(a) {
|
|
284
|
+
if (a === 0) return 0;
|
|
285
|
+
if (a === 90) return 1;
|
|
286
|
+
if (a === 180) return 0;
|
|
287
|
+
if (a === 270) return -1;
|
|
288
|
+
return Math.sin(a * Math.PI / 180);
|
|
289
|
+
}
|
|
266
290
|
|
|
267
291
|
const DEFAULT_MARGINS = {
|
|
268
292
|
top: 72,
|
|
@@ -326,35 +350,19 @@ class PDFPage {
|
|
|
326
350
|
constructor(document) {
|
|
327
351
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
328
352
|
this.document = document;
|
|
353
|
+
this._options = options;
|
|
329
354
|
this.size = options.size || 'letter';
|
|
330
355
|
this.layout = options.layout || 'portrait';
|
|
331
|
-
|
|
332
|
-
// process margins
|
|
333
|
-
if (typeof options.margin === 'number') {
|
|
334
|
-
this.margins = {
|
|
335
|
-
top: options.margin,
|
|
336
|
-
left: options.margin,
|
|
337
|
-
bottom: options.margin,
|
|
338
|
-
right: options.margin
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
// default to 1 inch margins
|
|
342
|
-
} else {
|
|
343
|
-
this.margins = options.margins || DEFAULT_MARGINS;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// calculate page dimensions
|
|
347
356
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
348
357
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
349
358
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
350
359
|
this.content = this.document.ref();
|
|
351
|
-
|
|
352
|
-
|
|
360
|
+
if (options.font) document.font(options.font, options.fontFamily);
|
|
361
|
+
if (options.fontSize) document.fontSize(options.fontSize);
|
|
362
|
+
this.margins = normalizeSides(options.margin ?? options.margins, DEFAULT_MARGINS, x => document.sizeToPoint(x, 0, this));
|
|
353
363
|
this.resources = this.document.ref({
|
|
354
364
|
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI']
|
|
355
365
|
});
|
|
356
|
-
|
|
357
|
-
// The page dictionary
|
|
358
366
|
this.dictionary = this.document.ref({
|
|
359
367
|
Type: 'Page',
|
|
360
368
|
Parent: this.document._root.data.Pages,
|
|
@@ -364,8 +372,6 @@ class PDFPage {
|
|
|
364
372
|
});
|
|
365
373
|
this.markings = [];
|
|
366
374
|
}
|
|
367
|
-
|
|
368
|
-
// Lazily create these objects
|
|
369
375
|
get fonts() {
|
|
370
376
|
const data = this.resources.data;
|
|
371
377
|
return data.Font != null ? data.Font : data.Font = {};
|
|
@@ -394,14 +400,18 @@ class PDFPage {
|
|
|
394
400
|
const data = this.dictionary.data;
|
|
395
401
|
return data.StructParents != null ? data.StructParents : data.StructParents = this.document.createStructParentTreeNextKey();
|
|
396
402
|
}
|
|
403
|
+
get contentWidth() {
|
|
404
|
+
return this.width - this.margins.left - this.margins.right;
|
|
405
|
+
}
|
|
406
|
+
get contentHeight() {
|
|
407
|
+
return this.height - this.margins.top - this.margins.bottom;
|
|
408
|
+
}
|
|
397
409
|
maxY() {
|
|
398
410
|
return this.height - this.margins.bottom;
|
|
399
411
|
}
|
|
400
412
|
write(chunk) {
|
|
401
413
|
return this.content.write(chunk);
|
|
402
414
|
}
|
|
403
|
-
|
|
404
|
-
// Set tab order if document is tagged for accessibility.
|
|
405
415
|
_setTabOrder() {
|
|
406
416
|
if (!this.dictionary.Tabs && this.document.hasMarkInfoDictionary()) {
|
|
407
417
|
this.dictionary.data.Tabs = 'S';
|
|
@@ -419,191 +429,57 @@ class PDFPage {
|
|
|
419
429
|
}
|
|
420
430
|
}
|
|
421
431
|
|
|
422
|
-
/*
|
|
423
|
-
PDFNameTree - represents a name tree object
|
|
424
|
-
*/
|
|
425
432
|
class PDFNameTree extends PDFTree {
|
|
426
433
|
_compareKeys(a, b) {
|
|
427
434
|
return a.localeCompare(b);
|
|
428
435
|
}
|
|
429
436
|
_keysName() {
|
|
430
|
-
return
|
|
437
|
+
return 'Names';
|
|
431
438
|
}
|
|
432
439
|
_dataForKey(k) {
|
|
433
440
|
return new String(k);
|
|
434
441
|
}
|
|
435
442
|
}
|
|
436
443
|
|
|
437
|
-
/**
|
|
438
|
-
* Check if value is in a range group.
|
|
439
|
-
* @param {number} value
|
|
440
|
-
* @param {number[]} rangeGroup
|
|
441
|
-
* @returns {boolean}
|
|
442
|
-
*/
|
|
443
444
|
function inRange(value, rangeGroup) {
|
|
444
445
|
if (value < rangeGroup[0]) return false;
|
|
445
446
|
let startRange = 0;
|
|
446
447
|
let endRange = rangeGroup.length / 2;
|
|
447
448
|
while (startRange <= endRange) {
|
|
448
449
|
const middleRange = Math.floor((startRange + endRange) / 2);
|
|
449
|
-
|
|
450
|
-
// actual array index
|
|
451
450
|
const arrayIndex = middleRange * 2;
|
|
452
|
-
|
|
453
|
-
// Check if value is in range pointed by actual index
|
|
454
451
|
if (value >= rangeGroup[arrayIndex] && value <= rangeGroup[arrayIndex + 1]) {
|
|
455
452
|
return true;
|
|
456
453
|
}
|
|
457
454
|
if (value > rangeGroup[arrayIndex + 1]) {
|
|
458
|
-
// Search Right Side Of Array
|
|
459
455
|
startRange = middleRange + 1;
|
|
460
456
|
} else {
|
|
461
|
-
// Search Left Side Of Array
|
|
462
457
|
endRange = middleRange - 1;
|
|
463
458
|
}
|
|
464
459
|
}
|
|
465
460
|
return false;
|
|
466
461
|
}
|
|
467
462
|
|
|
468
|
-
// prettier-ignore-start
|
|
469
|
-
/**
|
|
470
|
-
* A.1 Unassigned code points in Unicode 3.2
|
|
471
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-A.1
|
|
472
|
-
*/
|
|
473
463
|
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];
|
|
474
|
-
// prettier-ignore-end
|
|
475
|
-
|
|
476
464
|
const isUnassignedCodePoint = character => inRange(character, unassigned_code_points);
|
|
477
|
-
|
|
478
|
-
// prettier-ignore-start
|
|
479
|
-
/**
|
|
480
|
-
* B.1 Commonly mapped to nothing
|
|
481
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-B.1
|
|
482
|
-
*/
|
|
483
465
|
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];
|
|
484
|
-
// prettier-ignore-end
|
|
485
|
-
|
|
486
466
|
const isCommonlyMappedToNothing = character => inRange(character, commonly_mapped_to_nothing);
|
|
487
|
-
|
|
488
|
-
// prettier-ignore-start
|
|
489
|
-
/**
|
|
490
|
-
* C.1.2 Non-ASCII space characters
|
|
491
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.1.2
|
|
492
|
-
*/
|
|
493
|
-
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 */];
|
|
494
|
-
// prettier-ignore-end
|
|
495
|
-
|
|
467
|
+
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];
|
|
496
468
|
const isNonASCIISpaceCharacter = character => inRange(character, non_ASCII_space_characters);
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
const
|
|
500
|
-
/**
|
|
501
|
-
* C.2.2 Non-ASCII control characters
|
|
502
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.2.2
|
|
503
|
-
*/
|
|
504
|
-
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] */];
|
|
505
|
-
const non_character_codepoints = [
|
|
506
|
-
/**
|
|
507
|
-
* C.4 Non-character code points
|
|
508
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.4
|
|
509
|
-
*/
|
|
510
|
-
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] */];
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* 2.3. Prohibited Output
|
|
514
|
-
*/
|
|
515
|
-
const prohibited_characters = [
|
|
516
|
-
/**
|
|
517
|
-
* C.2.1 ASCII control characters
|
|
518
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.2.1
|
|
519
|
-
*/
|
|
520
|
-
0, 0x001f /* [CONTROL CHARACTERS] */, 0x007f, 0x007f /* DELETE */,
|
|
521
|
-
/**
|
|
522
|
-
* C.8 Change display properties or are deprecated
|
|
523
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.8
|
|
524
|
-
*/
|
|
525
|
-
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 */,
|
|
526
|
-
/**
|
|
527
|
-
* C.7 Inappropriate for canonical representation
|
|
528
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.7
|
|
529
|
-
*/
|
|
530
|
-
0x2ff0, 0x2ffb /* [IDEOGRAPHIC DESCRIPTION CHARACTERS] */,
|
|
531
|
-
/**
|
|
532
|
-
* C.5 Surrogate codes
|
|
533
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.5
|
|
534
|
-
*/
|
|
535
|
-
0xd800, 0xdfff,
|
|
536
|
-
/**
|
|
537
|
-
* C.3 Private use
|
|
538
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.3
|
|
539
|
-
*/
|
|
540
|
-
0xe000, 0xf8ff /* [PRIVATE USE, PLANE 0] */,
|
|
541
|
-
/**
|
|
542
|
-
* C.6 Inappropriate for plain text
|
|
543
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.6
|
|
544
|
-
*/
|
|
545
|
-
0xfff9, 0xfff9 /* INTERLINEAR ANNOTATION ANCHOR */, 0xfffa, 0xfffa /* INTERLINEAR ANNOTATION SEPARATOR */, 0xfffb, 0xfffb /* INTERLINEAR ANNOTATION TERMINATOR */, 0xfffc, 0xfffc /* OBJECT REPLACEMENT CHARACTER */, 0xfffd, 0xfffd /* REPLACEMENT CHARACTER */,
|
|
546
|
-
/**
|
|
547
|
-
* C.9 Tagging characters
|
|
548
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.9
|
|
549
|
-
*/
|
|
550
|
-
0xe0001, 0xe0001 /* LANGUAGE TAG */, 0xe0020, 0xe007f /* [TAGGING CHARACTERS] */,
|
|
551
|
-
/**
|
|
552
|
-
* C.3 Private use
|
|
553
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-C.3
|
|
554
|
-
*/
|
|
555
|
-
|
|
556
|
-
0xf0000, 0xffffd /* [PRIVATE USE, PLANE 15] */, 0x100000, 0x10fffd /* [PRIVATE USE, PLANE 16] */];
|
|
557
|
-
// prettier-ignore-end
|
|
558
|
-
|
|
469
|
+
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];
|
|
470
|
+
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];
|
|
471
|
+
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];
|
|
559
472
|
const isProhibitedCharacter = character => inRange(character, non_ASCII_space_characters) || inRange(character, prohibited_characters) || inRange(character, non_ASCII_controls_characters) || inRange(character, non_character_codepoints);
|
|
560
|
-
|
|
561
|
-
// prettier-ignore-start
|
|
562
|
-
/**
|
|
563
|
-
* D.1 Characters with bidirectional property "R" or "AL"
|
|
564
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-D.1
|
|
565
|
-
*/
|
|
566
473
|
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];
|
|
567
|
-
// prettier-ignore-end
|
|
568
|
-
|
|
569
474
|
const isBidirectionalRAL = character => inRange(character, bidirectional_r_al);
|
|
570
|
-
|
|
571
|
-
// prettier-ignore-start
|
|
572
|
-
/**
|
|
573
|
-
* D.2 Characters with bidirectional property "L"
|
|
574
|
-
* @link https://tools.ietf.org/html/rfc3454#appendix-D.2
|
|
575
|
-
*/
|
|
576
475
|
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];
|
|
577
|
-
// prettier-ignore-end
|
|
578
|
-
|
|
579
476
|
const isBidirectionalL = character => inRange(character, bidirectional_l);
|
|
580
477
|
|
|
581
|
-
// 2.1. Mapping
|
|
582
|
-
|
|
583
|
-
/**
|
|
584
|
-
* non-ASCII space characters [StringPrep, C.1.2] that can be
|
|
585
|
-
* mapped to SPACE (U+0020)
|
|
586
|
-
*/
|
|
587
478
|
const mapping2space = isNonASCIISpaceCharacter;
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* the "commonly mapped to nothing" characters [StringPrep, B.1]
|
|
591
|
-
* that can be mapped to nothing.
|
|
592
|
-
*/
|
|
593
479
|
const mapping2nothing = isCommonlyMappedToNothing;
|
|
594
|
-
|
|
595
|
-
// utils
|
|
596
480
|
const getCodePoint = character => character.codePointAt(0);
|
|
597
481
|
const first = x => x[0];
|
|
598
482
|
const last = x => x[x.length - 1];
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Convert provided string into an array of Unicode Code Points.
|
|
602
|
-
* Based on https://stackoverflow.com/a/21409165/1556249
|
|
603
|
-
* and https://www.npmjs.com/package/code-point-at.
|
|
604
|
-
* @param {string} input
|
|
605
|
-
* @returns {number[]}
|
|
606
|
-
*/
|
|
607
483
|
function toCodePoints(input) {
|
|
608
484
|
const codepoints = [];
|
|
609
485
|
const size = input.length;
|
|
@@ -621,14 +497,6 @@ function toCodePoints(input) {
|
|
|
621
497
|
}
|
|
622
498
|
return codepoints;
|
|
623
499
|
}
|
|
624
|
-
|
|
625
|
-
/**
|
|
626
|
-
* SASLprep.
|
|
627
|
-
* @param {string} input
|
|
628
|
-
* @param {Object} opts
|
|
629
|
-
* @param {boolean} opts.allowUnassigned
|
|
630
|
-
* @returns {string}
|
|
631
|
-
*/
|
|
632
500
|
function saslprep(input) {
|
|
633
501
|
let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
634
502
|
if (typeof input !== 'string') {
|
|
@@ -637,49 +505,24 @@ function saslprep(input) {
|
|
|
637
505
|
if (input.length === 0) {
|
|
638
506
|
return '';
|
|
639
507
|
}
|
|
640
|
-
|
|
641
|
-
// 1. Map
|
|
642
|
-
const mapped_input = toCodePoints(input)
|
|
643
|
-
// 1.1 mapping to space
|
|
644
|
-
.map(character => mapping2space(character) ? 0x20 : character)
|
|
645
|
-
// 1.2 mapping to nothing
|
|
646
|
-
.filter(character => !mapping2nothing(character));
|
|
647
|
-
|
|
648
|
-
// 2. Normalize
|
|
508
|
+
const mapped_input = toCodePoints(input).map(character => mapping2space(character) ? 0x20 : character).filter(character => !mapping2nothing(character));
|
|
649
509
|
const normalized_input = String.fromCodePoint.apply(null, mapped_input).normalize('NFKC');
|
|
650
510
|
const normalized_map = toCodePoints(normalized_input);
|
|
651
|
-
|
|
652
|
-
// 3. Prohibit
|
|
653
511
|
const hasProhibited = normalized_map.some(isProhibitedCharacter);
|
|
654
512
|
if (hasProhibited) {
|
|
655
513
|
throw new Error('Prohibited character, see https://tools.ietf.org/html/rfc4013#section-2.3');
|
|
656
514
|
}
|
|
657
|
-
|
|
658
|
-
// Unassigned Code Points
|
|
659
515
|
if (opts.allowUnassigned !== true) {
|
|
660
516
|
const hasUnassigned = normalized_map.some(isUnassignedCodePoint);
|
|
661
517
|
if (hasUnassigned) {
|
|
662
518
|
throw new Error('Unassigned code point, see https://tools.ietf.org/html/rfc4013#section-2.5');
|
|
663
519
|
}
|
|
664
520
|
}
|
|
665
|
-
|
|
666
|
-
// 4. check bidi
|
|
667
|
-
|
|
668
521
|
const hasBidiRAL = normalized_map.some(isBidirectionalRAL);
|
|
669
522
|
const hasBidiL = normalized_map.some(isBidirectionalL);
|
|
670
|
-
|
|
671
|
-
// 4.1 If a string contains any RandALCat character, the string MUST NOT
|
|
672
|
-
// contain any LCat character.
|
|
673
523
|
if (hasBidiRAL && hasBidiL) {
|
|
674
524
|
throw new Error('String must not contain RandALCat and LCat at the same time,' + ' see https://tools.ietf.org/html/rfc3454#section-6');
|
|
675
525
|
}
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* 4.2 If a string contains any RandALCat character, a RandALCat
|
|
679
|
-
* character MUST be the first character of the string, and a
|
|
680
|
-
* RandALCat character MUST be the last character of the string.
|
|
681
|
-
*/
|
|
682
|
-
|
|
683
526
|
const isFirstBidiRAL = isBidirectionalRAL(getCodePoint(first(normalized_input)));
|
|
684
527
|
const isLastBidiRAL = isBidirectionalRAL(getCodePoint(last(normalized_input)));
|
|
685
528
|
if (hasBidiRAL && !(isFirstBidiRAL && isLastBidiRAL)) {
|
|
@@ -688,16 +531,11 @@ function saslprep(input) {
|
|
|
688
531
|
return normalized_input;
|
|
689
532
|
}
|
|
690
533
|
|
|
691
|
-
/*
|
|
692
|
-
PDFSecurity - represents PDF security settings
|
|
693
|
-
By Yang Liu <hi@zesik.com>
|
|
694
|
-
*/
|
|
695
534
|
class PDFSecurity {
|
|
696
535
|
static generateFileID() {
|
|
697
536
|
let info = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
698
537
|
let infoStr = `${info.CreationDate.getTime()}\n`;
|
|
699
538
|
for (let key in info) {
|
|
700
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
701
539
|
if (!info.hasOwnProperty(key)) {
|
|
702
540
|
continue;
|
|
703
541
|
}
|
|
@@ -1077,8 +915,6 @@ class PDFGradient$1 {
|
|
|
1077
915
|
}
|
|
1078
916
|
this.embedded = true;
|
|
1079
917
|
this.matrix = m;
|
|
1080
|
-
|
|
1081
|
-
// if the last stop comes before 100%, add a copy at 100%
|
|
1082
918
|
const last = this.stops[stopsLength - 1];
|
|
1083
919
|
if (last[0] < 1) {
|
|
1084
920
|
this.stops.push([1, last[1], last[2]]);
|
|
@@ -1101,14 +937,11 @@ class PDFGradient$1 {
|
|
|
1101
937
|
stops.push(fn);
|
|
1102
938
|
fn.end();
|
|
1103
939
|
}
|
|
1104
|
-
|
|
1105
|
-
// if there are only two stops, we don't need a stitching function
|
|
1106
940
|
if (stopsLength === 1) {
|
|
1107
941
|
fn = stops[0];
|
|
1108
942
|
} else {
|
|
1109
943
|
fn = this.doc.ref({
|
|
1110
944
|
FunctionType: 3,
|
|
1111
|
-
// stitching function
|
|
1112
945
|
Domain: [0, 1],
|
|
1113
946
|
Functions: stops,
|
|
1114
947
|
Bounds: bounds,
|
|
@@ -1189,7 +1022,6 @@ class PDFGradient$1 {
|
|
|
1189
1022
|
return pattern;
|
|
1190
1023
|
}
|
|
1191
1024
|
apply(stroke) {
|
|
1192
|
-
// apply gradient transform to existing document ctm
|
|
1193
1025
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1194
1026
|
const [m11, m12, m21, m22, dx, dy] = this.transform;
|
|
1195
1027
|
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];
|
|
@@ -1252,10 +1084,6 @@ var Gradient = {
|
|
|
1252
1084
|
PDFRadialGradient: PDFRadialGradient$1
|
|
1253
1085
|
};
|
|
1254
1086
|
|
|
1255
|
-
/*
|
|
1256
|
-
PDF tiling pattern support. Uncolored only.
|
|
1257
|
-
*/
|
|
1258
|
-
|
|
1259
1087
|
const underlyingColorSpaces = ['DeviceCMYK', 'DeviceRGB'];
|
|
1260
1088
|
class PDFTilingPattern$1 {
|
|
1261
1089
|
constructor(doc, bBox, xStep, yStep, stream) {
|
|
@@ -1266,23 +1094,16 @@ class PDFTilingPattern$1 {
|
|
|
1266
1094
|
this.stream = stream;
|
|
1267
1095
|
}
|
|
1268
1096
|
createPattern() {
|
|
1269
|
-
// no resources needed for our current usage
|
|
1270
|
-
// required entry
|
|
1271
1097
|
const resources = this.doc.ref();
|
|
1272
1098
|
resources.end();
|
|
1273
|
-
// apply default transform matrix (flipped in the default doc._ctm)
|
|
1274
|
-
// see document.js & gradient.js
|
|
1275
1099
|
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
|
|
1276
1100
|
const [m11, m12, m21, m22, dx, dy] = [1, 0, 0, 1, 0, 0];
|
|
1277
1101
|
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];
|
|
1278
1102
|
const pattern = this.doc.ref({
|
|
1279
1103
|
Type: 'Pattern',
|
|
1280
1104
|
PatternType: 1,
|
|
1281
|
-
// tiling
|
|
1282
1105
|
PaintType: 2,
|
|
1283
|
-
// 1-colored, 2-uncolored
|
|
1284
1106
|
TilingType: 2,
|
|
1285
|
-
// 2-no distortion
|
|
1286
1107
|
BBox: this.bBox,
|
|
1287
1108
|
XStep: this.xStep,
|
|
1288
1109
|
YStep: this.yStep,
|
|
@@ -1293,8 +1114,6 @@ class PDFTilingPattern$1 {
|
|
|
1293
1114
|
return pattern;
|
|
1294
1115
|
}
|
|
1295
1116
|
embedPatternColorSpaces() {
|
|
1296
|
-
// map each pattern to an underlying color space
|
|
1297
|
-
// and embed on each page
|
|
1298
1117
|
underlyingColorSpaces.forEach(csName => {
|
|
1299
1118
|
const csId = this.getPatternColorSpaceId(csName);
|
|
1300
1119
|
if (this.doc.page.colorSpaces[csId]) return;
|
|
@@ -1312,24 +1131,17 @@ class PDFTilingPattern$1 {
|
|
|
1312
1131
|
this.id = 'P' + this.doc._patternCount;
|
|
1313
1132
|
this.pattern = this.createPattern();
|
|
1314
1133
|
}
|
|
1315
|
-
|
|
1316
|
-
// patterns are embedded in each page
|
|
1317
1134
|
if (!this.doc.page.patterns[this.id]) {
|
|
1318
1135
|
this.doc.page.patterns[this.id] = this.pattern;
|
|
1319
1136
|
}
|
|
1320
1137
|
}
|
|
1321
1138
|
apply(stroke, patternColor) {
|
|
1322
|
-
// do any embedding/creating that might be needed
|
|
1323
1139
|
this.embedPatternColorSpaces();
|
|
1324
1140
|
this.embed();
|
|
1325
1141
|
const normalizedColor = this.doc._normalizeColor(patternColor);
|
|
1326
1142
|
if (!normalizedColor) throw Error(`invalid pattern color. (value: ${patternColor})`);
|
|
1327
|
-
|
|
1328
|
-
// select one of the pattern color spaces
|
|
1329
1143
|
const csId = this.getPatternColorSpaceId(this.doc._getColorSpace(normalizedColor));
|
|
1330
1144
|
this.doc._setColorSpace(csId, stroke);
|
|
1331
|
-
|
|
1332
|
-
// stroke/fill using the pattern and color (in the above underlying color space)
|
|
1333
1145
|
const op = stroke ? 'SCN' : 'scn';
|
|
1334
1146
|
return this.doc.addContent(`${normalizedColor.join(' ')} /${this.id} ${op}`);
|
|
1335
1147
|
}
|
|
@@ -1349,11 +1161,10 @@ const {
|
|
|
1349
1161
|
var ColorMixin = {
|
|
1350
1162
|
initColor() {
|
|
1351
1163
|
this.spotColors = {};
|
|
1352
|
-
// The opacity dictionaries
|
|
1353
1164
|
this._opacityRegistry = {};
|
|
1354
1165
|
this._opacityCount = 0;
|
|
1355
1166
|
this._patternCount = 0;
|
|
1356
|
-
|
|
1167
|
+
this._gradCount = 0;
|
|
1357
1168
|
},
|
|
1358
1169
|
_normalizeColor(color) {
|
|
1359
1170
|
if (typeof color === 'string') {
|
|
@@ -1370,10 +1181,8 @@ var ColorMixin = {
|
|
|
1370
1181
|
}
|
|
1371
1182
|
}
|
|
1372
1183
|
if (Array.isArray(color)) {
|
|
1373
|
-
// RGB
|
|
1374
1184
|
if (color.length === 3) {
|
|
1375
1185
|
color = color.map(part => part / 255);
|
|
1376
|
-
// CMYK
|
|
1377
1186
|
} else if (color.length === 4) {
|
|
1378
1187
|
color = color.map(part => part / 100);
|
|
1379
1188
|
}
|
|
@@ -1385,12 +1194,10 @@ var ColorMixin = {
|
|
|
1385
1194
|
if (color instanceof PDFGradient) {
|
|
1386
1195
|
color.apply(stroke);
|
|
1387
1196
|
return true;
|
|
1388
|
-
// see if tiling pattern, decode & apply it it
|
|
1389
1197
|
} else if (Array.isArray(color) && color[0] instanceof PDFTilingPattern) {
|
|
1390
1198
|
color[0].apply(stroke, color[1]);
|
|
1391
1199
|
return true;
|
|
1392
1200
|
}
|
|
1393
|
-
// any other case should be a normal color and not a pattern
|
|
1394
1201
|
return this._setColorCore(color, stroke);
|
|
1395
1202
|
},
|
|
1396
1203
|
_setColorCore(color, stroke) {
|
|
@@ -1424,9 +1231,6 @@ var ColorMixin = {
|
|
|
1424
1231
|
if (set) {
|
|
1425
1232
|
this.fillOpacity(opacity);
|
|
1426
1233
|
}
|
|
1427
|
-
|
|
1428
|
-
// save this for text wrapper, which needs to reset
|
|
1429
|
-
// the fill color on new pages
|
|
1430
1234
|
this._fillColor = [color, opacity];
|
|
1431
1235
|
return this;
|
|
1432
1236
|
},
|
|
@@ -1682,7 +1486,6 @@ const parse = function (path) {
|
|
|
1682
1486
|
if (parameters[c] != null) {
|
|
1683
1487
|
params = parameters[c];
|
|
1684
1488
|
if (cmd) {
|
|
1685
|
-
// save existing command
|
|
1686
1489
|
if (curArg.length > 0) {
|
|
1687
1490
|
args[args.length] = +curArg;
|
|
1688
1491
|
}
|
|
@@ -1700,14 +1503,11 @@ const parse = function (path) {
|
|
|
1700
1503
|
continue;
|
|
1701
1504
|
}
|
|
1702
1505
|
if (args.length === params) {
|
|
1703
|
-
// handle reused commands
|
|
1704
1506
|
ret[ret.length] = {
|
|
1705
1507
|
cmd,
|
|
1706
1508
|
args
|
|
1707
1509
|
};
|
|
1708
1510
|
args = [+curArg];
|
|
1709
|
-
|
|
1710
|
-
// handle assumed commands
|
|
1711
1511
|
if (cmd === 'M') {
|
|
1712
1512
|
cmd = 'L';
|
|
1713
1513
|
}
|
|
@@ -1718,8 +1518,6 @@ const parse = function (path) {
|
|
|
1718
1518
|
args[args.length] = +curArg;
|
|
1719
1519
|
}
|
|
1720
1520
|
foundDecimal = c === '.';
|
|
1721
|
-
|
|
1722
|
-
// fix for negative numbers or repeated decimals with no delimeter between commands
|
|
1723
1521
|
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1724
1522
|
} else {
|
|
1725
1523
|
curArg += c;
|
|
@@ -1728,18 +1526,13 @@ const parse = function (path) {
|
|
|
1728
1526
|
}
|
|
1729
1527
|
}
|
|
1730
1528
|
}
|
|
1731
|
-
|
|
1732
|
-
// add the last command
|
|
1733
1529
|
if (curArg.length > 0) {
|
|
1734
1530
|
if (args.length === params) {
|
|
1735
|
-
// handle reused commands
|
|
1736
1531
|
ret[ret.length] = {
|
|
1737
1532
|
cmd,
|
|
1738
1533
|
args
|
|
1739
1534
|
};
|
|
1740
1535
|
args = [+curArg];
|
|
1741
|
-
|
|
1742
|
-
// handle assumed commands
|
|
1743
1536
|
if (cmd === 'M') {
|
|
1744
1537
|
cmd = 'L';
|
|
1745
1538
|
}
|
|
@@ -1757,10 +1550,7 @@ const parse = function (path) {
|
|
|
1757
1550
|
return ret;
|
|
1758
1551
|
};
|
|
1759
1552
|
const apply = function (commands, doc) {
|
|
1760
|
-
// current point, control point, and subpath starting point
|
|
1761
1553
|
cx = cy = px = py = sx = sy = 0;
|
|
1762
|
-
|
|
1763
|
-
// run the commands
|
|
1764
1554
|
for (let i = 0; i < commands.length; i++) {
|
|
1765
1555
|
const c = commands[i];
|
|
1766
1556
|
if (typeof runners[c.cmd] === 'function') {
|
|
@@ -1924,8 +1714,6 @@ const solveArc = function (doc, x, y, coords) {
|
|
|
1924
1714
|
doc.bezierCurveTo(...bez);
|
|
1925
1715
|
}
|
|
1926
1716
|
};
|
|
1927
|
-
|
|
1928
|
-
// from Inkscape svgtopdf, thanks!
|
|
1929
1717
|
const arcToSegments = function (x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
|
1930
1718
|
const th = rotateX * (Math.PI / 180);
|
|
1931
1719
|
const sin_th = Math.sin(th);
|
|
@@ -2001,18 +1789,14 @@ class SVGPath {
|
|
|
2001
1789
|
const {
|
|
2002
1790
|
number: number$1
|
|
2003
1791
|
} = PDFObject;
|
|
2004
|
-
|
|
2005
|
-
// This constant is used to approximate a symmetrical arc using a cubic
|
|
2006
|
-
// Bezier curve.
|
|
2007
1792
|
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
|
|
2008
1793
|
var VectorMixin = {
|
|
2009
1794
|
initVector() {
|
|
2010
|
-
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
2011
|
-
|
|
1795
|
+
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
1796
|
+
this._ctmStack = [];
|
|
2012
1797
|
},
|
|
2013
1798
|
save() {
|
|
2014
1799
|
this._ctmStack.push(this._ctm.slice());
|
|
2015
|
-
// TODO: save/restore colorspace and styles so not setting it unnessesarily all the time?
|
|
2016
1800
|
return this.addContent('q');
|
|
2017
1801
|
},
|
|
2018
1802
|
restore() {
|
|
@@ -2086,8 +1870,6 @@ var VectorMixin = {
|
|
|
2086
1870
|
r = 0;
|
|
2087
1871
|
}
|
|
2088
1872
|
r = Math.min(r, 0.5 * w, 0.5 * h);
|
|
2089
|
-
|
|
2090
|
-
// amount to inset control points from corners (see `ellipse`)
|
|
2091
1873
|
const c = r * (1.0 - KAPPA);
|
|
2092
1874
|
this.moveTo(x + r, y);
|
|
2093
1875
|
this.lineTo(x + w - r, y);
|
|
@@ -2101,7 +1883,6 @@ var VectorMixin = {
|
|
|
2101
1883
|
return this.closePath();
|
|
2102
1884
|
},
|
|
2103
1885
|
ellipse(x, y, r1, r2) {
|
|
2104
|
-
// based on http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas/2173084#2173084
|
|
2105
1886
|
if (r2 == null) {
|
|
2106
1887
|
r2 = r1;
|
|
2107
1888
|
}
|
|
@@ -2131,10 +1912,8 @@ var VectorMixin = {
|
|
|
2131
1912
|
const HALF_PI = 0.5 * Math.PI;
|
|
2132
1913
|
let deltaAng = endAngle - startAngle;
|
|
2133
1914
|
if (Math.abs(deltaAng) > TWO_PI) {
|
|
2134
|
-
// draw only full circle if more than that is specified
|
|
2135
1915
|
deltaAng = TWO_PI;
|
|
2136
1916
|
} else if (deltaAng !== 0 && anticlockwise !== deltaAng < 0) {
|
|
2137
|
-
// necessary to flip direction of rendering
|
|
2138
1917
|
const dir = anticlockwise ? -1 : 1;
|
|
2139
1918
|
deltaAng = dir * TWO_PI + deltaAng;
|
|
2140
1919
|
}
|
|
@@ -2142,38 +1921,21 @@ var VectorMixin = {
|
|
|
2142
1921
|
const segAng = deltaAng / numSegs;
|
|
2143
1922
|
const handleLen = segAng / HALF_PI * KAPPA * radius;
|
|
2144
1923
|
let curAng = startAngle;
|
|
2145
|
-
|
|
2146
|
-
// component distances between anchor point and control point
|
|
2147
1924
|
let deltaCx = -Math.sin(curAng) * handleLen;
|
|
2148
1925
|
let deltaCy = Math.cos(curAng) * handleLen;
|
|
2149
|
-
|
|
2150
|
-
// anchor point
|
|
2151
1926
|
let ax = x + Math.cos(curAng) * radius;
|
|
2152
1927
|
let ay = y + Math.sin(curAng) * radius;
|
|
2153
|
-
|
|
2154
|
-
// calculate and render segments
|
|
2155
1928
|
this.moveTo(ax, ay);
|
|
2156
1929
|
for (let segIdx = 0; segIdx < numSegs; segIdx++) {
|
|
2157
|
-
// starting control point
|
|
2158
1930
|
const cp1x = ax + deltaCx;
|
|
2159
1931
|
const cp1y = ay + deltaCy;
|
|
2160
|
-
|
|
2161
|
-
// step angle
|
|
2162
1932
|
curAng += segAng;
|
|
2163
|
-
|
|
2164
|
-
// next anchor point
|
|
2165
1933
|
ax = x + Math.cos(curAng) * radius;
|
|
2166
1934
|
ay = y + Math.sin(curAng) * radius;
|
|
2167
|
-
|
|
2168
|
-
// next control point delta
|
|
2169
1935
|
deltaCx = -Math.sin(curAng) * handleLen;
|
|
2170
1936
|
deltaCy = Math.cos(curAng) * handleLen;
|
|
2171
|
-
|
|
2172
|
-
// ending control point
|
|
2173
1937
|
const cp2x = ax - deltaCx;
|
|
2174
1938
|
const cp2y = ay - deltaCy;
|
|
2175
|
-
|
|
2176
|
-
// render segment
|
|
2177
1939
|
this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, ax, ay);
|
|
2178
1940
|
}
|
|
2179
1941
|
return this;
|
|
@@ -2237,9 +1999,7 @@ var VectorMixin = {
|
|
|
2237
1999
|
return this.addContent(`W${this._windingRule(rule)} n`);
|
|
2238
2000
|
},
|
|
2239
2001
|
transform(m11, m12, m21, m22, dx, dy) {
|
|
2240
|
-
// keep track of the current transformation matrix
|
|
2241
2002
|
if (m11 === 1 && m12 === 0 && m21 === 0 && m22 === 1 && dx === 0 && dy === 0) {
|
|
2242
|
-
// Ignore identity transforms
|
|
2243
2003
|
return this;
|
|
2244
2004
|
}
|
|
2245
2005
|
const m = this._ctm;
|
|
@@ -2405,7 +2165,6 @@ class AFMFont {
|
|
|
2405
2165
|
this.boundingBoxes = {};
|
|
2406
2166
|
this.kernPairs = {};
|
|
2407
2167
|
this.parse();
|
|
2408
|
-
// todo: remove charWidths since appears to not be used
|
|
2409
2168
|
this.charWidths = new Array(256);
|
|
2410
2169
|
for (let char = 0; char <= 255; char++) {
|
|
2411
2170
|
this.charWidths[char] = this.glyphWidths[characters[char]];
|
|
@@ -2512,21 +2271,18 @@ class PDFFont {
|
|
|
2512
2271
|
return;
|
|
2513
2272
|
}
|
|
2514
2273
|
this.embed();
|
|
2515
|
-
|
|
2274
|
+
this.embedded = true;
|
|
2516
2275
|
}
|
|
2517
2276
|
embed() {
|
|
2518
2277
|
throw new Error('Must be implemented by subclasses');
|
|
2519
2278
|
}
|
|
2520
|
-
lineHeight(size
|
|
2521
|
-
|
|
2522
|
-
includeGap = false;
|
|
2523
|
-
}
|
|
2279
|
+
lineHeight(size) {
|
|
2280
|
+
let includeGap = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
2524
2281
|
const gap = includeGap ? this.lineGap : 0;
|
|
2525
2282
|
return (this.ascender + gap - this.descender) / 1000 * size;
|
|
2526
2283
|
}
|
|
2527
2284
|
}
|
|
2528
2285
|
|
|
2529
|
-
// This insanity is so bundlers can inline the font files
|
|
2530
2286
|
const STANDARD_FONTS = {
|
|
2531
2287
|
Courier() {
|
|
2532
2288
|
return fs.readFileSync(__dirname + '/data/Courier.afm', 'utf8');
|
|
@@ -2654,8 +2410,6 @@ class EmbeddedFont extends PDFFont {
|
|
|
2654
2410
|
}
|
|
2655
2411
|
layoutRun(text, features) {
|
|
2656
2412
|
const run = this.font.layout(text, features);
|
|
2657
|
-
|
|
2658
|
-
// Normalize position values
|
|
2659
2413
|
for (let i = 0; i < run.positions.length; i++) {
|
|
2660
2414
|
const position = run.positions[i];
|
|
2661
2415
|
for (let key in position) {
|
|
@@ -2678,16 +2432,12 @@ class EmbeddedFont extends PDFFont {
|
|
|
2678
2432
|
return run;
|
|
2679
2433
|
}
|
|
2680
2434
|
layout(text, features, onlyWidth) {
|
|
2681
|
-
// Skip the cache if any user defined features are applied
|
|
2682
2435
|
if (features) {
|
|
2683
2436
|
return this.layoutRun(text, features);
|
|
2684
2437
|
}
|
|
2685
2438
|
let glyphs = onlyWidth ? null : [];
|
|
2686
2439
|
let positions = onlyWidth ? null : [];
|
|
2687
2440
|
let advanceWidth = 0;
|
|
2688
|
-
|
|
2689
|
-
// Split the string by words to increase cache efficiency.
|
|
2690
|
-
// For this purpose, spaces and tabs are a good enough delimeter.
|
|
2691
2441
|
let last = 0;
|
|
2692
2442
|
let index = 0;
|
|
2693
2443
|
while (index <= text.length) {
|
|
@@ -2749,17 +2499,15 @@ class EmbeddedFont extends PDFFont {
|
|
|
2749
2499
|
if (1 <= familyClass && familyClass <= 7) {
|
|
2750
2500
|
flags |= 1 << 1;
|
|
2751
2501
|
}
|
|
2752
|
-
flags |= 1 << 2;
|
|
2502
|
+
flags |= 1 << 2;
|
|
2753
2503
|
if (familyClass === 10) {
|
|
2754
2504
|
flags |= 1 << 3;
|
|
2755
2505
|
}
|
|
2756
2506
|
if (this.font.head.macStyle.italic) {
|
|
2757
2507
|
flags |= 1 << 6;
|
|
2758
2508
|
}
|
|
2759
|
-
|
|
2760
|
-
// generate a tag (6 uppercase letters. 17 is the char code offset from '0' to 'A'. 73 will map to 'Z')
|
|
2761
2509
|
const tag = [1, 2, 3, 4, 5, 6].map(i => String.fromCharCode((this.id.charCodeAt(i) || 73) + 17)).join('');
|
|
2762
|
-
const name = tag + '+' + this.font.postscriptName
|
|
2510
|
+
const name = tag + '+' + this.font.postscriptName?.replaceAll(' ', '_');
|
|
2763
2511
|
const {
|
|
2764
2512
|
bbox
|
|
2765
2513
|
} = this.font;
|
|
@@ -2774,8 +2522,7 @@ class EmbeddedFont extends PDFFont {
|
|
|
2774
2522
|
CapHeight: (this.font.capHeight || this.font.ascent) * this.scale,
|
|
2775
2523
|
XHeight: (this.font.xHeight || 0) * this.scale,
|
|
2776
2524
|
StemV: 0
|
|
2777
|
-
});
|
|
2778
|
-
|
|
2525
|
+
});
|
|
2779
2526
|
if (isCFF) {
|
|
2780
2527
|
descriptor.data.FontFile3 = fontFile;
|
|
2781
2528
|
} else {
|
|
@@ -2817,17 +2564,11 @@ class EmbeddedFont extends PDFFont {
|
|
|
2817
2564
|
};
|
|
2818
2565
|
return this.dictionary.end();
|
|
2819
2566
|
}
|
|
2820
|
-
|
|
2821
|
-
// Maps the glyph ids encoded in the PDF back to unicode strings
|
|
2822
|
-
// Because of ligature substitutions and the like, there may be one or more
|
|
2823
|
-
// unicode characters represented by each glyph.
|
|
2824
2567
|
toUnicodeCmap() {
|
|
2825
2568
|
const cmap = this.document.ref();
|
|
2826
2569
|
const entries = [];
|
|
2827
2570
|
for (let codePoints of this.unicode) {
|
|
2828
2571
|
const encoded = [];
|
|
2829
|
-
|
|
2830
|
-
// encode codePoints to utf16
|
|
2831
2572
|
for (let value of codePoints) {
|
|
2832
2573
|
if (value > 0xffff) {
|
|
2833
2574
|
value -= 0x10000;
|
|
@@ -2894,12 +2635,9 @@ class PDFFontFactory {
|
|
|
2894
2635
|
}
|
|
2895
2636
|
|
|
2896
2637
|
const isEqualFont = (font1, font2) => {
|
|
2897
|
-
// compare font checksum
|
|
2898
2638
|
if (font1.font._tables?.head?.checkSumAdjustment !== font2.font._tables?.head?.checkSumAdjustment) {
|
|
2899
2639
|
return false;
|
|
2900
2640
|
}
|
|
2901
|
-
|
|
2902
|
-
// compare font name table
|
|
2903
2641
|
if (JSON.stringify(font1.font._tables?.name?.records) !== JSON.stringify(font2.font._tables?.name?.records)) {
|
|
2904
2642
|
return false;
|
|
2905
2643
|
}
|
|
@@ -2908,18 +2646,18 @@ const isEqualFont = (font1, font2) => {
|
|
|
2908
2646
|
var FontsMixin = {
|
|
2909
2647
|
initFonts() {
|
|
2910
2648
|
let defaultFont = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'Helvetica';
|
|
2911
|
-
|
|
2649
|
+
let defaultFontFamily = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
2650
|
+
let defaultFontSize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 12;
|
|
2912
2651
|
this._fontFamilies = {};
|
|
2913
2652
|
this._fontCount = 0;
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
this._fontSize =
|
|
2653
|
+
this._fontSource = defaultFont;
|
|
2654
|
+
this._fontFamily = defaultFontFamily;
|
|
2655
|
+
this._fontSize = defaultFontSize;
|
|
2917
2656
|
this._font = null;
|
|
2657
|
+
this._remSize = defaultFontSize;
|
|
2918
2658
|
this._registeredFonts = {};
|
|
2919
|
-
|
|
2920
|
-
// Set the default font
|
|
2921
2659
|
if (defaultFont) {
|
|
2922
|
-
this.font(defaultFont);
|
|
2660
|
+
this.font(defaultFont, defaultFontFamily);
|
|
2923
2661
|
}
|
|
2924
2662
|
},
|
|
2925
2663
|
font(src, family, size) {
|
|
@@ -2928,8 +2666,6 @@ var FontsMixin = {
|
|
|
2928
2666
|
size = family;
|
|
2929
2667
|
family = null;
|
|
2930
2668
|
}
|
|
2931
|
-
|
|
2932
|
-
// check registered fonts if src is a string
|
|
2933
2669
|
if (typeof src === 'string' && this._registeredFonts[src]) {
|
|
2934
2670
|
cacheKey = src;
|
|
2935
2671
|
({
|
|
@@ -2942,28 +2678,21 @@ var FontsMixin = {
|
|
|
2942
2678
|
cacheKey = null;
|
|
2943
2679
|
}
|
|
2944
2680
|
}
|
|
2681
|
+
this._fontSource = src;
|
|
2682
|
+
this._fontFamily = family;
|
|
2945
2683
|
if (size != null) {
|
|
2946
2684
|
this.fontSize(size);
|
|
2947
2685
|
}
|
|
2948
|
-
|
|
2949
|
-
// fast path: check if the font is already in the PDF
|
|
2950
2686
|
if (font = this._fontFamilies[cacheKey]) {
|
|
2951
2687
|
this._font = font;
|
|
2952
2688
|
return this;
|
|
2953
2689
|
}
|
|
2954
|
-
|
|
2955
|
-
// load the font
|
|
2956
2690
|
const id = `F${++this._fontCount}`;
|
|
2957
2691
|
this._font = PDFFontFactory.open(this, src, family, id);
|
|
2958
|
-
|
|
2959
|
-
// check for existing font familes with the same name already in the PDF
|
|
2960
|
-
// useful if the font was passed as a buffer
|
|
2961
2692
|
if ((font = this._fontFamilies[this._font.name]) && isEqualFont(this._font, font)) {
|
|
2962
2693
|
this._font = font;
|
|
2963
2694
|
return this;
|
|
2964
2695
|
}
|
|
2965
|
-
|
|
2966
|
-
// save the font for reuse later
|
|
2967
2696
|
if (cacheKey) {
|
|
2968
2697
|
this._fontFamilies[cacheKey] = this._font;
|
|
2969
2698
|
}
|
|
@@ -2973,13 +2702,10 @@ var FontsMixin = {
|
|
|
2973
2702
|
return this;
|
|
2974
2703
|
},
|
|
2975
2704
|
fontSize(_fontSize) {
|
|
2976
|
-
this._fontSize = _fontSize;
|
|
2705
|
+
this._fontSize = this.sizeToPoint(_fontSize);
|
|
2977
2706
|
return this;
|
|
2978
2707
|
},
|
|
2979
2708
|
currentLineHeight(includeGap) {
|
|
2980
|
-
if (includeGap == null) {
|
|
2981
|
-
includeGap = false;
|
|
2982
|
-
}
|
|
2983
2709
|
return this._font.lineHeight(this._fontSize, includeGap);
|
|
2984
2710
|
},
|
|
2985
2711
|
registerFont(name, src, family) {
|
|
@@ -2988,6 +2714,67 @@ var FontsMixin = {
|
|
|
2988
2714
|
family
|
|
2989
2715
|
};
|
|
2990
2716
|
return this;
|
|
2717
|
+
},
|
|
2718
|
+
sizeToPoint(size) {
|
|
2719
|
+
let defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
2720
|
+
let page = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.page;
|
|
2721
|
+
let percentageWidth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
|
|
2722
|
+
if (!percentageWidth) percentageWidth = this._fontSize;
|
|
2723
|
+
if (typeof defaultValue !== 'number') defaultValue = this.sizeToPoint(defaultValue);
|
|
2724
|
+
if (size === undefined) return defaultValue;
|
|
2725
|
+
if (typeof size === 'number') return size;
|
|
2726
|
+
if (typeof size === 'boolean') return Number(size);
|
|
2727
|
+
const match = String(size).match(/((\d+)?(\.\d+)?)(em|in|px|cm|mm|pc|ex|ch|rem|vw|vh|vmin|vmax|%|pt)?/);
|
|
2728
|
+
if (!match) throw new Error(`Unsupported size '${size}'`);
|
|
2729
|
+
let multiplier;
|
|
2730
|
+
switch (match[4]) {
|
|
2731
|
+
case 'em':
|
|
2732
|
+
multiplier = this._fontSize;
|
|
2733
|
+
break;
|
|
2734
|
+
case 'in':
|
|
2735
|
+
multiplier = IN_TO_PT;
|
|
2736
|
+
break;
|
|
2737
|
+
case 'px':
|
|
2738
|
+
multiplier = PX_TO_IN * IN_TO_PT;
|
|
2739
|
+
break;
|
|
2740
|
+
case 'cm':
|
|
2741
|
+
multiplier = CM_TO_IN * IN_TO_PT;
|
|
2742
|
+
break;
|
|
2743
|
+
case 'mm':
|
|
2744
|
+
multiplier = MM_TO_CM * CM_TO_IN * IN_TO_PT;
|
|
2745
|
+
break;
|
|
2746
|
+
case 'pc':
|
|
2747
|
+
multiplier = PC_TO_PT;
|
|
2748
|
+
break;
|
|
2749
|
+
case 'ex':
|
|
2750
|
+
multiplier = this.currentLineHeight();
|
|
2751
|
+
break;
|
|
2752
|
+
case 'ch':
|
|
2753
|
+
multiplier = this.widthOfString('0');
|
|
2754
|
+
break;
|
|
2755
|
+
case 'rem':
|
|
2756
|
+
multiplier = this._remSize;
|
|
2757
|
+
break;
|
|
2758
|
+
case 'vw':
|
|
2759
|
+
multiplier = page.width / 100;
|
|
2760
|
+
break;
|
|
2761
|
+
case 'vh':
|
|
2762
|
+
multiplier = page.height / 100;
|
|
2763
|
+
break;
|
|
2764
|
+
case 'vmin':
|
|
2765
|
+
multiplier = Math.min(page.width, page.height) / 100;
|
|
2766
|
+
break;
|
|
2767
|
+
case 'vmax':
|
|
2768
|
+
multiplier = Math.max(page.width, page.height) / 100;
|
|
2769
|
+
break;
|
|
2770
|
+
case '%':
|
|
2771
|
+
multiplier = percentageWidth / 100;
|
|
2772
|
+
break;
|
|
2773
|
+
case 'pt':
|
|
2774
|
+
default:
|
|
2775
|
+
multiplier = 1;
|
|
2776
|
+
}
|
|
2777
|
+
return multiplier * Number(match[1]);
|
|
2991
2778
|
}
|
|
2992
2779
|
};
|
|
2993
2780
|
|
|
@@ -3002,7 +2789,7 @@ class LineWrapper extends EventEmitter {
|
|
|
3002
2789
|
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
3003
2790
|
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
3004
2791
|
this.columns = options.columns || 1;
|
|
3005
|
-
this.columnGap = (options.columnGap != null ? options.columnGap : 18) * this.horizontalScaling / 100;
|
|
2792
|
+
this.columnGap = (options.columnGap != null ? options.columnGap : 18) * this.horizontalScaling / 100;
|
|
3006
2793
|
this.lineWidth = (options.width * this.horizontalScaling / 100 - this.columnGap * (this.columns - 1)) / this.columns;
|
|
3007
2794
|
this.spaceLeft = this.lineWidth;
|
|
3008
2795
|
this.startX = this.document.x;
|
|
@@ -3011,44 +2798,30 @@ class LineWrapper extends EventEmitter {
|
|
|
3011
2798
|
this.ellipsis = options.ellipsis;
|
|
3012
2799
|
this.continuedX = 0;
|
|
3013
2800
|
this.features = options.features;
|
|
3014
|
-
|
|
3015
|
-
// calculate the maximum Y position the text can appear at
|
|
3016
2801
|
if (options.height != null) {
|
|
3017
2802
|
this.height = options.height;
|
|
3018
|
-
this.maxY = this.startY + options.height;
|
|
2803
|
+
this.maxY = PDFNumber(this.startY + options.height);
|
|
3019
2804
|
} else {
|
|
3020
|
-
this.maxY = this.document.page.maxY();
|
|
2805
|
+
this.maxY = PDFNumber(this.document.page.maxY());
|
|
3021
2806
|
}
|
|
3022
|
-
|
|
3023
|
-
// handle paragraph indents
|
|
3024
2807
|
this.on('firstLine', options => {
|
|
3025
|
-
// if this is the first line of the text segment, and
|
|
3026
|
-
// we're continuing where we left off, indent that much
|
|
3027
|
-
// otherwise use the user specified indent option
|
|
3028
2808
|
const indent = this.continuedX || this.indent;
|
|
3029
2809
|
this.document.x += indent;
|
|
3030
2810
|
this.lineWidth -= indent;
|
|
3031
|
-
|
|
3032
|
-
// if indentAllLines is set to true
|
|
3033
|
-
// we're not resetting the indentation for this paragraph after the first line
|
|
3034
2811
|
if (options.indentAllLines) {
|
|
3035
2812
|
return;
|
|
3036
2813
|
}
|
|
3037
|
-
|
|
3038
|
-
// otherwise we start the next line without indent
|
|
3039
|
-
return this.once('line', () => {
|
|
2814
|
+
this.once('line', () => {
|
|
3040
2815
|
this.document.x -= indent;
|
|
3041
2816
|
this.lineWidth += indent;
|
|
3042
2817
|
if (options.continued && !this.continuedX) {
|
|
3043
2818
|
this.continuedX = this.indent;
|
|
3044
2819
|
}
|
|
3045
2820
|
if (!options.continued) {
|
|
3046
|
-
|
|
2821
|
+
this.continuedX = 0;
|
|
3047
2822
|
}
|
|
3048
2823
|
});
|
|
3049
2824
|
});
|
|
3050
|
-
|
|
3051
|
-
// handle left aligning last lines of paragraphs
|
|
3052
2825
|
this.on('lastLine', options => {
|
|
3053
2826
|
const {
|
|
3054
2827
|
align
|
|
@@ -3057,7 +2830,7 @@ class LineWrapper extends EventEmitter {
|
|
|
3057
2830
|
options.align = 'left';
|
|
3058
2831
|
}
|
|
3059
2832
|
this.lastLine = true;
|
|
3060
|
-
|
|
2833
|
+
this.once('line', () => {
|
|
3061
2834
|
this.document.y += options.paragraphGap || 0;
|
|
3062
2835
|
options.align = align;
|
|
3063
2836
|
return this.lastLine = false;
|
|
@@ -3074,7 +2847,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3074
2847
|
return w + this.wordWidth(HYPHEN) <= this.spaceLeft;
|
|
3075
2848
|
}
|
|
3076
2849
|
eachWord(text, fn) {
|
|
3077
|
-
// setup a unicode line breaker
|
|
3078
2850
|
let bk;
|
|
3079
2851
|
const breaker = new LineBreaker(text);
|
|
3080
2852
|
let last = null;
|
|
@@ -3083,19 +2855,12 @@ class LineWrapper extends EventEmitter {
|
|
|
3083
2855
|
var shouldContinue;
|
|
3084
2856
|
let word = text.slice((last != null ? last.position : undefined) || 0, bk.position);
|
|
3085
2857
|
let w = wordWidths[word] != null ? wordWidths[word] : wordWidths[word] = this.wordWidth(word);
|
|
3086
|
-
|
|
3087
|
-
// if the word is longer than the whole line, chop it up
|
|
3088
|
-
// TODO: break by grapheme clusters, not JS string characters
|
|
3089
2858
|
if (w > this.lineWidth + this.continuedX) {
|
|
3090
|
-
// make some fake break objects
|
|
3091
2859
|
let lbk = last;
|
|
3092
2860
|
const fbk = {};
|
|
3093
2861
|
while (word.length) {
|
|
3094
|
-
// fit as much of the word as possible into the space we have
|
|
3095
2862
|
var l, mightGrow;
|
|
3096
2863
|
if (w > this.spaceLeft) {
|
|
3097
|
-
// start our check at the end of our available space - this method is faster than a loop of each character and it resolves
|
|
3098
|
-
// an issue with long loops when processing massive words, such as a huge number of spaces
|
|
3099
2864
|
l = Math.ceil(this.spaceLeft / (w / word.length));
|
|
3100
2865
|
w = this.wordWidth(word.slice(0, l));
|
|
3101
2866
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
@@ -3103,7 +2868,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3103
2868
|
l = word.length;
|
|
3104
2869
|
}
|
|
3105
2870
|
let mustShrink = w > this.spaceLeft && l > 0;
|
|
3106
|
-
// shrink or grow word as necessary after our near-guess above
|
|
3107
2871
|
while (mustShrink || mightGrow) {
|
|
3108
2872
|
if (mustShrink) {
|
|
3109
2873
|
w = this.wordWidth(word.slice(0, --l));
|
|
@@ -3114,20 +2878,14 @@ class LineWrapper extends EventEmitter {
|
|
|
3114
2878
|
mightGrow = w <= this.spaceLeft && l < word.length;
|
|
3115
2879
|
}
|
|
3116
2880
|
}
|
|
3117
|
-
|
|
3118
|
-
// check for the edge case where a single character cannot fit into a line.
|
|
3119
2881
|
if (l === 0 && this.spaceLeft === this.lineWidth) {
|
|
3120
2882
|
l = 1;
|
|
3121
2883
|
}
|
|
3122
|
-
|
|
3123
|
-
// send a required break unless this is the last piece and a linebreak is not specified
|
|
3124
2884
|
fbk.required = bk.required || l < word.length;
|
|
3125
2885
|
shouldContinue = fn(word.slice(0, l), w, fbk, lbk);
|
|
3126
2886
|
lbk = {
|
|
3127
2887
|
required: false
|
|
3128
2888
|
};
|
|
3129
|
-
|
|
3130
|
-
// get the remaining piece of the word
|
|
3131
2889
|
word = word.slice(l);
|
|
3132
2890
|
w = this.wordWidth(word);
|
|
3133
2891
|
if (shouldContinue === false) {
|
|
@@ -3135,7 +2893,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3135
2893
|
}
|
|
3136
2894
|
}
|
|
3137
2895
|
} else {
|
|
3138
|
-
// otherwise just emit the break as it was given to us
|
|
3139
2896
|
shouldContinue = fn(word, w, bk, last);
|
|
3140
2897
|
}
|
|
3141
2898
|
if (shouldContinue === false) {
|
|
@@ -3145,7 +2902,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3145
2902
|
}
|
|
3146
2903
|
}
|
|
3147
2904
|
wrap(text, options) {
|
|
3148
|
-
// override options from previous continued fragments
|
|
3149
2905
|
this.horizontalScaling = options.horizontalScaling || 100;
|
|
3150
2906
|
if (options.indent != null) {
|
|
3151
2907
|
this.indent = options.indent * this.horizontalScaling / 100;
|
|
@@ -3159,10 +2915,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3159
2915
|
if (options.ellipsis != null) {
|
|
3160
2916
|
this.ellipsis = options.ellipsis;
|
|
3161
2917
|
}
|
|
3162
|
-
|
|
3163
|
-
// make sure we're actually on the page
|
|
3164
|
-
// and that the first line of is never by
|
|
3165
|
-
// itself at the bottom of a page (orphans)
|
|
3166
2918
|
const nextY = this.document.y + this.document.currentLineHeight(true);
|
|
3167
2919
|
if (this.document.y > this.maxY || nextY > this.maxY) {
|
|
3168
2920
|
this.nextSection();
|
|
@@ -3173,7 +2925,7 @@ class LineWrapper extends EventEmitter {
|
|
|
3173
2925
|
let lc = 0;
|
|
3174
2926
|
let {
|
|
3175
2927
|
y
|
|
3176
|
-
} = this.document;
|
|
2928
|
+
} = this.document;
|
|
3177
2929
|
const emitLine = () => {
|
|
3178
2930
|
options.textWidth = textWidth + this.wordSpacing * (wc - 1);
|
|
3179
2931
|
options.wordCount = wc;
|
|
@@ -3196,23 +2948,17 @@ class LineWrapper extends EventEmitter {
|
|
|
3196
2948
|
wc++;
|
|
3197
2949
|
}
|
|
3198
2950
|
if (bk.required || !this.canFit(word, w)) {
|
|
3199
|
-
// if the user specified a max height and an ellipsis, and is about to pass the
|
|
3200
|
-
// max height and max columns after the next line, append the ellipsis
|
|
3201
2951
|
const lh = this.document.currentLineHeight(true);
|
|
3202
|
-
if (this.height != null && this.ellipsis && this.document.y + lh * 2 > this.maxY && this.column >= this.columns) {
|
|
2952
|
+
if (this.height != null && this.ellipsis && PDFNumber(this.document.y + lh * 2) > this.maxY && this.column >= this.columns) {
|
|
3203
2953
|
if (this.ellipsis === true) {
|
|
3204
2954
|
this.ellipsis = '…';
|
|
3205
|
-
}
|
|
2955
|
+
}
|
|
3206
2956
|
buffer = buffer.replace(/\s+$/, '');
|
|
3207
2957
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3208
|
-
|
|
3209
|
-
// remove characters from the buffer until the ellipsis fits
|
|
3210
|
-
// to avoid infinite loop need to stop while-loop if buffer is empty string
|
|
3211
2958
|
while (buffer && textWidth > this.lineWidth) {
|
|
3212
2959
|
buffer = buffer.slice(0, -1).replace(/\s+$/, '');
|
|
3213
2960
|
textWidth = this.wordWidth(buffer + this.ellipsis);
|
|
3214
2961
|
}
|
|
3215
|
-
// need to add ellipsis only if there is enough space for it
|
|
3216
2962
|
if (textWidth <= this.lineWidth) {
|
|
3217
2963
|
buffer = buffer + this.ellipsis;
|
|
3218
2964
|
}
|
|
@@ -3227,35 +2973,25 @@ class LineWrapper extends EventEmitter {
|
|
|
3227
2973
|
}
|
|
3228
2974
|
this.emit('lastLine', options, this);
|
|
3229
2975
|
}
|
|
3230
|
-
|
|
3231
|
-
// Previous entry is a soft hyphen - add visible hyphen.
|
|
3232
2976
|
if (buffer[buffer.length - 1] == SOFT_HYPHEN) {
|
|
3233
2977
|
buffer = buffer.slice(0, -1) + HYPHEN;
|
|
3234
2978
|
this.spaceLeft -= this.wordWidth(HYPHEN);
|
|
3235
2979
|
}
|
|
3236
2980
|
emitLine();
|
|
3237
|
-
|
|
3238
|
-
// if we've reached the edge of the page,
|
|
3239
|
-
// continue on a new page or column
|
|
3240
|
-
if (this.document.y + lh > this.maxY) {
|
|
2981
|
+
if (PDFNumber(this.document.y + lh) > this.maxY) {
|
|
3241
2982
|
const shouldContinue = this.nextSection();
|
|
3242
|
-
|
|
3243
|
-
// stop if we reached the maximum height
|
|
3244
2983
|
if (!shouldContinue) {
|
|
3245
2984
|
wc = 0;
|
|
3246
2985
|
buffer = '';
|
|
3247
2986
|
return false;
|
|
3248
2987
|
}
|
|
3249
2988
|
}
|
|
3250
|
-
|
|
3251
|
-
// reset the space left and buffer
|
|
3252
2989
|
if (bk.required) {
|
|
3253
2990
|
this.spaceLeft = this.lineWidth;
|
|
3254
2991
|
buffer = '';
|
|
3255
2992
|
textWidth = 0;
|
|
3256
2993
|
return wc = 0;
|
|
3257
2994
|
} else {
|
|
3258
|
-
// reset the space left and buffer
|
|
3259
2995
|
this.spaceLeft = this.lineWidth - w;
|
|
3260
2996
|
buffer = word;
|
|
3261
2997
|
textWidth = w;
|
|
@@ -3270,25 +3006,19 @@ class LineWrapper extends EventEmitter {
|
|
|
3270
3006
|
emitLine();
|
|
3271
3007
|
}
|
|
3272
3008
|
this.emit('sectionEnd', options, this);
|
|
3273
|
-
|
|
3274
|
-
// if the wrap is set to be continued, save the X position
|
|
3275
|
-
// to start the first line of the next segment at, and reset
|
|
3276
|
-
// the y position
|
|
3277
3009
|
if (options.continued === true) {
|
|
3278
3010
|
if (lc > 1) {
|
|
3279
3011
|
this.continuedX = 0;
|
|
3280
3012
|
}
|
|
3281
3013
|
this.continuedX += options.textWidth || 0;
|
|
3282
|
-
|
|
3014
|
+
this.document.y = y;
|
|
3283
3015
|
} else {
|
|
3284
|
-
|
|
3016
|
+
this.document.x = this.startX;
|
|
3285
3017
|
}
|
|
3286
3018
|
}
|
|
3287
3019
|
nextSection(options) {
|
|
3288
3020
|
this.emit('sectionEnd', options, this);
|
|
3289
3021
|
if (++this.column > this.columns) {
|
|
3290
|
-
// if a max height was specified by the user, we're done.
|
|
3291
|
-
// otherwise, the default is to make a new page at the bottom.
|
|
3292
3022
|
if (this.height != null) {
|
|
3293
3023
|
return false;
|
|
3294
3024
|
}
|
|
@@ -3317,10 +3047,9 @@ const {
|
|
|
3317
3047
|
var TextMixin = {
|
|
3318
3048
|
initText() {
|
|
3319
3049
|
this._line = this._line.bind(this);
|
|
3320
|
-
// Current coordinates
|
|
3321
3050
|
this.x = 0;
|
|
3322
3051
|
this.y = 0;
|
|
3323
|
-
|
|
3052
|
+
this._lineGap = 0;
|
|
3324
3053
|
},
|
|
3325
3054
|
lineGap(_lineGap) {
|
|
3326
3055
|
this._lineGap = _lineGap;
|
|
@@ -3342,11 +3071,7 @@ var TextMixin = {
|
|
|
3342
3071
|
},
|
|
3343
3072
|
_text(text, x, y, options, lineCallback) {
|
|
3344
3073
|
options = this._initOptions(x, y, options);
|
|
3345
|
-
|
|
3346
|
-
// Convert text to a string
|
|
3347
3074
|
text = text == null ? '' : `${text}`;
|
|
3348
|
-
|
|
3349
|
-
// if the wordSpacing option is specified, remove multiple consecutive spaces
|
|
3350
3075
|
if (options.wordSpacing) {
|
|
3351
3076
|
text = text.replace(/\s{2,}/g, ' ');
|
|
3352
3077
|
}
|
|
@@ -3355,8 +3080,12 @@ var TextMixin = {
|
|
|
3355
3080
|
options.structParent.add(this.struct(options.structType || 'P', [this.markStructureContent(options.structType || 'P')]));
|
|
3356
3081
|
}
|
|
3357
3082
|
};
|
|
3358
|
-
|
|
3359
|
-
|
|
3083
|
+
if (options.rotation !== 0) {
|
|
3084
|
+
this.save();
|
|
3085
|
+
this.rotate(-options.rotation, {
|
|
3086
|
+
origin: [this.x, this.y]
|
|
3087
|
+
});
|
|
3088
|
+
}
|
|
3360
3089
|
if (options.width) {
|
|
3361
3090
|
let wrapper = this._wrapper;
|
|
3362
3091
|
if (!wrapper) {
|
|
@@ -3367,14 +3096,13 @@ var TextMixin = {
|
|
|
3367
3096
|
this._wrapper = options.continued ? wrapper : null;
|
|
3368
3097
|
this._textOptions = options.continued ? options : null;
|
|
3369
3098
|
wrapper.wrap(text, options);
|
|
3370
|
-
|
|
3371
|
-
// render paragraphs as single lines
|
|
3372
3099
|
} else {
|
|
3373
3100
|
for (let line of text.split('\n')) {
|
|
3374
3101
|
addStructure();
|
|
3375
3102
|
lineCallback(line, options);
|
|
3376
3103
|
}
|
|
3377
3104
|
}
|
|
3105
|
+
if (options.rotation !== 0) this.restore();
|
|
3378
3106
|
return this;
|
|
3379
3107
|
},
|
|
3380
3108
|
text(text, x, y, options) {
|
|
@@ -3385,17 +3113,108 @@ var TextMixin = {
|
|
|
3385
3113
|
const horizontalScaling = options.horizontalScaling || 100;
|
|
3386
3114
|
return (this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1)) * horizontalScaling / 100;
|
|
3387
3115
|
},
|
|
3116
|
+
boundsOfString(string, x, y, options) {
|
|
3117
|
+
options = this._initOptions(x, y, options);
|
|
3118
|
+
({
|
|
3119
|
+
x,
|
|
3120
|
+
y
|
|
3121
|
+
} = this);
|
|
3122
|
+
const lineGap = options.lineGap ?? this._lineGap ?? 0;
|
|
3123
|
+
const lineHeight = this.currentLineHeight(true) + lineGap;
|
|
3124
|
+
let contentWidth = 0;
|
|
3125
|
+
string = String(string ?? '');
|
|
3126
|
+
if (options.wordSpacing) {
|
|
3127
|
+
string = string.replace(/\s{2,}/g, ' ');
|
|
3128
|
+
}
|
|
3129
|
+
if (options.width) {
|
|
3130
|
+
let wrapper = new LineWrapper(this, options);
|
|
3131
|
+
wrapper.on('line', (text, options) => {
|
|
3132
|
+
this.y += lineHeight;
|
|
3133
|
+
text = text.replace(/\n/g, '');
|
|
3134
|
+
if (text.length) {
|
|
3135
|
+
let wordSpacing = options.wordSpacing ?? 0;
|
|
3136
|
+
const characterSpacing = options.characterSpacing ?? 0;
|
|
3137
|
+
if (options.width && options.align === 'justify') {
|
|
3138
|
+
const words = text.trim().split(/\s+/);
|
|
3139
|
+
const textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3140
|
+
const spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
3141
|
+
wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth);
|
|
3142
|
+
}
|
|
3143
|
+
contentWidth = Math.max(contentWidth, options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1));
|
|
3144
|
+
}
|
|
3145
|
+
});
|
|
3146
|
+
wrapper.wrap(string, options);
|
|
3147
|
+
} else {
|
|
3148
|
+
for (let line of string.split('\n')) {
|
|
3149
|
+
const lineWidth = this.widthOfString(line, options);
|
|
3150
|
+
this.y += lineHeight;
|
|
3151
|
+
contentWidth = Math.max(contentWidth, lineWidth);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
let contentHeight = this.y - y;
|
|
3155
|
+
if (options.height) contentHeight = Math.min(contentHeight, options.height);
|
|
3156
|
+
this.x = x;
|
|
3157
|
+
this.y = y;
|
|
3158
|
+
if (options.rotation === 0) {
|
|
3159
|
+
return {
|
|
3160
|
+
x,
|
|
3161
|
+
y,
|
|
3162
|
+
width: contentWidth,
|
|
3163
|
+
height: contentHeight
|
|
3164
|
+
};
|
|
3165
|
+
} else if (options.rotation === 90) {
|
|
3166
|
+
return {
|
|
3167
|
+
x: x,
|
|
3168
|
+
y: y - contentWidth,
|
|
3169
|
+
width: contentHeight,
|
|
3170
|
+
height: contentWidth
|
|
3171
|
+
};
|
|
3172
|
+
} else if (options.rotation === 180) {
|
|
3173
|
+
return {
|
|
3174
|
+
x: x - contentWidth,
|
|
3175
|
+
y: y - contentHeight,
|
|
3176
|
+
width: contentWidth,
|
|
3177
|
+
height: contentHeight
|
|
3178
|
+
};
|
|
3179
|
+
} else if (options.rotation === 270) {
|
|
3180
|
+
return {
|
|
3181
|
+
x: x - contentHeight,
|
|
3182
|
+
y: y,
|
|
3183
|
+
width: contentHeight,
|
|
3184
|
+
height: contentWidth
|
|
3185
|
+
};
|
|
3186
|
+
}
|
|
3187
|
+
const cos = cosine(options.rotation);
|
|
3188
|
+
const sin = sine(options.rotation);
|
|
3189
|
+
const x1 = x;
|
|
3190
|
+
const y1 = y;
|
|
3191
|
+
const x2 = x + contentWidth * cos;
|
|
3192
|
+
const y2 = y - contentWidth * sin;
|
|
3193
|
+
const x3 = x + contentWidth * cos + contentHeight * sin;
|
|
3194
|
+
const y3 = y - contentWidth * sin + contentHeight * cos;
|
|
3195
|
+
const x4 = x + contentHeight * sin;
|
|
3196
|
+
const y4 = y + contentHeight * cos;
|
|
3197
|
+
const xMin = Math.min(x1, x2, x3, x4);
|
|
3198
|
+
const xMax = Math.max(x1, x2, x3, x4);
|
|
3199
|
+
const yMin = Math.min(y1, y2, y3, y4);
|
|
3200
|
+
const yMax = Math.max(y1, y2, y3, y4);
|
|
3201
|
+
return {
|
|
3202
|
+
x: xMin,
|
|
3203
|
+
y: yMin,
|
|
3204
|
+
width: xMax - xMin,
|
|
3205
|
+
height: yMax - yMin
|
|
3206
|
+
};
|
|
3207
|
+
},
|
|
3388
3208
|
heightOfString(text, options) {
|
|
3389
3209
|
const {
|
|
3390
3210
|
x,
|
|
3391
3211
|
y
|
|
3392
3212
|
} = this;
|
|
3393
3213
|
options = this._initOptions(options);
|
|
3394
|
-
options.height = Infinity;
|
|
3395
|
-
|
|
3214
|
+
options.height = Infinity;
|
|
3396
3215
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3397
3216
|
this._text(text, this.x, this.y, options, () => {
|
|
3398
|
-
|
|
3217
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3399
3218
|
});
|
|
3400
3219
|
const height = this.y - y;
|
|
3401
3220
|
this.x = x;
|
|
@@ -3493,12 +3312,12 @@ var TextMixin = {
|
|
|
3493
3312
|
wrapper.on('sectionStart', () => {
|
|
3494
3313
|
const pos = indent + itemIndent * (level - 1);
|
|
3495
3314
|
this.x += pos;
|
|
3496
|
-
|
|
3315
|
+
wrapper.lineWidth -= pos;
|
|
3497
3316
|
});
|
|
3498
3317
|
wrapper.on('sectionEnd', () => {
|
|
3499
3318
|
const pos = indent + itemIndent * (level - 1);
|
|
3500
3319
|
this.x -= pos;
|
|
3501
|
-
|
|
3320
|
+
wrapper.lineWidth += pos;
|
|
3502
3321
|
});
|
|
3503
3322
|
wrapper.wrap(listItem, options);
|
|
3504
3323
|
};
|
|
@@ -3515,11 +3334,7 @@ var TextMixin = {
|
|
|
3515
3334
|
options = x;
|
|
3516
3335
|
x = null;
|
|
3517
3336
|
}
|
|
3518
|
-
|
|
3519
|
-
// clone options object
|
|
3520
3337
|
const result = Object.assign({}, options);
|
|
3521
|
-
|
|
3522
|
-
// extend options with previous values for continued text
|
|
3523
3338
|
if (this._textOptions) {
|
|
3524
3339
|
for (let key in this._textOptions) {
|
|
3525
3340
|
const val = this._textOptions[key];
|
|
@@ -3530,16 +3345,12 @@ var TextMixin = {
|
|
|
3530
3345
|
}
|
|
3531
3346
|
}
|
|
3532
3347
|
}
|
|
3533
|
-
|
|
3534
|
-
// Update the current position
|
|
3535
3348
|
if (x != null) {
|
|
3536
3349
|
this.x = x;
|
|
3537
3350
|
}
|
|
3538
3351
|
if (y != null) {
|
|
3539
3352
|
this.y = y;
|
|
3540
3353
|
}
|
|
3541
|
-
|
|
3542
|
-
// wrap to margins if no x or y position passed
|
|
3543
3354
|
if (result.lineBreak !== false) {
|
|
3544
3355
|
if (result.width == null) {
|
|
3545
3356
|
result.width = this.page.width - this.x - this.page.margins.right;
|
|
@@ -3551,8 +3362,9 @@ var TextMixin = {
|
|
|
3551
3362
|
}
|
|
3552
3363
|
if (result.columnGap == null) {
|
|
3553
3364
|
result.columnGap = 18;
|
|
3554
|
-
}
|
|
3555
|
-
|
|
3365
|
+
}
|
|
3366
|
+
result.rotation = Number(options.rotation ?? 0) % 360;
|
|
3367
|
+
if (result.rotation < 0) result.rotation += 360;
|
|
3556
3368
|
return result;
|
|
3557
3369
|
},
|
|
3558
3370
|
_line(text) {
|
|
@@ -3561,9 +3373,9 @@ var TextMixin = {
|
|
|
3561
3373
|
this._fragment(text, this.x, this.y, options);
|
|
3562
3374
|
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3563
3375
|
if (!wrapper) {
|
|
3564
|
-
|
|
3376
|
+
this.x += this.widthOfString(text, options);
|
|
3565
3377
|
} else {
|
|
3566
|
-
|
|
3378
|
+
this.y += this.currentLineHeight(true) + lineGap;
|
|
3567
3379
|
}
|
|
3568
3380
|
},
|
|
3569
3381
|
_fragment(text, x, y, options) {
|
|
@@ -3572,14 +3384,10 @@ var TextMixin = {
|
|
|
3572
3384
|
if (text.length === 0) {
|
|
3573
3385
|
return;
|
|
3574
3386
|
}
|
|
3575
|
-
|
|
3576
|
-
// handle options
|
|
3577
3387
|
const align = options.align || 'left';
|
|
3578
3388
|
let wordSpacing = options.wordSpacing || 0;
|
|
3579
3389
|
const characterSpacing = options.characterSpacing || 0;
|
|
3580
3390
|
const horizontalScaling = options.horizontalScaling || 100;
|
|
3581
|
-
|
|
3582
|
-
// text alignments
|
|
3583
3391
|
if (options.width) {
|
|
3584
3392
|
switch (align) {
|
|
3585
3393
|
case 'right':
|
|
@@ -3590,7 +3398,6 @@ var TextMixin = {
|
|
|
3590
3398
|
x += options.lineWidth / 2 - options.textWidth / 2;
|
|
3591
3399
|
break;
|
|
3592
3400
|
case 'justify':
|
|
3593
|
-
// calculate the word spacing value
|
|
3594
3401
|
words = text.trim().split(/\s+/);
|
|
3595
3402
|
textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
|
|
3596
3403
|
var spaceWidth = this.widthOfString(' ') + characterSpacing;
|
|
@@ -3598,8 +3405,6 @@ var TextMixin = {
|
|
|
3598
3405
|
break;
|
|
3599
3406
|
}
|
|
3600
3407
|
}
|
|
3601
|
-
|
|
3602
|
-
// text baseline alignments based on http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
|
|
3603
3408
|
if (typeof options.baseline === 'number') {
|
|
3604
3409
|
dy = -options.baseline;
|
|
3605
3410
|
} else {
|
|
@@ -3632,11 +3437,7 @@ var TextMixin = {
|
|
|
3632
3437
|
}
|
|
3633
3438
|
dy = dy / 1000 * this._fontSize;
|
|
3634
3439
|
}
|
|
3635
|
-
|
|
3636
|
-
// calculate the actual rendered width of the string after word and character spacing
|
|
3637
3440
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3638
|
-
|
|
3639
|
-
// create link annotations if the link option is given
|
|
3640
3441
|
if (options.link != null) {
|
|
3641
3442
|
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);
|
|
3642
3443
|
}
|
|
@@ -3646,8 +3447,6 @@ var TextMixin = {
|
|
|
3646
3447
|
if (options.destination != null) {
|
|
3647
3448
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
3648
3449
|
}
|
|
3649
|
-
|
|
3650
|
-
// create underline
|
|
3651
3450
|
if (options.underline) {
|
|
3652
3451
|
this.save();
|
|
3653
3452
|
if (!options.stroke) {
|
|
@@ -3661,8 +3460,6 @@ var TextMixin = {
|
|
|
3661
3460
|
this.stroke();
|
|
3662
3461
|
this.restore();
|
|
3663
3462
|
}
|
|
3664
|
-
|
|
3665
|
-
// create strikethrough line
|
|
3666
3463
|
if (options.strike) {
|
|
3667
3464
|
this.save();
|
|
3668
3465
|
if (!options.stroke) {
|
|
@@ -3677,8 +3474,6 @@ var TextMixin = {
|
|
|
3677
3474
|
this.restore();
|
|
3678
3475
|
}
|
|
3679
3476
|
this.save();
|
|
3680
|
-
|
|
3681
|
-
// oblique (angle in degrees or boolean)
|
|
3682
3477
|
if (options.oblique) {
|
|
3683
3478
|
let skew;
|
|
3684
3479
|
if (typeof options.oblique === 'number') {
|
|
@@ -3690,45 +3485,24 @@ var TextMixin = {
|
|
|
3690
3485
|
this.transform(1, 0, skew, 1, -skew * dy, 0);
|
|
3691
3486
|
this.transform(1, 0, 0, 1, -x, -y);
|
|
3692
3487
|
}
|
|
3693
|
-
|
|
3694
|
-
// flip coordinate system
|
|
3695
3488
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
3696
3489
|
y = this.page.height - y - dy;
|
|
3697
|
-
|
|
3698
|
-
// add current font to page if necessary
|
|
3699
3490
|
if (this.page.fonts[this._font.id] == null) {
|
|
3700
3491
|
this.page.fonts[this._font.id] = this._font.ref();
|
|
3701
3492
|
}
|
|
3702
|
-
|
|
3703
|
-
// begin the text object
|
|
3704
3493
|
this.addContent('BT');
|
|
3705
|
-
|
|
3706
|
-
// text position
|
|
3707
3494
|
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3708
|
-
|
|
3709
|
-
// font and font size
|
|
3710
3495
|
this.addContent(`/${this._font.id} ${number(this._fontSize)} Tf`);
|
|
3711
|
-
|
|
3712
|
-
// rendering mode
|
|
3713
3496
|
const mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;
|
|
3714
3497
|
if (mode) {
|
|
3715
3498
|
this.addContent(`${mode} Tr`);
|
|
3716
3499
|
}
|
|
3717
|
-
|
|
3718
|
-
// Character spacing
|
|
3719
3500
|
if (characterSpacing) {
|
|
3720
3501
|
this.addContent(`${number(characterSpacing)} Tc`);
|
|
3721
3502
|
}
|
|
3722
|
-
|
|
3723
|
-
// Horizontal scaling
|
|
3724
3503
|
if (horizontalScaling !== 100) {
|
|
3725
3504
|
this.addContent(`${horizontalScaling} Tz`);
|
|
3726
3505
|
}
|
|
3727
|
-
|
|
3728
|
-
// Add the actual text
|
|
3729
|
-
// If we have a word spacing value, we need to encode each word separately
|
|
3730
|
-
// since the normal Tw operator only works on character code 32, which isn't
|
|
3731
|
-
// used for embedded fonts.
|
|
3732
3506
|
if (wordSpacing) {
|
|
3733
3507
|
words = text.trim().split(/\s+/);
|
|
3734
3508
|
wordSpacing += this.widthOfString(' ') + characterSpacing;
|
|
@@ -3739,9 +3513,6 @@ var TextMixin = {
|
|
|
3739
3513
|
const [encodedWord, positionsWord] = this._font.encode(word, options.features);
|
|
3740
3514
|
encoded = encoded.concat(encodedWord);
|
|
3741
3515
|
positions = positions.concat(positionsWord);
|
|
3742
|
-
|
|
3743
|
-
// add the word spacing to the end of the word
|
|
3744
|
-
// clone object because of cache
|
|
3745
3516
|
const space = {};
|
|
3746
3517
|
const object = positions[positions.length - 1];
|
|
3747
3518
|
for (let key in object) {
|
|
@@ -3758,60 +3529,42 @@ var TextMixin = {
|
|
|
3758
3529
|
const commands = [];
|
|
3759
3530
|
let last = 0;
|
|
3760
3531
|
let hadOffset = false;
|
|
3761
|
-
|
|
3762
|
-
// Adds a segment of text to the TJ command buffer
|
|
3763
3532
|
const addSegment = cur => {
|
|
3764
3533
|
if (last < cur) {
|
|
3765
3534
|
const hex = encoded.slice(last, cur).join('');
|
|
3766
3535
|
const advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;
|
|
3767
3536
|
commands.push(`<${hex}> ${number(-advance)}`);
|
|
3768
3537
|
}
|
|
3769
|
-
|
|
3538
|
+
last = cur;
|
|
3770
3539
|
};
|
|
3771
|
-
|
|
3772
|
-
// Flushes the current TJ commands to the output stream
|
|
3773
3540
|
const flush = i => {
|
|
3774
3541
|
addSegment(i);
|
|
3775
3542
|
if (commands.length > 0) {
|
|
3776
3543
|
this.addContent(`[${commands.join(' ')}] TJ`);
|
|
3777
|
-
|
|
3544
|
+
commands.length = 0;
|
|
3778
3545
|
}
|
|
3779
3546
|
};
|
|
3780
3547
|
for (i = 0; i < positions.length; i++) {
|
|
3781
|
-
// If we have an x or y offset, we have to break out of the current TJ command
|
|
3782
|
-
// so we can move the text position.
|
|
3783
3548
|
const pos = positions[i];
|
|
3784
3549
|
if (pos.xOffset || pos.yOffset) {
|
|
3785
|
-
// Flush the current buffer
|
|
3786
3550
|
flush(i);
|
|
3787
|
-
|
|
3788
|
-
// Move the text position and flush just the current character
|
|
3789
3551
|
this.addContent(`1 0 0 1 ${number(x + pos.xOffset * scale)} ${number(y + pos.yOffset * scale)} Tm`);
|
|
3790
3552
|
flush(i + 1);
|
|
3791
3553
|
hadOffset = true;
|
|
3792
3554
|
} else {
|
|
3793
|
-
// If the last character had an offset, reset the text position
|
|
3794
3555
|
if (hadOffset) {
|
|
3795
3556
|
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
|
|
3796
3557
|
hadOffset = false;
|
|
3797
3558
|
}
|
|
3798
|
-
|
|
3799
|
-
// Group segments that don't have any advance adjustments
|
|
3800
3559
|
if (pos.xAdvance - pos.advanceWidth !== 0) {
|
|
3801
3560
|
addSegment(i + 1);
|
|
3802
3561
|
}
|
|
3803
3562
|
}
|
|
3804
3563
|
x += pos.xAdvance * scale;
|
|
3805
3564
|
}
|
|
3806
|
-
|
|
3807
|
-
// Flush any remaining commands
|
|
3808
3565
|
flush(i);
|
|
3809
|
-
|
|
3810
|
-
// end the text object
|
|
3811
3566
|
this.addContent('ET');
|
|
3812
|
-
|
|
3813
|
-
// restore flipped coordinate system
|
|
3814
|
-
return this.restore();
|
|
3567
|
+
this.restore();
|
|
3815
3568
|
}
|
|
3816
3569
|
};
|
|
3817
3570
|
|
|
@@ -3829,8 +3582,6 @@ class JPEG {
|
|
|
3829
3582
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3830
3583
|
throw 'SOI not found in JPEG';
|
|
3831
3584
|
}
|
|
3832
|
-
|
|
3833
|
-
// Parse the EXIF orientation
|
|
3834
3585
|
this.orientation = exif.fromBuffer(this.data).Orientation || 1;
|
|
3835
3586
|
let pos = 2;
|
|
3836
3587
|
while (pos < this.data.length) {
|
|
@@ -3867,16 +3618,10 @@ class JPEG {
|
|
|
3867
3618
|
ColorSpace: this.colorSpace,
|
|
3868
3619
|
Filter: 'DCTDecode'
|
|
3869
3620
|
});
|
|
3870
|
-
|
|
3871
|
-
// add extra decode params for CMYK images. By swapping the
|
|
3872
|
-
// min and max values from the default, we invert the colors. See
|
|
3873
|
-
// section 4.8.4 of the spec.
|
|
3874
3621
|
if (this.colorSpace === 'DeviceCMYK') {
|
|
3875
3622
|
this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];
|
|
3876
3623
|
}
|
|
3877
3624
|
this.obj.end(this.data);
|
|
3878
|
-
|
|
3879
|
-
// free memory
|
|
3880
3625
|
return this.data = null;
|
|
3881
3626
|
}
|
|
3882
3627
|
}
|
|
@@ -3919,24 +3664,14 @@ class PNGImage {
|
|
|
3919
3664
|
if (this.image.palette.length === 0) {
|
|
3920
3665
|
this.obj.data['ColorSpace'] = this.image.colorSpace;
|
|
3921
3666
|
} else {
|
|
3922
|
-
// embed the color palette in the PDF as an object stream
|
|
3923
3667
|
const palette = this.document.ref();
|
|
3924
3668
|
palette.end(Buffer.from(this.image.palette));
|
|
3925
|
-
|
|
3926
|
-
// build the color space array for the image
|
|
3927
3669
|
this.obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', this.image.palette.length / 3 - 1, palette];
|
|
3928
3670
|
}
|
|
3929
|
-
|
|
3930
|
-
// For PNG color types 0, 2 and 3, the transparency data is stored in
|
|
3931
|
-
// a dedicated PNG chunk.
|
|
3932
3671
|
if (this.image.transparency.grayscale != null) {
|
|
3933
|
-
// Use Color Key Masking (spec section 4.8.5)
|
|
3934
|
-
// An array with N elements, where N is two times the number of color components.
|
|
3935
3672
|
const val = this.image.transparency.grayscale;
|
|
3936
3673
|
this.obj.data['Mask'] = [val, val];
|
|
3937
3674
|
} else if (this.image.transparency.rgb) {
|
|
3938
|
-
// Use Color Key Masking (spec section 4.8.5)
|
|
3939
|
-
// An array with N elements, where N is two times the number of color components.
|
|
3940
3675
|
const {
|
|
3941
3676
|
rgb
|
|
3942
3677
|
} = this.image.transparency;
|
|
@@ -3946,14 +3681,9 @@ class PNGImage {
|
|
|
3946
3681
|
}
|
|
3947
3682
|
this.obj.data['Mask'] = mask;
|
|
3948
3683
|
} else if (this.image.transparency.indexed) {
|
|
3949
|
-
// Create a transparency SMask for the image based on the data
|
|
3950
|
-
// in the PLTE and tRNS sections. See below for details on SMasks.
|
|
3951
3684
|
dataDecoded = true;
|
|
3952
3685
|
return this.loadIndexedAlphaChannel();
|
|
3953
3686
|
} else if (hasAlphaChannel) {
|
|
3954
|
-
// For PNG color types 4 and 6, the transparency data is stored as a alpha
|
|
3955
|
-
// channel mixed in with the main image data. Separate this data out into an
|
|
3956
|
-
// SMask object and store it separately in the PDF.
|
|
3957
3687
|
dataDecoded = true;
|
|
3958
3688
|
return this.splitAlphaChannel();
|
|
3959
3689
|
}
|
|
@@ -3977,11 +3707,7 @@ class PNGImage {
|
|
|
3977
3707
|
sMask.end(this.alphaChannel);
|
|
3978
3708
|
this.obj.data['SMask'] = sMask;
|
|
3979
3709
|
}
|
|
3980
|
-
|
|
3981
|
-
// add the actual image data
|
|
3982
3710
|
this.obj.end(this.imgData);
|
|
3983
|
-
|
|
3984
|
-
// free memory
|
|
3985
3711
|
this.image = null;
|
|
3986
3712
|
return this.imgData = null;
|
|
3987
3713
|
}
|
|
@@ -3994,7 +3720,6 @@ class PNGImage {
|
|
|
3994
3720
|
const alphaChannel = Buffer.alloc(pixelCount);
|
|
3995
3721
|
let i = p = a = 0;
|
|
3996
3722
|
const len = pixels.length;
|
|
3997
|
-
// For 16bit images copy only most significant byte (MSB) - PNG data is always stored in network byte order (MSB first)
|
|
3998
3723
|
const skipByteCount = this.image.bits === 16 ? 1 : 0;
|
|
3999
3724
|
while (i < len) {
|
|
4000
3725
|
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
|
|
@@ -4029,10 +3754,6 @@ class PNGImage {
|
|
|
4029
3754
|
}
|
|
4030
3755
|
}
|
|
4031
3756
|
|
|
4032
|
-
/*
|
|
4033
|
-
PDFImage - embeds images in PDF documents
|
|
4034
|
-
By Devon Govett
|
|
4035
|
-
*/
|
|
4036
3757
|
class PDFImage {
|
|
4037
3758
|
static open(src, label) {
|
|
4038
3759
|
let data;
|
|
@@ -4064,18 +3785,17 @@ class PDFImage {
|
|
|
4064
3785
|
var ImagesMixin = {
|
|
4065
3786
|
initImages() {
|
|
4066
3787
|
this._imageRegistry = {};
|
|
4067
|
-
|
|
3788
|
+
this._imageCount = 0;
|
|
4068
3789
|
},
|
|
4069
3790
|
image(src, x, y) {
|
|
4070
3791
|
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
4071
|
-
let bh, bp, bw, image, ip, left, left1,
|
|
3792
|
+
let bh, bp, bw, image, ip, left, left1, originX, originY;
|
|
4072
3793
|
if (typeof x === 'object') {
|
|
4073
3794
|
options = x;
|
|
4074
3795
|
x = null;
|
|
4075
3796
|
}
|
|
4076
|
-
|
|
4077
|
-
// Ignore orientation based on document options or image options
|
|
4078
3797
|
const ignoreOrientation = options.ignoreOrientation || options.ignoreOrientation !== false && this.options.ignoreOrientation;
|
|
3798
|
+
const inDocumentFlow = typeof y !== 'number';
|
|
4079
3799
|
x = (left = x != null ? x : options.x) != null ? left : this.x;
|
|
4080
3800
|
y = (left1 = y != null ? y : options.y) != null ? left1 : this.y;
|
|
4081
3801
|
if (typeof src === 'string') {
|
|
@@ -4098,8 +3818,6 @@ var ImagesMixin = {
|
|
|
4098
3818
|
width,
|
|
4099
3819
|
height
|
|
4100
3820
|
} = image;
|
|
4101
|
-
|
|
4102
|
-
// If EXIF orientation calls for it, swap width and height
|
|
4103
3821
|
if (!ignoreOrientation && image.orientation > 4) {
|
|
4104
3822
|
[width, height] = [height, width];
|
|
4105
3823
|
}
|
|
@@ -4151,80 +3869,70 @@ var ImagesMixin = {
|
|
|
4151
3869
|
y = y + bh - h;
|
|
4152
3870
|
}
|
|
4153
3871
|
}
|
|
3872
|
+
let rotateAngle = 0;
|
|
3873
|
+
let xTransform = x;
|
|
3874
|
+
let yTransform = y;
|
|
3875
|
+
let hTransform = h;
|
|
3876
|
+
let wTransform = w;
|
|
4154
3877
|
if (!ignoreOrientation) {
|
|
4155
3878
|
switch (image.orientation) {
|
|
4156
|
-
// No orientation (need to flip image, though, because of the default transform matrix on the document)
|
|
4157
3879
|
default:
|
|
4158
3880
|
case 1:
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
rotateAngle = 0;
|
|
3881
|
+
hTransform = -h;
|
|
3882
|
+
yTransform += h;
|
|
4162
3883
|
break;
|
|
4163
|
-
// Flip Horizontal
|
|
4164
3884
|
case 2:
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
rotateAngle = 0;
|
|
3885
|
+
wTransform = -w;
|
|
3886
|
+
hTransform = -h;
|
|
3887
|
+
xTransform += w;
|
|
3888
|
+
yTransform += h;
|
|
4170
3889
|
break;
|
|
4171
|
-
// Rotate 180 degrees
|
|
4172
3890
|
case 3:
|
|
4173
3891
|
originX = x;
|
|
4174
3892
|
originY = y;
|
|
4175
|
-
|
|
4176
|
-
|
|
3893
|
+
hTransform = -h;
|
|
3894
|
+
xTransform -= w;
|
|
4177
3895
|
rotateAngle = 180;
|
|
4178
3896
|
break;
|
|
4179
|
-
// Flip vertical
|
|
4180
3897
|
case 4:
|
|
4181
|
-
// Do nothing, image will be flipped
|
|
4182
|
-
|
|
4183
3898
|
break;
|
|
4184
|
-
// Flip horizontally and rotate 270 degrees CW
|
|
4185
3899
|
case 5:
|
|
4186
3900
|
originX = x;
|
|
4187
3901
|
originY = y;
|
|
4188
|
-
|
|
4189
|
-
|
|
3902
|
+
wTransform = h;
|
|
3903
|
+
hTransform = w;
|
|
3904
|
+
yTransform -= hTransform;
|
|
4190
3905
|
rotateAngle = 90;
|
|
4191
3906
|
break;
|
|
4192
|
-
// Rotate 90 degrees CW
|
|
4193
3907
|
case 6:
|
|
4194
3908
|
originX = x;
|
|
4195
3909
|
originY = y;
|
|
4196
|
-
|
|
4197
|
-
|
|
3910
|
+
wTransform = h;
|
|
3911
|
+
hTransform = -w;
|
|
4198
3912
|
rotateAngle = 90;
|
|
4199
3913
|
break;
|
|
4200
|
-
// Flip horizontally and rotate 90 degrees CW
|
|
4201
3914
|
case 7:
|
|
4202
3915
|
originX = x;
|
|
4203
3916
|
originY = y;
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
x -= w;
|
|
3917
|
+
hTransform = -w;
|
|
3918
|
+
wTransform = -h;
|
|
3919
|
+
xTransform += h;
|
|
4208
3920
|
rotateAngle = 90;
|
|
4209
3921
|
break;
|
|
4210
|
-
// Rotate 270 degrees CW
|
|
4211
3922
|
case 8:
|
|
4212
3923
|
originX = x;
|
|
4213
3924
|
originY = y;
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
3925
|
+
wTransform = h;
|
|
3926
|
+
hTransform = -w;
|
|
3927
|
+
xTransform -= h;
|
|
3928
|
+
yTransform += w;
|
|
4218
3929
|
rotateAngle = -90;
|
|
4219
3930
|
break;
|
|
4220
3931
|
}
|
|
4221
3932
|
} else {
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
rotateAngle = 0;
|
|
3933
|
+
hTransform = -h;
|
|
3934
|
+
yTransform += h;
|
|
4225
3935
|
}
|
|
4226
|
-
|
|
4227
|
-
// create link annotations if the link option is given
|
|
4228
3936
|
if (options.link != null) {
|
|
4229
3937
|
this.link(x, y, w, h, options.link);
|
|
4230
3938
|
}
|
|
@@ -4234,9 +3942,7 @@ var ImagesMixin = {
|
|
|
4234
3942
|
if (options.destination != null) {
|
|
4235
3943
|
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
|
|
4236
3944
|
}
|
|
4237
|
-
|
|
4238
|
-
// Set the current y position to below the image if it is in the document flow
|
|
4239
|
-
if (this.y === y) {
|
|
3945
|
+
if (inDocumentFlow) {
|
|
4240
3946
|
this.y += h;
|
|
4241
3947
|
}
|
|
4242
3948
|
this.save();
|
|
@@ -4245,7 +3951,7 @@ var ImagesMixin = {
|
|
|
4245
3951
|
origin: [originX, originY]
|
|
4246
3952
|
});
|
|
4247
3953
|
}
|
|
4248
|
-
this.transform(
|
|
3954
|
+
this.transform(wTransform, 0, 0, hTransform, xTransform, yTransform);
|
|
4249
3955
|
this.addContent(`/${image.label} Do`);
|
|
4250
3956
|
this.restore();
|
|
4251
3957
|
return this;
|
|
@@ -4271,19 +3977,17 @@ var AnnotationsMixin = {
|
|
|
4271
3977
|
options.Rect = this._convertRect(x, y, w, h);
|
|
4272
3978
|
options.Border = [0, 0, 0];
|
|
4273
3979
|
if (options.Subtype === 'Link' && typeof options.F === 'undefined') {
|
|
4274
|
-
options.F = 1 << 2;
|
|
3980
|
+
options.F = 1 << 2;
|
|
4275
3981
|
}
|
|
4276
3982
|
if (options.Subtype !== 'Link') {
|
|
4277
3983
|
if (options.C == null) {
|
|
4278
3984
|
options.C = this._normalizeColor(options.color || [0, 0, 0]);
|
|
4279
3985
|
}
|
|
4280
|
-
}
|
|
3986
|
+
}
|
|
4281
3987
|
delete options.color;
|
|
4282
3988
|
if (typeof options.Dest === 'string') {
|
|
4283
3989
|
options.Dest = new String(options.Dest);
|
|
4284
3990
|
}
|
|
4285
|
-
|
|
4286
|
-
// Capitalize keys
|
|
4287
3991
|
for (let key in options) {
|
|
4288
3992
|
const val = options[key];
|
|
4289
3993
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
@@ -4319,7 +4023,6 @@ var AnnotationsMixin = {
|
|
|
4319
4023
|
let options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
|
|
4320
4024
|
options.Subtype = 'Link';
|
|
4321
4025
|
if (typeof url === 'number') {
|
|
4322
|
-
// Link to a page in the document (the page must already exist)
|
|
4323
4026
|
const pages = this._root.data.Pages.data;
|
|
4324
4027
|
if (url >= 0 && url < pages.Kids.length) {
|
|
4325
4028
|
options.A = this.ref({
|
|
@@ -4331,7 +4034,6 @@ var AnnotationsMixin = {
|
|
|
4331
4034
|
throw new Error(`The document has no page ${url}`);
|
|
4332
4035
|
}
|
|
4333
4036
|
} else {
|
|
4334
|
-
// Link to an external url
|
|
4335
4037
|
options.A = this.ref({
|
|
4336
4038
|
S: 'URI',
|
|
4337
4039
|
URI: new String(url)
|
|
@@ -4394,14 +4096,11 @@ var AnnotationsMixin = {
|
|
|
4394
4096
|
fileAnnotation(x, y, w, h) {
|
|
4395
4097
|
let file = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
|
4396
4098
|
let options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
|
|
4397
|
-
// create hidden file
|
|
4398
4099
|
const filespec = this.file(file.src, Object.assign({
|
|
4399
4100
|
hidden: true
|
|
4400
4101
|
}, file));
|
|
4401
4102
|
options.Subtype = 'FileAttachment';
|
|
4402
4103
|
options.FS = filespec;
|
|
4403
|
-
|
|
4404
|
-
// add description from filespec unless description (Contents) has already been set
|
|
4405
4104
|
if (options.Contents) {
|
|
4406
4105
|
options.Contents = new String(options.Contents);
|
|
4407
4106
|
} else if (filespec.data.Desc) {
|
|
@@ -4410,14 +4109,9 @@ var AnnotationsMixin = {
|
|
|
4410
4109
|
return this.annotate(x, y, w, h, options);
|
|
4411
4110
|
},
|
|
4412
4111
|
_convertRect(x1, y1, w, h) {
|
|
4413
|
-
// flip y1 and y2
|
|
4414
4112
|
let y2 = y1;
|
|
4415
4113
|
y1 += h;
|
|
4416
|
-
|
|
4417
|
-
// make x2
|
|
4418
4114
|
let x2 = x1 + w;
|
|
4419
|
-
|
|
4420
|
-
// apply current transformation matrix to points
|
|
4421
4115
|
const [m0, m1, m2, m3, m4, m5] = this._ctm;
|
|
4422
4116
|
x1 = m0 * x1 + m2 * y1 + m4;
|
|
4423
4117
|
y1 = m1 * x1 + m3 * y1 + m5;
|
|
@@ -4481,7 +4175,7 @@ class PDFOutline {
|
|
|
4481
4175
|
|
|
4482
4176
|
var OutlineMixin = {
|
|
4483
4177
|
initOutline() {
|
|
4484
|
-
|
|
4178
|
+
this.outline = new PDFOutline(this, null, null, null);
|
|
4485
4179
|
},
|
|
4486
4180
|
endOutline() {
|
|
4487
4181
|
this.outline.endOutline();
|
|
@@ -4492,11 +4186,6 @@ var OutlineMixin = {
|
|
|
4492
4186
|
}
|
|
4493
4187
|
};
|
|
4494
4188
|
|
|
4495
|
-
/*
|
|
4496
|
-
PDFStructureContent - a reference to a marked structure content
|
|
4497
|
-
By Ben Schmidt
|
|
4498
|
-
*/
|
|
4499
|
-
|
|
4500
4189
|
class PDFStructureContent {
|
|
4501
4190
|
constructor(pageRef, mcid) {
|
|
4502
4191
|
this.refs = [{
|
|
@@ -4509,10 +4198,6 @@ class PDFStructureContent {
|
|
|
4509
4198
|
}
|
|
4510
4199
|
}
|
|
4511
4200
|
|
|
4512
|
-
/*
|
|
4513
|
-
PDFStructureElement - represents an element in the PDF logical structure tree
|
|
4514
|
-
By Ben Schmidt
|
|
4515
|
-
*/
|
|
4516
4201
|
class PDFStructureElement {
|
|
4517
4202
|
constructor(document, type) {
|
|
4518
4203
|
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
@@ -4522,7 +4207,6 @@ class PDFStructureElement {
|
|
|
4522
4207
|
this._ended = false;
|
|
4523
4208
|
this._flushed = false;
|
|
4524
4209
|
this.dictionary = document.ref({
|
|
4525
|
-
// Type: "StructElem",
|
|
4526
4210
|
S: type
|
|
4527
4211
|
});
|
|
4528
4212
|
const data = this.dictionary.data;
|
|
@@ -4571,7 +4255,6 @@ class PDFStructureElement {
|
|
|
4571
4255
|
this._addContentToParentTree(child);
|
|
4572
4256
|
}
|
|
4573
4257
|
if (typeof child === 'function' && this._attached) {
|
|
4574
|
-
// _contentForClosure() adds the content to the parent tree
|
|
4575
4258
|
child = this._contentForClosure(child);
|
|
4576
4259
|
}
|
|
4577
4260
|
this._children.push(child);
|
|
@@ -4648,10 +4331,6 @@ class PDFStructureElement {
|
|
|
4648
4331
|
this.dictionary.data.K = [];
|
|
4649
4332
|
this._children.forEach(child => this._flushChild(child));
|
|
4650
4333
|
this.dictionary.end();
|
|
4651
|
-
|
|
4652
|
-
// free memory used by children; the dictionary itself may still be
|
|
4653
|
-
// referenced by a parent structure element or root, but we can
|
|
4654
|
-
// at least trim the tree here
|
|
4655
4334
|
this._children = [];
|
|
4656
4335
|
this.dictionary.data.K = null;
|
|
4657
4336
|
this._flushed = true;
|
|
@@ -4673,7 +4352,7 @@ class PDFStructureElement {
|
|
|
4673
4352
|
this.dictionary.data.K.push(mcid);
|
|
4674
4353
|
} else {
|
|
4675
4354
|
this.dictionary.data.K.push({
|
|
4676
|
-
Type:
|
|
4355
|
+
Type: 'MCR',
|
|
4677
4356
|
Pg: pageRef,
|
|
4678
4357
|
MCID: mcid
|
|
4679
4358
|
});
|
|
@@ -4683,25 +4362,18 @@ class PDFStructureElement {
|
|
|
4683
4362
|
}
|
|
4684
4363
|
}
|
|
4685
4364
|
|
|
4686
|
-
/*
|
|
4687
|
-
PDFNumberTree - represents a number tree object
|
|
4688
|
-
*/
|
|
4689
4365
|
class PDFNumberTree extends PDFTree {
|
|
4690
4366
|
_compareKeys(a, b) {
|
|
4691
4367
|
return parseInt(a) - parseInt(b);
|
|
4692
4368
|
}
|
|
4693
4369
|
_keysName() {
|
|
4694
|
-
return
|
|
4370
|
+
return 'Nums';
|
|
4695
4371
|
}
|
|
4696
4372
|
_dataForKey(k) {
|
|
4697
4373
|
return parseInt(k);
|
|
4698
4374
|
}
|
|
4699
4375
|
}
|
|
4700
4376
|
|
|
4701
|
-
/*
|
|
4702
|
-
Markings mixin - support marked content sequences in content streams
|
|
4703
|
-
By Ben Schmidt
|
|
4704
|
-
*/
|
|
4705
4377
|
var MarkingsMixin = {
|
|
4706
4378
|
initMarkings(options) {
|
|
4707
4379
|
this.structChildren = [];
|
|
@@ -4841,7 +4513,6 @@ var MarkingsMixin = {
|
|
|
4841
4513
|
return this.getStructTreeRoot().data.ParentTree;
|
|
4842
4514
|
},
|
|
4843
4515
|
createStructParentTreeNextKey() {
|
|
4844
|
-
// initialise the MarkInfo dictionary
|
|
4845
4516
|
this.getMarkInfoDictionary();
|
|
4846
4517
|
const structTreeRoot = this.getStructTreeRoot();
|
|
4847
4518
|
const key = structTreeRoot.data.ParentTreeNextKey++;
|
|
@@ -4905,10 +4576,6 @@ const FORMAT_DEFAULT = {
|
|
|
4905
4576
|
}
|
|
4906
4577
|
};
|
|
4907
4578
|
var AcroFormMixin = {
|
|
4908
|
-
/**
|
|
4909
|
-
* Must call if adding AcroForms to a document. Must also call font() before
|
|
4910
|
-
* this method to set the default font.
|
|
4911
|
-
*/
|
|
4912
4579
|
initForm() {
|
|
4913
4580
|
if (!this._font) {
|
|
4914
4581
|
throw new Error('Must set a font before calling initForm method');
|
|
@@ -4931,9 +4598,6 @@ var AcroFormMixin = {
|
|
|
4931
4598
|
this._root.data.AcroForm = AcroForm;
|
|
4932
4599
|
return this;
|
|
4933
4600
|
},
|
|
4934
|
-
/**
|
|
4935
|
-
* Called automatically by document.js
|
|
4936
|
-
*/
|
|
4937
4601
|
endAcroForm() {
|
|
4938
4602
|
if (this._root.data.AcroForm) {
|
|
4939
4603
|
if (!Object.keys(this._acroform.fonts).length && !this._acroform.defaultFont) {
|
|
@@ -4959,13 +4623,6 @@ var AcroFormMixin = {
|
|
|
4959
4623
|
}
|
|
4960
4624
|
return this;
|
|
4961
4625
|
},
|
|
4962
|
-
/**
|
|
4963
|
-
* Creates and adds a form field to the document. Form fields are intermediate
|
|
4964
|
-
* nodes in a PDF form that are used to specify form name heirarchy and form
|
|
4965
|
-
* value defaults.
|
|
4966
|
-
* @param {string} name - field name (T attribute in field dictionary)
|
|
4967
|
-
* @param {object} options - other attributes to include in field dictionary
|
|
4968
|
-
*/
|
|
4969
4626
|
formField(name) {
|
|
4970
4627
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
4971
4628
|
let fieldDict = this._fieldDict(name, null, options);
|
|
@@ -4973,26 +4630,13 @@ var AcroFormMixin = {
|
|
|
4973
4630
|
this._addToParent(fieldRef);
|
|
4974
4631
|
return fieldRef;
|
|
4975
4632
|
},
|
|
4976
|
-
/**
|
|
4977
|
-
* Creates and adds a Form Annotation to the document. Form annotations are
|
|
4978
|
-
* called Widget annotations internally within a PDF file.
|
|
4979
|
-
* @param {string} name - form field name (T attribute of widget annotation
|
|
4980
|
-
* dictionary)
|
|
4981
|
-
* @param {number} x
|
|
4982
|
-
* @param {number} y
|
|
4983
|
-
* @param {number} w
|
|
4984
|
-
* @param {number} h
|
|
4985
|
-
* @param {object} options
|
|
4986
|
-
*/
|
|
4987
4633
|
formAnnotation(name, type, x, y, w, h) {
|
|
4988
4634
|
let options = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
|
|
4989
4635
|
let fieldDict = this._fieldDict(name, type, options);
|
|
4990
4636
|
fieldDict.Subtype = 'Widget';
|
|
4991
4637
|
if (fieldDict.F === undefined) {
|
|
4992
|
-
fieldDict.F = 4;
|
|
4638
|
+
fieldDict.F = 4;
|
|
4993
4639
|
}
|
|
4994
|
-
|
|
4995
|
-
// Add Field annot to page, and get it's ref
|
|
4996
4640
|
this.annotate(x, y, w, h, fieldDict);
|
|
4997
4641
|
let annotRef = this.page.annotations[this.page.annotations.length - 1];
|
|
4998
4642
|
return this._addToParent(annotRef);
|
|
@@ -5160,23 +4804,18 @@ var AcroFormMixin = {
|
|
|
5160
4804
|
delete options.align;
|
|
5161
4805
|
}
|
|
5162
4806
|
if (result !== 0) {
|
|
5163
|
-
options.Q = result;
|
|
4807
|
+
options.Q = result;
|
|
5164
4808
|
}
|
|
5165
4809
|
return options;
|
|
5166
4810
|
},
|
|
5167
4811
|
_resolveFont(options) {
|
|
5168
|
-
// add current font to document-level AcroForm dict if necessary
|
|
5169
4812
|
if (this._acroform.fonts[this._font.id] == null) {
|
|
5170
4813
|
this._acroform.fonts[this._font.id] = this._font.ref();
|
|
5171
4814
|
}
|
|
5172
|
-
|
|
5173
|
-
// add current font to field's resource dict (RD) if not the default acroform font
|
|
5174
4815
|
if (this._acroform.defaultFont !== this._font.name) {
|
|
5175
4816
|
options.DR = {
|
|
5176
4817
|
Font: {}
|
|
5177
4818
|
};
|
|
5178
|
-
|
|
5179
|
-
// Get the fontSize option. If not set use auto sizing
|
|
5180
4819
|
const fontSize = options.fontSize || 0;
|
|
5181
4820
|
options.DR.Font[this._font.id] = this._font.ref();
|
|
5182
4821
|
options.DA = new String(`/${this._font.id} ${fontSize} Tf 0 g`);
|
|
@@ -5228,19 +4867,6 @@ var AcroFormMixin = {
|
|
|
5228
4867
|
};
|
|
5229
4868
|
|
|
5230
4869
|
var AttachmentsMixin = {
|
|
5231
|
-
/**
|
|
5232
|
-
* Embed contents of `src` in PDF
|
|
5233
|
-
* @param {Buffer | ArrayBuffer | string} src input Buffer, ArrayBuffer, base64 encoded string or path to file
|
|
5234
|
-
* @param {object} options
|
|
5235
|
-
* * options.name: filename to be shown in PDF, will use `src` if none set
|
|
5236
|
-
* * options.type: filetype to be shown in PDF
|
|
5237
|
-
* * options.description: description to be shown in PDF
|
|
5238
|
-
* * options.hidden: if true, do not add attachment to EmbeddedFiles dictionary. Useful for file attachment annotations
|
|
5239
|
-
* * options.creationDate: override creation date
|
|
5240
|
-
* * options.modifiedDate: override modified date
|
|
5241
|
-
* * options.relationship: Relationship between the PDF document and its attached file. Can be 'Alternative', 'Data', 'Source', 'Supplement' or 'Unspecified'.
|
|
5242
|
-
* @returns filespec reference
|
|
5243
|
-
*/
|
|
5244
4870
|
file(src) {
|
|
5245
4871
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
5246
4872
|
options.name = options.name || src;
|
|
@@ -5269,8 +4895,6 @@ var AttachmentsMixin = {
|
|
|
5269
4895
|
if (!data) {
|
|
5270
4896
|
throw new Error(`Could not read contents of file at filepath ${src}`);
|
|
5271
4897
|
}
|
|
5272
|
-
|
|
5273
|
-
// update CreationDate and ModDate
|
|
5274
4898
|
const {
|
|
5275
4899
|
birthtime,
|
|
5276
4900
|
ctime
|
|
@@ -5279,26 +4903,18 @@ var AttachmentsMixin = {
|
|
|
5279
4903
|
refBody.Params.ModDate = ctime;
|
|
5280
4904
|
}
|
|
5281
4905
|
}
|
|
5282
|
-
|
|
5283
|
-
// override creation date and modified date
|
|
5284
4906
|
if (options.creationDate instanceof Date) {
|
|
5285
4907
|
refBody.Params.CreationDate = options.creationDate;
|
|
5286
4908
|
}
|
|
5287
4909
|
if (options.modifiedDate instanceof Date) {
|
|
5288
4910
|
refBody.Params.ModDate = options.modifiedDate;
|
|
5289
4911
|
}
|
|
5290
|
-
// add optional subtype
|
|
5291
4912
|
if (options.type) {
|
|
5292
4913
|
refBody.Subtype = options.type.replace('/', '#2F');
|
|
5293
4914
|
}
|
|
5294
|
-
|
|
5295
|
-
// add checksum and size information
|
|
5296
4915
|
const checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(new Uint8Array(data)));
|
|
5297
4916
|
refBody.Params.CheckSum = new String(checksum);
|
|
5298
4917
|
refBody.Params.Size = data.byteLength;
|
|
5299
|
-
|
|
5300
|
-
// save some space when embedding the same file again
|
|
5301
|
-
// if a file with the same name and metadata exists, reuse its reference
|
|
5302
4918
|
let ref;
|
|
5303
4919
|
if (!this._fileRegistry) this._fileRegistry = {};
|
|
5304
4920
|
let file = this._fileRegistry[options.name];
|
|
@@ -5312,7 +4928,6 @@ var AttachmentsMixin = {
|
|
|
5312
4928
|
ref
|
|
5313
4929
|
};
|
|
5314
4930
|
}
|
|
5315
|
-
// add filespec for embedded file
|
|
5316
4931
|
const fileSpecBody = {
|
|
5317
4932
|
Type: 'Filespec',
|
|
5318
4933
|
AFRelationship: options.relationship,
|
|
@@ -5330,8 +4945,6 @@ var AttachmentsMixin = {
|
|
|
5330
4945
|
if (!options.hidden) {
|
|
5331
4946
|
this.addNamedEmbeddedFile(options.name, filespec);
|
|
5332
4947
|
}
|
|
5333
|
-
|
|
5334
|
-
// Add file to the catalogue to be PDF/A3 compliant
|
|
5335
4948
|
if (this._root.data.AF) {
|
|
5336
4949
|
this._root.data.AF.push(filespec);
|
|
5337
4950
|
} else {
|
|
@@ -5340,8 +4953,6 @@ var AttachmentsMixin = {
|
|
|
5340
4953
|
return filespec;
|
|
5341
4954
|
}
|
|
5342
4955
|
};
|
|
5343
|
-
|
|
5344
|
-
/** check two embedded file metadata objects for equality */
|
|
5345
4956
|
function isEqual(a, b) {
|
|
5346
4957
|
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());
|
|
5347
4958
|
}
|
|
@@ -5352,7 +4963,6 @@ var PDFA = {
|
|
|
5352
4963
|
this.subset_conformance = pSubset.charAt(pSubset.length - 1).toUpperCase();
|
|
5353
4964
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 2));
|
|
5354
4965
|
} else {
|
|
5355
|
-
// Default to Basic conformance when user doesn't specify
|
|
5356
4966
|
this.subset_conformance = 'B';
|
|
5357
4967
|
this.subset = parseInt(pSubset.charAt(pSubset.length - 1));
|
|
5358
4968
|
}
|
|
@@ -5437,6 +5047,656 @@ var SubsetMixin = {
|
|
|
5437
5047
|
}
|
|
5438
5048
|
};
|
|
5439
5049
|
|
|
5050
|
+
const ROW_FIELDS = ['height', 'minHeight', 'maxHeight'];
|
|
5051
|
+
const COLUMN_FIELDS = ['width', 'minWidth', 'maxWidth'];
|
|
5052
|
+
function memoize(fn, maxSize) {
|
|
5053
|
+
const cache = new Map();
|
|
5054
|
+
return function () {
|
|
5055
|
+
const key = arguments.length <= 0 ? undefined : arguments[0];
|
|
5056
|
+
if (!cache.has(key)) {
|
|
5057
|
+
cache.set(key, fn(...arguments));
|
|
5058
|
+
if (cache.size > maxSize) cache.delete(cache.keys().next());
|
|
5059
|
+
}
|
|
5060
|
+
return cache.get(key);
|
|
5061
|
+
};
|
|
5062
|
+
}
|
|
5063
|
+
function isObject(item) {
|
|
5064
|
+
return item && typeof item === 'object' && !Array.isArray(item);
|
|
5065
|
+
}
|
|
5066
|
+
function deepMerge(target) {
|
|
5067
|
+
if (!isObject(target)) return target;
|
|
5068
|
+
target = deepClone(target);
|
|
5069
|
+
for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
5070
|
+
sources[_key - 1] = arguments[_key];
|
|
5071
|
+
}
|
|
5072
|
+
for (const source of sources) {
|
|
5073
|
+
if (isObject(source)) {
|
|
5074
|
+
for (const key in source) {
|
|
5075
|
+
if (isObject(source[key])) {
|
|
5076
|
+
if (!(key in target)) target[key] = {};
|
|
5077
|
+
target[key] = deepMerge(target[key], source[key]);
|
|
5078
|
+
} else if (source[key] !== undefined) {
|
|
5079
|
+
target[key] = deepClone(source[key]);
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
}
|
|
5084
|
+
return target;
|
|
5085
|
+
}
|
|
5086
|
+
function deepClone(obj) {
|
|
5087
|
+
let result = obj;
|
|
5088
|
+
if (typeof obj == 'object') {
|
|
5089
|
+
result = Array.isArray(obj) ? [] : {};
|
|
5090
|
+
for (const key in obj) result[key] = deepClone(obj[key]);
|
|
5091
|
+
}
|
|
5092
|
+
return result;
|
|
5093
|
+
}
|
|
5094
|
+
|
|
5095
|
+
function normalizedDefaultStyle(defaultStyleInternal) {
|
|
5096
|
+
let defaultStyle = defaultStyleInternal;
|
|
5097
|
+
if (typeof defaultStyle !== 'object') defaultStyle = {
|
|
5098
|
+
text: defaultStyle
|
|
5099
|
+
};
|
|
5100
|
+
const defaultRowStyle = Object.fromEntries(Object.entries(defaultStyle).filter(_ref => {
|
|
5101
|
+
let [k] = _ref;
|
|
5102
|
+
return ROW_FIELDS.includes(k);
|
|
5103
|
+
}));
|
|
5104
|
+
const defaultColStyle = Object.fromEntries(Object.entries(defaultStyle).filter(_ref2 => {
|
|
5105
|
+
let [k] = _ref2;
|
|
5106
|
+
return COLUMN_FIELDS.includes(k);
|
|
5107
|
+
}));
|
|
5108
|
+
defaultStyle.padding = normalizeSides(defaultStyle.padding);
|
|
5109
|
+
defaultStyle.border = normalizeSides(defaultStyle.border);
|
|
5110
|
+
defaultStyle.borderColor = normalizeSides(defaultStyle.borderColor);
|
|
5111
|
+
defaultStyle.align = normalizeAlignment(defaultStyle.align);
|
|
5112
|
+
return {
|
|
5113
|
+
defaultStyle,
|
|
5114
|
+
defaultRowStyle,
|
|
5115
|
+
defaultColStyle
|
|
5116
|
+
};
|
|
5117
|
+
}
|
|
5118
|
+
function normalizedRowStyle(defaultRowStyle, rowStyleInternal, i) {
|
|
5119
|
+
let rowStyle = rowStyleInternal(i);
|
|
5120
|
+
if (rowStyle == null || typeof rowStyle !== 'object') {
|
|
5121
|
+
rowStyle = {
|
|
5122
|
+
height: rowStyle
|
|
5123
|
+
};
|
|
5124
|
+
}
|
|
5125
|
+
rowStyle.padding = normalizeSides(rowStyle.padding);
|
|
5126
|
+
rowStyle.border = normalizeSides(rowStyle.border);
|
|
5127
|
+
rowStyle.borderColor = normalizeSides(rowStyle.borderColor);
|
|
5128
|
+
rowStyle.align = normalizeAlignment(rowStyle.align);
|
|
5129
|
+
rowStyle = deepMerge(defaultRowStyle, rowStyle);
|
|
5130
|
+
const document = this.document;
|
|
5131
|
+
const page = document.page;
|
|
5132
|
+
const contentHeight = page.contentHeight;
|
|
5133
|
+
if (rowStyle.height == null || rowStyle.height === 'auto') {
|
|
5134
|
+
rowStyle.height = 'auto';
|
|
5135
|
+
} else {
|
|
5136
|
+
rowStyle.height = document.sizeToPoint(rowStyle.height, 0, page, contentHeight);
|
|
5137
|
+
}
|
|
5138
|
+
rowStyle.minHeight = document.sizeToPoint(rowStyle.minHeight, 0, page, contentHeight);
|
|
5139
|
+
rowStyle.maxHeight = document.sizeToPoint(rowStyle.maxHeight, 0, page, contentHeight);
|
|
5140
|
+
return rowStyle;
|
|
5141
|
+
}
|
|
5142
|
+
function normalizedColumnStyle(defaultColStyle, colStyleInternal, i) {
|
|
5143
|
+
let colStyle = colStyleInternal(i);
|
|
5144
|
+
if (colStyle == null || typeof colStyle !== 'object') {
|
|
5145
|
+
colStyle = {
|
|
5146
|
+
width: colStyle
|
|
5147
|
+
};
|
|
5148
|
+
}
|
|
5149
|
+
colStyle.padding = normalizeSides(colStyle.padding);
|
|
5150
|
+
colStyle.border = normalizeSides(colStyle.border);
|
|
5151
|
+
colStyle.borderColor = normalizeSides(colStyle.borderColor);
|
|
5152
|
+
colStyle.align = normalizeAlignment(colStyle.align);
|
|
5153
|
+
colStyle = deepMerge(defaultColStyle, colStyle);
|
|
5154
|
+
if (colStyle.width == null || colStyle.width === '*') {
|
|
5155
|
+
colStyle.width = '*';
|
|
5156
|
+
} else {
|
|
5157
|
+
colStyle.width = this.document.sizeToPoint(colStyle.width, 0, this.document.page, this._maxWidth);
|
|
5158
|
+
}
|
|
5159
|
+
colStyle.minWidth = this.document.sizeToPoint(colStyle.minWidth, 0, this.document.page, this._maxWidth);
|
|
5160
|
+
colStyle.maxWidth = this.document.sizeToPoint(colStyle.maxWidth, 0, this.document.page, this._maxWidth);
|
|
5161
|
+
return colStyle;
|
|
5162
|
+
}
|
|
5163
|
+
function normalizeAlignment(align) {
|
|
5164
|
+
return align == null || typeof align === 'string' ? {
|
|
5165
|
+
x: align,
|
|
5166
|
+
y: align
|
|
5167
|
+
} : align;
|
|
5168
|
+
}
|
|
5169
|
+
|
|
5170
|
+
function normalizeTable() {
|
|
5171
|
+
const doc = this.document;
|
|
5172
|
+
const opts = this.opts;
|
|
5173
|
+
let index = doc._tableIndex++;
|
|
5174
|
+
this._id = new String(opts.id ?? `table-${index}`);
|
|
5175
|
+
this._position = {
|
|
5176
|
+
x: doc.sizeToPoint(opts.position?.x, doc.x),
|
|
5177
|
+
y: doc.sizeToPoint(opts.position?.y, doc.y)
|
|
5178
|
+
};
|
|
5179
|
+
this._maxWidth = doc.sizeToPoint(opts.maxWidth, doc.page.width - doc.page.margins.right - this._position.x);
|
|
5180
|
+
const {
|
|
5181
|
+
defaultStyle,
|
|
5182
|
+
defaultColStyle,
|
|
5183
|
+
defaultRowStyle
|
|
5184
|
+
} = normalizedDefaultStyle(opts.defaultStyle);
|
|
5185
|
+
this._defaultStyle = defaultStyle;
|
|
5186
|
+
let colStyle;
|
|
5187
|
+
if (opts.columnStyles) {
|
|
5188
|
+
if (Array.isArray(opts.columnStyles)) {
|
|
5189
|
+
colStyle = i => opts.columnStyles[i];
|
|
5190
|
+
} else if (typeof opts.columnStyles === 'function') {
|
|
5191
|
+
colStyle = memoize(i => opts.columnStyles(i), Infinity);
|
|
5192
|
+
} else if (typeof opts.columnStyles === 'object') {
|
|
5193
|
+
colStyle = () => opts.columnStyles;
|
|
5194
|
+
}
|
|
5195
|
+
}
|
|
5196
|
+
if (!colStyle) colStyle = () => ({});
|
|
5197
|
+
this._colStyle = normalizedColumnStyle.bind(this, defaultColStyle, colStyle);
|
|
5198
|
+
let rowStyle;
|
|
5199
|
+
if (opts.rowStyles) {
|
|
5200
|
+
if (Array.isArray(opts.rowStyles)) {
|
|
5201
|
+
rowStyle = i => opts.rowStyles[i];
|
|
5202
|
+
} else if (typeof opts.rowStyles === 'function') {
|
|
5203
|
+
rowStyle = memoize(i => opts.rowStyles(i), 10);
|
|
5204
|
+
} else if (typeof opts.rowStyles === 'object') {
|
|
5205
|
+
rowStyle = () => opts.rowStyles;
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
if (!rowStyle) rowStyle = () => ({});
|
|
5209
|
+
this._rowStyle = normalizedRowStyle.bind(this, defaultRowStyle, rowStyle);
|
|
5210
|
+
}
|
|
5211
|
+
function normalizeText(text) {
|
|
5212
|
+
if (text != null) text = `${text}`;
|
|
5213
|
+
return text;
|
|
5214
|
+
}
|
|
5215
|
+
function normalizeCell(cell, rowIndex, colIndex) {
|
|
5216
|
+
const colStyle = this._colStyle(colIndex);
|
|
5217
|
+
let rowStyle = this._rowStyle(rowIndex);
|
|
5218
|
+
const font = deepMerge({}, colStyle.font, rowStyle.font, cell.font);
|
|
5219
|
+
const customFont = Object.values(font).filter(v => v != null).length > 0;
|
|
5220
|
+
const doc = this.document;
|
|
5221
|
+
const rollbackFont = doc._fontSource;
|
|
5222
|
+
const rollbackFontSize = doc._fontSize;
|
|
5223
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5224
|
+
if (customFont) {
|
|
5225
|
+
if (font.src) doc.font(font.src, font.family);
|
|
5226
|
+
if (font.size) doc.fontSize(font.size);
|
|
5227
|
+
rowStyle = this._rowStyle(rowIndex);
|
|
5228
|
+
}
|
|
5229
|
+
cell.padding = normalizeSides(cell.padding);
|
|
5230
|
+
cell.border = normalizeSides(cell.border);
|
|
5231
|
+
cell.borderColor = normalizeSides(cell.borderColor);
|
|
5232
|
+
const config = deepMerge(this._defaultStyle, colStyle, rowStyle, cell);
|
|
5233
|
+
config.rowIndex = rowIndex;
|
|
5234
|
+
config.colIndex = colIndex;
|
|
5235
|
+
config.font = font ?? {};
|
|
5236
|
+
config.customFont = customFont;
|
|
5237
|
+
config.text = normalizeText(config.text);
|
|
5238
|
+
config.rowSpan = config.rowSpan ?? 1;
|
|
5239
|
+
config.colSpan = config.colSpan ?? 1;
|
|
5240
|
+
config.padding = normalizeSides(config.padding, '0.25em', x => doc.sizeToPoint(x, '0.25em'));
|
|
5241
|
+
config.border = normalizeSides(config.border, 1, x => doc.sizeToPoint(x, 1));
|
|
5242
|
+
config.borderColor = normalizeSides(config.borderColor, 'black', x => x ?? 'black');
|
|
5243
|
+
config.align = normalizeAlignment(config.align);
|
|
5244
|
+
config.align.x = config.align.x ?? 'left';
|
|
5245
|
+
config.align.y = config.align.y ?? 'top';
|
|
5246
|
+
config.textStroke = doc.sizeToPoint(config.textStroke, 0);
|
|
5247
|
+
config.textStrokeColor = config.textStrokeColor ?? 'black';
|
|
5248
|
+
config.textColor = config.textColor ?? 'black';
|
|
5249
|
+
config.textOptions = config.textOptions ?? {};
|
|
5250
|
+
config.id = new String(config.id ?? `${this._id}-${rowIndex}-${colIndex}`);
|
|
5251
|
+
config.type = config.type?.toUpperCase() === 'TH' ? 'TH' : 'TD';
|
|
5252
|
+
if (config.scope) {
|
|
5253
|
+
config.scope = config.scope.toLowerCase();
|
|
5254
|
+
if (config.scope === 'row') config.scope = 'Row';else if (config.scope === 'both') config.scope = 'Both';else if (config.scope === 'column') config.scope = 'Column';
|
|
5255
|
+
}
|
|
5256
|
+
if (typeof this.opts.debug === 'boolean') config.debug = this.opts.debug;
|
|
5257
|
+
if (customFont) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5258
|
+
return config;
|
|
5259
|
+
}
|
|
5260
|
+
function normalizeRow(row, rowIndex) {
|
|
5261
|
+
if (!this._cellClaim) this._cellClaim = new Set();
|
|
5262
|
+
let colIndex = 0;
|
|
5263
|
+
return row.map(cell => {
|
|
5264
|
+
if (cell == null || typeof cell !== 'object') cell = {
|
|
5265
|
+
text: cell
|
|
5266
|
+
};
|
|
5267
|
+
while (this._cellClaim.has(`${rowIndex},${colIndex}`)) {
|
|
5268
|
+
colIndex++;
|
|
5269
|
+
}
|
|
5270
|
+
cell = normalizeCell.call(this, cell, rowIndex, colIndex);
|
|
5271
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5272
|
+
for (let j = 0; j < cell.colSpan; j++) {
|
|
5273
|
+
this._cellClaim.add(`${rowIndex + i},${colIndex + j}`);
|
|
5274
|
+
}
|
|
5275
|
+
}
|
|
5276
|
+
colIndex += cell.colSpan;
|
|
5277
|
+
return cell;
|
|
5278
|
+
});
|
|
5279
|
+
}
|
|
5280
|
+
|
|
5281
|
+
function ensure(row) {
|
|
5282
|
+
this._columnWidths = [];
|
|
5283
|
+
ensureColumnWidths.call(this, row.reduce((a, cell) => a + cell.colSpan, 0));
|
|
5284
|
+
this._rowHeights = [];
|
|
5285
|
+
this._rowYPos = [this._position.y];
|
|
5286
|
+
this._rowBuffer = new Set();
|
|
5287
|
+
}
|
|
5288
|
+
function ensureColumnWidths(numCols) {
|
|
5289
|
+
let starColumnIndexes = [];
|
|
5290
|
+
let starMinAcc = 0;
|
|
5291
|
+
let unclaimedWidth = this._maxWidth;
|
|
5292
|
+
for (let i = 0; i < numCols; i++) {
|
|
5293
|
+
let col = this._colStyle(i);
|
|
5294
|
+
if (col.width === '*') {
|
|
5295
|
+
starColumnIndexes[i] = col;
|
|
5296
|
+
starMinAcc += col.minWidth;
|
|
5297
|
+
} else {
|
|
5298
|
+
unclaimedWidth -= col.width;
|
|
5299
|
+
this._columnWidths[i] = col.width;
|
|
5300
|
+
}
|
|
5301
|
+
}
|
|
5302
|
+
let starColCount = starColumnIndexes.reduce(x => x + 1, 0);
|
|
5303
|
+
if (starMinAcc >= unclaimedWidth) {
|
|
5304
|
+
starColumnIndexes.forEach((cell, i) => {
|
|
5305
|
+
this._columnWidths[i] = cell.minWidth;
|
|
5306
|
+
});
|
|
5307
|
+
} else if (starColCount > 0) {
|
|
5308
|
+
starColumnIndexes.forEach((col, i) => {
|
|
5309
|
+
let starSize = unclaimedWidth / starColCount;
|
|
5310
|
+
this._columnWidths[i] = Math.max(starSize, col.minWidth);
|
|
5311
|
+
if (col.maxWidth > 0) {
|
|
5312
|
+
this._columnWidths[i] = Math.min(this._columnWidths[i], col.maxWidth);
|
|
5313
|
+
}
|
|
5314
|
+
unclaimedWidth -= this._columnWidths[i];
|
|
5315
|
+
starColCount--;
|
|
5316
|
+
});
|
|
5317
|
+
}
|
|
5318
|
+
let tempX = this._position.x;
|
|
5319
|
+
this._columnXPos = Array.from(this._columnWidths, v => {
|
|
5320
|
+
const t = tempX;
|
|
5321
|
+
tempX += v;
|
|
5322
|
+
return t;
|
|
5323
|
+
});
|
|
5324
|
+
}
|
|
5325
|
+
function measure(row, rowIndex) {
|
|
5326
|
+
row.forEach(cell => this._rowBuffer.add(cell));
|
|
5327
|
+
if (rowIndex > 0) {
|
|
5328
|
+
this._rowYPos[rowIndex] = this._rowYPos[rowIndex - 1] + this._rowHeights[rowIndex - 1];
|
|
5329
|
+
}
|
|
5330
|
+
const rowStyle = this._rowStyle(rowIndex);
|
|
5331
|
+
let toRender = [];
|
|
5332
|
+
this._rowBuffer.forEach(cell => {
|
|
5333
|
+
if (cell.rowIndex + cell.rowSpan - 1 === rowIndex) {
|
|
5334
|
+
toRender.push(measureCell.call(this, cell, rowStyle.height));
|
|
5335
|
+
this._rowBuffer.delete(cell);
|
|
5336
|
+
}
|
|
5337
|
+
});
|
|
5338
|
+
let rowHeight = rowStyle.height;
|
|
5339
|
+
if (rowHeight === 'auto') {
|
|
5340
|
+
rowHeight = toRender.reduce((acc, cell) => {
|
|
5341
|
+
let minHeight = cell.textBounds.height + cell.padding.top + cell.padding.bottom;
|
|
5342
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5343
|
+
minHeight -= this._rowHeights[cell.rowIndex + i];
|
|
5344
|
+
}
|
|
5345
|
+
return Math.max(acc, minHeight);
|
|
5346
|
+
}, 0);
|
|
5347
|
+
}
|
|
5348
|
+
rowHeight = Math.max(rowHeight, rowStyle.minHeight);
|
|
5349
|
+
if (rowStyle.maxHeight > 0) {
|
|
5350
|
+
rowHeight = Math.min(rowHeight, rowStyle.maxHeight);
|
|
5351
|
+
}
|
|
5352
|
+
this._rowHeights[rowIndex] = rowHeight;
|
|
5353
|
+
let newPage = false;
|
|
5354
|
+
if (rowHeight > this.document.page.contentHeight) {
|
|
5355
|
+
console.warn(new Error(`Row ${rowIndex} requested more than the safe page height, row has been clamped`).stack.slice(7));
|
|
5356
|
+
this._rowHeights[rowIndex] = this.document.page.maxY() - this._rowYPos[rowIndex];
|
|
5357
|
+
} else if (this._rowYPos[rowIndex] + rowHeight >= this.document.page.maxY()) {
|
|
5358
|
+
this._rowYPos[rowIndex] = this.document.page.margins.top;
|
|
5359
|
+
newPage = true;
|
|
5360
|
+
}
|
|
5361
|
+
return {
|
|
5362
|
+
newPage,
|
|
5363
|
+
toRender: toRender.map(cell => measureCell.call(this, cell, rowHeight))
|
|
5364
|
+
};
|
|
5365
|
+
}
|
|
5366
|
+
function measureCell(cell, rowHeight) {
|
|
5367
|
+
let cellWidth = 0;
|
|
5368
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5369
|
+
cellWidth += this._columnWidths[cell.colIndex + i];
|
|
5370
|
+
}
|
|
5371
|
+
let cellHeight = rowHeight;
|
|
5372
|
+
if (cellHeight === 'auto') {
|
|
5373
|
+
cellHeight = this.document.page.contentHeight;
|
|
5374
|
+
} else {
|
|
5375
|
+
for (let i = 0; i < cell.rowSpan - 1; i++) {
|
|
5376
|
+
cellHeight += this._rowHeights[cell.rowIndex + i];
|
|
5377
|
+
}
|
|
5378
|
+
}
|
|
5379
|
+
const textAllocatedWidth = cellWidth - cell.padding.left - cell.padding.right;
|
|
5380
|
+
const textAllocatedHeight = cellHeight - cell.padding.top - cell.padding.bottom;
|
|
5381
|
+
const rotation = cell.textOptions.rotation ?? 0;
|
|
5382
|
+
const {
|
|
5383
|
+
width: textMaxWidth,
|
|
5384
|
+
height: textMaxHeight
|
|
5385
|
+
} = computeBounds(rotation, textAllocatedWidth, textAllocatedHeight);
|
|
5386
|
+
const textOptions = {
|
|
5387
|
+
align: cell.align.x,
|
|
5388
|
+
ellipsis: true,
|
|
5389
|
+
stroke: cell.textStroke > 0,
|
|
5390
|
+
fill: true,
|
|
5391
|
+
width: textMaxWidth,
|
|
5392
|
+
height: textMaxHeight,
|
|
5393
|
+
rotation,
|
|
5394
|
+
...cell.textOptions
|
|
5395
|
+
};
|
|
5396
|
+
let textBounds = {
|
|
5397
|
+
x: 0,
|
|
5398
|
+
y: 0,
|
|
5399
|
+
width: 0,
|
|
5400
|
+
height: 0
|
|
5401
|
+
};
|
|
5402
|
+
if (cell.text) {
|
|
5403
|
+
const rollbackFont = this.document._fontSource;
|
|
5404
|
+
const rollbackFontSize = this.document._fontSize;
|
|
5405
|
+
const rollbackFontFamily = this.document._fontFamily;
|
|
5406
|
+
if (cell.font?.src) this.document.font(cell.font.src, cell.font?.family);
|
|
5407
|
+
if (cell.font?.size) this.document.fontSize(cell.font.size);
|
|
5408
|
+
const unRotatedTextBounds = this.document.boundsOfString(cell.text, 0, 0, {
|
|
5409
|
+
...textOptions,
|
|
5410
|
+
rotation: 0
|
|
5411
|
+
});
|
|
5412
|
+
textOptions.width = unRotatedTextBounds.width;
|
|
5413
|
+
textOptions.height = unRotatedTextBounds.height;
|
|
5414
|
+
textBounds = this.document.boundsOfString(cell.text, 0, 0, textOptions);
|
|
5415
|
+
this.document.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5416
|
+
}
|
|
5417
|
+
return {
|
|
5418
|
+
...cell,
|
|
5419
|
+
textOptions,
|
|
5420
|
+
x: this._columnXPos[cell.colIndex],
|
|
5421
|
+
y: this._rowYPos[cell.rowIndex],
|
|
5422
|
+
textX: this._columnXPos[cell.colIndex] + cell.padding.left,
|
|
5423
|
+
textY: this._rowYPos[cell.rowIndex] + cell.padding.top,
|
|
5424
|
+
width: cellWidth,
|
|
5425
|
+
height: cellHeight,
|
|
5426
|
+
textAllocatedHeight,
|
|
5427
|
+
textAllocatedWidth,
|
|
5428
|
+
textBounds
|
|
5429
|
+
};
|
|
5430
|
+
}
|
|
5431
|
+
function computeBounds(rotation, allocWidth, allocHeight) {
|
|
5432
|
+
let textMaxWidth, textMaxHeight;
|
|
5433
|
+
const cos = cosine(rotation);
|
|
5434
|
+
const sin = sine(rotation);
|
|
5435
|
+
if (rotation === 0 || rotation === 180) {
|
|
5436
|
+
textMaxWidth = allocWidth;
|
|
5437
|
+
textMaxHeight = allocHeight;
|
|
5438
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5439
|
+
textMaxWidth = allocHeight;
|
|
5440
|
+
textMaxHeight = allocWidth;
|
|
5441
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5442
|
+
textMaxWidth = allocWidth / (2 * cos);
|
|
5443
|
+
textMaxHeight = allocWidth / (2 * sin);
|
|
5444
|
+
} else {
|
|
5445
|
+
textMaxHeight = allocWidth / (2 * cos);
|
|
5446
|
+
textMaxWidth = allocWidth / (2 * sin);
|
|
5447
|
+
}
|
|
5448
|
+
const EF = sin * textMaxWidth;
|
|
5449
|
+
const FG = cos * textMaxHeight;
|
|
5450
|
+
if (EF + FG > allocHeight) {
|
|
5451
|
+
const denominator = cos * cos - sin * sin;
|
|
5452
|
+
if (rotation === 0 || rotation === 180) {
|
|
5453
|
+
textMaxWidth = allocWidth;
|
|
5454
|
+
textMaxHeight = allocHeight;
|
|
5455
|
+
} else if (rotation === 90 || rotation === 270) {
|
|
5456
|
+
textMaxWidth = allocHeight;
|
|
5457
|
+
textMaxHeight = allocWidth;
|
|
5458
|
+
} else if (rotation < 90 || rotation > 180 && rotation < 270) {
|
|
5459
|
+
textMaxWidth = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5460
|
+
textMaxHeight = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5461
|
+
} else {
|
|
5462
|
+
textMaxHeight = (allocWidth * cos - allocHeight * sin) / denominator;
|
|
5463
|
+
textMaxWidth = (allocHeight * cos - allocWidth * sin) / denominator;
|
|
5464
|
+
}
|
|
5465
|
+
}
|
|
5466
|
+
return {
|
|
5467
|
+
width: Math.abs(textMaxWidth),
|
|
5468
|
+
height: Math.abs(textMaxHeight)
|
|
5469
|
+
};
|
|
5470
|
+
}
|
|
5471
|
+
|
|
5472
|
+
function accommodateTable() {
|
|
5473
|
+
const structParent = this.opts.structParent;
|
|
5474
|
+
if (structParent) {
|
|
5475
|
+
this._tableStruct = this.document.struct('Table');
|
|
5476
|
+
this._tableStruct.dictionary.data.ID = this._id;
|
|
5477
|
+
if (structParent instanceof PDFStructureElement) {
|
|
5478
|
+
structParent.add(this._tableStruct);
|
|
5479
|
+
} else if (structParent instanceof PDFDocument) {
|
|
5480
|
+
structParent.addStructure(this._tableStruct);
|
|
5481
|
+
}
|
|
5482
|
+
this._headerRowLookup = {};
|
|
5483
|
+
this._headerColumnLookup = {};
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
function accommodateCleanup() {
|
|
5487
|
+
if (this._tableStruct) this._tableStruct.end();
|
|
5488
|
+
}
|
|
5489
|
+
function accessibleRow(row, rowIndex, renderCell) {
|
|
5490
|
+
const rowStruct = this.document.struct('TR');
|
|
5491
|
+
rowStruct.dictionary.data.ID = new String(`${this._id}-${rowIndex}`);
|
|
5492
|
+
this._tableStruct.add(rowStruct);
|
|
5493
|
+
row.forEach(cell => renderCell(cell, rowStruct));
|
|
5494
|
+
rowStruct.end();
|
|
5495
|
+
}
|
|
5496
|
+
function accessibleCell(cell, rowStruct, callback) {
|
|
5497
|
+
const doc = this.document;
|
|
5498
|
+
const cellStruct = doc.struct(cell.type, {
|
|
5499
|
+
title: cell.title
|
|
5500
|
+
});
|
|
5501
|
+
cellStruct.dictionary.data.ID = cell.id;
|
|
5502
|
+
rowStruct.add(cellStruct);
|
|
5503
|
+
const padding = cell.padding;
|
|
5504
|
+
const border = cell.border;
|
|
5505
|
+
const attributes = {
|
|
5506
|
+
O: 'Table',
|
|
5507
|
+
Width: cell.width,
|
|
5508
|
+
Height: cell.height,
|
|
5509
|
+
Padding: [padding.top, padding.bottom, padding.left, padding.right],
|
|
5510
|
+
RowSpan: cell.rowSpan > 1 ? cell.rowSpan : undefined,
|
|
5511
|
+
ColSpan: cell.colSpan > 1 ? cell.colSpan : undefined,
|
|
5512
|
+
BorderThickness: [border.top, border.bottom, border.left, border.right]
|
|
5513
|
+
};
|
|
5514
|
+
if (cell.type === 'TH') {
|
|
5515
|
+
if (cell.scope === 'Row' || cell.scope === 'Both') {
|
|
5516
|
+
for (let i = 0; i < cell.rowSpan; i++) {
|
|
5517
|
+
if (!this._headerRowLookup[cell.rowIndex + i]) {
|
|
5518
|
+
this._headerRowLookup[cell.rowIndex + i] = [];
|
|
5519
|
+
}
|
|
5520
|
+
this._headerRowLookup[cell.rowIndex + i].push(cell.id);
|
|
5521
|
+
}
|
|
5522
|
+
attributes.Scope = cell.scope;
|
|
5523
|
+
}
|
|
5524
|
+
if (cell.scope === 'Column' || cell.scope === 'Both') {
|
|
5525
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
5526
|
+
if (!this._headerColumnLookup[cell.colIndex + i]) {
|
|
5527
|
+
this._headerColumnLookup[cell.colIndex + i] = [];
|
|
5528
|
+
}
|
|
5529
|
+
this._headerColumnLookup[cell.colIndex + i].push(cell.id);
|
|
5530
|
+
}
|
|
5531
|
+
attributes.Scope = cell.scope;
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
const Headers = new Set([...Array.from({
|
|
5535
|
+
length: cell.colSpan
|
|
5536
|
+
}, (_, i) => this._headerColumnLookup[cell.colIndex + i]).flat(), ...Array.from({
|
|
5537
|
+
length: cell.rowSpan
|
|
5538
|
+
}, (_, i) => this._headerRowLookup[cell.rowIndex + i]).flat()].filter(Boolean));
|
|
5539
|
+
if (Headers.size) attributes.Headers = Array.from(Headers);
|
|
5540
|
+
const normalizeColor = doc._normalizeColor;
|
|
5541
|
+
if (cell.backgroundColor != null) {
|
|
5542
|
+
attributes.BackgroundColor = normalizeColor(cell.backgroundColor);
|
|
5543
|
+
}
|
|
5544
|
+
const hasBorder = [border.top, border.bottom, border.left, border.right];
|
|
5545
|
+
if (hasBorder.some(x => x)) {
|
|
5546
|
+
const borderColor = cell.borderColor;
|
|
5547
|
+
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];
|
|
5548
|
+
}
|
|
5549
|
+
Object.keys(attributes).forEach(key => attributes[key] === undefined && delete attributes[key]);
|
|
5550
|
+
cellStruct.dictionary.data.A = doc.ref(attributes);
|
|
5551
|
+
cellStruct.add(callback);
|
|
5552
|
+
cellStruct.end();
|
|
5553
|
+
cellStruct.dictionary.data.A.end();
|
|
5554
|
+
}
|
|
5555
|
+
|
|
5556
|
+
function renderRow(row, rowIndex) {
|
|
5557
|
+
if (this._tableStruct) {
|
|
5558
|
+
accessibleRow.call(this, row, rowIndex, renderCell.bind(this));
|
|
5559
|
+
} else {
|
|
5560
|
+
row.forEach(cell => renderCell.call(this, cell));
|
|
5561
|
+
}
|
|
5562
|
+
return this._rowYPos[rowIndex] + this._rowHeights[rowIndex];
|
|
5563
|
+
}
|
|
5564
|
+
function renderCell(cell, rowStruct) {
|
|
5565
|
+
const cellRenderer = () => {
|
|
5566
|
+
if (cell.backgroundColor != null) {
|
|
5567
|
+
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(cell.backgroundColor).restore();
|
|
5568
|
+
}
|
|
5569
|
+
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5570
|
+
if (cell.debug) {
|
|
5571
|
+
this.document.save();
|
|
5572
|
+
this.document.dash(1, {
|
|
5573
|
+
space: 1
|
|
5574
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5575
|
+
this.document.rect(cell.x, cell.y, cell.width, cell.height).stroke('green');
|
|
5576
|
+
this.document.restore();
|
|
5577
|
+
}
|
|
5578
|
+
if (cell.text) renderCellText.call(this, cell);
|
|
5579
|
+
};
|
|
5580
|
+
if (rowStruct) accessibleCell.call(this, cell, rowStruct, cellRenderer);else cellRenderer();
|
|
5581
|
+
}
|
|
5582
|
+
function renderCellText(cell) {
|
|
5583
|
+
const doc = this.document;
|
|
5584
|
+
const rollbackFont = doc._fontSource;
|
|
5585
|
+
const rollbackFontSize = doc._fontSize;
|
|
5586
|
+
const rollbackFontFamily = doc._fontFamily;
|
|
5587
|
+
if (cell.customFont) {
|
|
5588
|
+
if (cell.font.src) doc.font(cell.font.src, cell.font.family);
|
|
5589
|
+
if (cell.font.size) doc.fontSize(cell.font.size);
|
|
5590
|
+
}
|
|
5591
|
+
const x = cell.textX;
|
|
5592
|
+
const y = cell.textY;
|
|
5593
|
+
const Ah = cell.textAllocatedHeight;
|
|
5594
|
+
const Aw = cell.textAllocatedWidth;
|
|
5595
|
+
const Cw = cell.textBounds.width;
|
|
5596
|
+
const Ch = cell.textBounds.height;
|
|
5597
|
+
const Ox = -cell.textBounds.x;
|
|
5598
|
+
const Oy = -cell.textBounds.y;
|
|
5599
|
+
const PxScale = cell.align.x === 'right' ? 1 : cell.align.x === 'center' ? 0.5 : 0;
|
|
5600
|
+
const Px = (Aw - Cw) * PxScale;
|
|
5601
|
+
const PyScale = cell.align.y === 'bottom' ? 1 : cell.align.y === 'center' ? 0.5 : 0;
|
|
5602
|
+
const Py = (Ah - Ch) * PyScale;
|
|
5603
|
+
const dx = Px + Ox;
|
|
5604
|
+
const dy = Py + Oy;
|
|
5605
|
+
if (cell.debug) {
|
|
5606
|
+
doc.save();
|
|
5607
|
+
doc.dash(1, {
|
|
5608
|
+
space: 1
|
|
5609
|
+
}).lineWidth(1).strokeOpacity(0.3);
|
|
5610
|
+
if (cell.text) {
|
|
5611
|
+
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');
|
|
5612
|
+
}
|
|
5613
|
+
doc.rect(x, y, Aw, Ah).stroke('orange');
|
|
5614
|
+
doc.restore();
|
|
5615
|
+
}
|
|
5616
|
+
doc.save().rect(x, y, Aw, Ah).clip();
|
|
5617
|
+
doc.fillColor(cell.textColor).strokeColor(cell.textStrokeColor);
|
|
5618
|
+
if (cell.textStroke > 0) doc.lineWidth(cell.textStroke);
|
|
5619
|
+
doc.text(cell.text, x + dx, y + dy, cell.textOptions);
|
|
5620
|
+
doc.restore();
|
|
5621
|
+
if (cell.font) doc.font(rollbackFont, rollbackFontFamily, rollbackFontSize);
|
|
5622
|
+
}
|
|
5623
|
+
function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
5624
|
+
border = Object.fromEntries(Object.entries(border).map(_ref => {
|
|
5625
|
+
let [k, v] = _ref;
|
|
5626
|
+
return [k, mask && !mask[k] ? 0 : v];
|
|
5627
|
+
}));
|
|
5628
|
+
const doc = this.document;
|
|
5629
|
+
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5630
|
+
if (border.top > 0) {
|
|
5631
|
+
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(borderColor.top).restore();
|
|
5632
|
+
}
|
|
5633
|
+
} else {
|
|
5634
|
+
if (border.top > 0) {
|
|
5635
|
+
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(borderColor.top).restore();
|
|
5636
|
+
}
|
|
5637
|
+
if (border.right > 0) {
|
|
5638
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(borderColor.right).restore();
|
|
5639
|
+
}
|
|
5640
|
+
if (border.bottom > 0) {
|
|
5641
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(borderColor.bottom).restore();
|
|
5642
|
+
}
|
|
5643
|
+
if (border.left > 0) {
|
|
5644
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(borderColor.left).restore();
|
|
5645
|
+
}
|
|
5646
|
+
}
|
|
5647
|
+
}
|
|
5648
|
+
|
|
5649
|
+
class PDFTable {
|
|
5650
|
+
constructor(document) {
|
|
5651
|
+
let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
5652
|
+
this.document = document;
|
|
5653
|
+
this.opts = Object.freeze(opts);
|
|
5654
|
+
normalizeTable.call(this);
|
|
5655
|
+
accommodateTable.call(this);
|
|
5656
|
+
this._currRowIndex = 0;
|
|
5657
|
+
this._ended = false;
|
|
5658
|
+
if (opts.data) {
|
|
5659
|
+
for (const row of opts.data) this.row(row);
|
|
5660
|
+
return this.end();
|
|
5661
|
+
}
|
|
5662
|
+
}
|
|
5663
|
+
row(row) {
|
|
5664
|
+
let lastRow = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
5665
|
+
if (this._ended) {
|
|
5666
|
+
throw new Error(`Table was marked as ended on row ${this._currRowIndex}`);
|
|
5667
|
+
}
|
|
5668
|
+
row = Array.from(row);
|
|
5669
|
+
row = normalizeRow.call(this, row, this._currRowIndex);
|
|
5670
|
+
if (this._currRowIndex === 0) ensure.call(this, row);
|
|
5671
|
+
const {
|
|
5672
|
+
newPage,
|
|
5673
|
+
toRender
|
|
5674
|
+
} = measure.call(this, row, this._currRowIndex);
|
|
5675
|
+
if (newPage) this.document.continueOnNewPage();
|
|
5676
|
+
const yPos = renderRow.call(this, toRender, this._currRowIndex);
|
|
5677
|
+
this.document.x = this._position.x;
|
|
5678
|
+
this.document.y = yPos;
|
|
5679
|
+
if (lastRow) return this.end();
|
|
5680
|
+
this._currRowIndex++;
|
|
5681
|
+
return this;
|
|
5682
|
+
}
|
|
5683
|
+
end() {
|
|
5684
|
+
while (this._rowBuffer?.size) this.row([]);
|
|
5685
|
+
this._ended = true;
|
|
5686
|
+
accommodateCleanup.call(this);
|
|
5687
|
+
return this.document;
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
|
|
5691
|
+
var TableMixin = {
|
|
5692
|
+
initTables() {
|
|
5693
|
+
this._tableIndex = 0;
|
|
5694
|
+
},
|
|
5695
|
+
table(opts) {
|
|
5696
|
+
return new PDFTable(this, opts);
|
|
5697
|
+
}
|
|
5698
|
+
};
|
|
5699
|
+
|
|
5440
5700
|
class PDFMetadata {
|
|
5441
5701
|
constructor() {
|
|
5442
5702
|
this._metadata = `
|
|
@@ -5480,7 +5740,7 @@ var MetadataMixin = {
|
|
|
5480
5740
|
_addInfo() {
|
|
5481
5741
|
this.appendXML(`
|
|
5482
5742
|
<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
|
|
5483
|
-
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] +
|
|
5743
|
+
<xmp:CreateDate>${this.info.CreationDate.toISOString().split('.')[0] + 'Z'}</xmp:CreateDate>
|
|
5484
5744
|
<xmp:CreatorTool>${this.info.Creator}</xmp:CreatorTool>
|
|
5485
5745
|
</rdf:Description>
|
|
5486
5746
|
`);
|
|
@@ -5533,11 +5793,6 @@ var MetadataMixin = {
|
|
|
5533
5793
|
endMetadata() {
|
|
5534
5794
|
this._addInfo();
|
|
5535
5795
|
this.metadata.end();
|
|
5536
|
-
|
|
5537
|
-
/*
|
|
5538
|
-
Metadata was introduced in PDF 1.4, so adding it to 1.3
|
|
5539
|
-
will likely only take up more space.
|
|
5540
|
-
*/
|
|
5541
5796
|
if (this.version != 1.3) {
|
|
5542
5797
|
this.metadataRef = this.ref({
|
|
5543
5798
|
length: this.metadata.getLength(),
|
|
@@ -5552,17 +5807,11 @@ var MetadataMixin = {
|
|
|
5552
5807
|
}
|
|
5553
5808
|
};
|
|
5554
5809
|
|
|
5555
|
-
/*
|
|
5556
|
-
PDFDocument - represents an entire PDF document
|
|
5557
|
-
By Devon Govett
|
|
5558
|
-
*/
|
|
5559
5810
|
class PDFDocument extends stream.Readable {
|
|
5560
5811
|
constructor() {
|
|
5561
5812
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
5562
5813
|
super(options);
|
|
5563
5814
|
this.options = options;
|
|
5564
|
-
|
|
5565
|
-
// PDF version
|
|
5566
5815
|
switch (options.pdfVersion) {
|
|
5567
5816
|
case '1.4':
|
|
5568
5817
|
this.version = 1.4;
|
|
@@ -5581,13 +5830,9 @@ class PDFDocument extends stream.Readable {
|
|
|
5581
5830
|
this.version = 1.3;
|
|
5582
5831
|
break;
|
|
5583
5832
|
}
|
|
5584
|
-
|
|
5585
|
-
// Whether streams should be compressed
|
|
5586
5833
|
this.compress = this.options.compress != null ? this.options.compress : true;
|
|
5587
5834
|
this._pageBuffer = [];
|
|
5588
5835
|
this._pageBufferStart = 0;
|
|
5589
|
-
|
|
5590
|
-
// The PDF object store
|
|
5591
5836
|
this._offsets = [];
|
|
5592
5837
|
this._waiting = 0;
|
|
5593
5838
|
this._ended = false;
|
|
@@ -5608,11 +5853,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5608
5853
|
if (this.options.lang) {
|
|
5609
5854
|
this._root.data.Lang = new String(this.options.lang);
|
|
5610
5855
|
}
|
|
5611
|
-
|
|
5612
|
-
// The current page
|
|
5613
5856
|
this.page = null;
|
|
5614
|
-
|
|
5615
|
-
// Initialize mixins
|
|
5616
5857
|
this.initMetadata();
|
|
5617
5858
|
this.initColor();
|
|
5618
5859
|
this.initVector();
|
|
@@ -5621,9 +5862,8 @@ class PDFDocument extends stream.Readable {
|
|
|
5621
5862
|
this.initImages();
|
|
5622
5863
|
this.initOutline();
|
|
5623
5864
|
this.initMarkings(options);
|
|
5865
|
+
this.initTables();
|
|
5624
5866
|
this.initSubset(options);
|
|
5625
|
-
|
|
5626
|
-
// Initialize the metadata
|
|
5627
5867
|
this.info = {
|
|
5628
5868
|
Producer: 'PDFKit',
|
|
5629
5869
|
Creator: 'PDFKit',
|
|
@@ -5640,21 +5880,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5640
5880
|
DisplayDocTitle: true
|
|
5641
5881
|
});
|
|
5642
5882
|
}
|
|
5643
|
-
|
|
5644
|
-
// Generate file ID
|
|
5645
5883
|
this._id = PDFSecurity.generateFileID(this.info);
|
|
5646
|
-
|
|
5647
|
-
// Initialize security settings
|
|
5648
5884
|
this._security = PDFSecurity.create(this, options);
|
|
5649
|
-
|
|
5650
|
-
// Write the header
|
|
5651
|
-
// PDF version
|
|
5652
5885
|
this._write(`%PDF-${this.version}`);
|
|
5653
|
-
|
|
5654
|
-
// 4 binary chars, as recommended by the spec
|
|
5655
5886
|
this._write('%\xFF\xFF\xFF\xFF');
|
|
5656
|
-
|
|
5657
|
-
// Add the first page
|
|
5658
5887
|
if (this.options.autoFirstPage !== false) {
|
|
5659
5888
|
this.addPage();
|
|
5660
5889
|
}
|
|
@@ -5665,27 +5894,16 @@ class PDFDocument extends stream.Readable {
|
|
|
5665
5894
|
options
|
|
5666
5895
|
} = this);
|
|
5667
5896
|
}
|
|
5668
|
-
|
|
5669
|
-
// end the current page if needed
|
|
5670
5897
|
if (!this.options.bufferPages) {
|
|
5671
5898
|
this.flushPages();
|
|
5672
5899
|
}
|
|
5673
|
-
|
|
5674
|
-
// create a page object
|
|
5675
5900
|
this.page = new PDFPage(this, options);
|
|
5676
5901
|
this._pageBuffer.push(this.page);
|
|
5677
|
-
|
|
5678
|
-
// add the page to the object store
|
|
5679
5902
|
const pages = this._root.data.Pages.data;
|
|
5680
5903
|
pages.Kids.push(this.page.dictionary);
|
|
5681
5904
|
pages.Count++;
|
|
5682
|
-
|
|
5683
|
-
// reset x and y coordinates
|
|
5684
5905
|
this.x = this.page.margins.left;
|
|
5685
5906
|
this.y = this.page.margins.top;
|
|
5686
|
-
|
|
5687
|
-
// flip PDF coordinate system so that the origin is in
|
|
5688
|
-
// the top left rather than the bottom left
|
|
5689
5907
|
this._ctm = [1, 0, 0, 1, 0, 0];
|
|
5690
5908
|
this.transform(1, 0, 0, -1, 0, this.page.height);
|
|
5691
5909
|
this.emit('pageAdded');
|
|
@@ -5693,7 +5911,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5693
5911
|
}
|
|
5694
5912
|
continueOnNewPage(options) {
|
|
5695
5913
|
const pageMarkings = this.endPageMarkings(this.page);
|
|
5696
|
-
this.addPage(options);
|
|
5914
|
+
this.addPage(options ?? this.page._options);
|
|
5697
5915
|
this.initPageMarkings(pageMarkings);
|
|
5698
5916
|
return this;
|
|
5699
5917
|
}
|
|
@@ -5711,8 +5929,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5711
5929
|
return this.page = page;
|
|
5712
5930
|
}
|
|
5713
5931
|
flushPages() {
|
|
5714
|
-
// this local variable exists so we're future-proof against
|
|
5715
|
-
// reentrant calls to flushPages.
|
|
5716
5932
|
const pages = this._pageBuffer;
|
|
5717
5933
|
this._pageBuffer = [];
|
|
5718
5934
|
this._pageBufferStart += pages.length;
|
|
@@ -5736,13 +5952,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5736
5952
|
}
|
|
5737
5953
|
addNamedEmbeddedFile(name, ref) {
|
|
5738
5954
|
if (!this._root.data.Names.data.EmbeddedFiles) {
|
|
5739
|
-
// disabling /Limits for this tree fixes attachments not showing in Adobe Reader
|
|
5740
5955
|
this._root.data.Names.data.EmbeddedFiles = new PDFNameTree({
|
|
5741
5956
|
limits: false
|
|
5742
5957
|
});
|
|
5743
5958
|
}
|
|
5744
|
-
|
|
5745
|
-
// add filespec to EmbeddedFiles
|
|
5746
5959
|
this._root.data.Names.data.EmbeddedFiles.add(name, ref);
|
|
5747
5960
|
}
|
|
5748
5961
|
addNamedJavaScript(name, js) {
|
|
@@ -5757,19 +5970,17 @@ class PDFDocument extends stream.Readable {
|
|
|
5757
5970
|
}
|
|
5758
5971
|
ref(data) {
|
|
5759
5972
|
const ref = new PDFReference(this, this._offsets.length + 1, data);
|
|
5760
|
-
this._offsets.push(null);
|
|
5973
|
+
this._offsets.push(null);
|
|
5761
5974
|
this._waiting++;
|
|
5762
5975
|
return ref;
|
|
5763
5976
|
}
|
|
5764
5977
|
_read() {}
|
|
5765
|
-
// do nothing, but this method is required by node
|
|
5766
|
-
|
|
5767
5978
|
_write(data) {
|
|
5768
5979
|
if (!Buffer.isBuffer(data)) {
|
|
5769
5980
|
data = Buffer.from(data + '\n', 'binary');
|
|
5770
5981
|
}
|
|
5771
5982
|
this.push(data);
|
|
5772
|
-
|
|
5983
|
+
this._offset += data.length;
|
|
5773
5984
|
}
|
|
5774
5985
|
addContent(data) {
|
|
5775
5986
|
this.page.write(data);
|
|
@@ -5779,7 +5990,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5779
5990
|
this._offsets[ref.id - 1] = ref.offset;
|
|
5780
5991
|
if (--this._waiting === 0 && this._ended) {
|
|
5781
5992
|
this._finalize();
|
|
5782
|
-
|
|
5993
|
+
this._ended = false;
|
|
5783
5994
|
}
|
|
5784
5995
|
}
|
|
5785
5996
|
end() {
|
|
@@ -5816,13 +6027,12 @@ class PDFDocument extends stream.Readable {
|
|
|
5816
6027
|
this._security.end();
|
|
5817
6028
|
}
|
|
5818
6029
|
if (this._waiting === 0) {
|
|
5819
|
-
|
|
6030
|
+
this._finalize();
|
|
5820
6031
|
} else {
|
|
5821
|
-
|
|
6032
|
+
this._ended = true;
|
|
5822
6033
|
}
|
|
5823
6034
|
}
|
|
5824
6035
|
_finalize() {
|
|
5825
|
-
// generate xref
|
|
5826
6036
|
const xRefOffset = this._offset;
|
|
5827
6037
|
this._write('xref');
|
|
5828
6038
|
this._write(`0 ${this._offsets.length + 1}`);
|
|
@@ -5831,8 +6041,6 @@ class PDFDocument extends stream.Readable {
|
|
|
5831
6041
|
offset = `0000000000${offset}`.slice(-10);
|
|
5832
6042
|
this._write(offset + ' 00000 n ');
|
|
5833
6043
|
}
|
|
5834
|
-
|
|
5835
|
-
// trailer
|
|
5836
6044
|
const trailer = {
|
|
5837
6045
|
Size: this._offsets.length + 1,
|
|
5838
6046
|
Root: this._root,
|
|
@@ -5847,9 +6055,7 @@ class PDFDocument extends stream.Readable {
|
|
|
5847
6055
|
this._write('startxref');
|
|
5848
6056
|
this._write(`${xRefOffset}`);
|
|
5849
6057
|
this._write('%%EOF');
|
|
5850
|
-
|
|
5851
|
-
// end the stream
|
|
5852
|
-
return this.push(null);
|
|
6058
|
+
this.push(null);
|
|
5853
6059
|
}
|
|
5854
6060
|
toString() {
|
|
5855
6061
|
return '[object PDFDocument]';
|
|
@@ -5870,6 +6076,7 @@ mixin(MarkingsMixin);
|
|
|
5870
6076
|
mixin(AcroFormMixin);
|
|
5871
6077
|
mixin(AttachmentsMixin);
|
|
5872
6078
|
mixin(SubsetMixin);
|
|
6079
|
+
mixin(TableMixin);
|
|
5873
6080
|
PDFDocument.LineWrapper = LineWrapper;
|
|
5874
6081
|
|
|
5875
6082
|
export { PDFDocument as default };
|