pdfkit 0.17.2 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.yarn/install-state.gz +0 -0
- package/.yarn/releases/yarn-4.10.3.cjs +942 -0
- package/.yarnrc.yml +3 -0
- package/CHANGELOG.md +163 -134
- package/LICENSE +7 -7
- package/README.md +189 -182
- package/js/data/Courier-Bold.afm +342 -342
- package/js/data/Courier-BoldOblique.afm +342 -342
- package/js/data/Courier-Oblique.afm +342 -342
- package/js/data/Courier.afm +342 -342
- package/js/data/Helvetica-Bold.afm +2827 -2827
- package/js/data/Helvetica-BoldOblique.afm +2827 -2827
- package/js/data/Helvetica-Oblique.afm +3051 -3051
- package/js/data/Helvetica.afm +3051 -3051
- package/js/data/Symbol.afm +213 -213
- package/js/data/Times-Bold.afm +2588 -2588
- package/js/data/Times-BoldItalic.afm +2384 -2384
- package/js/data/Times-Italic.afm +2667 -2667
- package/js/data/Times-Roman.afm +2419 -2419
- package/js/data/ZapfDingbats.afm +225 -225
- package/js/pdfkit.es.js +679 -407
- package/js/pdfkit.es.js.map +1 -1
- package/js/pdfkit.js +605 -246
- package/js/pdfkit.js.map +1 -1
- package/js/pdfkit.standalone.js +27578 -31717
- package/js/virtual-fs.js +1 -3
- package/jsconfig.json +12 -12
- package/package.json +83 -92
- package/rollup.config.mjs +124 -0
- package/types/jest.custom-matchers.d.ts +28 -28
- package/vitest.config.js +11 -0
- package/js/pdfkit.es5.js +0 -7493
- package/js/pdfkit.es5.js.map +0 -1
- package/js/pdfkit.esnext.js +0 -6782
- package/js/pdfkit.esnext.js.map +0 -1
package/js/pdfkit.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
var stream = require('stream');
|
|
4
4
|
var zlib = require('zlib');
|
|
5
|
-
var
|
|
5
|
+
var utils = require('@noble/hashes/utils');
|
|
6
|
+
var md5 = require('js-md5');
|
|
7
|
+
var sha2 = require('@noble/hashes/sha2');
|
|
8
|
+
var aes = require('@noble/ciphers/aes');
|
|
6
9
|
var fs = require('fs');
|
|
7
10
|
var fontkit = require('fontkit');
|
|
8
|
-
var events = require('events');
|
|
9
11
|
var LineBreaker = require('linebreak');
|
|
10
|
-
var exif = require('jpeg-exif');
|
|
11
12
|
var PNG = require('png-js');
|
|
12
13
|
|
|
13
14
|
class PDFAbstractReference {
|
|
@@ -59,7 +60,7 @@ class SpotColor {
|
|
|
59
60
|
this.id = 'CS' + Object.keys(doc.spotColors).length;
|
|
60
61
|
this.name = name;
|
|
61
62
|
this.values = [C, M, Y, K];
|
|
62
|
-
this.ref = doc.ref(['Separation', this.name, 'DeviceCMYK', {
|
|
63
|
+
this.ref = doc.ref(['Separation', escapeName(this.name), 'DeviceCMYK', {
|
|
63
64
|
Range: [0, 1, 0, 1, 0, 1, 0, 1],
|
|
64
65
|
C0: [0, 0, 0, 0],
|
|
65
66
|
C1: this.values.map(value => value / 100),
|
|
@@ -75,6 +76,10 @@ class SpotColor {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
const pad = (str, length) => (Array(length + 1).join('0') + str).slice(-length);
|
|
79
|
+
const isSafeCharCode = code => {
|
|
80
|
+
if (code > 0x7f) return true;
|
|
81
|
+
return code > 0x20 && code !== 0x7f && code !== 0x23 && code !== 0x25 && code !== 0x28 && code !== 0x29 && code !== 0x2f && code !== 0x3c && code !== 0x3e && code !== 0x5b && code !== 0x5d && code !== 0x7b && code !== 0x7d;
|
|
82
|
+
};
|
|
78
83
|
const escapableRe = /[\n\r\t\b\f()\\]/g;
|
|
79
84
|
const escapable = {
|
|
80
85
|
'\n': '\\n',
|
|
@@ -86,6 +91,18 @@ const escapable = {
|
|
|
86
91
|
'(': '\\(',
|
|
87
92
|
')': '\\)'
|
|
88
93
|
};
|
|
94
|
+
const escapeName = function (name) {
|
|
95
|
+
let escapedName = '';
|
|
96
|
+
for (const char of name) {
|
|
97
|
+
const code = char.charCodeAt(0);
|
|
98
|
+
if (isSafeCharCode(code)) {
|
|
99
|
+
escapedName += char;
|
|
100
|
+
} else {
|
|
101
|
+
escapedName += `#${code.toString(16).toUpperCase().padStart(2, '0')}`;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return escapedName;
|
|
105
|
+
};
|
|
89
106
|
const swapBytes = function (buff) {
|
|
90
107
|
const l = buff.length;
|
|
91
108
|
if (l & 0x01) {
|
|
@@ -359,6 +376,7 @@ class PDFPage {
|
|
|
359
376
|
this._options = options;
|
|
360
377
|
this.size = options.size || 'letter';
|
|
361
378
|
this.layout = options.layout || 'portrait';
|
|
379
|
+
this.userUnit = options.userUnit || 1.0;
|
|
362
380
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
363
381
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
364
382
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
@@ -374,7 +392,8 @@ class PDFPage {
|
|
|
374
392
|
Parent: this.document._root.data.Pages,
|
|
375
393
|
MediaBox: [0, 0, this.width, this.height],
|
|
376
394
|
Contents: this.content,
|
|
377
|
-
Resources: this.resources
|
|
395
|
+
Resources: this.resources,
|
|
396
|
+
UserUnit: this.userUnit
|
|
378
397
|
});
|
|
379
398
|
this.markings = [];
|
|
380
399
|
}
|
|
@@ -447,6 +466,54 @@ class PDFNameTree extends PDFTree {
|
|
|
447
466
|
}
|
|
448
467
|
}
|
|
449
468
|
|
|
469
|
+
function md5Hash(data) {
|
|
470
|
+
return new Uint8Array(md5.arrayBuffer(data));
|
|
471
|
+
}
|
|
472
|
+
function md5Hex(data) {
|
|
473
|
+
return md5(data);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function sha256Hash(data) {
|
|
477
|
+
return sha2.sha256(data);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function aesCbcEncrypt(data, key, iv, padding = true) {
|
|
481
|
+
return aes.cbc(key, iv, {
|
|
482
|
+
disablePadding: !padding
|
|
483
|
+
}).encrypt(data);
|
|
484
|
+
}
|
|
485
|
+
function aesEcbEncrypt(data, key) {
|
|
486
|
+
return aes.ecb(key, {
|
|
487
|
+
disablePadding: true
|
|
488
|
+
}).encrypt(data);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function rc4(data, key) {
|
|
492
|
+
const s = new Uint8Array(256);
|
|
493
|
+
for (let i = 0; i < 256; i++) {
|
|
494
|
+
s[i] = i;
|
|
495
|
+
}
|
|
496
|
+
let j = 0;
|
|
497
|
+
for (let i = 0; i < 256; i++) {
|
|
498
|
+
j = j + s[i] + key[i % key.length] & 0xff;
|
|
499
|
+
[s[i], s[j]] = [s[j], s[i]];
|
|
500
|
+
}
|
|
501
|
+
const output = new Uint8Array(data.length);
|
|
502
|
+
for (let i = 0, j = 0, k = 0; k < data.length; k++) {
|
|
503
|
+
i = i + 1 & 0xff;
|
|
504
|
+
j = j + s[i] & 0xff;
|
|
505
|
+
[s[i], s[j]] = [s[j], s[i]];
|
|
506
|
+
output[k] = data[k] ^ s[s[i] + s[j] & 0xff];
|
|
507
|
+
}
|
|
508
|
+
return output;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function randomBytes(length) {
|
|
512
|
+
const bytes = new Uint8Array(length);
|
|
513
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
514
|
+
return bytes;
|
|
515
|
+
}
|
|
516
|
+
|
|
450
517
|
function inRange(value, rangeGroup) {
|
|
451
518
|
if (value < rangeGroup[0]) return false;
|
|
452
519
|
let startRange = 0;
|
|
@@ -545,10 +612,10 @@ class PDFSecurity {
|
|
|
545
612
|
}
|
|
546
613
|
infoStr += `${key}: ${info[key].valueOf()}\n`;
|
|
547
614
|
}
|
|
548
|
-
return
|
|
615
|
+
return Buffer.from(md5Hash(infoStr));
|
|
549
616
|
}
|
|
550
617
|
static generateRandomWordArray(bytes) {
|
|
551
|
-
return
|
|
618
|
+
return randomBytes(bytes);
|
|
552
619
|
}
|
|
553
620
|
static create(document, options = {}) {
|
|
554
621
|
if (!options.ownerPassword && !options.userPassword) {
|
|
@@ -640,8 +707,8 @@ class PDFSecurity {
|
|
|
640
707
|
encDict.StrF = 'StdCF';
|
|
641
708
|
}
|
|
642
709
|
encDict.R = r;
|
|
643
|
-
encDict.O =
|
|
644
|
-
encDict.U =
|
|
710
|
+
encDict.O = Buffer.from(ownerPasswordEntry);
|
|
711
|
+
encDict.U = Buffer.from(userPasswordEntry);
|
|
645
712
|
encDict.P = permissions;
|
|
646
713
|
}
|
|
647
714
|
_setupEncryptionV5(encDict, options) {
|
|
@@ -651,10 +718,10 @@ class PDFSecurity {
|
|
|
651
718
|
const processedOwnerPassword = options.ownerPassword ? processPasswordR5(options.ownerPassword) : processedUserPassword;
|
|
652
719
|
this.encryptionKey = getEncryptionKeyR5(PDFSecurity.generateRandomWordArray);
|
|
653
720
|
const userPasswordEntry = getUserPasswordR5(processedUserPassword, PDFSecurity.generateRandomWordArray);
|
|
654
|
-
const userKeySalt =
|
|
721
|
+
const userKeySalt = userPasswordEntry.slice(40, 48);
|
|
655
722
|
const userEncryptionKeyEntry = getUserEncryptionKeyR5(processedUserPassword, userKeySalt, this.encryptionKey);
|
|
656
723
|
const ownerPasswordEntry = getOwnerPasswordR5(processedOwnerPassword, userPasswordEntry, PDFSecurity.generateRandomWordArray);
|
|
657
|
-
const ownerKeySalt =
|
|
724
|
+
const ownerKeySalt = ownerPasswordEntry.slice(40, 48);
|
|
658
725
|
const ownerEncryptionKeyEntry = getOwnerEncryptionKeyR5(processedOwnerPassword, ownerKeySalt, userPasswordEntry, this.encryptionKey);
|
|
659
726
|
const permsEntry = getEncryptedPermissionsR5(permissions, this.encryptionKey, PDFSecurity.generateRandomWordArray);
|
|
660
727
|
encDict.V = 5;
|
|
@@ -669,36 +736,37 @@ class PDFSecurity {
|
|
|
669
736
|
encDict.StmF = 'StdCF';
|
|
670
737
|
encDict.StrF = 'StdCF';
|
|
671
738
|
encDict.R = 5;
|
|
672
|
-
encDict.O =
|
|
673
|
-
encDict.OE =
|
|
674
|
-
encDict.U =
|
|
675
|
-
encDict.UE =
|
|
739
|
+
encDict.O = Buffer.from(ownerPasswordEntry);
|
|
740
|
+
encDict.OE = Buffer.from(ownerEncryptionKeyEntry);
|
|
741
|
+
encDict.U = Buffer.from(userPasswordEntry);
|
|
742
|
+
encDict.UE = Buffer.from(userEncryptionKeyEntry);
|
|
676
743
|
encDict.P = permissions;
|
|
677
|
-
encDict.Perms =
|
|
744
|
+
encDict.Perms = Buffer.from(permsEntry);
|
|
678
745
|
}
|
|
679
746
|
getEncryptFn(obj, gen) {
|
|
680
747
|
let digest;
|
|
681
748
|
if (this.version < 5) {
|
|
682
|
-
|
|
749
|
+
const suffix = new Uint8Array([obj & 0xff, obj >> 8 & 0xff, obj >> 16 & 0xff, gen & 0xff, gen >> 8 & 0xff]);
|
|
750
|
+
digest = utils.concatBytes(this.encryptionKey, suffix);
|
|
683
751
|
}
|
|
684
752
|
if (this.version === 1 || this.version === 2) {
|
|
685
|
-
let key =
|
|
686
|
-
|
|
687
|
-
|
|
753
|
+
let key = md5Hash(digest);
|
|
754
|
+
const keyLen = Math.min(16, this.keyBits / 8 + 5);
|
|
755
|
+
key = key.slice(0, keyLen);
|
|
756
|
+
return buffer => Buffer.from(rc4(new Uint8Array(buffer), key));
|
|
688
757
|
}
|
|
689
758
|
let key;
|
|
690
759
|
if (this.version === 4) {
|
|
691
|
-
|
|
760
|
+
const saltMarker = new Uint8Array([0x73, 0x41, 0x6c, 0x54]);
|
|
761
|
+
key = md5Hash(utils.concatBytes(digest, saltMarker));
|
|
692
762
|
} else {
|
|
693
763
|
key = this.encryptionKey;
|
|
694
764
|
}
|
|
695
765
|
const iv = PDFSecurity.generateRandomWordArray(16);
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
iv
|
|
766
|
+
return buffer => {
|
|
767
|
+
const encrypted = aesCbcEncrypt(new Uint8Array(buffer), key, iv, true);
|
|
768
|
+
return Buffer.from(utils.concatBytes(iv, encrypted));
|
|
700
769
|
};
|
|
701
|
-
return buffer => wordArrayToBuffer(iv.clone().concat(CryptoJS.AES.encrypt(CryptoJS.lib.WordArray.create(buffer), key, options).ciphertext));
|
|
702
770
|
}
|
|
703
771
|
end() {
|
|
704
772
|
this.dictionary.end();
|
|
@@ -749,89 +817,97 @@ function getPermissionsR3(permissionObject = {}) {
|
|
|
749
817
|
return permissions;
|
|
750
818
|
}
|
|
751
819
|
function getUserPasswordR2(encryptionKey) {
|
|
752
|
-
return
|
|
820
|
+
return rc4(processPasswordR2R3R4(), encryptionKey);
|
|
753
821
|
}
|
|
754
822
|
function getUserPasswordR3R4(documentId, encryptionKey) {
|
|
755
|
-
const key = encryptionKey.
|
|
756
|
-
let cipher =
|
|
823
|
+
const key = encryptionKey.slice();
|
|
824
|
+
let cipher = md5Hash(utils.concatBytes(processPasswordR2R3R4(), new Uint8Array(documentId)));
|
|
757
825
|
for (let i = 0; i < 20; i++) {
|
|
758
|
-
const
|
|
759
|
-
for (let j = 0; j <
|
|
760
|
-
|
|
826
|
+
const xorKey = new Uint8Array(key.length);
|
|
827
|
+
for (let j = 0; j < key.length; j++) {
|
|
828
|
+
xorKey[j] = encryptionKey[j] ^ i;
|
|
761
829
|
}
|
|
762
|
-
cipher =
|
|
830
|
+
cipher = rc4(cipher, xorKey);
|
|
763
831
|
}
|
|
764
|
-
|
|
832
|
+
const result = new Uint8Array(32);
|
|
833
|
+
result.set(cipher);
|
|
834
|
+
return result;
|
|
765
835
|
}
|
|
766
836
|
function getOwnerPasswordR2R3R4(r, keyBits, paddedUserPassword, paddedOwnerPassword) {
|
|
767
837
|
let digest = paddedOwnerPassword;
|
|
768
838
|
let round = r >= 3 ? 51 : 1;
|
|
769
839
|
for (let i = 0; i < round; i++) {
|
|
770
|
-
digest =
|
|
840
|
+
digest = md5Hash(digest);
|
|
771
841
|
}
|
|
772
|
-
const
|
|
773
|
-
key
|
|
842
|
+
const keyLen = keyBits / 8;
|
|
843
|
+
let key = digest.slice(0, keyLen);
|
|
774
844
|
let cipher = paddedUserPassword;
|
|
775
845
|
round = r >= 3 ? 20 : 1;
|
|
776
846
|
for (let i = 0; i < round; i++) {
|
|
777
|
-
const
|
|
778
|
-
for (let j = 0; j <
|
|
779
|
-
|
|
847
|
+
const xorKey = new Uint8Array(keyLen);
|
|
848
|
+
for (let j = 0; j < keyLen; j++) {
|
|
849
|
+
xorKey[j] = key[j] ^ i;
|
|
780
850
|
}
|
|
781
|
-
cipher =
|
|
851
|
+
cipher = rc4(cipher, xorKey);
|
|
782
852
|
}
|
|
783
853
|
return cipher;
|
|
784
854
|
}
|
|
785
855
|
function getEncryptionKeyR2R3R4(r, keyBits, documentId, paddedUserPassword, ownerPasswordEntry, permissions) {
|
|
786
|
-
|
|
856
|
+
const permBytes = new Uint8Array([permissions & 0xff, permissions >> 8 & 0xff, permissions >> 16 & 0xff, permissions >> 24 & 0xff]);
|
|
857
|
+
let key = utils.concatBytes(paddedUserPassword, ownerPasswordEntry, permBytes, new Uint8Array(documentId));
|
|
787
858
|
const round = r >= 3 ? 51 : 1;
|
|
859
|
+
const keyLen = keyBits / 8;
|
|
788
860
|
for (let i = 0; i < round; i++) {
|
|
789
|
-
key =
|
|
790
|
-
key
|
|
861
|
+
key = md5Hash(key);
|
|
862
|
+
key = key.slice(0, keyLen);
|
|
791
863
|
}
|
|
792
864
|
return key;
|
|
793
865
|
}
|
|
794
866
|
function getUserPasswordR5(processedUserPassword, generateRandomWordArray) {
|
|
795
867
|
const validationSalt = generateRandomWordArray(8);
|
|
796
868
|
const keySalt = generateRandomWordArray(8);
|
|
797
|
-
|
|
869
|
+
const hash = sha256Hash(utils.concatBytes(processedUserPassword, validationSalt));
|
|
870
|
+
return utils.concatBytes(hash, validationSalt, keySalt);
|
|
798
871
|
}
|
|
799
872
|
function getUserEncryptionKeyR5(processedUserPassword, userKeySalt, encryptionKey) {
|
|
800
|
-
const key =
|
|
801
|
-
const
|
|
802
|
-
|
|
803
|
-
padding: CryptoJS.pad.NoPadding,
|
|
804
|
-
iv: CryptoJS.lib.WordArray.create(null, 16)
|
|
805
|
-
};
|
|
806
|
-
return CryptoJS.AES.encrypt(encryptionKey, key, options).ciphertext;
|
|
873
|
+
const key = sha256Hash(utils.concatBytes(processedUserPassword, userKeySalt));
|
|
874
|
+
const iv = new Uint8Array(16);
|
|
875
|
+
return aesCbcEncrypt(encryptionKey, key, iv, false);
|
|
807
876
|
}
|
|
808
877
|
function getOwnerPasswordR5(processedOwnerPassword, userPasswordEntry, generateRandomWordArray) {
|
|
809
878
|
const validationSalt = generateRandomWordArray(8);
|
|
810
879
|
const keySalt = generateRandomWordArray(8);
|
|
811
|
-
|
|
880
|
+
const hash = sha256Hash(utils.concatBytes(processedOwnerPassword, validationSalt, userPasswordEntry));
|
|
881
|
+
return utils.concatBytes(hash, validationSalt, keySalt);
|
|
812
882
|
}
|
|
813
883
|
function getOwnerEncryptionKeyR5(processedOwnerPassword, ownerKeySalt, userPasswordEntry, encryptionKey) {
|
|
814
|
-
const key =
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
padding: CryptoJS.pad.NoPadding,
|
|
818
|
-
iv: CryptoJS.lib.WordArray.create(null, 16)
|
|
819
|
-
};
|
|
820
|
-
return CryptoJS.AES.encrypt(encryptionKey, key, options).ciphertext;
|
|
884
|
+
const key = sha256Hash(utils.concatBytes(processedOwnerPassword, ownerKeySalt, userPasswordEntry));
|
|
885
|
+
const iv = new Uint8Array(16);
|
|
886
|
+
return aesCbcEncrypt(encryptionKey, key, iv, false);
|
|
821
887
|
}
|
|
822
888
|
function getEncryptionKeyR5(generateRandomWordArray) {
|
|
823
889
|
return generateRandomWordArray(32);
|
|
824
890
|
}
|
|
825
891
|
function getEncryptedPermissionsR5(permissions, encryptionKey, generateRandomWordArray) {
|
|
826
|
-
const
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
892
|
+
const data = new Uint8Array(16);
|
|
893
|
+
data[0] = permissions & 0xff;
|
|
894
|
+
data[1] = permissions >> 8 & 0xff;
|
|
895
|
+
data[2] = permissions >> 16 & 0xff;
|
|
896
|
+
data[3] = permissions >> 24 & 0xff;
|
|
897
|
+
data[4] = 0xff;
|
|
898
|
+
data[5] = 0xff;
|
|
899
|
+
data[6] = 0xff;
|
|
900
|
+
data[7] = 0xff;
|
|
901
|
+
data[8] = 0x54;
|
|
902
|
+
data[9] = 0x61;
|
|
903
|
+
data[10] = 0x64;
|
|
904
|
+
data[11] = 0x62;
|
|
905
|
+
const randomPart = generateRandomWordArray(4);
|
|
906
|
+
data.set(randomPart, 12);
|
|
907
|
+
return aesEcbEncrypt(data, encryptionKey);
|
|
832
908
|
}
|
|
833
909
|
function processPasswordR2R3R4(password = '') {
|
|
834
|
-
const out =
|
|
910
|
+
const out = new Uint8Array(32);
|
|
835
911
|
const length = password.length;
|
|
836
912
|
let index = 0;
|
|
837
913
|
while (index < length && index < 32) {
|
|
@@ -846,33 +922,23 @@ function processPasswordR2R3R4(password = '') {
|
|
|
846
922
|
out[index] = PASSWORD_PADDING[index - length];
|
|
847
923
|
index++;
|
|
848
924
|
}
|
|
849
|
-
return
|
|
925
|
+
return out;
|
|
850
926
|
}
|
|
851
927
|
function processPasswordR5(password = '') {
|
|
852
928
|
password = unescape(encodeURIComponent(saslprep(password)));
|
|
853
929
|
const length = Math.min(127, password.length);
|
|
854
|
-
const out =
|
|
930
|
+
const out = new Uint8Array(length);
|
|
855
931
|
for (let i = 0; i < length; i++) {
|
|
856
932
|
out[i] = password.charCodeAt(i);
|
|
857
933
|
}
|
|
858
|
-
return
|
|
859
|
-
}
|
|
860
|
-
function lsbFirstWord(data) {
|
|
861
|
-
return (data & 0xff) << 24 | (data & 0xff00) << 8 | data >> 8 & 0xff00 | data >> 24 & 0xff;
|
|
862
|
-
}
|
|
863
|
-
function wordArrayToBuffer(wordArray) {
|
|
864
|
-
const byteArray = [];
|
|
865
|
-
for (let i = 0; i < wordArray.sigBytes; i++) {
|
|
866
|
-
byteArray.push(wordArray.words[Math.floor(i / 4)] >> 8 * (3 - i % 4) & 0xff);
|
|
867
|
-
}
|
|
868
|
-
return Buffer.from(byteArray);
|
|
934
|
+
return out;
|
|
869
935
|
}
|
|
870
936
|
const PASSWORD_PADDING = [0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a];
|
|
871
937
|
|
|
872
938
|
const {
|
|
873
939
|
number: number$2
|
|
874
940
|
} = PDFObject;
|
|
875
|
-
|
|
941
|
+
let PDFGradient$1 = class PDFGradient {
|
|
876
942
|
constructor(doc) {
|
|
877
943
|
this.doc = doc;
|
|
878
944
|
this.stops = [];
|
|
@@ -1030,8 +1096,8 @@ class PDFGradient$1 {
|
|
|
1030
1096
|
const op = stroke ? 'SCN' : 'scn';
|
|
1031
1097
|
return this.doc.addContent(`/${this.id} ${op}`);
|
|
1032
1098
|
}
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1099
|
+
};
|
|
1100
|
+
let PDFLinearGradient$1 = class PDFLinearGradient extends PDFGradient$1 {
|
|
1035
1101
|
constructor(doc, x1, y1, x2, y2) {
|
|
1036
1102
|
super(doc);
|
|
1037
1103
|
this.x1 = x1;
|
|
@@ -1049,10 +1115,10 @@ class PDFLinearGradient$1 extends PDFGradient$1 {
|
|
|
1049
1115
|
});
|
|
1050
1116
|
}
|
|
1051
1117
|
opacityGradient() {
|
|
1052
|
-
return new PDFLinearGradient
|
|
1118
|
+
return new PDFLinearGradient(this.doc, this.x1, this.y1, this.x2, this.y2);
|
|
1053
1119
|
}
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1120
|
+
};
|
|
1121
|
+
let PDFRadialGradient$1 = class PDFRadialGradient extends PDFGradient$1 {
|
|
1056
1122
|
constructor(doc, x1, y1, r1, x2, y2, r2) {
|
|
1057
1123
|
super(doc);
|
|
1058
1124
|
this.doc = doc;
|
|
@@ -1073,9 +1139,9 @@ class PDFRadialGradient$1 extends PDFGradient$1 {
|
|
|
1073
1139
|
});
|
|
1074
1140
|
}
|
|
1075
1141
|
opacityGradient() {
|
|
1076
|
-
return new PDFRadialGradient
|
|
1142
|
+
return new PDFRadialGradient(this.doc, this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);
|
|
1077
1143
|
}
|
|
1078
|
-
}
|
|
1144
|
+
};
|
|
1079
1145
|
var Gradient = {
|
|
1080
1146
|
PDFGradient: PDFGradient$1,
|
|
1081
1147
|
PDFLinearGradient: PDFLinearGradient$1,
|
|
@@ -1083,7 +1149,7 @@ var Gradient = {
|
|
|
1083
1149
|
};
|
|
1084
1150
|
|
|
1085
1151
|
const underlyingColorSpaces = ['DeviceCMYK', 'DeviceRGB'];
|
|
1086
|
-
|
|
1152
|
+
let PDFTilingPattern$1 = class PDFTilingPattern {
|
|
1087
1153
|
constructor(doc, bBox, xStep, yStep, stream) {
|
|
1088
1154
|
this.doc = doc;
|
|
1089
1155
|
this.bBox = bBox;
|
|
@@ -1143,7 +1209,7 @@ class PDFTilingPattern$1 {
|
|
|
1143
1209
|
const op = stroke ? 'SCN' : 'scn';
|
|
1144
1210
|
return this.doc.addContent(`${normalizedColor.join(' ')} /${this.id} ${op}`);
|
|
1145
1211
|
}
|
|
1146
|
-
}
|
|
1212
|
+
};
|
|
1147
1213
|
var pattern = {
|
|
1148
1214
|
PDFTilingPattern: PDFTilingPattern$1
|
|
1149
1215
|
};
|
|
@@ -1473,86 +1539,176 @@ const parameters = {
|
|
|
1473
1539
|
Z: 0,
|
|
1474
1540
|
z: 0
|
|
1475
1541
|
};
|
|
1542
|
+
const isCommand = function (c) {
|
|
1543
|
+
return c in parameters;
|
|
1544
|
+
};
|
|
1545
|
+
const isWsp = function (c) {
|
|
1546
|
+
const codePoint = c.codePointAt(0);
|
|
1547
|
+
return codePoint === 0x20 || codePoint === 0x9 || codePoint === 0xd || codePoint === 0xa;
|
|
1548
|
+
};
|
|
1549
|
+
const isDigit = function (c) {
|
|
1550
|
+
const codePoint = c.codePointAt(0);
|
|
1551
|
+
if (codePoint == null) {
|
|
1552
|
+
return false;
|
|
1553
|
+
}
|
|
1554
|
+
return 48 <= codePoint && codePoint <= 57;
|
|
1555
|
+
};
|
|
1556
|
+
const readNumber = function (string, cursor) {
|
|
1557
|
+
let i = cursor;
|
|
1558
|
+
let value = '';
|
|
1559
|
+
let state = 'none';
|
|
1560
|
+
for (; i < string.length; i += 1) {
|
|
1561
|
+
const c = string[i];
|
|
1562
|
+
if (c === '+' || c === '-') {
|
|
1563
|
+
if (state === 'none') {
|
|
1564
|
+
state = 'sign';
|
|
1565
|
+
value += c;
|
|
1566
|
+
continue;
|
|
1567
|
+
}
|
|
1568
|
+
if (state === 'e') {
|
|
1569
|
+
state = 'exponent_sign';
|
|
1570
|
+
value += c;
|
|
1571
|
+
continue;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
if (isDigit(c)) {
|
|
1575
|
+
if (state === 'none' || state === 'sign' || state === 'whole') {
|
|
1576
|
+
state = 'whole';
|
|
1577
|
+
value += c;
|
|
1578
|
+
continue;
|
|
1579
|
+
}
|
|
1580
|
+
if (state === 'decimal_point' || state === 'decimal') {
|
|
1581
|
+
state = 'decimal';
|
|
1582
|
+
value += c;
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
if (state === 'e' || state === 'exponent_sign' || state === 'exponent') {
|
|
1586
|
+
state = 'exponent';
|
|
1587
|
+
value += c;
|
|
1588
|
+
continue;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
if (c === '.') {
|
|
1592
|
+
if (state === 'none' || state === 'sign' || state === 'whole') {
|
|
1593
|
+
state = 'decimal_point';
|
|
1594
|
+
value += c;
|
|
1595
|
+
continue;
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
if (c === 'E' || c === 'e') {
|
|
1599
|
+
if (state === 'whole' || state === 'decimal_point' || state === 'decimal') {
|
|
1600
|
+
state = 'e';
|
|
1601
|
+
value += c;
|
|
1602
|
+
continue;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
break;
|
|
1606
|
+
}
|
|
1607
|
+
const number = Number.parseFloat(value);
|
|
1608
|
+
if (Number.isNaN(number)) {
|
|
1609
|
+
return [cursor, null];
|
|
1610
|
+
}
|
|
1611
|
+
return [i - 1, number];
|
|
1612
|
+
};
|
|
1476
1613
|
const parse = function (path) {
|
|
1477
|
-
|
|
1478
|
-
|
|
1614
|
+
const pathData = [];
|
|
1615
|
+
let command = null;
|
|
1479
1616
|
let args = [];
|
|
1480
|
-
let
|
|
1481
|
-
let
|
|
1482
|
-
let
|
|
1483
|
-
for (let
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1617
|
+
let argsCount = 0;
|
|
1618
|
+
let canHaveComma = false;
|
|
1619
|
+
let hadComma = false;
|
|
1620
|
+
for (let i = 0; i < path.length; i += 1) {
|
|
1621
|
+
const c = path.charAt(i);
|
|
1622
|
+
if (isWsp(c)) {
|
|
1623
|
+
continue;
|
|
1624
|
+
}
|
|
1625
|
+
if (canHaveComma && c === ',') {
|
|
1626
|
+
if (hadComma) {
|
|
1627
|
+
break;
|
|
1628
|
+
}
|
|
1629
|
+
hadComma = true;
|
|
1630
|
+
continue;
|
|
1631
|
+
}
|
|
1632
|
+
if (isCommand(c)) {
|
|
1633
|
+
if (hadComma) {
|
|
1634
|
+
return pathData;
|
|
1635
|
+
}
|
|
1636
|
+
if (command == null) {
|
|
1637
|
+
if (c !== 'M' && c !== 'm') {
|
|
1638
|
+
return pathData;
|
|
1639
|
+
}
|
|
1640
|
+
} else {
|
|
1641
|
+
if (args.length !== 0) {
|
|
1642
|
+
return pathData;
|
|
1489
1643
|
}
|
|
1490
|
-
ret[ret.length] = {
|
|
1491
|
-
cmd,
|
|
1492
|
-
args
|
|
1493
|
-
};
|
|
1494
|
-
args = [];
|
|
1495
|
-
curArg = '';
|
|
1496
|
-
foundDecimal = false;
|
|
1497
|
-
}
|
|
1498
|
-
cmd = c;
|
|
1499
|
-
} else if ([' ', ','].includes(c) || c === '-' && curArg.length > 0 && curArg[curArg.length - 1] !== 'e' || c === '.' && foundDecimal) {
|
|
1500
|
-
if (curArg.length === 0) {
|
|
1501
|
-
continue;
|
|
1502
1644
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1645
|
+
command = c;
|
|
1646
|
+
args = [];
|
|
1647
|
+
argsCount = parameters[command];
|
|
1648
|
+
canHaveComma = false;
|
|
1649
|
+
if (argsCount === 0) {
|
|
1650
|
+
pathData.push({
|
|
1651
|
+
command,
|
|
1506
1652
|
args
|
|
1507
|
-
};
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
continue;
|
|
1656
|
+
}
|
|
1657
|
+
if (command == null) {
|
|
1658
|
+
return pathData;
|
|
1659
|
+
}
|
|
1660
|
+
let newCursor = i;
|
|
1661
|
+
let number = null;
|
|
1662
|
+
if (command === 'A' || command === 'a') {
|
|
1663
|
+
const position = args.length;
|
|
1664
|
+
if (position === 0 || position === 1) {
|
|
1665
|
+
if (c !== '+' && c !== '-') {
|
|
1666
|
+
[newCursor, number] = readNumber(path, i);
|
|
1511
1667
|
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1668
|
+
}
|
|
1669
|
+
if (position === 2 || position === 5 || position === 6) {
|
|
1670
|
+
[newCursor, number] = readNumber(path, i);
|
|
1671
|
+
}
|
|
1672
|
+
if (position === 3 || position === 4) {
|
|
1673
|
+
if (c === '0') {
|
|
1674
|
+
number = 0;
|
|
1675
|
+
}
|
|
1676
|
+
if (c === '1') {
|
|
1677
|
+
number = 1;
|
|
1514
1678
|
}
|
|
1515
|
-
} else {
|
|
1516
|
-
args[args.length] = +curArg;
|
|
1517
1679
|
}
|
|
1518
|
-
foundDecimal = c === '.';
|
|
1519
|
-
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1520
1680
|
} else {
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1681
|
+
[newCursor, number] = readNumber(path, i);
|
|
1682
|
+
}
|
|
1683
|
+
if (number == null) {
|
|
1684
|
+
return pathData;
|
|
1685
|
+
}
|
|
1686
|
+
args.push(number);
|
|
1687
|
+
canHaveComma = true;
|
|
1688
|
+
hadComma = false;
|
|
1689
|
+
i = newCursor;
|
|
1690
|
+
if (args.length === argsCount) {
|
|
1691
|
+
pathData.push({
|
|
1692
|
+
command,
|
|
1531
1693
|
args
|
|
1532
|
-
};
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
cmd = 'L';
|
|
1694
|
+
});
|
|
1695
|
+
if (command === 'M') {
|
|
1696
|
+
command = 'L';
|
|
1536
1697
|
}
|
|
1537
|
-
if (
|
|
1538
|
-
|
|
1698
|
+
if (command === 'm') {
|
|
1699
|
+
command = 'l';
|
|
1539
1700
|
}
|
|
1540
|
-
|
|
1541
|
-
args[args.length] = +curArg;
|
|
1701
|
+
args = [];
|
|
1542
1702
|
}
|
|
1543
1703
|
}
|
|
1544
|
-
|
|
1545
|
-
cmd,
|
|
1546
|
-
args
|
|
1547
|
-
};
|
|
1548
|
-
return ret;
|
|
1704
|
+
return pathData;
|
|
1549
1705
|
};
|
|
1550
1706
|
const apply = function (commands, doc) {
|
|
1551
1707
|
cx = cy = px = py = sx = sy = 0;
|
|
1552
1708
|
for (let i = 0; i < commands.length; i++) {
|
|
1553
1709
|
const c = commands[i];
|
|
1554
|
-
if (typeof runners[c.
|
|
1555
|
-
runners[c.
|
|
1710
|
+
if (typeof runners[c.command] === 'function') {
|
|
1711
|
+
runners[c.command](doc, c.args);
|
|
1556
1712
|
}
|
|
1557
1713
|
}
|
|
1558
1714
|
};
|
|
@@ -1862,21 +2018,42 @@ var VectorMixin = {
|
|
|
1862
2018
|
rect(x, y, w, h) {
|
|
1863
2019
|
return this.addContent(`${number$1(x)} ${number$1(y)} ${number$1(w)} ${number$1(h)} re`);
|
|
1864
2020
|
},
|
|
1865
|
-
roundedRect(x, y, w, h,
|
|
1866
|
-
if (
|
|
1867
|
-
|
|
1868
|
-
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
2021
|
+
roundedRect(x, y, w, h, borderRadius) {
|
|
2022
|
+
if (borderRadius == null) {
|
|
2023
|
+
borderRadius = 0;
|
|
2024
|
+
}
|
|
2025
|
+
let radii;
|
|
2026
|
+
if (Array.isArray(borderRadius)) {
|
|
2027
|
+
radii = borderRadius.slice(0, 4);
|
|
2028
|
+
} else {
|
|
2029
|
+
radii = [borderRadius, borderRadius, borderRadius, borderRadius];
|
|
2030
|
+
}
|
|
2031
|
+
const limit = Math.min(0.5 * w, 0.5 * h);
|
|
2032
|
+
const rTL = Math.max(0, Math.min(radii[0] || 0, limit));
|
|
2033
|
+
const rTR = Math.max(0, Math.min(radii[1] || 0, limit));
|
|
2034
|
+
const rBR = Math.max(0, Math.min(radii[2] || 0, limit));
|
|
2035
|
+
const rBL = Math.max(0, Math.min(radii[3] || 0, limit));
|
|
2036
|
+
const cpTR = rTR * (1.0 - KAPPA);
|
|
2037
|
+
const cpBR = rBR * (1.0 - KAPPA);
|
|
2038
|
+
const cpBL = rBL * (1.0 - KAPPA);
|
|
2039
|
+
const cpTL = rTL * (1.0 - KAPPA);
|
|
2040
|
+
this.moveTo(x + rTL, y);
|
|
2041
|
+
this.lineTo(x + w - rTR, y);
|
|
2042
|
+
if (rTR > 0) {
|
|
2043
|
+
this.bezierCurveTo(x + w - cpTR, y, x + w, y + cpTR, x + w, y + rTR);
|
|
2044
|
+
}
|
|
2045
|
+
this.lineTo(x + w, y + h - rBR);
|
|
2046
|
+
if (rBR > 0) {
|
|
2047
|
+
this.bezierCurveTo(x + w, y + h - cpBR, x + w - cpBR, y + h, x + w - rBR, y + h);
|
|
2048
|
+
}
|
|
2049
|
+
this.lineTo(x + rBL, y + h);
|
|
2050
|
+
if (rBL > 0) {
|
|
2051
|
+
this.bezierCurveTo(x + cpBL, y + h, x, y + h - cpBL, x, y + h - rBL);
|
|
2052
|
+
}
|
|
2053
|
+
this.lineTo(x, y + rTL);
|
|
2054
|
+
if (rTL > 0) {
|
|
2055
|
+
this.bezierCurveTo(x, y + cpTL, x + cpTL, y, x + rTL, y);
|
|
2056
|
+
}
|
|
1880
2057
|
return this.closePath();
|
|
1881
2058
|
},
|
|
1882
2059
|
ellipse(x, y, r1, r2) {
|
|
@@ -2168,7 +2345,7 @@ class AFMFont {
|
|
|
2168
2345
|
if (match = line.match(/^Start(\w+)/)) {
|
|
2169
2346
|
section = match[1];
|
|
2170
2347
|
continue;
|
|
2171
|
-
} else if (
|
|
2348
|
+
} else if (line.match(/^End(\w+)/)) {
|
|
2172
2349
|
section = '';
|
|
2173
2350
|
continue;
|
|
2174
2351
|
}
|
|
@@ -2512,9 +2689,15 @@ class EmbeddedFont extends PDFFont {
|
|
|
2512
2689
|
descriptor.data.FontFile2 = fontFile;
|
|
2513
2690
|
}
|
|
2514
2691
|
if (this.document.subset && this.document.subset === 1) {
|
|
2515
|
-
const
|
|
2692
|
+
const maxCID = this.widths.length - 1;
|
|
2693
|
+
const cidSetBuffer = Buffer.alloc(Math.ceil((maxCID + 1) / 8), 0);
|
|
2694
|
+
for (let cid = 0; cid <= maxCID; cid++) {
|
|
2695
|
+
if (this.widths[cid] != null) {
|
|
2696
|
+
cidSetBuffer[Math.floor(cid / 8)] |= 0x80 >> cid % 8;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2516
2699
|
const CIDSetRef = this.document.ref();
|
|
2517
|
-
CIDSetRef.write(
|
|
2700
|
+
CIDSetRef.write(cidSetBuffer);
|
|
2518
2701
|
CIDSetRef.end();
|
|
2519
2702
|
descriptor.data.CIDSet = CIDSetRef;
|
|
2520
2703
|
}
|
|
@@ -2584,7 +2767,7 @@ begincmap
|
|
|
2584
2767
|
1 begincodespacerange
|
|
2585
2768
|
<0000><ffff>
|
|
2586
2769
|
endcodespacerange
|
|
2587
|
-
|
|
2770
|
+
${ranges.length} beginbfrange
|
|
2588
2771
|
${ranges.join('\n')}
|
|
2589
2772
|
endbfrange
|
|
2590
2773
|
endcmap
|
|
@@ -2676,9 +2859,12 @@ var FontsMixin = {
|
|
|
2676
2859
|
if (cacheKey) {
|
|
2677
2860
|
this._fontFamilies[cacheKey] = this._font;
|
|
2678
2861
|
}
|
|
2679
|
-
if (this._font.name) {
|
|
2862
|
+
if (this._font.name && !this._fontFamilies[this._font.name]) {
|
|
2680
2863
|
this._fontFamilies[this._font.name] = this._font;
|
|
2681
2864
|
}
|
|
2865
|
+
if (!cacheKey && (!this._font.name || this._fontFamilies[this._font.name] !== this._font)) {
|
|
2866
|
+
this._fontFamilies[this._font.id] = this._font;
|
|
2867
|
+
}
|
|
2682
2868
|
return this;
|
|
2683
2869
|
},
|
|
2684
2870
|
fontSize(_fontSize) {
|
|
@@ -2757,12 +2943,13 @@ var FontsMixin = {
|
|
|
2757
2943
|
|
|
2758
2944
|
const SOFT_HYPHEN = '\u00AD';
|
|
2759
2945
|
const HYPHEN = '-';
|
|
2760
|
-
class LineWrapper
|
|
2946
|
+
class LineWrapper {
|
|
2761
2947
|
constructor(document, options) {
|
|
2762
|
-
|
|
2948
|
+
this._listeners = Object.create(null);
|
|
2763
2949
|
this.document = document;
|
|
2764
2950
|
this.horizontalScaling = options.horizontalScaling || 100;
|
|
2765
2951
|
this.indent = (options.indent || 0) * this.horizontalScaling / 100;
|
|
2952
|
+
this.indentAllLines = options.indentAllLines || false;
|
|
2766
2953
|
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
2767
2954
|
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
2768
2955
|
this.columns = options.columns || 1;
|
|
@@ -2814,6 +3001,22 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2814
3001
|
});
|
|
2815
3002
|
});
|
|
2816
3003
|
}
|
|
3004
|
+
on(event, listener) {
|
|
3005
|
+
(this._listeners[event] || (this._listeners[event] = [])).push(listener);
|
|
3006
|
+
}
|
|
3007
|
+
once(event, listener) {
|
|
3008
|
+
const wrapper = (...args) => {
|
|
3009
|
+
const listeners = this._listeners[event];
|
|
3010
|
+
listeners.splice(listeners.indexOf(wrapper), 1);
|
|
3011
|
+
listener(...args);
|
|
3012
|
+
};
|
|
3013
|
+
this.on(event, wrapper);
|
|
3014
|
+
}
|
|
3015
|
+
emit(event, ...args) {
|
|
3016
|
+
const listeners = this._listeners[event];
|
|
3017
|
+
if (!listeners) return;
|
|
3018
|
+
for (const listener of listeners.slice()) listener(...args);
|
|
3019
|
+
}
|
|
2817
3020
|
wordWidth(word) {
|
|
2818
3021
|
return PDFNumber(this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing);
|
|
2819
3022
|
}
|
|
@@ -2879,6 +3082,9 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2879
3082
|
}
|
|
2880
3083
|
}
|
|
2881
3084
|
wrap(text, options) {
|
|
3085
|
+
const {
|
|
3086
|
+
document
|
|
3087
|
+
} = this;
|
|
2882
3088
|
this.horizontalScaling = options.horizontalScaling || 100;
|
|
2883
3089
|
if (options.indent != null) {
|
|
2884
3090
|
this.indent = options.indent * this.horizontalScaling / 100;
|
|
@@ -2892,24 +3098,20 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2892
3098
|
if (options.ellipsis != null) {
|
|
2893
3099
|
this.ellipsis = options.ellipsis;
|
|
2894
3100
|
}
|
|
2895
|
-
const nextY =
|
|
2896
|
-
if (
|
|
3101
|
+
const nextY = document.y + document.currentLineHeight(true);
|
|
3102
|
+
if (document.y > this.maxY || nextY > this.maxY) {
|
|
2897
3103
|
this.nextSection();
|
|
2898
3104
|
}
|
|
2899
3105
|
let buffer = '';
|
|
2900
3106
|
let textWidth = 0;
|
|
2901
3107
|
let wc = 0;
|
|
2902
3108
|
let lc = 0;
|
|
2903
|
-
let
|
|
2904
|
-
y
|
|
2905
|
-
} = this.document;
|
|
3109
|
+
let continueY = document.y;
|
|
2906
3110
|
const emitLine = () => {
|
|
2907
3111
|
options.textWidth = textWidth + this.wordSpacing * (wc - 1);
|
|
2908
3112
|
options.wordCount = wc;
|
|
2909
3113
|
options.lineWidth = this.lineWidth;
|
|
2910
|
-
|
|
2911
|
-
y
|
|
2912
|
-
} = this.document);
|
|
3114
|
+
continueY = document.y;
|
|
2913
3115
|
this.emit('line', buffer, options, this);
|
|
2914
3116
|
return lc++;
|
|
2915
3117
|
};
|
|
@@ -2925,8 +3127,8 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2925
3127
|
wc++;
|
|
2926
3128
|
}
|
|
2927
3129
|
if (bk.required || !this.canFit(word, w)) {
|
|
2928
|
-
const lh =
|
|
2929
|
-
if (this.height != null && this.ellipsis && PDFNumber(
|
|
3130
|
+
const lh = document.currentLineHeight(true);
|
|
3131
|
+
if (this.height != null && this.ellipsis && PDFNumber(document.y + lh * 2) > this.maxY && this.column >= this.columns) {
|
|
2930
3132
|
if (this.ellipsis === true) {
|
|
2931
3133
|
this.ellipsis = '…';
|
|
2932
3134
|
}
|
|
@@ -2955,7 +3157,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2955
3157
|
this.spaceLeft -= this.wordWidth(HYPHEN);
|
|
2956
3158
|
}
|
|
2957
3159
|
emitLine();
|
|
2958
|
-
if (PDFNumber(
|
|
3160
|
+
if (PDFNumber(document.y + lh) > this.maxY) {
|
|
2959
3161
|
this.emit('sectionEnd', options, this);
|
|
2960
3162
|
const shouldContinue = this.nextSection();
|
|
2961
3163
|
if (!shouldContinue) {
|
|
@@ -2990,9 +3192,9 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2990
3192
|
this.continuedX = 0;
|
|
2991
3193
|
}
|
|
2992
3194
|
this.continuedX += options.textWidth || 0;
|
|
2993
|
-
|
|
3195
|
+
document.y = continueY;
|
|
2994
3196
|
} else {
|
|
2995
|
-
|
|
3197
|
+
document.x = this.startX;
|
|
2996
3198
|
}
|
|
2997
3199
|
}
|
|
2998
3200
|
nextSection(options) {
|
|
@@ -3004,7 +3206,13 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3004
3206
|
this.column = 1;
|
|
3005
3207
|
this.startY = this.document.page.margins.top;
|
|
3006
3208
|
this.maxY = this.document.page.maxY();
|
|
3007
|
-
this.
|
|
3209
|
+
if (this.indentAllLines) {
|
|
3210
|
+
const indent = this.continuedX || this.indent;
|
|
3211
|
+
this.document.x += indent;
|
|
3212
|
+
this.lineWidth -= indent;
|
|
3213
|
+
} else {
|
|
3214
|
+
this.document.x = this.startX;
|
|
3215
|
+
}
|
|
3008
3216
|
if (this.document._fillColor) {
|
|
3009
3217
|
this.document.fillColor(...this.document._fillColor);
|
|
3010
3218
|
}
|
|
@@ -3301,7 +3509,7 @@ var TextMixin = {
|
|
|
3301
3509
|
return this;
|
|
3302
3510
|
},
|
|
3303
3511
|
_initOptions(x = {}, y, options = {}) {
|
|
3304
|
-
if (typeof x === 'object') {
|
|
3512
|
+
if (x && typeof x === 'object') {
|
|
3305
3513
|
options = x;
|
|
3306
3514
|
x = null;
|
|
3307
3515
|
}
|
|
@@ -3334,7 +3542,7 @@ var TextMixin = {
|
|
|
3334
3542
|
if (result.columnGap == null) {
|
|
3335
3543
|
result.columnGap = 18;
|
|
3336
3544
|
}
|
|
3337
|
-
result.rotation = Number(
|
|
3545
|
+
result.rotation = Number(result.rotation ?? 0) % 360;
|
|
3338
3546
|
if (result.rotation < 0) result.rotation += 360;
|
|
3339
3547
|
return result;
|
|
3340
3548
|
},
|
|
@@ -3408,7 +3616,11 @@ var TextMixin = {
|
|
|
3408
3616
|
}
|
|
3409
3617
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3410
3618
|
if (options.link != null) {
|
|
3411
|
-
|
|
3619
|
+
const linkOptions = {};
|
|
3620
|
+
if (this._currentStructureElement && this._currentStructureElement.dictionary.data.S === 'Link') {
|
|
3621
|
+
linkOptions.structParent = this._currentStructureElement;
|
|
3622
|
+
}
|
|
3623
|
+
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link, linkOptions);
|
|
3412
3624
|
}
|
|
3413
3625
|
if (options.goTo != null) {
|
|
3414
3626
|
this.goTo(x, y, renderedWidth, this.currentLineHeight(), options.goTo);
|
|
@@ -3537,6 +3749,61 @@ var TextMixin = {
|
|
|
3537
3749
|
}
|
|
3538
3750
|
};
|
|
3539
3751
|
|
|
3752
|
+
const toBinaryString = bytes => {
|
|
3753
|
+
const chunkSize = 0x8000;
|
|
3754
|
+
let out = '';
|
|
3755
|
+
for (let i = 0; i < bytes.length; i += chunkSize) {
|
|
3756
|
+
const end = Math.min(i + chunkSize, bytes.length);
|
|
3757
|
+
out += String.fromCharCode.apply(null, bytes.subarray(i, end));
|
|
3758
|
+
}
|
|
3759
|
+
return out;
|
|
3760
|
+
};
|
|
3761
|
+
const readUInt16BE = (bytes, offset = 0) => (bytes[offset] << 8 | bytes[offset + 1]) >>> 0;
|
|
3762
|
+
const readUInt16LE = (bytes, offset = 0) => (bytes[offset + 1] << 8 | bytes[offset]) >>> 0;
|
|
3763
|
+
const readUInt32BE = (bytes, offset = 0) => bytes[offset] * 0x1000000 + (bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
3764
|
+
const readUInt32LE = (bytes, offset = 0) => (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16) + bytes[offset + 3] * 0x1000000 >>> 0;
|
|
3765
|
+
|
|
3766
|
+
const parseExifOrientation = data => {
|
|
3767
|
+
if (!data || data.length < 20) return null;
|
|
3768
|
+
let pos = 2;
|
|
3769
|
+
while (pos < data.length - 4) {
|
|
3770
|
+
while (pos < data.length && data[pos] !== 0xff) pos++;
|
|
3771
|
+
if (pos >= data.length - 4) return null;
|
|
3772
|
+
const marker = readUInt16BE(data, pos);
|
|
3773
|
+
pos += 2;
|
|
3774
|
+
if (marker === 0xffda) return null;
|
|
3775
|
+
if (marker >= 0xffd0 && marker <= 0xffd9 || marker === 0xff01) continue;
|
|
3776
|
+
if (pos + 2 > data.length) return null;
|
|
3777
|
+
const segmentLength = readUInt16BE(data, pos);
|
|
3778
|
+
if (marker === 0xffe1 && pos + 8 <= data.length) {
|
|
3779
|
+
const exifHeader = toBinaryString(data.subarray(pos + 2, pos + 8));
|
|
3780
|
+
if (exifHeader === 'Exif\x00\x00') {
|
|
3781
|
+
const tiffStart = pos + 8;
|
|
3782
|
+
if (tiffStart + 8 > data.length) return null;
|
|
3783
|
+
const byteOrder = toBinaryString(data.subarray(tiffStart, tiffStart + 2));
|
|
3784
|
+
const isLittleEndian = byteOrder === 'II';
|
|
3785
|
+
if (!isLittleEndian && byteOrder !== 'MM') return null;
|
|
3786
|
+
const read16 = isLittleEndian ? o => readUInt16LE(data, o) : o => readUInt16BE(data, o);
|
|
3787
|
+
const read32 = isLittleEndian ? o => readUInt32LE(data, o) : o => readUInt32BE(data, o);
|
|
3788
|
+
if (read16(tiffStart + 2) !== 42) return null;
|
|
3789
|
+
const ifdPos = tiffStart + read32(tiffStart + 4);
|
|
3790
|
+
if (ifdPos + 2 > data.length) return null;
|
|
3791
|
+
const entryCount = read16(ifdPos);
|
|
3792
|
+
for (let i = 0; i < entryCount; i++) {
|
|
3793
|
+
const entryPos = ifdPos + 2 + i * 12;
|
|
3794
|
+
if (entryPos + 12 > data.length) return null;
|
|
3795
|
+
if (read16(entryPos) === 0x0112) {
|
|
3796
|
+
const value = read16(entryPos + 8);
|
|
3797
|
+
return value >= 1 && value <= 8 ? value : null;
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
return null;
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
pos += segmentLength;
|
|
3804
|
+
}
|
|
3805
|
+
return null;
|
|
3806
|
+
};
|
|
3540
3807
|
const MARKERS = [0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf];
|
|
3541
3808
|
const COLOR_SPACE_MAP = {
|
|
3542
3809
|
1: 'DeviceGray',
|
|
@@ -3551,9 +3818,11 @@ class JPEG {
|
|
|
3551
3818
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3552
3819
|
throw 'SOI not found in JPEG';
|
|
3553
3820
|
}
|
|
3554
|
-
this.orientation =
|
|
3821
|
+
this.orientation = parseExifOrientation(this.data) || 1;
|
|
3555
3822
|
let pos = 2;
|
|
3556
3823
|
while (pos < this.data.length) {
|
|
3824
|
+
while (pos < this.data.length && this.data[pos] !== 0xff) pos++;
|
|
3825
|
+
if (pos >= this.data.length) break;
|
|
3557
3826
|
marker = this.data.readUInt16BE(pos);
|
|
3558
3827
|
pos += 2;
|
|
3559
3828
|
if (MARKERS.includes(marker)) {
|
|
@@ -3570,7 +3839,7 @@ class JPEG {
|
|
|
3570
3839
|
pos += 2;
|
|
3571
3840
|
this.width = this.data.readUInt16BE(pos);
|
|
3572
3841
|
pos += 2;
|
|
3573
|
-
const channels = this.data[pos
|
|
3842
|
+
const channels = this.data[pos + 1];
|
|
3574
3843
|
this.colorSpace = COLOR_SPACE_MAP[channels];
|
|
3575
3844
|
this.obj = null;
|
|
3576
3845
|
}
|
|
@@ -3605,58 +3874,60 @@ class PNGImage {
|
|
|
3605
3874
|
this.obj = null;
|
|
3606
3875
|
}
|
|
3607
3876
|
embed(document) {
|
|
3608
|
-
let dataDecoded = false;
|
|
3609
3877
|
this.document = document;
|
|
3610
3878
|
if (this.obj) {
|
|
3611
3879
|
return;
|
|
3612
3880
|
}
|
|
3613
|
-
const
|
|
3614
|
-
|
|
3615
|
-
|
|
3881
|
+
const {
|
|
3882
|
+
image,
|
|
3883
|
+
height,
|
|
3884
|
+
width
|
|
3885
|
+
} = this;
|
|
3886
|
+
const hasAlphaChannel = image.hasAlphaChannel;
|
|
3887
|
+
const isInterlaced = image.interlaceMethod === 1;
|
|
3888
|
+
const obj = this.obj = document.ref({
|
|
3616
3889
|
Type: 'XObject',
|
|
3617
3890
|
Subtype: 'Image',
|
|
3618
|
-
BitsPerComponent: hasAlphaChannel ? 8 :
|
|
3619
|
-
Width:
|
|
3620
|
-
Height:
|
|
3891
|
+
BitsPerComponent: hasAlphaChannel ? 8 : image.bits,
|
|
3892
|
+
Width: width,
|
|
3893
|
+
Height: height,
|
|
3621
3894
|
Filter: 'FlateDecode'
|
|
3622
3895
|
});
|
|
3623
3896
|
if (!hasAlphaChannel) {
|
|
3624
|
-
const params =
|
|
3897
|
+
const params = document.ref({
|
|
3625
3898
|
Predictor: isInterlaced ? 1 : 15,
|
|
3626
|
-
Colors:
|
|
3627
|
-
BitsPerComponent:
|
|
3628
|
-
Columns:
|
|
3899
|
+
Colors: image.colors,
|
|
3900
|
+
BitsPerComponent: image.bits,
|
|
3901
|
+
Columns: width
|
|
3629
3902
|
});
|
|
3630
|
-
|
|
3903
|
+
obj.data['DecodeParms'] = params;
|
|
3631
3904
|
params.end();
|
|
3632
3905
|
}
|
|
3633
|
-
if (
|
|
3634
|
-
|
|
3906
|
+
if (image.palette.length === 0) {
|
|
3907
|
+
obj.data['ColorSpace'] = image.colorSpace;
|
|
3635
3908
|
} else {
|
|
3636
|
-
const palette =
|
|
3637
|
-
palette.end(Buffer.from(
|
|
3638
|
-
|
|
3639
|
-
}
|
|
3640
|
-
if (
|
|
3641
|
-
const val =
|
|
3642
|
-
|
|
3643
|
-
} else if (
|
|
3909
|
+
const palette = document.ref();
|
|
3910
|
+
palette.end(Buffer.from(image.palette));
|
|
3911
|
+
obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', image.palette.length / 3 - 1, palette];
|
|
3912
|
+
}
|
|
3913
|
+
if (image.transparency.grayscale != null) {
|
|
3914
|
+
const val = image.transparency.grayscale;
|
|
3915
|
+
obj.data['Mask'] = [val, val];
|
|
3916
|
+
} else if (image.transparency.rgb) {
|
|
3644
3917
|
const {
|
|
3645
3918
|
rgb
|
|
3646
|
-
} =
|
|
3919
|
+
} = image.transparency;
|
|
3647
3920
|
const mask = [];
|
|
3648
3921
|
for (let x of rgb) {
|
|
3649
3922
|
mask.push(x, x);
|
|
3650
3923
|
}
|
|
3651
|
-
|
|
3652
|
-
} else if (
|
|
3653
|
-
dataDecoded = true;
|
|
3924
|
+
obj.data['Mask'] = mask;
|
|
3925
|
+
} else if (image.transparency.indexed) {
|
|
3654
3926
|
return this.loadIndexedAlphaChannel();
|
|
3655
3927
|
} else if (hasAlphaChannel) {
|
|
3656
|
-
dataDecoded = true;
|
|
3657
3928
|
return this.splitAlphaChannel();
|
|
3658
3929
|
}
|
|
3659
|
-
if (isInterlaced &&
|
|
3930
|
+
if (isInterlaced && true) {
|
|
3660
3931
|
return this.decodeData();
|
|
3661
3932
|
}
|
|
3662
3933
|
this.finalize();
|
|
@@ -3705,12 +3976,16 @@ class PNGImage {
|
|
|
3705
3976
|
}
|
|
3706
3977
|
loadIndexedAlphaChannel() {
|
|
3707
3978
|
const transparency = this.image.transparency.indexed;
|
|
3979
|
+
const isInterlaced = this.image.interlaceMethod === 1;
|
|
3708
3980
|
return this.image.decodePixels(pixels => {
|
|
3709
3981
|
const alphaChannel = Buffer.alloc(this.width * this.height);
|
|
3710
3982
|
let i = 0;
|
|
3711
3983
|
for (let j = 0, end = pixels.length; j < end; j++) {
|
|
3712
3984
|
alphaChannel[i++] = transparency[pixels[j]];
|
|
3713
3985
|
}
|
|
3986
|
+
if (isInterlaced) {
|
|
3987
|
+
this.imgData = zlib.deflateSync(Buffer.from(pixels));
|
|
3988
|
+
}
|
|
3714
3989
|
this.alphaChannel = zlib.deflateSync(alphaChannel);
|
|
3715
3990
|
return this.finalize();
|
|
3716
3991
|
});
|
|
@@ -3743,7 +4018,7 @@ class PDFImage {
|
|
|
3743
4018
|
}
|
|
3744
4019
|
if (data[0] === 0xff && data[1] === 0xd8) {
|
|
3745
4020
|
return new JPEG(data, label);
|
|
3746
|
-
} else if (data[0] === 0x89 && data
|
|
4021
|
+
} else if (data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47) {
|
|
3747
4022
|
return new PNGImage(data, label);
|
|
3748
4023
|
} else {
|
|
3749
4024
|
throw new Error('Unknown image format.');
|
|
@@ -3914,6 +4189,9 @@ var ImagesMixin = {
|
|
|
3914
4189
|
this.y += h;
|
|
3915
4190
|
}
|
|
3916
4191
|
this.save();
|
|
4192
|
+
if (options.opacity != null) {
|
|
4193
|
+
this._doOpacity(options.opacity, null);
|
|
4194
|
+
}
|
|
3917
4195
|
if (rotateAngle) {
|
|
3918
4196
|
this.rotate(rotateAngle, {
|
|
3919
4197
|
origin: [originX, originY]
|
|
@@ -3939,6 +4217,12 @@ var ImagesMixin = {
|
|
|
3939
4217
|
}
|
|
3940
4218
|
};
|
|
3941
4219
|
|
|
4220
|
+
class PDFAnnotationReference {
|
|
4221
|
+
constructor(annotationRef) {
|
|
4222
|
+
this.annotationRef = annotationRef;
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
|
|
3942
4226
|
var AnnotationsMixin = {
|
|
3943
4227
|
annotate(x, y, w, h, options) {
|
|
3944
4228
|
options.Type = 'Annot';
|
|
@@ -3956,12 +4240,18 @@ var AnnotationsMixin = {
|
|
|
3956
4240
|
if (typeof options.Dest === 'string') {
|
|
3957
4241
|
options.Dest = new String(options.Dest);
|
|
3958
4242
|
}
|
|
4243
|
+
const structParent = options.structParent;
|
|
4244
|
+
delete options.structParent;
|
|
3959
4245
|
for (let key in options) {
|
|
3960
4246
|
const val = options[key];
|
|
3961
4247
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
3962
4248
|
}
|
|
3963
4249
|
const ref = this.ref(options);
|
|
3964
4250
|
this.page.annotations.push(ref);
|
|
4251
|
+
if (structParent && typeof structParent.add === 'function') {
|
|
4252
|
+
const annotRef = new PDFAnnotationReference(ref);
|
|
4253
|
+
structParent.add(annotRef);
|
|
4254
|
+
}
|
|
3965
4255
|
ref.end();
|
|
3966
4256
|
return this;
|
|
3967
4257
|
},
|
|
@@ -4005,6 +4295,9 @@ var AnnotationsMixin = {
|
|
|
4005
4295
|
});
|
|
4006
4296
|
options.A.end();
|
|
4007
4297
|
}
|
|
4298
|
+
if (options.structParent && !options.Contents) {
|
|
4299
|
+
options.Contents = new String('');
|
|
4300
|
+
}
|
|
4008
4301
|
return this.annotate(x, y, w, h, options);
|
|
4009
4302
|
},
|
|
4010
4303
|
_markup(x, y, w, h, options = {}) {
|
|
@@ -4076,15 +4369,26 @@ var AnnotationsMixin = {
|
|
|
4076
4369
|
}
|
|
4077
4370
|
};
|
|
4078
4371
|
|
|
4372
|
+
const DEFAULT_OPTIONS = {
|
|
4373
|
+
top: 0,
|
|
4374
|
+
left: 0,
|
|
4375
|
+
zoom: 0,
|
|
4376
|
+
fit: true,
|
|
4377
|
+
pageNumber: null,
|
|
4378
|
+
expanded: false
|
|
4379
|
+
};
|
|
4079
4380
|
class PDFOutline {
|
|
4080
|
-
constructor(document, parent, title, dest, options = {
|
|
4081
|
-
expanded: false
|
|
4082
|
-
}) {
|
|
4381
|
+
constructor(document, parent, title, dest, options = DEFAULT_OPTIONS) {
|
|
4083
4382
|
this.document = document;
|
|
4084
4383
|
this.options = options;
|
|
4085
4384
|
this.outlineData = {};
|
|
4086
4385
|
if (dest !== null) {
|
|
4087
|
-
|
|
4386
|
+
const destWidth = dest.data.MediaBox[2];
|
|
4387
|
+
const destHeight = dest.data.MediaBox[3];
|
|
4388
|
+
const top = destHeight - (options.top || 0);
|
|
4389
|
+
const left = destWidth - (options.left || 0);
|
|
4390
|
+
const zoom = options.zoom || 0;
|
|
4391
|
+
this.outlineData['Dest'] = options.fit ? [dest, 'Fit'] : [dest, 'XYZ', left, top, zoom];
|
|
4088
4392
|
}
|
|
4089
4393
|
if (parent !== null) {
|
|
4090
4394
|
this.outlineData['Parent'] = parent;
|
|
@@ -4095,10 +4399,10 @@ class PDFOutline {
|
|
|
4095
4399
|
this.dictionary = this.document.ref(this.outlineData);
|
|
4096
4400
|
this.children = [];
|
|
4097
4401
|
}
|
|
4098
|
-
addItem(title, options = {
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
const result = new PDFOutline(this.document, this.dictionary, title,
|
|
4402
|
+
addItem(title, options = DEFAULT_OPTIONS) {
|
|
4403
|
+
const pages = this.document._root.data.Pages.data.Kids;
|
|
4404
|
+
const dest = options.pageNumber != null ? pages[options.pageNumber] : this.document.page.dictionary;
|
|
4405
|
+
const result = new PDFOutline(this.document, this.dictionary, title, dest, options);
|
|
4102
4406
|
this.children.push(result);
|
|
4103
4407
|
return result;
|
|
4104
4408
|
}
|
|
@@ -4134,7 +4438,7 @@ var OutlineMixin = {
|
|
|
4134
4438
|
this.outline.endOutline();
|
|
4135
4439
|
if (this.outline.children.length > 0) {
|
|
4136
4440
|
this._root.data.Outlines = this.outline.dictionary;
|
|
4137
|
-
return this._root.data.PageMode = 'UseOutlines';
|
|
4441
|
+
return this._root.data.PageMode = this._root.data.PageMode || 'UseOutlines';
|
|
4138
4442
|
}
|
|
4139
4443
|
}
|
|
4140
4444
|
};
|
|
@@ -4165,21 +4469,41 @@ class PDFStructureElement {
|
|
|
4165
4469
|
children = options;
|
|
4166
4470
|
options = {};
|
|
4167
4471
|
}
|
|
4168
|
-
if (
|
|
4472
|
+
if (options.title) {
|
|
4169
4473
|
data.T = new String(options.title);
|
|
4170
4474
|
}
|
|
4171
|
-
if (
|
|
4475
|
+
if (options.lang) {
|
|
4172
4476
|
data.Lang = new String(options.lang);
|
|
4173
4477
|
}
|
|
4174
|
-
if (
|
|
4478
|
+
if (options.alt) {
|
|
4175
4479
|
data.Alt = new String(options.alt);
|
|
4176
4480
|
}
|
|
4177
|
-
if (
|
|
4481
|
+
if (options.expanded) {
|
|
4178
4482
|
data.E = new String(options.expanded);
|
|
4179
4483
|
}
|
|
4180
|
-
if (
|
|
4484
|
+
if (options.actual) {
|
|
4181
4485
|
data.ActualText = new String(options.actual);
|
|
4182
4486
|
}
|
|
4487
|
+
const hasBbox = Array.isArray(options.bbox) && options.bbox.length === 4;
|
|
4488
|
+
const hasPlacement = typeof options.placement === 'string';
|
|
4489
|
+
if (hasBbox || hasPlacement) {
|
|
4490
|
+
const attrs = {
|
|
4491
|
+
O: 'Layout'
|
|
4492
|
+
};
|
|
4493
|
+
attrs.Placement = hasPlacement ? options.placement : 'Block';
|
|
4494
|
+
if (hasBbox) {
|
|
4495
|
+
const height = document.page.height;
|
|
4496
|
+
attrs.BBox = [options.bbox[0], height - options.bbox[3], options.bbox[2], height - options.bbox[1]];
|
|
4497
|
+
}
|
|
4498
|
+
data.A = attrs;
|
|
4499
|
+
}
|
|
4500
|
+
if (options.scope) {
|
|
4501
|
+
data.A = {
|
|
4502
|
+
...(data.A || {}),
|
|
4503
|
+
O: 'Table',
|
|
4504
|
+
Scope: options.scope
|
|
4505
|
+
};
|
|
4506
|
+
}
|
|
4183
4507
|
this._children = [];
|
|
4184
4508
|
if (children) {
|
|
4185
4509
|
if (!Array.isArray(children)) {
|
|
@@ -4205,6 +4529,9 @@ class PDFStructureElement {
|
|
|
4205
4529
|
if (child instanceof PDFStructureContent) {
|
|
4206
4530
|
this._addContentToParentTree(child);
|
|
4207
4531
|
}
|
|
4532
|
+
if (child instanceof PDFAnnotationReference) {
|
|
4533
|
+
this._addAnnotationToParentTree(child.annotationRef);
|
|
4534
|
+
}
|
|
4208
4535
|
if (typeof child === 'function' && this._attached) {
|
|
4209
4536
|
child = this._contentForClosure(child);
|
|
4210
4537
|
}
|
|
@@ -4220,6 +4547,12 @@ class PDFStructureElement {
|
|
|
4220
4547
|
pageStructParents[mcid] = this.dictionary;
|
|
4221
4548
|
});
|
|
4222
4549
|
}
|
|
4550
|
+
_addAnnotationToParentTree(annotRef) {
|
|
4551
|
+
const parentTreeKey = this.document.createStructParentTreeNextKey();
|
|
4552
|
+
annotRef.data.StructParent = parentTreeKey;
|
|
4553
|
+
const parentTree = this.document.getStructParentTree();
|
|
4554
|
+
parentTree.add(parentTreeKey, this.dictionary);
|
|
4555
|
+
}
|
|
4223
4556
|
setParent(parentRef) {
|
|
4224
4557
|
if (this.dictionary.data.P) {
|
|
4225
4558
|
throw new Error(`Structure element added to more than one parent`);
|
|
@@ -4251,11 +4584,17 @@ class PDFStructureElement {
|
|
|
4251
4584
|
this._flush();
|
|
4252
4585
|
}
|
|
4253
4586
|
_isValidChild(child) {
|
|
4254
|
-
return child instanceof PDFStructureElement || child instanceof PDFStructureContent || typeof child === 'function';
|
|
4587
|
+
return child instanceof PDFStructureElement || child instanceof PDFStructureContent || child instanceof PDFAnnotationReference || typeof child === 'function';
|
|
4255
4588
|
}
|
|
4256
4589
|
_contentForClosure(closure) {
|
|
4257
4590
|
const content = this.document.markStructureContent(this.dictionary.data.S);
|
|
4591
|
+
const prevStructElement = this.document._currentStructureElement;
|
|
4592
|
+
this.document._currentStructureElement = this;
|
|
4593
|
+
const wasEnded = this._ended;
|
|
4594
|
+
this._ended = false;
|
|
4258
4595
|
closure();
|
|
4596
|
+
this._ended = wasEnded;
|
|
4597
|
+
this.document._currentStructureElement = prevStructElement;
|
|
4259
4598
|
this.document.endMarkedContent();
|
|
4260
4599
|
this._addContentToParentTree(content);
|
|
4261
4600
|
return content;
|
|
@@ -4308,6 +4647,15 @@ class PDFStructureElement {
|
|
|
4308
4647
|
}
|
|
4309
4648
|
});
|
|
4310
4649
|
}
|
|
4650
|
+
if (child instanceof PDFAnnotationReference) {
|
|
4651
|
+
const pageRef = this.document.page.dictionary;
|
|
4652
|
+
const objr = {
|
|
4653
|
+
Type: 'OBJR',
|
|
4654
|
+
Obj: child.annotationRef,
|
|
4655
|
+
Pg: pageRef
|
|
4656
|
+
};
|
|
4657
|
+
this.dictionary.data.K.push(objr);
|
|
4658
|
+
}
|
|
4311
4659
|
}
|
|
4312
4660
|
}
|
|
4313
4661
|
|
|
@@ -4401,6 +4749,13 @@ var MarkingsMixin = {
|
|
|
4401
4749
|
endMarkedContent() {
|
|
4402
4750
|
this.page.markings.pop();
|
|
4403
4751
|
this.addContent('EMC');
|
|
4752
|
+
if (this._textOptions) {
|
|
4753
|
+
delete this._textOptions.link;
|
|
4754
|
+
delete this._textOptions.goTo;
|
|
4755
|
+
delete this._textOptions.destination;
|
|
4756
|
+
delete this._textOptions.underline;
|
|
4757
|
+
delete this._textOptions.strike;
|
|
4758
|
+
}
|
|
4404
4759
|
return this;
|
|
4405
4760
|
},
|
|
4406
4761
|
struct(type, options = {}, children = null) {
|
|
@@ -4822,7 +5177,7 @@ var AttachmentsMixin = {
|
|
|
4822
5177
|
const match = /^data:(.*?);base64,(.*)$/.exec(src);
|
|
4823
5178
|
if (match) {
|
|
4824
5179
|
if (match[1]) {
|
|
4825
|
-
refBody.Subtype = match[1]
|
|
5180
|
+
refBody.Subtype = escapeName(match[1]);
|
|
4826
5181
|
}
|
|
4827
5182
|
data = Buffer.from(match[2], 'base64');
|
|
4828
5183
|
} else {
|
|
@@ -4845,9 +5200,9 @@ var AttachmentsMixin = {
|
|
|
4845
5200
|
refBody.Params.ModDate = options.modifiedDate;
|
|
4846
5201
|
}
|
|
4847
5202
|
if (options.type) {
|
|
4848
|
-
refBody.Subtype = options.type
|
|
5203
|
+
refBody.Subtype = escapeName(options.type);
|
|
4849
5204
|
}
|
|
4850
|
-
const checksum =
|
|
5205
|
+
const checksum = md5Hex(new Uint8Array(data));
|
|
4851
5206
|
refBody.Params.CheckSum = new String(checksum);
|
|
4852
5207
|
refBody.Params.Size = data.byteLength;
|
|
4853
5208
|
let ref;
|
|
@@ -5490,7 +5845,7 @@ function renderRow(row, rowIndex) {
|
|
|
5490
5845
|
function renderCell(cell, rowStruct) {
|
|
5491
5846
|
const cellRenderer = () => {
|
|
5492
5847
|
if (cell.backgroundColor != null) {
|
|
5493
|
-
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(
|
|
5848
|
+
this.document.save().fillColor(cell.backgroundColor).rect(cell.x, cell.y, cell.width, cell.height).fill().restore();
|
|
5494
5849
|
}
|
|
5495
5850
|
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5496
5851
|
if (cell.debug) {
|
|
@@ -5551,20 +5906,20 @@ function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
|
5551
5906
|
const doc = this.document;
|
|
5552
5907
|
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5553
5908
|
if (border.top > 0) {
|
|
5554
|
-
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(
|
|
5909
|
+
doc.save().lineWidth(border.top).strokeColor(borderColor.top).rect(x, y, width, height).stroke().restore();
|
|
5555
5910
|
}
|
|
5556
5911
|
} else {
|
|
5557
5912
|
if (border.top > 0) {
|
|
5558
|
-
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(
|
|
5913
|
+
doc.save().lineWidth(border.top).moveTo(x, y).strokeColor(borderColor.top).lineTo(x + width, y).stroke().restore();
|
|
5559
5914
|
}
|
|
5560
5915
|
if (border.right > 0) {
|
|
5561
|
-
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(
|
|
5916
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).strokeColor(borderColor.right).lineTo(x + width, y + height).stroke().restore();
|
|
5562
5917
|
}
|
|
5563
5918
|
if (border.bottom > 0) {
|
|
5564
|
-
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(
|
|
5919
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).strokeColor(borderColor.bottom).lineTo(x, y + height).stroke().restore();
|
|
5565
5920
|
}
|
|
5566
5921
|
if (border.left > 0) {
|
|
5567
|
-
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(
|
|
5922
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).strokeColor(borderColor.left).lineTo(x, y).stroke().restore();
|
|
5568
5923
|
}
|
|
5569
5924
|
}
|
|
5570
5925
|
}
|
|
@@ -5700,7 +6055,7 @@ var MetadataMixin = {
|
|
|
5700
6055
|
}
|
|
5701
6056
|
this.appendXML(`
|
|
5702
6057
|
<rdf:Description rdf:about="" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
|
|
5703
|
-
<pdf:Producer>${this.info.
|
|
6058
|
+
<pdf:Producer>${this.info.Producer}</pdf:Producer>`, false);
|
|
5704
6059
|
if (this.info.Keywords) {
|
|
5705
6060
|
this.appendXML(`
|
|
5706
6061
|
<pdf:Keywords>${this.info.Keywords}</pdf:Keywords>`, false);
|
|
@@ -5771,6 +6126,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5771
6126
|
if (this.options.lang) {
|
|
5772
6127
|
this._root.data.Lang = new String(this.options.lang);
|
|
5773
6128
|
}
|
|
6129
|
+
if (this.options.pageLayout) {
|
|
6130
|
+
const layout = this.options.pageLayout;
|
|
6131
|
+
this._root.data.PageLayout = layout.charAt(0).toUpperCase() + layout.slice(1);
|
|
6132
|
+
}
|
|
5774
6133
|
this.page = null;
|
|
5775
6134
|
this.initMetadata();
|
|
5776
6135
|
this.initColor();
|