pdfkit 0.17.1 → 0.18.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 +150 -130
- 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 +442 -179
- package/js/pdfkit.es.js.map +1 -1
- package/js/pdfkit.js +441 -179
- package/js/pdfkit.js.map +1 -1
- package/js/pdfkit.standalone.js +15805 -19818
- package/jsconfig.json +13 -0
- package/package.json +93 -92
- package/types/jest.custom-matchers.d.ts +28 -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,14 @@
|
|
|
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 sha256 = require('@noble/hashes/sha256');
|
|
8
|
+
var aes = require('@noble/ciphers/aes');
|
|
6
9
|
var fs = require('fs');
|
|
7
10
|
var fontkit = require('fontkit');
|
|
8
11
|
var events = require('events');
|
|
9
12
|
var LineBreaker = require('linebreak');
|
|
10
|
-
var exif = require('jpeg-exif');
|
|
11
13
|
var PNG = require('png-js');
|
|
12
14
|
|
|
13
15
|
class PDFAbstractReference {
|
|
@@ -359,6 +361,7 @@ class PDFPage {
|
|
|
359
361
|
this._options = options;
|
|
360
362
|
this.size = options.size || 'letter';
|
|
361
363
|
this.layout = options.layout || 'portrait';
|
|
364
|
+
this.userUnit = options.userUnit || 1.0;
|
|
362
365
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
363
366
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
364
367
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
@@ -374,7 +377,8 @@ class PDFPage {
|
|
|
374
377
|
Parent: this.document._root.data.Pages,
|
|
375
378
|
MediaBox: [0, 0, this.width, this.height],
|
|
376
379
|
Contents: this.content,
|
|
377
|
-
Resources: this.resources
|
|
380
|
+
Resources: this.resources,
|
|
381
|
+
UserUnit: this.userUnit
|
|
378
382
|
});
|
|
379
383
|
this.markings = [];
|
|
380
384
|
}
|
|
@@ -447,6 +451,58 @@ class PDFNameTree extends PDFTree {
|
|
|
447
451
|
}
|
|
448
452
|
}
|
|
449
453
|
|
|
454
|
+
function md5Hash(data) {
|
|
455
|
+
return new Uint8Array(md5.arrayBuffer(data));
|
|
456
|
+
}
|
|
457
|
+
function md5Hex(data) {
|
|
458
|
+
return md5(data);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function sha256Hash(data) {
|
|
462
|
+
return sha256.sha256(data);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function aesCbcEncrypt(data, key, iv, padding = true) {
|
|
466
|
+
return aes.cbc(key, iv, {
|
|
467
|
+
disablePadding: !padding
|
|
468
|
+
}).encrypt(data);
|
|
469
|
+
}
|
|
470
|
+
function aesEcbEncrypt(data, key) {
|
|
471
|
+
return aes.ecb(key, {
|
|
472
|
+
disablePadding: true
|
|
473
|
+
}).encrypt(data);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function rc4(data, key) {
|
|
477
|
+
const s = new Uint8Array(256);
|
|
478
|
+
for (let i = 0; i < 256; i++) {
|
|
479
|
+
s[i] = i;
|
|
480
|
+
}
|
|
481
|
+
let j = 0;
|
|
482
|
+
for (let i = 0; i < 256; i++) {
|
|
483
|
+
j = j + s[i] + key[i % key.length] & 0xff;
|
|
484
|
+
[s[i], s[j]] = [s[j], s[i]];
|
|
485
|
+
}
|
|
486
|
+
const output = new Uint8Array(data.length);
|
|
487
|
+
for (let i = 0, j = 0, k = 0; k < data.length; k++) {
|
|
488
|
+
i = i + 1 & 0xff;
|
|
489
|
+
j = j + s[i] & 0xff;
|
|
490
|
+
[s[i], s[j]] = [s[j], s[i]];
|
|
491
|
+
output[k] = data[k] ^ s[s[i] + s[j] & 0xff];
|
|
492
|
+
}
|
|
493
|
+
return output;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function randomBytes(length) {
|
|
497
|
+
const bytes = new Uint8Array(length);
|
|
498
|
+
if (globalThis.crypto?.getRandomValues) {
|
|
499
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
500
|
+
} else {
|
|
501
|
+
require('crypto').randomFillSync(bytes);
|
|
502
|
+
}
|
|
503
|
+
return bytes;
|
|
504
|
+
}
|
|
505
|
+
|
|
450
506
|
function inRange(value, rangeGroup) {
|
|
451
507
|
if (value < rangeGroup[0]) return false;
|
|
452
508
|
let startRange = 0;
|
|
@@ -545,10 +601,10 @@ class PDFSecurity {
|
|
|
545
601
|
}
|
|
546
602
|
infoStr += `${key}: ${info[key].valueOf()}\n`;
|
|
547
603
|
}
|
|
548
|
-
return
|
|
604
|
+
return Buffer.from(md5Hash(infoStr));
|
|
549
605
|
}
|
|
550
606
|
static generateRandomWordArray(bytes) {
|
|
551
|
-
return
|
|
607
|
+
return randomBytes(bytes);
|
|
552
608
|
}
|
|
553
609
|
static create(document, options = {}) {
|
|
554
610
|
if (!options.ownerPassword && !options.userPassword) {
|
|
@@ -640,8 +696,8 @@ class PDFSecurity {
|
|
|
640
696
|
encDict.StrF = 'StdCF';
|
|
641
697
|
}
|
|
642
698
|
encDict.R = r;
|
|
643
|
-
encDict.O =
|
|
644
|
-
encDict.U =
|
|
699
|
+
encDict.O = Buffer.from(ownerPasswordEntry);
|
|
700
|
+
encDict.U = Buffer.from(userPasswordEntry);
|
|
645
701
|
encDict.P = permissions;
|
|
646
702
|
}
|
|
647
703
|
_setupEncryptionV5(encDict, options) {
|
|
@@ -651,10 +707,10 @@ class PDFSecurity {
|
|
|
651
707
|
const processedOwnerPassword = options.ownerPassword ? processPasswordR5(options.ownerPassword) : processedUserPassword;
|
|
652
708
|
this.encryptionKey = getEncryptionKeyR5(PDFSecurity.generateRandomWordArray);
|
|
653
709
|
const userPasswordEntry = getUserPasswordR5(processedUserPassword, PDFSecurity.generateRandomWordArray);
|
|
654
|
-
const userKeySalt =
|
|
710
|
+
const userKeySalt = userPasswordEntry.slice(40, 48);
|
|
655
711
|
const userEncryptionKeyEntry = getUserEncryptionKeyR5(processedUserPassword, userKeySalt, this.encryptionKey);
|
|
656
712
|
const ownerPasswordEntry = getOwnerPasswordR5(processedOwnerPassword, userPasswordEntry, PDFSecurity.generateRandomWordArray);
|
|
657
|
-
const ownerKeySalt =
|
|
713
|
+
const ownerKeySalt = ownerPasswordEntry.slice(40, 48);
|
|
658
714
|
const ownerEncryptionKeyEntry = getOwnerEncryptionKeyR5(processedOwnerPassword, ownerKeySalt, userPasswordEntry, this.encryptionKey);
|
|
659
715
|
const permsEntry = getEncryptedPermissionsR5(permissions, this.encryptionKey, PDFSecurity.generateRandomWordArray);
|
|
660
716
|
encDict.V = 5;
|
|
@@ -669,36 +725,37 @@ class PDFSecurity {
|
|
|
669
725
|
encDict.StmF = 'StdCF';
|
|
670
726
|
encDict.StrF = 'StdCF';
|
|
671
727
|
encDict.R = 5;
|
|
672
|
-
encDict.O =
|
|
673
|
-
encDict.OE =
|
|
674
|
-
encDict.U =
|
|
675
|
-
encDict.UE =
|
|
728
|
+
encDict.O = Buffer.from(ownerPasswordEntry);
|
|
729
|
+
encDict.OE = Buffer.from(ownerEncryptionKeyEntry);
|
|
730
|
+
encDict.U = Buffer.from(userPasswordEntry);
|
|
731
|
+
encDict.UE = Buffer.from(userEncryptionKeyEntry);
|
|
676
732
|
encDict.P = permissions;
|
|
677
|
-
encDict.Perms =
|
|
733
|
+
encDict.Perms = Buffer.from(permsEntry);
|
|
678
734
|
}
|
|
679
735
|
getEncryptFn(obj, gen) {
|
|
680
736
|
let digest;
|
|
681
737
|
if (this.version < 5) {
|
|
682
|
-
|
|
738
|
+
const suffix = new Uint8Array([obj & 0xff, obj >> 8 & 0xff, obj >> 16 & 0xff, gen & 0xff, gen >> 8 & 0xff]);
|
|
739
|
+
digest = utils.concatBytes(this.encryptionKey, suffix);
|
|
683
740
|
}
|
|
684
741
|
if (this.version === 1 || this.version === 2) {
|
|
685
|
-
let key =
|
|
686
|
-
|
|
687
|
-
|
|
742
|
+
let key = md5Hash(digest);
|
|
743
|
+
const keyLen = Math.min(16, this.keyBits / 8 + 5);
|
|
744
|
+
key = key.slice(0, keyLen);
|
|
745
|
+
return buffer => Buffer.from(rc4(new Uint8Array(buffer), key));
|
|
688
746
|
}
|
|
689
747
|
let key;
|
|
690
748
|
if (this.version === 4) {
|
|
691
|
-
|
|
749
|
+
const saltMarker = new Uint8Array([0x73, 0x41, 0x6c, 0x54]);
|
|
750
|
+
key = md5Hash(utils.concatBytes(digest, saltMarker));
|
|
692
751
|
} else {
|
|
693
752
|
key = this.encryptionKey;
|
|
694
753
|
}
|
|
695
754
|
const iv = PDFSecurity.generateRandomWordArray(16);
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
iv
|
|
755
|
+
return buffer => {
|
|
756
|
+
const encrypted = aesCbcEncrypt(new Uint8Array(buffer), key, iv, true);
|
|
757
|
+
return Buffer.from(utils.concatBytes(iv, encrypted));
|
|
700
758
|
};
|
|
701
|
-
return buffer => wordArrayToBuffer(iv.clone().concat(CryptoJS.AES.encrypt(CryptoJS.lib.WordArray.create(buffer), key, options).ciphertext));
|
|
702
759
|
}
|
|
703
760
|
end() {
|
|
704
761
|
this.dictionary.end();
|
|
@@ -749,89 +806,97 @@ function getPermissionsR3(permissionObject = {}) {
|
|
|
749
806
|
return permissions;
|
|
750
807
|
}
|
|
751
808
|
function getUserPasswordR2(encryptionKey) {
|
|
752
|
-
return
|
|
809
|
+
return rc4(processPasswordR2R3R4(), encryptionKey);
|
|
753
810
|
}
|
|
754
811
|
function getUserPasswordR3R4(documentId, encryptionKey) {
|
|
755
|
-
const key = encryptionKey.
|
|
756
|
-
let cipher =
|
|
812
|
+
const key = encryptionKey.slice();
|
|
813
|
+
let cipher = md5Hash(utils.concatBytes(processPasswordR2R3R4(), new Uint8Array(documentId)));
|
|
757
814
|
for (let i = 0; i < 20; i++) {
|
|
758
|
-
const
|
|
759
|
-
for (let j = 0; j <
|
|
760
|
-
|
|
815
|
+
const xorKey = new Uint8Array(key.length);
|
|
816
|
+
for (let j = 0; j < key.length; j++) {
|
|
817
|
+
xorKey[j] = encryptionKey[j] ^ i;
|
|
761
818
|
}
|
|
762
|
-
cipher =
|
|
819
|
+
cipher = rc4(cipher, xorKey);
|
|
763
820
|
}
|
|
764
|
-
|
|
821
|
+
const result = new Uint8Array(32);
|
|
822
|
+
result.set(cipher);
|
|
823
|
+
return result;
|
|
765
824
|
}
|
|
766
825
|
function getOwnerPasswordR2R3R4(r, keyBits, paddedUserPassword, paddedOwnerPassword) {
|
|
767
826
|
let digest = paddedOwnerPassword;
|
|
768
827
|
let round = r >= 3 ? 51 : 1;
|
|
769
828
|
for (let i = 0; i < round; i++) {
|
|
770
|
-
digest =
|
|
829
|
+
digest = md5Hash(digest);
|
|
771
830
|
}
|
|
772
|
-
const
|
|
773
|
-
key
|
|
831
|
+
const keyLen = keyBits / 8;
|
|
832
|
+
let key = digest.slice(0, keyLen);
|
|
774
833
|
let cipher = paddedUserPassword;
|
|
775
834
|
round = r >= 3 ? 20 : 1;
|
|
776
835
|
for (let i = 0; i < round; i++) {
|
|
777
|
-
const
|
|
778
|
-
for (let j = 0; j <
|
|
779
|
-
|
|
836
|
+
const xorKey = new Uint8Array(keyLen);
|
|
837
|
+
for (let j = 0; j < keyLen; j++) {
|
|
838
|
+
xorKey[j] = key[j] ^ i;
|
|
780
839
|
}
|
|
781
|
-
cipher =
|
|
840
|
+
cipher = rc4(cipher, xorKey);
|
|
782
841
|
}
|
|
783
842
|
return cipher;
|
|
784
843
|
}
|
|
785
844
|
function getEncryptionKeyR2R3R4(r, keyBits, documentId, paddedUserPassword, ownerPasswordEntry, permissions) {
|
|
786
|
-
|
|
845
|
+
const permBytes = new Uint8Array([permissions & 0xff, permissions >> 8 & 0xff, permissions >> 16 & 0xff, permissions >> 24 & 0xff]);
|
|
846
|
+
let key = utils.concatBytes(paddedUserPassword, ownerPasswordEntry, permBytes, new Uint8Array(documentId));
|
|
787
847
|
const round = r >= 3 ? 51 : 1;
|
|
848
|
+
const keyLen = keyBits / 8;
|
|
788
849
|
for (let i = 0; i < round; i++) {
|
|
789
|
-
key =
|
|
790
|
-
key
|
|
850
|
+
key = md5Hash(key);
|
|
851
|
+
key = key.slice(0, keyLen);
|
|
791
852
|
}
|
|
792
853
|
return key;
|
|
793
854
|
}
|
|
794
855
|
function getUserPasswordR5(processedUserPassword, generateRandomWordArray) {
|
|
795
856
|
const validationSalt = generateRandomWordArray(8);
|
|
796
857
|
const keySalt = generateRandomWordArray(8);
|
|
797
|
-
|
|
858
|
+
const hash = sha256Hash(utils.concatBytes(processedUserPassword, validationSalt));
|
|
859
|
+
return utils.concatBytes(hash, validationSalt, keySalt);
|
|
798
860
|
}
|
|
799
861
|
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;
|
|
862
|
+
const key = sha256Hash(utils.concatBytes(processedUserPassword, userKeySalt));
|
|
863
|
+
const iv = new Uint8Array(16);
|
|
864
|
+
return aesCbcEncrypt(encryptionKey, key, iv, false);
|
|
807
865
|
}
|
|
808
866
|
function getOwnerPasswordR5(processedOwnerPassword, userPasswordEntry, generateRandomWordArray) {
|
|
809
867
|
const validationSalt = generateRandomWordArray(8);
|
|
810
868
|
const keySalt = generateRandomWordArray(8);
|
|
811
|
-
|
|
869
|
+
const hash = sha256Hash(utils.concatBytes(processedOwnerPassword, validationSalt, userPasswordEntry));
|
|
870
|
+
return utils.concatBytes(hash, validationSalt, keySalt);
|
|
812
871
|
}
|
|
813
872
|
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;
|
|
873
|
+
const key = sha256Hash(utils.concatBytes(processedOwnerPassword, ownerKeySalt, userPasswordEntry));
|
|
874
|
+
const iv = new Uint8Array(16);
|
|
875
|
+
return aesCbcEncrypt(encryptionKey, key, iv, false);
|
|
821
876
|
}
|
|
822
877
|
function getEncryptionKeyR5(generateRandomWordArray) {
|
|
823
878
|
return generateRandomWordArray(32);
|
|
824
879
|
}
|
|
825
880
|
function getEncryptedPermissionsR5(permissions, encryptionKey, generateRandomWordArray) {
|
|
826
|
-
const
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
881
|
+
const data = new Uint8Array(16);
|
|
882
|
+
data[0] = permissions & 0xff;
|
|
883
|
+
data[1] = permissions >> 8 & 0xff;
|
|
884
|
+
data[2] = permissions >> 16 & 0xff;
|
|
885
|
+
data[3] = permissions >> 24 & 0xff;
|
|
886
|
+
data[4] = 0xff;
|
|
887
|
+
data[5] = 0xff;
|
|
888
|
+
data[6] = 0xff;
|
|
889
|
+
data[7] = 0xff;
|
|
890
|
+
data[8] = 0x54;
|
|
891
|
+
data[9] = 0x61;
|
|
892
|
+
data[10] = 0x64;
|
|
893
|
+
data[11] = 0x62;
|
|
894
|
+
const randomPart = generateRandomWordArray(4);
|
|
895
|
+
data.set(randomPart, 12);
|
|
896
|
+
return aesEcbEncrypt(data, encryptionKey);
|
|
832
897
|
}
|
|
833
898
|
function processPasswordR2R3R4(password = '') {
|
|
834
|
-
const out =
|
|
899
|
+
const out = new Uint8Array(32);
|
|
835
900
|
const length = password.length;
|
|
836
901
|
let index = 0;
|
|
837
902
|
while (index < length && index < 32) {
|
|
@@ -846,26 +911,16 @@ function processPasswordR2R3R4(password = '') {
|
|
|
846
911
|
out[index] = PASSWORD_PADDING[index - length];
|
|
847
912
|
index++;
|
|
848
913
|
}
|
|
849
|
-
return
|
|
914
|
+
return out;
|
|
850
915
|
}
|
|
851
916
|
function processPasswordR5(password = '') {
|
|
852
917
|
password = unescape(encodeURIComponent(saslprep(password)));
|
|
853
918
|
const length = Math.min(127, password.length);
|
|
854
|
-
const out =
|
|
919
|
+
const out = new Uint8Array(length);
|
|
855
920
|
for (let i = 0; i < length; i++) {
|
|
856
921
|
out[i] = password.charCodeAt(i);
|
|
857
922
|
}
|
|
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);
|
|
923
|
+
return out;
|
|
869
924
|
}
|
|
870
925
|
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
926
|
|
|
@@ -1473,86 +1528,176 @@ const parameters = {
|
|
|
1473
1528
|
Z: 0,
|
|
1474
1529
|
z: 0
|
|
1475
1530
|
};
|
|
1531
|
+
const isCommand = function (c) {
|
|
1532
|
+
return c in parameters;
|
|
1533
|
+
};
|
|
1534
|
+
const isWsp = function (c) {
|
|
1535
|
+
const codePoint = c.codePointAt(0);
|
|
1536
|
+
return codePoint === 0x20 || codePoint === 0x9 || codePoint === 0xd || codePoint === 0xa;
|
|
1537
|
+
};
|
|
1538
|
+
const isDigit = function (c) {
|
|
1539
|
+
const codePoint = c.codePointAt(0);
|
|
1540
|
+
if (codePoint == null) {
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
return 48 <= codePoint && codePoint <= 57;
|
|
1544
|
+
};
|
|
1545
|
+
const readNumber = function (string, cursor) {
|
|
1546
|
+
let i = cursor;
|
|
1547
|
+
let value = '';
|
|
1548
|
+
let state = 'none';
|
|
1549
|
+
for (; i < string.length; i += 1) {
|
|
1550
|
+
const c = string[i];
|
|
1551
|
+
if (c === '+' || c === '-') {
|
|
1552
|
+
if (state === 'none') {
|
|
1553
|
+
state = 'sign';
|
|
1554
|
+
value += c;
|
|
1555
|
+
continue;
|
|
1556
|
+
}
|
|
1557
|
+
if (state === 'e') {
|
|
1558
|
+
state = 'exponent_sign';
|
|
1559
|
+
value += c;
|
|
1560
|
+
continue;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
if (isDigit(c)) {
|
|
1564
|
+
if (state === 'none' || state === 'sign' || state === 'whole') {
|
|
1565
|
+
state = 'whole';
|
|
1566
|
+
value += c;
|
|
1567
|
+
continue;
|
|
1568
|
+
}
|
|
1569
|
+
if (state === 'decimal_point' || state === 'decimal') {
|
|
1570
|
+
state = 'decimal';
|
|
1571
|
+
value += c;
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
if (state === 'e' || state === 'exponent_sign' || state === 'exponent') {
|
|
1575
|
+
state = 'exponent';
|
|
1576
|
+
value += c;
|
|
1577
|
+
continue;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
if (c === '.') {
|
|
1581
|
+
if (state === 'none' || state === 'sign' || state === 'whole') {
|
|
1582
|
+
state = 'decimal_point';
|
|
1583
|
+
value += c;
|
|
1584
|
+
continue;
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
if (c === 'E' || c === 'e') {
|
|
1588
|
+
if (state === 'whole' || state === 'decimal_point' || state === 'decimal') {
|
|
1589
|
+
state = 'e';
|
|
1590
|
+
value += c;
|
|
1591
|
+
continue;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
break;
|
|
1595
|
+
}
|
|
1596
|
+
const number = Number.parseFloat(value);
|
|
1597
|
+
if (Number.isNaN(number)) {
|
|
1598
|
+
return [cursor, null];
|
|
1599
|
+
}
|
|
1600
|
+
return [i - 1, number];
|
|
1601
|
+
};
|
|
1476
1602
|
const parse = function (path) {
|
|
1477
|
-
|
|
1478
|
-
|
|
1603
|
+
const pathData = [];
|
|
1604
|
+
let command = null;
|
|
1479
1605
|
let args = [];
|
|
1480
|
-
let
|
|
1481
|
-
let
|
|
1482
|
-
let
|
|
1483
|
-
for (let
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1606
|
+
let argsCount = 0;
|
|
1607
|
+
let canHaveComma = false;
|
|
1608
|
+
let hadComma = false;
|
|
1609
|
+
for (let i = 0; i < path.length; i += 1) {
|
|
1610
|
+
const c = path.charAt(i);
|
|
1611
|
+
if (isWsp(c)) {
|
|
1612
|
+
continue;
|
|
1613
|
+
}
|
|
1614
|
+
if (canHaveComma && c === ',') {
|
|
1615
|
+
if (hadComma) {
|
|
1616
|
+
break;
|
|
1617
|
+
}
|
|
1618
|
+
hadComma = true;
|
|
1619
|
+
continue;
|
|
1620
|
+
}
|
|
1621
|
+
if (isCommand(c)) {
|
|
1622
|
+
if (hadComma) {
|
|
1623
|
+
return pathData;
|
|
1624
|
+
}
|
|
1625
|
+
if (command == null) {
|
|
1626
|
+
if (c !== 'M' && c !== 'm') {
|
|
1627
|
+
return pathData;
|
|
1628
|
+
}
|
|
1629
|
+
} else {
|
|
1630
|
+
if (args.length !== 0) {
|
|
1631
|
+
return pathData;
|
|
1489
1632
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1633
|
+
}
|
|
1634
|
+
command = c;
|
|
1635
|
+
args = [];
|
|
1636
|
+
argsCount = parameters[command];
|
|
1637
|
+
canHaveComma = false;
|
|
1638
|
+
if (argsCount === 0) {
|
|
1639
|
+
pathData.push({
|
|
1640
|
+
command,
|
|
1492
1641
|
args
|
|
1493
|
-
};
|
|
1494
|
-
args = [];
|
|
1495
|
-
curArg = '';
|
|
1496
|
-
foundDecimal = false;
|
|
1642
|
+
});
|
|
1497
1643
|
}
|
|
1498
|
-
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
|
|
1644
|
+
continue;
|
|
1645
|
+
}
|
|
1646
|
+
if (command == null) {
|
|
1647
|
+
return pathData;
|
|
1648
|
+
}
|
|
1649
|
+
let newCursor = i;
|
|
1650
|
+
let number = null;
|
|
1651
|
+
if (command === 'A' || command === 'a') {
|
|
1652
|
+
const position = args.length;
|
|
1653
|
+
if (position === 0 || position === 1) {
|
|
1654
|
+
if (c !== '+' && c !== '-') {
|
|
1655
|
+
[newCursor, number] = readNumber(path, i);
|
|
1656
|
+
}
|
|
1502
1657
|
}
|
|
1503
|
-
if (
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
if (cmd === 'M') {
|
|
1510
|
-
cmd = 'L';
|
|
1658
|
+
if (position === 2 || position === 5 || position === 6) {
|
|
1659
|
+
[newCursor, number] = readNumber(path, i);
|
|
1660
|
+
}
|
|
1661
|
+
if (position === 3 || position === 4) {
|
|
1662
|
+
if (c === '0') {
|
|
1663
|
+
number = 0;
|
|
1511
1664
|
}
|
|
1512
|
-
if (
|
|
1513
|
-
|
|
1665
|
+
if (c === '1') {
|
|
1666
|
+
number = 1;
|
|
1514
1667
|
}
|
|
1515
|
-
} else {
|
|
1516
|
-
args[args.length] = +curArg;
|
|
1517
1668
|
}
|
|
1518
|
-
foundDecimal = c === '.';
|
|
1519
|
-
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1520
1669
|
} else {
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1670
|
+
[newCursor, number] = readNumber(path, i);
|
|
1671
|
+
}
|
|
1672
|
+
if (number == null) {
|
|
1673
|
+
return pathData;
|
|
1674
|
+
}
|
|
1675
|
+
args.push(number);
|
|
1676
|
+
canHaveComma = true;
|
|
1677
|
+
hadComma = false;
|
|
1678
|
+
i = newCursor;
|
|
1679
|
+
if (args.length === argsCount) {
|
|
1680
|
+
pathData.push({
|
|
1681
|
+
command,
|
|
1531
1682
|
args
|
|
1532
|
-
};
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
cmd = 'L';
|
|
1683
|
+
});
|
|
1684
|
+
if (command === 'M') {
|
|
1685
|
+
command = 'L';
|
|
1536
1686
|
}
|
|
1537
|
-
if (
|
|
1538
|
-
|
|
1687
|
+
if (command === 'm') {
|
|
1688
|
+
command = 'l';
|
|
1539
1689
|
}
|
|
1540
|
-
|
|
1541
|
-
args[args.length] = +curArg;
|
|
1690
|
+
args = [];
|
|
1542
1691
|
}
|
|
1543
1692
|
}
|
|
1544
|
-
|
|
1545
|
-
cmd,
|
|
1546
|
-
args
|
|
1547
|
-
};
|
|
1548
|
-
return ret;
|
|
1693
|
+
return pathData;
|
|
1549
1694
|
};
|
|
1550
1695
|
const apply = function (commands, doc) {
|
|
1551
1696
|
cx = cy = px = py = sx = sy = 0;
|
|
1552
1697
|
for (let i = 0; i < commands.length; i++) {
|
|
1553
1698
|
const c = commands[i];
|
|
1554
|
-
if (typeof runners[c.
|
|
1555
|
-
runners[c.
|
|
1699
|
+
if (typeof runners[c.command] === 'function') {
|
|
1700
|
+
runners[c.command](doc, c.args);
|
|
1556
1701
|
}
|
|
1557
1702
|
}
|
|
1558
1703
|
};
|
|
@@ -2584,7 +2729,7 @@ begincmap
|
|
|
2584
2729
|
1 begincodespacerange
|
|
2585
2730
|
<0000><ffff>
|
|
2586
2731
|
endcodespacerange
|
|
2587
|
-
|
|
2732
|
+
${ranges.length} beginbfrange
|
|
2588
2733
|
${ranges.join('\n')}
|
|
2589
2734
|
endbfrange
|
|
2590
2735
|
endcmap
|
|
@@ -2763,6 +2908,7 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2763
2908
|
this.document = document;
|
|
2764
2909
|
this.horizontalScaling = options.horizontalScaling || 100;
|
|
2765
2910
|
this.indent = (options.indent || 0) * this.horizontalScaling / 100;
|
|
2911
|
+
this.indentAllLines = options.indentAllLines || false;
|
|
2766
2912
|
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
2767
2913
|
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
2768
2914
|
this.columns = options.columns || 1;
|
|
@@ -2956,12 +3102,14 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2956
3102
|
}
|
|
2957
3103
|
emitLine();
|
|
2958
3104
|
if (PDFNumber(this.document.y + lh) > this.maxY) {
|
|
3105
|
+
this.emit('sectionEnd', options, this);
|
|
2959
3106
|
const shouldContinue = this.nextSection();
|
|
2960
3107
|
if (!shouldContinue) {
|
|
2961
3108
|
wc = 0;
|
|
2962
3109
|
buffer = '';
|
|
2963
3110
|
return false;
|
|
2964
3111
|
}
|
|
3112
|
+
this.emit('sectionStart', options, this);
|
|
2965
3113
|
}
|
|
2966
3114
|
if (bk.required) {
|
|
2967
3115
|
this.spaceLeft = this.lineWidth;
|
|
@@ -2994,7 +3142,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
2994
3142
|
}
|
|
2995
3143
|
}
|
|
2996
3144
|
nextSection(options) {
|
|
2997
|
-
this.emit('sectionEnd', options, this);
|
|
2998
3145
|
if (++this.column > this.columns) {
|
|
2999
3146
|
if (this.height != null) {
|
|
3000
3147
|
return false;
|
|
@@ -3003,7 +3150,13 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3003
3150
|
this.column = 1;
|
|
3004
3151
|
this.startY = this.document.page.margins.top;
|
|
3005
3152
|
this.maxY = this.document.page.maxY();
|
|
3006
|
-
this.
|
|
3153
|
+
if (this.indentAllLines) {
|
|
3154
|
+
const indent = this.continuedX || this.indent;
|
|
3155
|
+
this.document.x += indent;
|
|
3156
|
+
this.lineWidth -= indent;
|
|
3157
|
+
} else {
|
|
3158
|
+
this.document.x = this.startX;
|
|
3159
|
+
}
|
|
3007
3160
|
if (this.document._fillColor) {
|
|
3008
3161
|
this.document.fillColor(...this.document._fillColor);
|
|
3009
3162
|
}
|
|
@@ -3013,7 +3166,6 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3013
3166
|
this.document.y = this.startY;
|
|
3014
3167
|
this.emit('columnBreak', options, this);
|
|
3015
3168
|
}
|
|
3016
|
-
this.emit('sectionStart', options, this);
|
|
3017
3169
|
return true;
|
|
3018
3170
|
}
|
|
3019
3171
|
}
|
|
@@ -3021,6 +3173,15 @@ class LineWrapper extends events.EventEmitter {
|
|
|
3021
3173
|
const {
|
|
3022
3174
|
number
|
|
3023
3175
|
} = PDFObject;
|
|
3176
|
+
function formatListLabel(n, listType) {
|
|
3177
|
+
if (listType === 'numbered') {
|
|
3178
|
+
return `${n}.`;
|
|
3179
|
+
}
|
|
3180
|
+
var letter = String.fromCharCode((n - 1) % 26 + 65);
|
|
3181
|
+
var times = Math.floor((n - 1) / 26 + 1);
|
|
3182
|
+
var text = Array(times + 1).join(letter);
|
|
3183
|
+
return `${text}.`;
|
|
3184
|
+
}
|
|
3024
3185
|
var TextMixin = {
|
|
3025
3186
|
initText() {
|
|
3026
3187
|
this._line = this._line.bind(this);
|
|
@@ -3197,7 +3358,7 @@ var TextMixin = {
|
|
|
3197
3358
|
this.y = y;
|
|
3198
3359
|
return height;
|
|
3199
3360
|
},
|
|
3200
|
-
list(list, x, y, options
|
|
3361
|
+
list(list, x, y, options) {
|
|
3201
3362
|
options = this._initOptions(x, y, options);
|
|
3202
3363
|
const listType = options.listType || 'bullet';
|
|
3203
3364
|
const unit = Math.round(this._font.ascender / 1000 * this._fontSize);
|
|
@@ -3227,19 +3388,8 @@ var TextMixin = {
|
|
|
3227
3388
|
}
|
|
3228
3389
|
};
|
|
3229
3390
|
flatten(list);
|
|
3230
|
-
const label = function (n) {
|
|
3231
|
-
switch (listType) {
|
|
3232
|
-
case 'numbered':
|
|
3233
|
-
return `${n}.`;
|
|
3234
|
-
case 'lettered':
|
|
3235
|
-
var letter = String.fromCharCode((n - 1) % 26 + 65);
|
|
3236
|
-
var times = Math.floor((n - 1) / 26 + 1);
|
|
3237
|
-
var text = Array(times + 1).join(letter);
|
|
3238
|
-
return `${text}.`;
|
|
3239
|
-
}
|
|
3240
|
-
};
|
|
3241
3391
|
const drawListItem = function (listItem, i) {
|
|
3242
|
-
wrapper = new LineWrapper(this, options);
|
|
3392
|
+
const wrapper = new LineWrapper(this, options);
|
|
3243
3393
|
wrapper.on('line', this._line);
|
|
3244
3394
|
level = 1;
|
|
3245
3395
|
wrapper.once('firstLine', () => {
|
|
@@ -3274,7 +3424,7 @@ var TextMixin = {
|
|
|
3274
3424
|
break;
|
|
3275
3425
|
case 'numbered':
|
|
3276
3426
|
case 'lettered':
|
|
3277
|
-
var text =
|
|
3427
|
+
var text = formatListLabel(numbers[i - 1], listType);
|
|
3278
3428
|
this._fragment(text, this.x - indent, this.y, options);
|
|
3279
3429
|
break;
|
|
3280
3430
|
}
|
|
@@ -3342,11 +3492,11 @@ var TextMixin = {
|
|
|
3342
3492
|
},
|
|
3343
3493
|
_line(text, options = {}, wrapper) {
|
|
3344
3494
|
this._fragment(text, this.x, this.y, options);
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
this.x += this.widthOfString(text, options);
|
|
3348
|
-
} else {
|
|
3495
|
+
if (wrapper) {
|
|
3496
|
+
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3349
3497
|
this.y += this.currentLineHeight(true) + lineGap;
|
|
3498
|
+
} else {
|
|
3499
|
+
this.x += this.widthOfString(text, options);
|
|
3350
3500
|
}
|
|
3351
3501
|
},
|
|
3352
3502
|
_fragment(text, x, y, options) {
|
|
@@ -3410,7 +3560,11 @@ var TextMixin = {
|
|
|
3410
3560
|
}
|
|
3411
3561
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3412
3562
|
if (options.link != null) {
|
|
3413
|
-
|
|
3563
|
+
const linkOptions = {};
|
|
3564
|
+
if (this._currentStructureElement && this._currentStructureElement.dictionary.data.S === 'Link') {
|
|
3565
|
+
linkOptions.structParent = this._currentStructureElement;
|
|
3566
|
+
}
|
|
3567
|
+
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link, linkOptions);
|
|
3414
3568
|
}
|
|
3415
3569
|
if (options.goTo != null) {
|
|
3416
3570
|
this.goTo(x, y, renderedWidth, this.currentLineHeight(), options.goTo);
|
|
@@ -3539,6 +3693,47 @@ var TextMixin = {
|
|
|
3539
3693
|
}
|
|
3540
3694
|
};
|
|
3541
3695
|
|
|
3696
|
+
const parseExifOrientation = data => {
|
|
3697
|
+
if (!data || data.length < 20) return null;
|
|
3698
|
+
let pos = 2;
|
|
3699
|
+
while (pos < data.length - 4) {
|
|
3700
|
+
while (pos < data.length && data[pos] !== 0xff) pos++;
|
|
3701
|
+
if (pos >= data.length - 4) return null;
|
|
3702
|
+
const marker = data.readUInt16BE(pos);
|
|
3703
|
+
pos += 2;
|
|
3704
|
+
if (marker === 0xffda) return null;
|
|
3705
|
+
if (marker >= 0xffd0 && marker <= 0xffd9 || marker === 0xff01) continue;
|
|
3706
|
+
if (pos + 2 > data.length) return null;
|
|
3707
|
+
const segmentLength = data.readUInt16BE(pos);
|
|
3708
|
+
if (marker === 0xffe1 && pos + 8 <= data.length) {
|
|
3709
|
+
const exifHeader = data.subarray(pos + 2, pos + 8).toString('binary');
|
|
3710
|
+
if (exifHeader === 'Exif\x00\x00') {
|
|
3711
|
+
const tiffStart = pos + 8;
|
|
3712
|
+
if (tiffStart + 8 > data.length) return null;
|
|
3713
|
+
const byteOrder = data.subarray(tiffStart, tiffStart + 2).toString('ascii');
|
|
3714
|
+
const isLittleEndian = byteOrder === 'II';
|
|
3715
|
+
if (!isLittleEndian && byteOrder !== 'MM') return null;
|
|
3716
|
+
const read16 = isLittleEndian ? o => data.readUInt16LE(o) : o => data.readUInt16BE(o);
|
|
3717
|
+
const read32 = isLittleEndian ? o => data.readUInt32LE(o) : o => data.readUInt32BE(o);
|
|
3718
|
+
if (read16(tiffStart + 2) !== 42) return null;
|
|
3719
|
+
const ifdPos = tiffStart + read32(tiffStart + 4);
|
|
3720
|
+
if (ifdPos + 2 > data.length) return null;
|
|
3721
|
+
const entryCount = read16(ifdPos);
|
|
3722
|
+
for (let i = 0; i < entryCount; i++) {
|
|
3723
|
+
const entryPos = ifdPos + 2 + i * 12;
|
|
3724
|
+
if (entryPos + 12 > data.length) return null;
|
|
3725
|
+
if (read16(entryPos) === 0x0112) {
|
|
3726
|
+
const value = read16(entryPos + 8);
|
|
3727
|
+
return value >= 1 && value <= 8 ? value : null;
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
return null;
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
pos += segmentLength;
|
|
3734
|
+
}
|
|
3735
|
+
return null;
|
|
3736
|
+
};
|
|
3542
3737
|
const MARKERS = [0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf];
|
|
3543
3738
|
const COLOR_SPACE_MAP = {
|
|
3544
3739
|
1: 'DeviceGray',
|
|
@@ -3553,9 +3748,11 @@ class JPEG {
|
|
|
3553
3748
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3554
3749
|
throw 'SOI not found in JPEG';
|
|
3555
3750
|
}
|
|
3556
|
-
this.orientation =
|
|
3751
|
+
this.orientation = parseExifOrientation(this.data) || 1;
|
|
3557
3752
|
let pos = 2;
|
|
3558
3753
|
while (pos < this.data.length) {
|
|
3754
|
+
while (pos < this.data.length && this.data[pos] !== 0xff) pos++;
|
|
3755
|
+
if (pos >= this.data.length) break;
|
|
3559
3756
|
marker = this.data.readUInt16BE(pos);
|
|
3560
3757
|
pos += 2;
|
|
3561
3758
|
if (MARKERS.includes(marker)) {
|
|
@@ -3707,12 +3904,16 @@ class PNGImage {
|
|
|
3707
3904
|
}
|
|
3708
3905
|
loadIndexedAlphaChannel() {
|
|
3709
3906
|
const transparency = this.image.transparency.indexed;
|
|
3907
|
+
const isInterlaced = this.image.interlaceMethod === 1;
|
|
3710
3908
|
return this.image.decodePixels(pixels => {
|
|
3711
3909
|
const alphaChannel = Buffer.alloc(this.width * this.height);
|
|
3712
3910
|
let i = 0;
|
|
3713
3911
|
for (let j = 0, end = pixels.length; j < end; j++) {
|
|
3714
3912
|
alphaChannel[i++] = transparency[pixels[j]];
|
|
3715
3913
|
}
|
|
3914
|
+
if (isInterlaced) {
|
|
3915
|
+
this.imgData = zlib.deflateSync(Buffer.from(pixels));
|
|
3916
|
+
}
|
|
3716
3917
|
this.alphaChannel = zlib.deflateSync(alphaChannel);
|
|
3717
3918
|
return this.finalize();
|
|
3718
3919
|
});
|
|
@@ -3941,6 +4142,12 @@ var ImagesMixin = {
|
|
|
3941
4142
|
}
|
|
3942
4143
|
};
|
|
3943
4144
|
|
|
4145
|
+
class PDFAnnotationReference {
|
|
4146
|
+
constructor(annotationRef) {
|
|
4147
|
+
this.annotationRef = annotationRef;
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
|
|
3944
4151
|
var AnnotationsMixin = {
|
|
3945
4152
|
annotate(x, y, w, h, options) {
|
|
3946
4153
|
options.Type = 'Annot';
|
|
@@ -3958,12 +4165,18 @@ var AnnotationsMixin = {
|
|
|
3958
4165
|
if (typeof options.Dest === 'string') {
|
|
3959
4166
|
options.Dest = new String(options.Dest);
|
|
3960
4167
|
}
|
|
4168
|
+
const structParent = options.structParent;
|
|
4169
|
+
delete options.structParent;
|
|
3961
4170
|
for (let key in options) {
|
|
3962
4171
|
const val = options[key];
|
|
3963
4172
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
3964
4173
|
}
|
|
3965
4174
|
const ref = this.ref(options);
|
|
3966
4175
|
this.page.annotations.push(ref);
|
|
4176
|
+
if (structParent && typeof structParent.add === 'function') {
|
|
4177
|
+
const annotRef = new PDFAnnotationReference(ref);
|
|
4178
|
+
structParent.add(annotRef);
|
|
4179
|
+
}
|
|
3967
4180
|
ref.end();
|
|
3968
4181
|
return this;
|
|
3969
4182
|
},
|
|
@@ -4007,6 +4220,9 @@ var AnnotationsMixin = {
|
|
|
4007
4220
|
});
|
|
4008
4221
|
options.A.end();
|
|
4009
4222
|
}
|
|
4223
|
+
if (options.structParent && !options.Contents) {
|
|
4224
|
+
options.Contents = new String('');
|
|
4225
|
+
}
|
|
4010
4226
|
return this.annotate(x, y, w, h, options);
|
|
4011
4227
|
},
|
|
4012
4228
|
_markup(x, y, w, h, options = {}) {
|
|
@@ -4078,15 +4294,26 @@ var AnnotationsMixin = {
|
|
|
4078
4294
|
}
|
|
4079
4295
|
};
|
|
4080
4296
|
|
|
4297
|
+
const DEFAULT_OPTIONS = {
|
|
4298
|
+
top: 0,
|
|
4299
|
+
left: 0,
|
|
4300
|
+
zoom: 0,
|
|
4301
|
+
fit: true,
|
|
4302
|
+
pageNumber: null,
|
|
4303
|
+
expanded: false
|
|
4304
|
+
};
|
|
4081
4305
|
class PDFOutline {
|
|
4082
|
-
constructor(document, parent, title, dest, options = {
|
|
4083
|
-
expanded: false
|
|
4084
|
-
}) {
|
|
4306
|
+
constructor(document, parent, title, dest, options = DEFAULT_OPTIONS) {
|
|
4085
4307
|
this.document = document;
|
|
4086
4308
|
this.options = options;
|
|
4087
4309
|
this.outlineData = {};
|
|
4088
4310
|
if (dest !== null) {
|
|
4089
|
-
|
|
4311
|
+
const destWidth = dest.data.MediaBox[2];
|
|
4312
|
+
const destHeight = dest.data.MediaBox[3];
|
|
4313
|
+
const top = destHeight - (options.top || 0);
|
|
4314
|
+
const left = destWidth - (options.left || 0);
|
|
4315
|
+
const zoom = options.zoom || 0;
|
|
4316
|
+
this.outlineData['Dest'] = options.fit ? [dest, 'Fit'] : [dest, 'XYZ', left, top, zoom];
|
|
4090
4317
|
}
|
|
4091
4318
|
if (parent !== null) {
|
|
4092
4319
|
this.outlineData['Parent'] = parent;
|
|
@@ -4097,10 +4324,10 @@ class PDFOutline {
|
|
|
4097
4324
|
this.dictionary = this.document.ref(this.outlineData);
|
|
4098
4325
|
this.children = [];
|
|
4099
4326
|
}
|
|
4100
|
-
addItem(title, options = {
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
const result = new PDFOutline(this.document, this.dictionary, title,
|
|
4327
|
+
addItem(title, options = DEFAULT_OPTIONS) {
|
|
4328
|
+
const pages = this.document._root.data.Pages.data.Kids;
|
|
4329
|
+
const dest = options.pageNumber != null ? pages[options.pageNumber] : this.document.page.dictionary;
|
|
4330
|
+
const result = new PDFOutline(this.document, this.dictionary, title, dest, options);
|
|
4104
4331
|
this.children.push(result);
|
|
4105
4332
|
return result;
|
|
4106
4333
|
}
|
|
@@ -4136,7 +4363,7 @@ var OutlineMixin = {
|
|
|
4136
4363
|
this.outline.endOutline();
|
|
4137
4364
|
if (this.outline.children.length > 0) {
|
|
4138
4365
|
this._root.data.Outlines = this.outline.dictionary;
|
|
4139
|
-
return this._root.data.PageMode = 'UseOutlines';
|
|
4366
|
+
return this._root.data.PageMode = this._root.data.PageMode || 'UseOutlines';
|
|
4140
4367
|
}
|
|
4141
4368
|
}
|
|
4142
4369
|
};
|
|
@@ -4207,6 +4434,9 @@ class PDFStructureElement {
|
|
|
4207
4434
|
if (child instanceof PDFStructureContent) {
|
|
4208
4435
|
this._addContentToParentTree(child);
|
|
4209
4436
|
}
|
|
4437
|
+
if (child instanceof PDFAnnotationReference) {
|
|
4438
|
+
this._addAnnotationToParentTree(child.annotationRef);
|
|
4439
|
+
}
|
|
4210
4440
|
if (typeof child === 'function' && this._attached) {
|
|
4211
4441
|
child = this._contentForClosure(child);
|
|
4212
4442
|
}
|
|
@@ -4222,6 +4452,12 @@ class PDFStructureElement {
|
|
|
4222
4452
|
pageStructParents[mcid] = this.dictionary;
|
|
4223
4453
|
});
|
|
4224
4454
|
}
|
|
4455
|
+
_addAnnotationToParentTree(annotRef) {
|
|
4456
|
+
const parentTreeKey = this.document.createStructParentTreeNextKey();
|
|
4457
|
+
annotRef.data.StructParent = parentTreeKey;
|
|
4458
|
+
const parentTree = this.document.getStructParentTree();
|
|
4459
|
+
parentTree.add(parentTreeKey, this.dictionary);
|
|
4460
|
+
}
|
|
4225
4461
|
setParent(parentRef) {
|
|
4226
4462
|
if (this.dictionary.data.P) {
|
|
4227
4463
|
throw new Error(`Structure element added to more than one parent`);
|
|
@@ -4253,11 +4489,17 @@ class PDFStructureElement {
|
|
|
4253
4489
|
this._flush();
|
|
4254
4490
|
}
|
|
4255
4491
|
_isValidChild(child) {
|
|
4256
|
-
return child instanceof PDFStructureElement || child instanceof PDFStructureContent || typeof child === 'function';
|
|
4492
|
+
return child instanceof PDFStructureElement || child instanceof PDFStructureContent || child instanceof PDFAnnotationReference || typeof child === 'function';
|
|
4257
4493
|
}
|
|
4258
4494
|
_contentForClosure(closure) {
|
|
4259
4495
|
const content = this.document.markStructureContent(this.dictionary.data.S);
|
|
4496
|
+
const prevStructElement = this.document._currentStructureElement;
|
|
4497
|
+
this.document._currentStructureElement = this;
|
|
4498
|
+
const wasEnded = this._ended;
|
|
4499
|
+
this._ended = false;
|
|
4260
4500
|
closure();
|
|
4501
|
+
this._ended = wasEnded;
|
|
4502
|
+
this.document._currentStructureElement = prevStructElement;
|
|
4261
4503
|
this.document.endMarkedContent();
|
|
4262
4504
|
this._addContentToParentTree(content);
|
|
4263
4505
|
return content;
|
|
@@ -4310,6 +4552,15 @@ class PDFStructureElement {
|
|
|
4310
4552
|
}
|
|
4311
4553
|
});
|
|
4312
4554
|
}
|
|
4555
|
+
if (child instanceof PDFAnnotationReference) {
|
|
4556
|
+
const pageRef = this.document.page.dictionary;
|
|
4557
|
+
const objr = {
|
|
4558
|
+
Type: 'OBJR',
|
|
4559
|
+
Obj: child.annotationRef,
|
|
4560
|
+
Pg: pageRef
|
|
4561
|
+
};
|
|
4562
|
+
this.dictionary.data.K.push(objr);
|
|
4563
|
+
}
|
|
4313
4564
|
}
|
|
4314
4565
|
}
|
|
4315
4566
|
|
|
@@ -4403,6 +4654,13 @@ var MarkingsMixin = {
|
|
|
4403
4654
|
endMarkedContent() {
|
|
4404
4655
|
this.page.markings.pop();
|
|
4405
4656
|
this.addContent('EMC');
|
|
4657
|
+
if (this._textOptions) {
|
|
4658
|
+
delete this._textOptions.link;
|
|
4659
|
+
delete this._textOptions.goTo;
|
|
4660
|
+
delete this._textOptions.destination;
|
|
4661
|
+
delete this._textOptions.underline;
|
|
4662
|
+
delete this._textOptions.strike;
|
|
4663
|
+
}
|
|
4406
4664
|
return this;
|
|
4407
4665
|
},
|
|
4408
4666
|
struct(type, options = {}, children = null) {
|
|
@@ -4849,7 +5107,7 @@ var AttachmentsMixin = {
|
|
|
4849
5107
|
if (options.type) {
|
|
4850
5108
|
refBody.Subtype = options.type.replace('/', '#2F');
|
|
4851
5109
|
}
|
|
4852
|
-
const checksum =
|
|
5110
|
+
const checksum = md5Hex(new Uint8Array(data));
|
|
4853
5111
|
refBody.Params.CheckSum = new String(checksum);
|
|
4854
5112
|
refBody.Params.Size = data.byteLength;
|
|
4855
5113
|
let ref;
|
|
@@ -5492,7 +5750,7 @@ function renderRow(row, rowIndex) {
|
|
|
5492
5750
|
function renderCell(cell, rowStruct) {
|
|
5493
5751
|
const cellRenderer = () => {
|
|
5494
5752
|
if (cell.backgroundColor != null) {
|
|
5495
|
-
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(
|
|
5753
|
+
this.document.save().fillColor(cell.backgroundColor).rect(cell.x, cell.y, cell.width, cell.height).fill().restore();
|
|
5496
5754
|
}
|
|
5497
5755
|
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5498
5756
|
if (cell.debug) {
|
|
@@ -5553,20 +5811,20 @@ function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
|
5553
5811
|
const doc = this.document;
|
|
5554
5812
|
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5555
5813
|
if (border.top > 0) {
|
|
5556
|
-
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(
|
|
5814
|
+
doc.save().lineWidth(border.top).strokeColor(borderColor.top).rect(x, y, width, height).stroke().restore();
|
|
5557
5815
|
}
|
|
5558
5816
|
} else {
|
|
5559
5817
|
if (border.top > 0) {
|
|
5560
|
-
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(
|
|
5818
|
+
doc.save().lineWidth(border.top).moveTo(x, y).strokeColor(borderColor.top).lineTo(x + width, y).stroke().restore();
|
|
5561
5819
|
}
|
|
5562
5820
|
if (border.right > 0) {
|
|
5563
|
-
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(
|
|
5821
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).strokeColor(borderColor.right).lineTo(x + width, y + height).stroke().restore();
|
|
5564
5822
|
}
|
|
5565
5823
|
if (border.bottom > 0) {
|
|
5566
|
-
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(
|
|
5824
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).strokeColor(borderColor.bottom).lineTo(x, y + height).stroke().restore();
|
|
5567
5825
|
}
|
|
5568
5826
|
if (border.left > 0) {
|
|
5569
|
-
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(
|
|
5827
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).strokeColor(borderColor.left).lineTo(x, y).stroke().restore();
|
|
5570
5828
|
}
|
|
5571
5829
|
}
|
|
5572
5830
|
}
|
|
@@ -5773,6 +6031,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5773
6031
|
if (this.options.lang) {
|
|
5774
6032
|
this._root.data.Lang = new String(this.options.lang);
|
|
5775
6033
|
}
|
|
6034
|
+
if (this.options.pageLayout) {
|
|
6035
|
+
const layout = this.options.pageLayout;
|
|
6036
|
+
this._root.data.PageLayout = layout.charAt(0).toUpperCase() + layout.slice(1);
|
|
6037
|
+
}
|
|
5776
6038
|
this.page = null;
|
|
5777
6039
|
this.initMetadata();
|
|
5778
6040
|
this.initColor();
|