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.es.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import stream from 'stream';
|
|
2
2
|
import zlib from 'zlib';
|
|
3
|
-
import
|
|
3
|
+
import { concatBytes } from '@noble/hashes/utils';
|
|
4
|
+
import md5 from 'js-md5';
|
|
5
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
6
|
+
import { cbc, ecb } from '@noble/ciphers/aes';
|
|
4
7
|
import fs from 'fs';
|
|
5
8
|
import * as fontkit from 'fontkit';
|
|
6
9
|
import { EventEmitter } from 'events';
|
|
7
10
|
import LineBreaker from 'linebreak';
|
|
8
|
-
import exif from 'jpeg-exif';
|
|
9
11
|
import PNG from 'png-js';
|
|
10
12
|
|
|
11
13
|
class PDFAbstractReference {
|
|
@@ -363,6 +365,7 @@ class PDFPage {
|
|
|
363
365
|
this._options = options;
|
|
364
366
|
this.size = options.size || 'letter';
|
|
365
367
|
this.layout = options.layout || 'portrait';
|
|
368
|
+
this.userUnit = options.userUnit || 1.0;
|
|
366
369
|
const dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];
|
|
367
370
|
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
|
|
368
371
|
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
|
|
@@ -378,7 +381,8 @@ class PDFPage {
|
|
|
378
381
|
Parent: this.document._root.data.Pages,
|
|
379
382
|
MediaBox: [0, 0, this.width, this.height],
|
|
380
383
|
Contents: this.content,
|
|
381
|
-
Resources: this.resources
|
|
384
|
+
Resources: this.resources,
|
|
385
|
+
UserUnit: this.userUnit
|
|
382
386
|
});
|
|
383
387
|
this.markings = [];
|
|
384
388
|
}
|
|
@@ -451,6 +455,59 @@ class PDFNameTree extends PDFTree {
|
|
|
451
455
|
}
|
|
452
456
|
}
|
|
453
457
|
|
|
458
|
+
function md5Hash(data) {
|
|
459
|
+
return new Uint8Array(md5.arrayBuffer(data));
|
|
460
|
+
}
|
|
461
|
+
function md5Hex(data) {
|
|
462
|
+
return md5(data);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function sha256Hash(data) {
|
|
466
|
+
return sha256(data);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function aesCbcEncrypt(data, key, iv) {
|
|
470
|
+
let padding = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
|
|
471
|
+
return cbc(key, iv, {
|
|
472
|
+
disablePadding: !padding
|
|
473
|
+
}).encrypt(data);
|
|
474
|
+
}
|
|
475
|
+
function aesEcbEncrypt(data, key) {
|
|
476
|
+
return ecb(key, {
|
|
477
|
+
disablePadding: true
|
|
478
|
+
}).encrypt(data);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function rc4(data, key) {
|
|
482
|
+
const s = new Uint8Array(256);
|
|
483
|
+
for (let i = 0; i < 256; i++) {
|
|
484
|
+
s[i] = i;
|
|
485
|
+
}
|
|
486
|
+
let j = 0;
|
|
487
|
+
for (let i = 0; i < 256; i++) {
|
|
488
|
+
j = j + s[i] + key[i % key.length] & 0xff;
|
|
489
|
+
[s[i], s[j]] = [s[j], s[i]];
|
|
490
|
+
}
|
|
491
|
+
const output = new Uint8Array(data.length);
|
|
492
|
+
for (let i = 0, j = 0, k = 0; k < data.length; k++) {
|
|
493
|
+
i = i + 1 & 0xff;
|
|
494
|
+
j = j + s[i] & 0xff;
|
|
495
|
+
[s[i], s[j]] = [s[j], s[i]];
|
|
496
|
+
output[k] = data[k] ^ s[s[i] + s[j] & 0xff];
|
|
497
|
+
}
|
|
498
|
+
return output;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function randomBytes(length) {
|
|
502
|
+
const bytes = new Uint8Array(length);
|
|
503
|
+
if (globalThis.crypto?.getRandomValues) {
|
|
504
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
505
|
+
} else {
|
|
506
|
+
require('crypto').randomFillSync(bytes);
|
|
507
|
+
}
|
|
508
|
+
return bytes;
|
|
509
|
+
}
|
|
510
|
+
|
|
454
511
|
function inRange(value, rangeGroup) {
|
|
455
512
|
if (value < rangeGroup[0]) return false;
|
|
456
513
|
let startRange = 0;
|
|
@@ -551,10 +608,10 @@ class PDFSecurity {
|
|
|
551
608
|
}
|
|
552
609
|
infoStr += `${key}: ${info[key].valueOf()}\n`;
|
|
553
610
|
}
|
|
554
|
-
return
|
|
611
|
+
return Buffer.from(md5Hash(infoStr));
|
|
555
612
|
}
|
|
556
613
|
static generateRandomWordArray(bytes) {
|
|
557
|
-
return
|
|
614
|
+
return randomBytes(bytes);
|
|
558
615
|
}
|
|
559
616
|
static create(document) {
|
|
560
617
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -648,8 +705,8 @@ class PDFSecurity {
|
|
|
648
705
|
encDict.StrF = 'StdCF';
|
|
649
706
|
}
|
|
650
707
|
encDict.R = r;
|
|
651
|
-
encDict.O =
|
|
652
|
-
encDict.U =
|
|
708
|
+
encDict.O = Buffer.from(ownerPasswordEntry);
|
|
709
|
+
encDict.U = Buffer.from(userPasswordEntry);
|
|
653
710
|
encDict.P = permissions;
|
|
654
711
|
}
|
|
655
712
|
_setupEncryptionV5(encDict, options) {
|
|
@@ -659,10 +716,10 @@ class PDFSecurity {
|
|
|
659
716
|
const processedOwnerPassword = options.ownerPassword ? processPasswordR5(options.ownerPassword) : processedUserPassword;
|
|
660
717
|
this.encryptionKey = getEncryptionKeyR5(PDFSecurity.generateRandomWordArray);
|
|
661
718
|
const userPasswordEntry = getUserPasswordR5(processedUserPassword, PDFSecurity.generateRandomWordArray);
|
|
662
|
-
const userKeySalt =
|
|
719
|
+
const userKeySalt = userPasswordEntry.slice(40, 48);
|
|
663
720
|
const userEncryptionKeyEntry = getUserEncryptionKeyR5(processedUserPassword, userKeySalt, this.encryptionKey);
|
|
664
721
|
const ownerPasswordEntry = getOwnerPasswordR5(processedOwnerPassword, userPasswordEntry, PDFSecurity.generateRandomWordArray);
|
|
665
|
-
const ownerKeySalt =
|
|
722
|
+
const ownerKeySalt = ownerPasswordEntry.slice(40, 48);
|
|
666
723
|
const ownerEncryptionKeyEntry = getOwnerEncryptionKeyR5(processedOwnerPassword, ownerKeySalt, userPasswordEntry, this.encryptionKey);
|
|
667
724
|
const permsEntry = getEncryptedPermissionsR5(permissions, this.encryptionKey, PDFSecurity.generateRandomWordArray);
|
|
668
725
|
encDict.V = 5;
|
|
@@ -677,36 +734,37 @@ class PDFSecurity {
|
|
|
677
734
|
encDict.StmF = 'StdCF';
|
|
678
735
|
encDict.StrF = 'StdCF';
|
|
679
736
|
encDict.R = 5;
|
|
680
|
-
encDict.O =
|
|
681
|
-
encDict.OE =
|
|
682
|
-
encDict.U =
|
|
683
|
-
encDict.UE =
|
|
737
|
+
encDict.O = Buffer.from(ownerPasswordEntry);
|
|
738
|
+
encDict.OE = Buffer.from(ownerEncryptionKeyEntry);
|
|
739
|
+
encDict.U = Buffer.from(userPasswordEntry);
|
|
740
|
+
encDict.UE = Buffer.from(userEncryptionKeyEntry);
|
|
684
741
|
encDict.P = permissions;
|
|
685
|
-
encDict.Perms =
|
|
742
|
+
encDict.Perms = Buffer.from(permsEntry);
|
|
686
743
|
}
|
|
687
744
|
getEncryptFn(obj, gen) {
|
|
688
745
|
let digest;
|
|
689
746
|
if (this.version < 5) {
|
|
690
|
-
|
|
747
|
+
const suffix = new Uint8Array([obj & 0xff, obj >> 8 & 0xff, obj >> 16 & 0xff, gen & 0xff, gen >> 8 & 0xff]);
|
|
748
|
+
digest = concatBytes(this.encryptionKey, suffix);
|
|
691
749
|
}
|
|
692
750
|
if (this.version === 1 || this.version === 2) {
|
|
693
|
-
let key =
|
|
694
|
-
|
|
695
|
-
|
|
751
|
+
let key = md5Hash(digest);
|
|
752
|
+
const keyLen = Math.min(16, this.keyBits / 8 + 5);
|
|
753
|
+
key = key.slice(0, keyLen);
|
|
754
|
+
return buffer => Buffer.from(rc4(new Uint8Array(buffer), key));
|
|
696
755
|
}
|
|
697
756
|
let key;
|
|
698
757
|
if (this.version === 4) {
|
|
699
|
-
|
|
758
|
+
const saltMarker = new Uint8Array([0x73, 0x41, 0x6c, 0x54]);
|
|
759
|
+
key = md5Hash(concatBytes(digest, saltMarker));
|
|
700
760
|
} else {
|
|
701
761
|
key = this.encryptionKey;
|
|
702
762
|
}
|
|
703
763
|
const iv = PDFSecurity.generateRandomWordArray(16);
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
iv
|
|
764
|
+
return buffer => {
|
|
765
|
+
const encrypted = aesCbcEncrypt(new Uint8Array(buffer), key, iv, true);
|
|
766
|
+
return Buffer.from(concatBytes(iv, encrypted));
|
|
708
767
|
};
|
|
709
|
-
return buffer => wordArrayToBuffer(iv.clone().concat(CryptoJS.AES.encrypt(CryptoJS.lib.WordArray.create(buffer), key, options).ciphertext));
|
|
710
768
|
}
|
|
711
769
|
end() {
|
|
712
770
|
this.dictionary.end();
|
|
@@ -759,90 +817,98 @@ function getPermissionsR3() {
|
|
|
759
817
|
return permissions;
|
|
760
818
|
}
|
|
761
819
|
function getUserPasswordR2(encryptionKey) {
|
|
762
|
-
return
|
|
820
|
+
return rc4(processPasswordR2R3R4(), encryptionKey);
|
|
763
821
|
}
|
|
764
822
|
function getUserPasswordR3R4(documentId, encryptionKey) {
|
|
765
|
-
const key = encryptionKey.
|
|
766
|
-
let cipher =
|
|
823
|
+
const key = encryptionKey.slice();
|
|
824
|
+
let cipher = md5Hash(concatBytes(processPasswordR2R3R4(), new Uint8Array(documentId)));
|
|
767
825
|
for (let i = 0; i < 20; i++) {
|
|
768
|
-
const
|
|
769
|
-
for (let j = 0; j <
|
|
770
|
-
|
|
826
|
+
const xorKey = new Uint8Array(key.length);
|
|
827
|
+
for (let j = 0; j < key.length; j++) {
|
|
828
|
+
xorKey[j] = encryptionKey[j] ^ i;
|
|
771
829
|
}
|
|
772
|
-
cipher =
|
|
830
|
+
cipher = rc4(cipher, xorKey);
|
|
773
831
|
}
|
|
774
|
-
|
|
832
|
+
const result = new Uint8Array(32);
|
|
833
|
+
result.set(cipher);
|
|
834
|
+
return result;
|
|
775
835
|
}
|
|
776
836
|
function getOwnerPasswordR2R3R4(r, keyBits, paddedUserPassword, paddedOwnerPassword) {
|
|
777
837
|
let digest = paddedOwnerPassword;
|
|
778
838
|
let round = r >= 3 ? 51 : 1;
|
|
779
839
|
for (let i = 0; i < round; i++) {
|
|
780
|
-
digest =
|
|
840
|
+
digest = md5Hash(digest);
|
|
781
841
|
}
|
|
782
|
-
const
|
|
783
|
-
key
|
|
842
|
+
const keyLen = keyBits / 8;
|
|
843
|
+
let key = digest.slice(0, keyLen);
|
|
784
844
|
let cipher = paddedUserPassword;
|
|
785
845
|
round = r >= 3 ? 20 : 1;
|
|
786
846
|
for (let i = 0; i < round; i++) {
|
|
787
|
-
const
|
|
788
|
-
for (let j = 0; j <
|
|
789
|
-
|
|
847
|
+
const xorKey = new Uint8Array(keyLen);
|
|
848
|
+
for (let j = 0; j < keyLen; j++) {
|
|
849
|
+
xorKey[j] = key[j] ^ i;
|
|
790
850
|
}
|
|
791
|
-
cipher =
|
|
851
|
+
cipher = rc4(cipher, xorKey);
|
|
792
852
|
}
|
|
793
853
|
return cipher;
|
|
794
854
|
}
|
|
795
855
|
function getEncryptionKeyR2R3R4(r, keyBits, documentId, paddedUserPassword, ownerPasswordEntry, permissions) {
|
|
796
|
-
|
|
856
|
+
const permBytes = new Uint8Array([permissions & 0xff, permissions >> 8 & 0xff, permissions >> 16 & 0xff, permissions >> 24 & 0xff]);
|
|
857
|
+
let key = concatBytes(paddedUserPassword, ownerPasswordEntry, permBytes, new Uint8Array(documentId));
|
|
797
858
|
const round = r >= 3 ? 51 : 1;
|
|
859
|
+
const keyLen = keyBits / 8;
|
|
798
860
|
for (let i = 0; i < round; i++) {
|
|
799
|
-
key =
|
|
800
|
-
key
|
|
861
|
+
key = md5Hash(key);
|
|
862
|
+
key = key.slice(0, keyLen);
|
|
801
863
|
}
|
|
802
864
|
return key;
|
|
803
865
|
}
|
|
804
866
|
function getUserPasswordR5(processedUserPassword, generateRandomWordArray) {
|
|
805
867
|
const validationSalt = generateRandomWordArray(8);
|
|
806
868
|
const keySalt = generateRandomWordArray(8);
|
|
807
|
-
|
|
869
|
+
const hash = sha256Hash(concatBytes(processedUserPassword, validationSalt));
|
|
870
|
+
return concatBytes(hash, validationSalt, keySalt);
|
|
808
871
|
}
|
|
809
872
|
function getUserEncryptionKeyR5(processedUserPassword, userKeySalt, encryptionKey) {
|
|
810
|
-
const key =
|
|
811
|
-
const
|
|
812
|
-
|
|
813
|
-
padding: CryptoJS.pad.NoPadding,
|
|
814
|
-
iv: CryptoJS.lib.WordArray.create(null, 16)
|
|
815
|
-
};
|
|
816
|
-
return CryptoJS.AES.encrypt(encryptionKey, key, options).ciphertext;
|
|
873
|
+
const key = sha256Hash(concatBytes(processedUserPassword, userKeySalt));
|
|
874
|
+
const iv = new Uint8Array(16);
|
|
875
|
+
return aesCbcEncrypt(encryptionKey, key, iv, false);
|
|
817
876
|
}
|
|
818
877
|
function getOwnerPasswordR5(processedOwnerPassword, userPasswordEntry, generateRandomWordArray) {
|
|
819
878
|
const validationSalt = generateRandomWordArray(8);
|
|
820
879
|
const keySalt = generateRandomWordArray(8);
|
|
821
|
-
|
|
880
|
+
const hash = sha256Hash(concatBytes(processedOwnerPassword, validationSalt, userPasswordEntry));
|
|
881
|
+
return concatBytes(hash, validationSalt, keySalt);
|
|
822
882
|
}
|
|
823
883
|
function getOwnerEncryptionKeyR5(processedOwnerPassword, ownerKeySalt, userPasswordEntry, encryptionKey) {
|
|
824
|
-
const key =
|
|
825
|
-
const
|
|
826
|
-
|
|
827
|
-
padding: CryptoJS.pad.NoPadding,
|
|
828
|
-
iv: CryptoJS.lib.WordArray.create(null, 16)
|
|
829
|
-
};
|
|
830
|
-
return CryptoJS.AES.encrypt(encryptionKey, key, options).ciphertext;
|
|
884
|
+
const key = sha256Hash(concatBytes(processedOwnerPassword, ownerKeySalt, userPasswordEntry));
|
|
885
|
+
const iv = new Uint8Array(16);
|
|
886
|
+
return aesCbcEncrypt(encryptionKey, key, iv, false);
|
|
831
887
|
}
|
|
832
888
|
function getEncryptionKeyR5(generateRandomWordArray) {
|
|
833
889
|
return generateRandomWordArray(32);
|
|
834
890
|
}
|
|
835
891
|
function getEncryptedPermissionsR5(permissions, encryptionKey, generateRandomWordArray) {
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
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);
|
|
842
908
|
}
|
|
843
909
|
function processPasswordR2R3R4() {
|
|
844
910
|
let password = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
845
|
-
const out =
|
|
911
|
+
const out = new Uint8Array(32);
|
|
846
912
|
const length = password.length;
|
|
847
913
|
let index = 0;
|
|
848
914
|
while (index < length && index < 32) {
|
|
@@ -857,27 +923,17 @@ function processPasswordR2R3R4() {
|
|
|
857
923
|
out[index] = PASSWORD_PADDING[index - length];
|
|
858
924
|
index++;
|
|
859
925
|
}
|
|
860
|
-
return
|
|
926
|
+
return out;
|
|
861
927
|
}
|
|
862
928
|
function processPasswordR5() {
|
|
863
929
|
let password = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
864
930
|
password = unescape(encodeURIComponent(saslprep(password)));
|
|
865
931
|
const length = Math.min(127, password.length);
|
|
866
|
-
const out =
|
|
932
|
+
const out = new Uint8Array(length);
|
|
867
933
|
for (let i = 0; i < length; i++) {
|
|
868
934
|
out[i] = password.charCodeAt(i);
|
|
869
935
|
}
|
|
870
|
-
return
|
|
871
|
-
}
|
|
872
|
-
function lsbFirstWord(data) {
|
|
873
|
-
return (data & 0xff) << 24 | (data & 0xff00) << 8 | data >> 8 & 0xff00 | data >> 24 & 0xff;
|
|
874
|
-
}
|
|
875
|
-
function wordArrayToBuffer(wordArray) {
|
|
876
|
-
const byteArray = [];
|
|
877
|
-
for (let i = 0; i < wordArray.sigBytes; i++) {
|
|
878
|
-
byteArray.push(wordArray.words[Math.floor(i / 4)] >> 8 * (3 - i % 4) & 0xff);
|
|
879
|
-
}
|
|
880
|
-
return Buffer.from(byteArray);
|
|
936
|
+
return out;
|
|
881
937
|
}
|
|
882
938
|
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];
|
|
883
939
|
|
|
@@ -1485,86 +1541,176 @@ const parameters = {
|
|
|
1485
1541
|
Z: 0,
|
|
1486
1542
|
z: 0
|
|
1487
1543
|
};
|
|
1544
|
+
const isCommand = function (c) {
|
|
1545
|
+
return c in parameters;
|
|
1546
|
+
};
|
|
1547
|
+
const isWsp = function (c) {
|
|
1548
|
+
const codePoint = c.codePointAt(0);
|
|
1549
|
+
return codePoint === 0x20 || codePoint === 0x9 || codePoint === 0xd || codePoint === 0xa;
|
|
1550
|
+
};
|
|
1551
|
+
const isDigit = function (c) {
|
|
1552
|
+
const codePoint = c.codePointAt(0);
|
|
1553
|
+
if (codePoint == null) {
|
|
1554
|
+
return false;
|
|
1555
|
+
}
|
|
1556
|
+
return 48 <= codePoint && codePoint <= 57;
|
|
1557
|
+
};
|
|
1558
|
+
const readNumber = function (string, cursor) {
|
|
1559
|
+
let i = cursor;
|
|
1560
|
+
let value = '';
|
|
1561
|
+
let state = 'none';
|
|
1562
|
+
for (; i < string.length; i += 1) {
|
|
1563
|
+
const c = string[i];
|
|
1564
|
+
if (c === '+' || c === '-') {
|
|
1565
|
+
if (state === 'none') {
|
|
1566
|
+
state = 'sign';
|
|
1567
|
+
value += c;
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
if (state === 'e') {
|
|
1571
|
+
state = 'exponent_sign';
|
|
1572
|
+
value += c;
|
|
1573
|
+
continue;
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
if (isDigit(c)) {
|
|
1577
|
+
if (state === 'none' || state === 'sign' || state === 'whole') {
|
|
1578
|
+
state = 'whole';
|
|
1579
|
+
value += c;
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
if (state === 'decimal_point' || state === 'decimal') {
|
|
1583
|
+
state = 'decimal';
|
|
1584
|
+
value += c;
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
if (state === 'e' || state === 'exponent_sign' || state === 'exponent') {
|
|
1588
|
+
state = 'exponent';
|
|
1589
|
+
value += c;
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
if (c === '.') {
|
|
1594
|
+
if (state === 'none' || state === 'sign' || state === 'whole') {
|
|
1595
|
+
state = 'decimal_point';
|
|
1596
|
+
value += c;
|
|
1597
|
+
continue;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
if (c === 'E' || c === 'e') {
|
|
1601
|
+
if (state === 'whole' || state === 'decimal_point' || state === 'decimal') {
|
|
1602
|
+
state = 'e';
|
|
1603
|
+
value += c;
|
|
1604
|
+
continue;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
break;
|
|
1608
|
+
}
|
|
1609
|
+
const number = Number.parseFloat(value);
|
|
1610
|
+
if (Number.isNaN(number)) {
|
|
1611
|
+
return [cursor, null];
|
|
1612
|
+
}
|
|
1613
|
+
return [i - 1, number];
|
|
1614
|
+
};
|
|
1488
1615
|
const parse = function (path) {
|
|
1489
|
-
|
|
1490
|
-
|
|
1616
|
+
const pathData = [];
|
|
1617
|
+
let command = null;
|
|
1491
1618
|
let args = [];
|
|
1492
|
-
let
|
|
1493
|
-
let
|
|
1494
|
-
let
|
|
1495
|
-
for (let
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1619
|
+
let argsCount = 0;
|
|
1620
|
+
let canHaveComma = false;
|
|
1621
|
+
let hadComma = false;
|
|
1622
|
+
for (let i = 0; i < path.length; i += 1) {
|
|
1623
|
+
const c = path.charAt(i);
|
|
1624
|
+
if (isWsp(c)) {
|
|
1625
|
+
continue;
|
|
1626
|
+
}
|
|
1627
|
+
if (canHaveComma && c === ',') {
|
|
1628
|
+
if (hadComma) {
|
|
1629
|
+
break;
|
|
1630
|
+
}
|
|
1631
|
+
hadComma = true;
|
|
1632
|
+
continue;
|
|
1633
|
+
}
|
|
1634
|
+
if (isCommand(c)) {
|
|
1635
|
+
if (hadComma) {
|
|
1636
|
+
return pathData;
|
|
1637
|
+
}
|
|
1638
|
+
if (command == null) {
|
|
1639
|
+
if (c !== 'M' && c !== 'm') {
|
|
1640
|
+
return pathData;
|
|
1501
1641
|
}
|
|
1502
|
-
|
|
1503
|
-
|
|
1642
|
+
} else {
|
|
1643
|
+
if (args.length !== 0) {
|
|
1644
|
+
return pathData;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
command = c;
|
|
1648
|
+
args = [];
|
|
1649
|
+
argsCount = parameters[command];
|
|
1650
|
+
canHaveComma = false;
|
|
1651
|
+
if (argsCount === 0) {
|
|
1652
|
+
pathData.push({
|
|
1653
|
+
command,
|
|
1504
1654
|
args
|
|
1505
|
-
};
|
|
1506
|
-
args = [];
|
|
1507
|
-
curArg = '';
|
|
1508
|
-
foundDecimal = false;
|
|
1655
|
+
});
|
|
1509
1656
|
}
|
|
1510
|
-
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1657
|
+
continue;
|
|
1658
|
+
}
|
|
1659
|
+
if (command == null) {
|
|
1660
|
+
return pathData;
|
|
1661
|
+
}
|
|
1662
|
+
let newCursor = i;
|
|
1663
|
+
let number = null;
|
|
1664
|
+
if (command === 'A' || command === 'a') {
|
|
1665
|
+
const position = args.length;
|
|
1666
|
+
if (position === 0 || position === 1) {
|
|
1667
|
+
if (c !== '+' && c !== '-') {
|
|
1668
|
+
[newCursor, number] = readNumber(path, i);
|
|
1669
|
+
}
|
|
1514
1670
|
}
|
|
1515
|
-
if (
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
if (cmd === 'M') {
|
|
1522
|
-
cmd = 'L';
|
|
1671
|
+
if (position === 2 || position === 5 || position === 6) {
|
|
1672
|
+
[newCursor, number] = readNumber(path, i);
|
|
1673
|
+
}
|
|
1674
|
+
if (position === 3 || position === 4) {
|
|
1675
|
+
if (c === '0') {
|
|
1676
|
+
number = 0;
|
|
1523
1677
|
}
|
|
1524
|
-
if (
|
|
1525
|
-
|
|
1678
|
+
if (c === '1') {
|
|
1679
|
+
number = 1;
|
|
1526
1680
|
}
|
|
1527
|
-
} else {
|
|
1528
|
-
args[args.length] = +curArg;
|
|
1529
1681
|
}
|
|
1530
|
-
foundDecimal = c === '.';
|
|
1531
|
-
curArg = ['-', '.'].includes(c) ? c : '';
|
|
1532
1682
|
} else {
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1683
|
+
[newCursor, number] = readNumber(path, i);
|
|
1684
|
+
}
|
|
1685
|
+
if (number == null) {
|
|
1686
|
+
return pathData;
|
|
1687
|
+
}
|
|
1688
|
+
args.push(number);
|
|
1689
|
+
canHaveComma = true;
|
|
1690
|
+
hadComma = false;
|
|
1691
|
+
i = newCursor;
|
|
1692
|
+
if (args.length === argsCount) {
|
|
1693
|
+
pathData.push({
|
|
1694
|
+
command,
|
|
1543
1695
|
args
|
|
1544
|
-
};
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
cmd = 'L';
|
|
1696
|
+
});
|
|
1697
|
+
if (command === 'M') {
|
|
1698
|
+
command = 'L';
|
|
1548
1699
|
}
|
|
1549
|
-
if (
|
|
1550
|
-
|
|
1700
|
+
if (command === 'm') {
|
|
1701
|
+
command = 'l';
|
|
1551
1702
|
}
|
|
1552
|
-
|
|
1553
|
-
args[args.length] = +curArg;
|
|
1703
|
+
args = [];
|
|
1554
1704
|
}
|
|
1555
1705
|
}
|
|
1556
|
-
|
|
1557
|
-
cmd,
|
|
1558
|
-
args
|
|
1559
|
-
};
|
|
1560
|
-
return ret;
|
|
1706
|
+
return pathData;
|
|
1561
1707
|
};
|
|
1562
1708
|
const apply = function (commands, doc) {
|
|
1563
1709
|
cx = cy = px = py = sx = sy = 0;
|
|
1564
1710
|
for (let i = 0; i < commands.length; i++) {
|
|
1565
1711
|
const c = commands[i];
|
|
1566
|
-
if (typeof runners[c.
|
|
1567
|
-
runners[c.
|
|
1712
|
+
if (typeof runners[c.command] === 'function') {
|
|
1713
|
+
runners[c.command](doc, c.args);
|
|
1568
1714
|
}
|
|
1569
1715
|
}
|
|
1570
1716
|
};
|
|
@@ -2603,7 +2749,7 @@ begincmap
|
|
|
2603
2749
|
1 begincodespacerange
|
|
2604
2750
|
<0000><ffff>
|
|
2605
2751
|
endcodespacerange
|
|
2606
|
-
|
|
2752
|
+
${ranges.length} beginbfrange
|
|
2607
2753
|
${ranges.join('\n')}
|
|
2608
2754
|
endbfrange
|
|
2609
2755
|
endcmap
|
|
@@ -2788,6 +2934,7 @@ class LineWrapper extends EventEmitter {
|
|
|
2788
2934
|
this.document = document;
|
|
2789
2935
|
this.horizontalScaling = options.horizontalScaling || 100;
|
|
2790
2936
|
this.indent = (options.indent || 0) * this.horizontalScaling / 100;
|
|
2937
|
+
this.indentAllLines = options.indentAllLines || false;
|
|
2791
2938
|
this.characterSpacing = (options.characterSpacing || 0) * this.horizontalScaling / 100;
|
|
2792
2939
|
this.wordSpacing = (options.wordSpacing === 0) * this.horizontalScaling / 100;
|
|
2793
2940
|
this.columns = options.columns || 1;
|
|
@@ -2981,12 +3128,14 @@ class LineWrapper extends EventEmitter {
|
|
|
2981
3128
|
}
|
|
2982
3129
|
emitLine();
|
|
2983
3130
|
if (PDFNumber(this.document.y + lh) > this.maxY) {
|
|
3131
|
+
this.emit('sectionEnd', options, this);
|
|
2984
3132
|
const shouldContinue = this.nextSection();
|
|
2985
3133
|
if (!shouldContinue) {
|
|
2986
3134
|
wc = 0;
|
|
2987
3135
|
buffer = '';
|
|
2988
3136
|
return false;
|
|
2989
3137
|
}
|
|
3138
|
+
this.emit('sectionStart', options, this);
|
|
2990
3139
|
}
|
|
2991
3140
|
if (bk.required) {
|
|
2992
3141
|
this.spaceLeft = this.lineWidth;
|
|
@@ -3019,7 +3168,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3019
3168
|
}
|
|
3020
3169
|
}
|
|
3021
3170
|
nextSection(options) {
|
|
3022
|
-
this.emit('sectionEnd', options, this);
|
|
3023
3171
|
if (++this.column > this.columns) {
|
|
3024
3172
|
if (this.height != null) {
|
|
3025
3173
|
return false;
|
|
@@ -3028,7 +3176,13 @@ class LineWrapper extends EventEmitter {
|
|
|
3028
3176
|
this.column = 1;
|
|
3029
3177
|
this.startY = this.document.page.margins.top;
|
|
3030
3178
|
this.maxY = this.document.page.maxY();
|
|
3031
|
-
this.
|
|
3179
|
+
if (this.indentAllLines) {
|
|
3180
|
+
const indent = this.continuedX || this.indent;
|
|
3181
|
+
this.document.x += indent;
|
|
3182
|
+
this.lineWidth -= indent;
|
|
3183
|
+
} else {
|
|
3184
|
+
this.document.x = this.startX;
|
|
3185
|
+
}
|
|
3032
3186
|
if (this.document._fillColor) {
|
|
3033
3187
|
this.document.fillColor(...this.document._fillColor);
|
|
3034
3188
|
}
|
|
@@ -3038,7 +3192,6 @@ class LineWrapper extends EventEmitter {
|
|
|
3038
3192
|
this.document.y = this.startY;
|
|
3039
3193
|
this.emit('columnBreak', options, this);
|
|
3040
3194
|
}
|
|
3041
|
-
this.emit('sectionStart', options, this);
|
|
3042
3195
|
return true;
|
|
3043
3196
|
}
|
|
3044
3197
|
}
|
|
@@ -3046,6 +3199,15 @@ class LineWrapper extends EventEmitter {
|
|
|
3046
3199
|
const {
|
|
3047
3200
|
number
|
|
3048
3201
|
} = PDFObject;
|
|
3202
|
+
function formatListLabel(n, listType) {
|
|
3203
|
+
if (listType === 'numbered') {
|
|
3204
|
+
return `${n}.`;
|
|
3205
|
+
}
|
|
3206
|
+
var letter = String.fromCharCode((n - 1) % 26 + 65);
|
|
3207
|
+
var times = Math.floor((n - 1) / 26 + 1);
|
|
3208
|
+
var text = Array(times + 1).join(letter);
|
|
3209
|
+
return `${text}.`;
|
|
3210
|
+
}
|
|
3049
3211
|
var TextMixin = {
|
|
3050
3212
|
initText() {
|
|
3051
3213
|
this._line = this._line.bind(this);
|
|
@@ -3223,7 +3385,7 @@ var TextMixin = {
|
|
|
3223
3385
|
this.y = y;
|
|
3224
3386
|
return height;
|
|
3225
3387
|
},
|
|
3226
|
-
list(list, x, y, options
|
|
3388
|
+
list(list, x, y, options) {
|
|
3227
3389
|
options = this._initOptions(x, y, options);
|
|
3228
3390
|
const listType = options.listType || 'bullet';
|
|
3229
3391
|
const unit = Math.round(this._font.ascender / 1000 * this._fontSize);
|
|
@@ -3253,19 +3415,8 @@ var TextMixin = {
|
|
|
3253
3415
|
}
|
|
3254
3416
|
};
|
|
3255
3417
|
flatten(list);
|
|
3256
|
-
const label = function (n) {
|
|
3257
|
-
switch (listType) {
|
|
3258
|
-
case 'numbered':
|
|
3259
|
-
return `${n}.`;
|
|
3260
|
-
case 'lettered':
|
|
3261
|
-
var letter = String.fromCharCode((n - 1) % 26 + 65);
|
|
3262
|
-
var times = Math.floor((n - 1) / 26 + 1);
|
|
3263
|
-
var text = Array(times + 1).join(letter);
|
|
3264
|
-
return `${text}.`;
|
|
3265
|
-
}
|
|
3266
|
-
};
|
|
3267
3418
|
const drawListItem = function (listItem, i) {
|
|
3268
|
-
wrapper = new LineWrapper(this, options);
|
|
3419
|
+
const wrapper = new LineWrapper(this, options);
|
|
3269
3420
|
wrapper.on('line', this._line);
|
|
3270
3421
|
level = 1;
|
|
3271
3422
|
wrapper.once('firstLine', () => {
|
|
@@ -3300,7 +3451,7 @@ var TextMixin = {
|
|
|
3300
3451
|
break;
|
|
3301
3452
|
case 'numbered':
|
|
3302
3453
|
case 'lettered':
|
|
3303
|
-
var text =
|
|
3454
|
+
var text = formatListLabel(numbers[i - 1], listType);
|
|
3304
3455
|
this._fragment(text, this.x - indent, this.y, options);
|
|
3305
3456
|
break;
|
|
3306
3457
|
}
|
|
@@ -3373,11 +3524,11 @@ var TextMixin = {
|
|
|
3373
3524
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
3374
3525
|
let wrapper = arguments.length > 2 ? arguments[2] : undefined;
|
|
3375
3526
|
this._fragment(text, this.x, this.y, options);
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
this.x += this.widthOfString(text, options);
|
|
3379
|
-
} else {
|
|
3527
|
+
if (wrapper) {
|
|
3528
|
+
const lineGap = options.lineGap || this._lineGap || 0;
|
|
3380
3529
|
this.y += this.currentLineHeight(true) + lineGap;
|
|
3530
|
+
} else {
|
|
3531
|
+
this.x += this.widthOfString(text, options);
|
|
3381
3532
|
}
|
|
3382
3533
|
},
|
|
3383
3534
|
_fragment(text, x, y, options) {
|
|
@@ -3441,7 +3592,11 @@ var TextMixin = {
|
|
|
3441
3592
|
}
|
|
3442
3593
|
const renderedWidth = options.textWidth + wordSpacing * (options.wordCount - 1) + characterSpacing * (text.length - 1);
|
|
3443
3594
|
if (options.link != null) {
|
|
3444
|
-
|
|
3595
|
+
const linkOptions = {};
|
|
3596
|
+
if (this._currentStructureElement && this._currentStructureElement.dictionary.data.S === 'Link') {
|
|
3597
|
+
linkOptions.structParent = this._currentStructureElement;
|
|
3598
|
+
}
|
|
3599
|
+
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link, linkOptions);
|
|
3445
3600
|
}
|
|
3446
3601
|
if (options.goTo != null) {
|
|
3447
3602
|
this.goTo(x, y, renderedWidth, this.currentLineHeight(), options.goTo);
|
|
@@ -3570,6 +3725,47 @@ var TextMixin = {
|
|
|
3570
3725
|
}
|
|
3571
3726
|
};
|
|
3572
3727
|
|
|
3728
|
+
const parseExifOrientation = data => {
|
|
3729
|
+
if (!data || data.length < 20) return null;
|
|
3730
|
+
let pos = 2;
|
|
3731
|
+
while (pos < data.length - 4) {
|
|
3732
|
+
while (pos < data.length && data[pos] !== 0xff) pos++;
|
|
3733
|
+
if (pos >= data.length - 4) return null;
|
|
3734
|
+
const marker = data.readUInt16BE(pos);
|
|
3735
|
+
pos += 2;
|
|
3736
|
+
if (marker === 0xffda) return null;
|
|
3737
|
+
if (marker >= 0xffd0 && marker <= 0xffd9 || marker === 0xff01) continue;
|
|
3738
|
+
if (pos + 2 > data.length) return null;
|
|
3739
|
+
const segmentLength = data.readUInt16BE(pos);
|
|
3740
|
+
if (marker === 0xffe1 && pos + 8 <= data.length) {
|
|
3741
|
+
const exifHeader = data.subarray(pos + 2, pos + 8).toString('binary');
|
|
3742
|
+
if (exifHeader === 'Exif\x00\x00') {
|
|
3743
|
+
const tiffStart = pos + 8;
|
|
3744
|
+
if (tiffStart + 8 > data.length) return null;
|
|
3745
|
+
const byteOrder = data.subarray(tiffStart, tiffStart + 2).toString('ascii');
|
|
3746
|
+
const isLittleEndian = byteOrder === 'II';
|
|
3747
|
+
if (!isLittleEndian && byteOrder !== 'MM') return null;
|
|
3748
|
+
const read16 = isLittleEndian ? o => data.readUInt16LE(o) : o => data.readUInt16BE(o);
|
|
3749
|
+
const read32 = isLittleEndian ? o => data.readUInt32LE(o) : o => data.readUInt32BE(o);
|
|
3750
|
+
if (read16(tiffStart + 2) !== 42) return null;
|
|
3751
|
+
const ifdPos = tiffStart + read32(tiffStart + 4);
|
|
3752
|
+
if (ifdPos + 2 > data.length) return null;
|
|
3753
|
+
const entryCount = read16(ifdPos);
|
|
3754
|
+
for (let i = 0; i < entryCount; i++) {
|
|
3755
|
+
const entryPos = ifdPos + 2 + i * 12;
|
|
3756
|
+
if (entryPos + 12 > data.length) return null;
|
|
3757
|
+
if (read16(entryPos) === 0x0112) {
|
|
3758
|
+
const value = read16(entryPos + 8);
|
|
3759
|
+
return value >= 1 && value <= 8 ? value : null;
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
return null;
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
pos += segmentLength;
|
|
3766
|
+
}
|
|
3767
|
+
return null;
|
|
3768
|
+
};
|
|
3573
3769
|
const MARKERS = [0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf];
|
|
3574
3770
|
const COLOR_SPACE_MAP = {
|
|
3575
3771
|
1: 'DeviceGray',
|
|
@@ -3584,9 +3780,11 @@ class JPEG {
|
|
|
3584
3780
|
if (this.data.readUInt16BE(0) !== 0xffd8) {
|
|
3585
3781
|
throw 'SOI not found in JPEG';
|
|
3586
3782
|
}
|
|
3587
|
-
this.orientation =
|
|
3783
|
+
this.orientation = parseExifOrientation(this.data) || 1;
|
|
3588
3784
|
let pos = 2;
|
|
3589
3785
|
while (pos < this.data.length) {
|
|
3786
|
+
while (pos < this.data.length && this.data[pos] !== 0xff) pos++;
|
|
3787
|
+
if (pos >= this.data.length) break;
|
|
3590
3788
|
marker = this.data.readUInt16BE(pos);
|
|
3591
3789
|
pos += 2;
|
|
3592
3790
|
if (MARKERS.includes(marker)) {
|
|
@@ -3738,12 +3936,16 @@ class PNGImage {
|
|
|
3738
3936
|
}
|
|
3739
3937
|
loadIndexedAlphaChannel() {
|
|
3740
3938
|
const transparency = this.image.transparency.indexed;
|
|
3939
|
+
const isInterlaced = this.image.interlaceMethod === 1;
|
|
3741
3940
|
return this.image.decodePixels(pixels => {
|
|
3742
3941
|
const alphaChannel = Buffer.alloc(this.width * this.height);
|
|
3743
3942
|
let i = 0;
|
|
3744
3943
|
for (let j = 0, end = pixels.length; j < end; j++) {
|
|
3745
3944
|
alphaChannel[i++] = transparency[pixels[j]];
|
|
3746
3945
|
}
|
|
3946
|
+
if (isInterlaced) {
|
|
3947
|
+
this.imgData = zlib.deflateSync(Buffer.from(pixels));
|
|
3948
|
+
}
|
|
3747
3949
|
this.alphaChannel = zlib.deflateSync(alphaChannel);
|
|
3748
3950
|
return this.finalize();
|
|
3749
3951
|
});
|
|
@@ -3973,6 +4175,12 @@ var ImagesMixin = {
|
|
|
3973
4175
|
}
|
|
3974
4176
|
};
|
|
3975
4177
|
|
|
4178
|
+
class PDFAnnotationReference {
|
|
4179
|
+
constructor(annotationRef) {
|
|
4180
|
+
this.annotationRef = annotationRef;
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
|
|
3976
4184
|
var AnnotationsMixin = {
|
|
3977
4185
|
annotate(x, y, w, h, options) {
|
|
3978
4186
|
options.Type = 'Annot';
|
|
@@ -3990,12 +4198,18 @@ var AnnotationsMixin = {
|
|
|
3990
4198
|
if (typeof options.Dest === 'string') {
|
|
3991
4199
|
options.Dest = new String(options.Dest);
|
|
3992
4200
|
}
|
|
4201
|
+
const structParent = options.structParent;
|
|
4202
|
+
delete options.structParent;
|
|
3993
4203
|
for (let key in options) {
|
|
3994
4204
|
const val = options[key];
|
|
3995
4205
|
options[key[0].toUpperCase() + key.slice(1)] = val;
|
|
3996
4206
|
}
|
|
3997
4207
|
const ref = this.ref(options);
|
|
3998
4208
|
this.page.annotations.push(ref);
|
|
4209
|
+
if (structParent && typeof structParent.add === 'function') {
|
|
4210
|
+
const annotRef = new PDFAnnotationReference(ref);
|
|
4211
|
+
structParent.add(annotRef);
|
|
4212
|
+
}
|
|
3999
4213
|
ref.end();
|
|
4000
4214
|
return this;
|
|
4001
4215
|
},
|
|
@@ -4042,6 +4256,9 @@ var AnnotationsMixin = {
|
|
|
4042
4256
|
});
|
|
4043
4257
|
options.A.end();
|
|
4044
4258
|
}
|
|
4259
|
+
if (options.structParent && !options.Contents) {
|
|
4260
|
+
options.Contents = new String('');
|
|
4261
|
+
}
|
|
4045
4262
|
return this.annotate(x, y, w, h, options);
|
|
4046
4263
|
},
|
|
4047
4264
|
_markup(x, y, w, h) {
|
|
@@ -4123,16 +4340,27 @@ var AnnotationsMixin = {
|
|
|
4123
4340
|
}
|
|
4124
4341
|
};
|
|
4125
4342
|
|
|
4343
|
+
const DEFAULT_OPTIONS = {
|
|
4344
|
+
top: 0,
|
|
4345
|
+
left: 0,
|
|
4346
|
+
zoom: 0,
|
|
4347
|
+
fit: true,
|
|
4348
|
+
pageNumber: null,
|
|
4349
|
+
expanded: false
|
|
4350
|
+
};
|
|
4126
4351
|
class PDFOutline {
|
|
4127
4352
|
constructor(document, parent, title, dest) {
|
|
4128
|
-
let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] :
|
|
4129
|
-
expanded: false
|
|
4130
|
-
};
|
|
4353
|
+
let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : DEFAULT_OPTIONS;
|
|
4131
4354
|
this.document = document;
|
|
4132
4355
|
this.options = options;
|
|
4133
4356
|
this.outlineData = {};
|
|
4134
4357
|
if (dest !== null) {
|
|
4135
|
-
|
|
4358
|
+
const destWidth = dest.data.MediaBox[2];
|
|
4359
|
+
const destHeight = dest.data.MediaBox[3];
|
|
4360
|
+
const top = destHeight - (options.top || 0);
|
|
4361
|
+
const left = destWidth - (options.left || 0);
|
|
4362
|
+
const zoom = options.zoom || 0;
|
|
4363
|
+
this.outlineData['Dest'] = options.fit ? [dest, 'Fit'] : [dest, 'XYZ', left, top, zoom];
|
|
4136
4364
|
}
|
|
4137
4365
|
if (parent !== null) {
|
|
4138
4366
|
this.outlineData['Parent'] = parent;
|
|
@@ -4144,10 +4372,10 @@ class PDFOutline {
|
|
|
4144
4372
|
this.children = [];
|
|
4145
4373
|
}
|
|
4146
4374
|
addItem(title) {
|
|
4147
|
-
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] :
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
const result = new PDFOutline(this.document, this.dictionary, title,
|
|
4375
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_OPTIONS;
|
|
4376
|
+
const pages = this.document._root.data.Pages.data.Kids;
|
|
4377
|
+
const dest = options.pageNumber != null ? pages[options.pageNumber] : this.document.page.dictionary;
|
|
4378
|
+
const result = new PDFOutline(this.document, this.dictionary, title, dest, options);
|
|
4151
4379
|
this.children.push(result);
|
|
4152
4380
|
return result;
|
|
4153
4381
|
}
|
|
@@ -4183,7 +4411,7 @@ var OutlineMixin = {
|
|
|
4183
4411
|
this.outline.endOutline();
|
|
4184
4412
|
if (this.outline.children.length > 0) {
|
|
4185
4413
|
this._root.data.Outlines = this.outline.dictionary;
|
|
4186
|
-
return this._root.data.PageMode = 'UseOutlines';
|
|
4414
|
+
return this._root.data.PageMode = this._root.data.PageMode || 'UseOutlines';
|
|
4187
4415
|
}
|
|
4188
4416
|
}
|
|
4189
4417
|
};
|
|
@@ -4256,6 +4484,9 @@ class PDFStructureElement {
|
|
|
4256
4484
|
if (child instanceof PDFStructureContent) {
|
|
4257
4485
|
this._addContentToParentTree(child);
|
|
4258
4486
|
}
|
|
4487
|
+
if (child instanceof PDFAnnotationReference) {
|
|
4488
|
+
this._addAnnotationToParentTree(child.annotationRef);
|
|
4489
|
+
}
|
|
4259
4490
|
if (typeof child === 'function' && this._attached) {
|
|
4260
4491
|
child = this._contentForClosure(child);
|
|
4261
4492
|
}
|
|
@@ -4272,6 +4503,12 @@ class PDFStructureElement {
|
|
|
4272
4503
|
pageStructParents[mcid] = this.dictionary;
|
|
4273
4504
|
});
|
|
4274
4505
|
}
|
|
4506
|
+
_addAnnotationToParentTree(annotRef) {
|
|
4507
|
+
const parentTreeKey = this.document.createStructParentTreeNextKey();
|
|
4508
|
+
annotRef.data.StructParent = parentTreeKey;
|
|
4509
|
+
const parentTree = this.document.getStructParentTree();
|
|
4510
|
+
parentTree.add(parentTreeKey, this.dictionary);
|
|
4511
|
+
}
|
|
4275
4512
|
setParent(parentRef) {
|
|
4276
4513
|
if (this.dictionary.data.P) {
|
|
4277
4514
|
throw new Error(`Structure element added to more than one parent`);
|
|
@@ -4303,11 +4540,17 @@ class PDFStructureElement {
|
|
|
4303
4540
|
this._flush();
|
|
4304
4541
|
}
|
|
4305
4542
|
_isValidChild(child) {
|
|
4306
|
-
return child instanceof PDFStructureElement || child instanceof PDFStructureContent || typeof child === 'function';
|
|
4543
|
+
return child instanceof PDFStructureElement || child instanceof PDFStructureContent || child instanceof PDFAnnotationReference || typeof child === 'function';
|
|
4307
4544
|
}
|
|
4308
4545
|
_contentForClosure(closure) {
|
|
4309
4546
|
const content = this.document.markStructureContent(this.dictionary.data.S);
|
|
4547
|
+
const prevStructElement = this.document._currentStructureElement;
|
|
4548
|
+
this.document._currentStructureElement = this;
|
|
4549
|
+
const wasEnded = this._ended;
|
|
4550
|
+
this._ended = false;
|
|
4310
4551
|
closure();
|
|
4552
|
+
this._ended = wasEnded;
|
|
4553
|
+
this.document._currentStructureElement = prevStructElement;
|
|
4311
4554
|
this.document.endMarkedContent();
|
|
4312
4555
|
this._addContentToParentTree(content);
|
|
4313
4556
|
return content;
|
|
@@ -4361,6 +4604,15 @@ class PDFStructureElement {
|
|
|
4361
4604
|
}
|
|
4362
4605
|
});
|
|
4363
4606
|
}
|
|
4607
|
+
if (child instanceof PDFAnnotationReference) {
|
|
4608
|
+
const pageRef = this.document.page.dictionary;
|
|
4609
|
+
const objr = {
|
|
4610
|
+
Type: 'OBJR',
|
|
4611
|
+
Obj: child.annotationRef,
|
|
4612
|
+
Pg: pageRef
|
|
4613
|
+
};
|
|
4614
|
+
this.dictionary.data.K.push(objr);
|
|
4615
|
+
}
|
|
4364
4616
|
}
|
|
4365
4617
|
}
|
|
4366
4618
|
|
|
@@ -4456,6 +4708,13 @@ var MarkingsMixin = {
|
|
|
4456
4708
|
endMarkedContent() {
|
|
4457
4709
|
this.page.markings.pop();
|
|
4458
4710
|
this.addContent('EMC');
|
|
4711
|
+
if (this._textOptions) {
|
|
4712
|
+
delete this._textOptions.link;
|
|
4713
|
+
delete this._textOptions.goTo;
|
|
4714
|
+
delete this._textOptions.destination;
|
|
4715
|
+
delete this._textOptions.underline;
|
|
4716
|
+
delete this._textOptions.strike;
|
|
4717
|
+
}
|
|
4459
4718
|
return this;
|
|
4460
4719
|
},
|
|
4461
4720
|
struct(type) {
|
|
@@ -4914,7 +5173,7 @@ var AttachmentsMixin = {
|
|
|
4914
5173
|
if (options.type) {
|
|
4915
5174
|
refBody.Subtype = options.type.replace('/', '#2F');
|
|
4916
5175
|
}
|
|
4917
|
-
const checksum =
|
|
5176
|
+
const checksum = md5Hex(new Uint8Array(data));
|
|
4918
5177
|
refBody.Params.CheckSum = new String(checksum);
|
|
4919
5178
|
refBody.Params.Size = data.byteLength;
|
|
4920
5179
|
let ref;
|
|
@@ -5566,7 +5825,7 @@ function renderRow(row, rowIndex) {
|
|
|
5566
5825
|
function renderCell(cell, rowStruct) {
|
|
5567
5826
|
const cellRenderer = () => {
|
|
5568
5827
|
if (cell.backgroundColor != null) {
|
|
5569
|
-
this.document.save().rect(cell.x, cell.y, cell.width, cell.height).fill(
|
|
5828
|
+
this.document.save().fillColor(cell.backgroundColor).rect(cell.x, cell.y, cell.width, cell.height).fill().restore();
|
|
5570
5829
|
}
|
|
5571
5830
|
renderBorder.call(this, cell.border, cell.borderColor, cell.x, cell.y, cell.width, cell.height);
|
|
5572
5831
|
if (cell.debug) {
|
|
@@ -5630,20 +5889,20 @@ function renderBorder(border, borderColor, x, y, width, height, mask) {
|
|
|
5630
5889
|
const doc = this.document;
|
|
5631
5890
|
if ([border.right, border.bottom, border.left].every(val => val === border.top)) {
|
|
5632
5891
|
if (border.top > 0) {
|
|
5633
|
-
doc.save().lineWidth(border.top).rect(x, y, width, height).stroke(
|
|
5892
|
+
doc.save().lineWidth(border.top).strokeColor(borderColor.top).rect(x, y, width, height).stroke().restore();
|
|
5634
5893
|
}
|
|
5635
5894
|
} else {
|
|
5636
5895
|
if (border.top > 0) {
|
|
5637
|
-
doc.save().lineWidth(border.top).moveTo(x, y).lineTo(x + width, y).stroke(
|
|
5896
|
+
doc.save().lineWidth(border.top).moveTo(x, y).strokeColor(borderColor.top).lineTo(x + width, y).stroke().restore();
|
|
5638
5897
|
}
|
|
5639
5898
|
if (border.right > 0) {
|
|
5640
|
-
doc.save().lineWidth(border.right).moveTo(x + width, y).lineTo(x + width, y + height).stroke(
|
|
5899
|
+
doc.save().lineWidth(border.right).moveTo(x + width, y).strokeColor(borderColor.right).lineTo(x + width, y + height).stroke().restore();
|
|
5641
5900
|
}
|
|
5642
5901
|
if (border.bottom > 0) {
|
|
5643
|
-
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).lineTo(x, y + height).stroke(
|
|
5902
|
+
doc.save().lineWidth(border.bottom).moveTo(x + width, y + height).strokeColor(borderColor.bottom).lineTo(x, y + height).stroke().restore();
|
|
5644
5903
|
}
|
|
5645
5904
|
if (border.left > 0) {
|
|
5646
|
-
doc.save().lineWidth(border.left).moveTo(x, y + height).lineTo(x, y).stroke(
|
|
5905
|
+
doc.save().lineWidth(border.left).moveTo(x, y + height).strokeColor(borderColor.left).lineTo(x, y).stroke().restore();
|
|
5647
5906
|
}
|
|
5648
5907
|
}
|
|
5649
5908
|
}
|
|
@@ -5855,6 +6114,10 @@ class PDFDocument extends stream.Readable {
|
|
|
5855
6114
|
if (this.options.lang) {
|
|
5856
6115
|
this._root.data.Lang = new String(this.options.lang);
|
|
5857
6116
|
}
|
|
6117
|
+
if (this.options.pageLayout) {
|
|
6118
|
+
const layout = this.options.pageLayout;
|
|
6119
|
+
this._root.data.PageLayout = layout.charAt(0).toUpperCase() + layout.slice(1);
|
|
6120
|
+
}
|
|
5858
6121
|
this.page = null;
|
|
5859
6122
|
this.initMetadata();
|
|
5860
6123
|
this.initColor();
|