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