Added support to add a signature to a pdf which has already been signed.

pull/2/head 2.3.0
zboris12 2022-10-20 21:28:27 +09:00
parent 5c9ac474b5
commit 22f6628584
3 changed files with 490 additions and 79 deletions

View File

@ -10,6 +10,7 @@ And I use this name to hope the merits from this application will be dedicated t
* Sign a pdf with an invisible pkcs#7 signature.
* Sign a pdf with a visible pkcs#7 signature by drawing an image.
* Sign a pdf and set DocMDP(document modification detection and prevention).
* Add a new signature to a pdf if it has been signed already. (An incremental update)
* Sign a pdf with a timestamp from TSA(Time Stamp Authority). (Only in Google Apps Script)
* Set password protection to a pdf. Supported algorithms:
* 40bit RC4 Encryption
@ -213,7 +214,7 @@ async function protect2(pdf, cert){
var eopt = {
mode: Zga.Crypto.Mode.AES_128,
pubkeys: [{
c: Zga.u8arrToRaw(new Uint8Array(cert)),
c: cert,
p: ["copy", "modify", "copy-extract", "annot-forms", "fill-forms", "extract", "assemble"],
}],
};

View File

@ -11,6 +11,19 @@ var PdfLoadOptions;
/** @const */
var PDFLib = {};
/**
* @param {string} str
* @param {Array<number>} buffer
* @param {number} offset
* @return {number}
*/
PDFLib.copyStringIntoBuffer = function(str, buffer, offset){};
/**
* @param {string|ArrayBuffer|Uint8Array} input
* @return {Uint8Array}
*/
PDFLib.toUint8Array = function(input){};
/** @constructor */
PDFLib.PDFDocument = function(){};
/**
@ -56,6 +69,45 @@ PDFLib.PDFDocument.prototype.catalog;
/** @type {PDFLib.PDFContext} */
PDFLib.PDFDocument.prototype.context;
/** @constructor */
PDFLib.PDFAcroField = function(){};
/**
* @returns {PDFLib.PDFString|PDFLib.PDFHexString}
*/
PDFLib.PDFAcroField.prototype.T = function(){};
/**
* @constructor
* @extends {PDFLib.PDFAcroField}
*/
PDFLib.PDFAcroTerminal = function(){};
/**
* @constructor
* @extends {PDFLib.PDFAcroTerminal}
*/
PDFLib.PDFAcroSignature = function(){};
/** @constructor */
PDFLib.PDFAcroForm = function(){};
/**
* @typedef
* {{
* 0: PDFLib.PDFAcroField,
* 1: PDFLib.PDFRef,
* }}
*/
var PdfFieldInfo;
/**
* @return {Array<PdfFieldInfo>}
*/
PDFLib.PDFAcroForm.prototype.getAllFields = function(){};
/**
* @param {PDFLib.PDFRef} field
*/
PDFLib.PDFAcroForm.prototype.addField = function(field){};
/** @type {PDFLib.PDFDict} */
PDFLib.PDFAcroForm.prototype.dict;
/** @constructor */
PDFLib.PDFCatalog = function(){};
/**
@ -63,6 +115,14 @@ PDFLib.PDFCatalog = function(){};
* @param {PDFLib.PDFObject} object
*/
PDFLib.PDFCatalog.prototype.set = function(name, object){};
/**
* @return {PDFLib.PDFDict}
*/
PDFLib.PDFCatalog.prototype.AcroForm = function(){};
/**
* @return {PDFLib.PDFAcroForm}
*/
PDFLib.PDFCatalog.prototype.getOrCreateAcroForm = function(){};
/** @constructor */
PDFLib.PDFPage = function(){};
@ -87,15 +147,25 @@ var PdfSize;
*/
PDFLib.PDFPage.prototype.getSize = function(){};
/** @constructor */
/**
* @constructor
* @extends {PDFLib.PDFDict}
*/
PDFLib.PDFPageLeaf = function(){};
/**
* @param {PDFLib.PDFName} name
* @param {PDFLib.PDFObject} object
*/
PDFLib.PDFPageLeaf.prototype.set = function(name, object){};
/**
* @return {PDFLib.PDFArray}
*/
PDFLib.PDFPageLeaf.prototype.Annots = function(){};
/** @constructor */
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFRef = function(){};
/** @type {number} */
PDFLib.PDFRef.prototype.objectNumber;
@ -108,7 +178,9 @@ PDFLib.PDFRef.prototype.generationNumber;
*/
PDFLib.PDFRef.of = function(objectNumber, generationNumber){};
/** @constructor */
/**
* @constructor
*/
PDFLib.PDFContext = function(){};
/**
* @typedef
@ -154,6 +226,12 @@ PDFLib.PDFContext.prototype.obj = function(literal){};
* @return {PDFLib.PDFObject}
*/
PDFLib.PDFContext.prototype.lookup = function(ref){};
/**
* @param {PDFLib.PDFRef} ref
* @param {*} typ
* @return {PDFLib.PDFObject}
*/
PDFLib.PDFContext.prototype.lookupMaybe = function(ref, typ){};
/** @constructor */
PDFLib.PDFObject = function(){};
@ -161,12 +239,20 @@ PDFLib.PDFObject = function(){};
PDFLib.PDFObject.prototype.dict;
/** @type {Array<PDFLib.PDFName>} */
PDFLib.PDFObject.prototype.array;
/**
* @param {Array<number>} _buffer
* @param {number} _offset
* @return {number}
*/
PDFLib.PDFObject.prototype.copyBytesInto = function(_buffer, _offset){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFName = function(){};
/** @type {PDFLib.PDFName} */
PDFLib.PDFName.Annots;
/**
* @param {string} value
* @return {PDFLib.PDFName}
@ -176,9 +262,12 @@ PDFLib.PDFName.of = function(value){};
PDFLib.PDFName.prototype.encodedName;
/** @type {number} */
PDFLib.PDFName.prototype.numberValue;
/** @return {string} */
PDFLib.PDFName.prototype.value = function(){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
* @param {PDFLib.PDFContext} context
*/
PDFLib.PDFArray = function(context){};
@ -191,6 +280,10 @@ PDFLib.PDFArray.prototype.push = function(object){};
* @return {PDFLib.PDFObject}
*/
PDFLib.PDFArray.prototype.get = function(idx){};
/**
* @return {Array<PDFLib.PDFObject>}
*/
PDFLib.PDFArray.prototype.asArray = function(){};
/**
* @constructor
@ -207,6 +300,10 @@ PDFLib.PDFString.of = function(value){};
* @return {PDFLib.PDFString}
*/
PDFLib.PDFString.fromDate = function(value){};
/**
* @return {string}
*/
PDFLib.PDFString.prototype.asString = function(){};
/**
* @constructor
@ -223,6 +320,10 @@ PDFLib.PDFHexString.of = function(value){};
* @return {PDFLib.PDFHexString}
*/
PDFLib.PDFHexString.fromText = function(value){};
/**
* @return {string}
*/
PDFLib.PDFHexString.prototype.decodeText = function(){};
/**
* @constructor
@ -318,9 +419,81 @@ PDFLib.PDFFlateStream.prototype.contentsCache;
*/
PDFLib.PDFContentStream = function(){};
/**
* @param {PDFLib.PDFObject} dict
* @param {PDFLib.PDFDict} dict
* @param {Array<PDFLib.PDFOperator>} operators
* @param {boolean=} encode
* @return {PDFLib.PDFContentStream}
*/
PDFLib.PDFContentStream.of = function(dict, operators, encode){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFCrossRefSection = function(){};
/**
* @return {PDFLib.PDFCrossRefSection}
*/
PDFLib.PDFCrossRefSection.create = function(){};
/**
* @param {PDFLib.PDFRef} ref
* @param {number} offset
*/
PDFLib.PDFCrossRefSection.prototype.addEntry = function (ref, offset){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFDict = function(){};
/**
* @param {PDFLib.PDFName} key
* @param {PDFLib.PDFObject} value
*/
PDFLib.PDFDict.prototype.set = function(key, value){};
/**
* @param {PDFLib.PDFName} key
* @param {*} typ
* @return {PDFLib.PDFObject}
*/
PDFLib.PDFDict.prototype.lookupMaybe = function(key, typ){};
/**
* @param {PDFLib.PDFName} key
* @return {PDFLib.PDFObject}
*/
PDFLib.PDFDict.prototype.lookup = function(key){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFWriter = function(){};
/**
* @param {PDFLib.PDFContext} context
* @param {number} objectsPerTick
* @return {PDFLib.PDFWriter}
*/
PDFLib.PDFWriter.forContext = function(context, objectsPerTick){};
/**
* @return {PDFLib.PDFDict}
*/
PDFLib.PDFWriter.prototype.createTrailerDict = function(){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFTrailerDict = function(){};
/**
* @param {PDFLib.PDFDict} dict
* @return {PDFLib.PDFTrailerDict}
*/
PDFLib.PDFTrailerDict.of = function(dict){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFTrailer = function(){};
/**
* @param {number} offset
* @return {PDFLib.PDFTrailer}
*/
PDFLib.PDFTrailer.forLastCrossRefSectionOffset = function(offset){};

View File

@ -76,6 +76,8 @@ z.NewRefMap = class extends Map{
this.idx = 0;
/** @private @type {PDFLib.PDFContext} */
this.pdfcont = null;
/** @private @type {number} */
this.oriLastOnum = 0;
}
/**
@ -85,28 +87,32 @@ z.NewRefMap = class extends Map{
* @return {PDFLib.PDFRef} If enc is true, the return value is the unique reference reserved for encrypting information.
*/
reorderPdfRefs(pdfdoc, enc){
this.pdfcont = pdfdoc.context;
/** @type {z.NewRefMap} */
const _this = this;
_this.pdfcont = pdfdoc.context;
/** @type {PDFLib.PDFRef} */
var encref = enc ? this.pdfcont.nextRef() : null;
var encref = enc ? _this.pdfcont.nextRef() : null;
pdfdoc.getPages().forEach(function(/** @type {PDFLib.PDFPage} */a_pg){
this.addAndFindRelates(a_pg.ref, "Page");
}.bind(this));
this.addAndFindRelates(this.pdfcont.trailerInfo.Root, "Catalog");
_this.addAndFindRelates(a_pg.ref, "Page");
});
_this.addAndFindRelates(_this.pdfcont.trailerInfo.Root, "Catalog");
if(encref){
this.addAndFindRelates(encref, "Encrypt");
_this.addAndFindRelates(encref, "Encrypt");
}
this.pdfcont.enumerateIndirectObjects().forEach(function(/** @type {PdfObjEntry} */a_oety){
_this.pdfcont.enumerateIndirectObjects().forEach(function(/** @type {PdfObjEntry} */a_oety){
/** @type {string} */
var a_tag = a_oety[0].tag;
/** @type {z.NewRef} */
var a_new = this.get(a_tag);
var a_new = _this.get(a_tag);
if(!a_new){
a_new = new z.NewRef(a_oety[0], ++this.idx);
this.set(a_tag, a_new);
a_new = new z.NewRef(a_oety[0], ++_this.idx);
_this.set(a_tag, a_new);
}
}.bind(this));
this.changeAll();
});
_this.changeAll();
_this.oriLastOnum = _this.pdfcont.largestObjectNumber;
_this.pdfcont.largestObjectNumber = _this.idx;
return encref;
}
@ -115,8 +121,10 @@ z.NewRefMap = class extends Map{
*/
restoreAll(){
this.changeAll(true);
this.pdfcont.largestObjectNumber = this.oriLastOnum;
this.clear();
this.idx = 0;
this.oriLastOnum = 0;
this.pdfcont = null;
}
@ -134,7 +142,7 @@ z.NewRefMap = class extends Map{
/**
* @private
* @param {PDFLib.PDFObject|Array|Map} a_val
* @param {PDFLib.PDFObject|Array<PDFLib.PDFObject>|Map} a_val
* @param {string=} a_nm
*/
findRefs(a_val, a_nm){
@ -200,6 +208,8 @@ z.PdfSigner = class{
constructor(signopt){
/** @private @const {string} */
this.DEFAULT_BYTE_RANGE_PLACEHOLDER = "**********";
/** @private @const {number} */
this.NEWLINE = 10;
/** @private @type {SignOption} */
this.opt = signopt;
/** @type {forge_key} */
@ -214,6 +224,10 @@ z.PdfSigner = class{
this.siglen = 0;
/** @private @type {PDFLib.PDFHexString} */
this.sigContents = null;
/** @private @type {Uint8Array} */
this.oriU8pdf = null;
/** @type {Array<PdfObjEntry>} */
this.apobjs = [];
/** @private @type {boolean} */
this.debug = false;
@ -263,42 +277,74 @@ z.PdfSigner = class{
throw new Error("ZgaPdfCryptor is not imported.");
}
/** @const {z.PdfSigner} */
const _this = this;
/** @type {PDFLib.PDFDocument} */
var pdfdoc = await z.loadPdf(pdf);
var pdfdoc = null;
if(pdf.addPage){
pdfdoc = /** @type {PDFLib.PDFDocument} */(pdf);
}else{
if(Array.isArray(pdf)){
_this.oriU8pdf = new Uint8Array(pdf);
}else{
_this.oriU8pdf = PDFLib.toUint8Array(/** @type {(ArrayBuffer|Uint8Array|string)} */(pdf));
}
pdfdoc = await PDFLib.PDFDocument.load(_this.oriU8pdf);
}
if(this.opt.drawinf && this.opt.drawinf.imgData && !this.opt.drawinf.img){
if(_this.opt.drawinf && _this.opt.drawinf.imgData && !_this.opt.drawinf.img){
/** @type {Uint8Array|ArrayBuffer|string} */
var imgData2 = null;
if(Array.isArray(this.opt.drawinf.imgData)){
imgData2 = new Uint8Array(this.opt.drawinf.imgData);
if(Array.isArray(_this.opt.drawinf.imgData)){
imgData2 = new Uint8Array(_this.opt.drawinf.imgData);
}else{
imgData2 = this.opt.drawinf.imgData;
imgData2 = _this.opt.drawinf.imgData;
}
if(this.opt.drawinf.imgType == "png"){
this.opt.drawinf.img = await pdfdoc.embedPng(imgData2);
}else if(this.opt.drawinf.imgType == "jpg"){
this.opt.drawinf.img = await pdfdoc.embedJpg(imgData2);
if(_this.opt.drawinf.imgType == "png"){
_this.opt.drawinf.img = await pdfdoc.embedPng(imgData2);
}else if(_this.opt.drawinf.imgType == "jpg"){
_this.opt.drawinf.img = await pdfdoc.embedJpg(imgData2);
}else{
throw new Error("Unkown image type. " + this.opt.drawinf.imgType);
throw new Error("Unkown image type. " + _this.opt.drawinf.imgType);
}
}
/** @type {PDFLib.PDFRef} */
var encref = null;
if(this.addSignHolder(pdfdoc)){
// Signature in DocMDP mode may be invalid if the definitions of references are too chaotic
// So we make the order of references more neet.
/** @type {boolean} *///append mode or not
var apmode = _this.addSignHolder(pdfdoc);
await pdfdoc.flush();
encref = z.newRefs.reorderPdfRefs(pdfdoc, cypopt ? true : false);
}
this.log("A signature holder has been added to the pdf.");
_this.log("A signature holder has been added to the pdf.");
/** @type {forge_cert} */
var cert = this.loadP12cert(this.opt.p12cert, this.opt.pwd);
var cert = _this.loadP12cert(_this.opt.p12cert, _this.opt.pwd);
if(cert){
z.fixCertAttributes(cert);
}
if(apmode){
if(_this.oriU8pdf){
_this.log("The pdf has been signed already, so we add a new signature to it.");
}else{
throw new Error("When adding a new signature to a signed pdf, the original literal datas are necessary.");
}
// Find the changed objects
/** @type {PDFLib.PDFDocument} */
var oriPdfdoc = await PDFLib.PDFDocument.load(_this.oriU8pdf);
pdfdoc.context.enumerateIndirectObjects().forEach(function(/** @type {PdfObjEntry} */a_ele){
/** @type {PDFLib.PDFObject} */
var a_obj = oriPdfdoc.context.lookup(a_ele[0]);
if(!(a_obj && _this.isamePdfObject(a_ele[1], a_obj))){
_this.apobjs.push(a_ele);
}
});
}else{
// If the definitions of references are too chaotic, a signature contains DocMDP or after adding a new signature,
// this signature may be invalid. So we make the order of references more neet.
/** @type {PDFLib.PDFRef} */
var encref = z.newRefs.reorderPdfRefs(pdfdoc, cypopt ? true : false);
if(cypopt){
if(cypopt.pubkeys){
if(cypopt.pubkeys.length == 0){
@ -317,18 +363,19 @@ z.PdfSigner = class{
/** @type {Zga.PdfCryptor} */
var cypt = new z.PdfCryptor(cypopt);
await cypt.encryptPdf(pdfdoc, encref);
this.log("Pdf data has been encrypted.");
_this.log("Pdf data has been encrypted.");
}
}
/** @type {Uint8Array} */
var ret = await this.saveAndSign(pdfdoc);
var ret = await _this.saveAndSign(pdfdoc);
if(!ret){
this.log("Change size of signature's placeholder and retry.");
this.sigContents.value = "0".repeat(this.siglen);
ret = await this.saveAndSign(pdfdoc);
_this.log("Change size of signature's placeholder and retry.");
_this.sigContents.value = "0".repeat(_this.siglen);
ret = await _this.saveAndSign(pdfdoc);
}
if(ret){
this.log("Signing pdf accomplished.");
_this.log("Signing pdf accomplished.");
}else{
throw new Error("Failed to sign the pdf.");
}
@ -350,16 +397,158 @@ z.PdfSigner = class{
*/
async saveAndSign(pdfdoc){
/** @type {Uint8Array} */
var uarr = await pdfdoc.save({"useObjectStreams": false});
var uarr = null;
if(this.apobjs.length > 0){
uarr = this.appendSignature(pdfdoc);
}else{
uarr = await pdfdoc.save({"useObjectStreams": false});
}
/** @type {string} */
var pdfstr = z.u8arrToRaw(uarr);
var pdfstr = z.u8arrToRaw(uarr) + String.fromCharCode(this.NEWLINE);
return this.signPdf(pdfstr);
}
/**
* @private
* @param {PDFLib.PDFDocument} pdfdoc
* @return {boolean} DocMDP mode or not.
* @return {Uint8Array}
*/
appendSignature(pdfdoc){
/** @const {z.PdfSigner} */
const _this = this;
/** @type {PDFLib.PDFCrossRefSection} */
var xref = PDFLib.PDFCrossRefSection.create();
/** @type {number} */
var stpos = _this.oriU8pdf.length;
/** @type {Array<number>} */
var buff = [];
buff[0] = _this.NEWLINE;
stpos++;
_this.apobjs.forEach(function(/** @type {PdfObjEntry} */a_ele){
/** @type {number} */
var a_len = _this.objEntryToBytes(a_ele, buff);
xref.addEntry(a_ele[0], stpos);
stpos += a_len;
});
xref.copyBytesInto(buff, buff.length);
/** @type {PDFLib.PDFDict} */
var tdic = PDFLib.PDFWriter.forContext(pdfdoc.context, 0).createTrailerDict();
tdic.set(PDFLib.PDFName.of("Prev"), PDFLib.PDFNumber.of(_this.findPrev(_this.oriU8pdf)));
/** @type {PDFLib.PDFTrailerDict} */
var ptdic = PDFLib.PDFTrailerDict.of(tdic);
ptdic.copyBytesInto(buff, buff.length);
buff.push(_this.NEWLINE);
/** @type {PDFLib.PDFTrailer} */
var ptlr = PDFLib.PDFTrailer.forLastCrossRefSectionOffset(stpos);
ptlr.copyBytesInto(buff, buff.length);
/** @type {Uint8Array} */
var ret = new Uint8Array(_this.oriU8pdf.length + buff.length);
ret.set(/** @type {!ArrayBufferView} */(_this.oriU8pdf));
ret.set(/** @type {!ArrayBufferView} */(new Uint8Array(buff)), _this.oriU8pdf.length);
return ret;
}
/**
* @private
* @param {Uint8Array} u8pdf
* @return {number}
*/
findPrev(u8pdf){
/** @const {Uint8Array} */
const eof = Zga.rawToU8arr("%%EOF");
/** @const {number} */
const c0 = "0".charCodeAt(0);
/** @const {number} */
const c9 = "9".charCodeAt(0);
/** @type {number} */
var step = 0;
/** @type {string} */
var num = "";
for(var i = u8pdf.length - eof.length; i >= 0; i--){
switch(step){
case 0:
/** @type {boolean} */
var flg = true;
for(var j=0; j<eof.length; j++){
if(u8pdf[i+j] != eof[j]){
flg = false;
break;
}
}
if(flg){
step = 1;
}
break;
case 1:
if(u8pdf[i] >= c0 && u8pdf[i] <= c9){
num = String.fromCharCode(u8pdf[i]);
step = 2;
}
break;
case 2:
if(u8pdf[i] >= c0 && u8pdf[i] <= c9){
num = String.fromCharCode(u8pdf[i]) + num;
}else{
step = 9;
}
break;
}
if(step >= 9){
break;
}
}
return parseInt(num, 10);
}
/**
* @private
* @param {PDFLib.PDFObject} obj1
* @param {PDFLib.PDFObject} obj2
* @return {boolean}
*/
isamePdfObject(obj1, obj2){
/** @type {Array<number>} */
var buff1 = [];
obj1.copyBytesInto(buff1, 0);
/** @type {Array<number>} */
var buff2 = [];
obj2.copyBytesInto(buff2, 0);
if(buff1.length != buff2.length){
return false;
}
for(var i=0; i<buff1.length; i++){
if(buff1[i] != buff2[i]){
return false;
}
}
return true;
}
/**
* @private
* @param {PdfObjEntry} objety
* @param {Array<number>} buff
* @return {number}
*/
objEntryToBytes(objety, buff){
/** @type {number} */
var before = buff.length;
objety[0].copyBytesInto(buff, buff.length);
PDFLib.copyStringIntoBuffer("obj", buff, buff.length - 1);
buff[buff.length] = this.NEWLINE;
objety[1].copyBytesInto(buff, buff.length);
buff[buff.length] = this.NEWLINE;
PDFLib.copyStringIntoBuffer("endobj", buff, buff.length);
buff[buff.length] = this.NEWLINE;
return buff.length - before;
}
/**
* @private
* @param {PDFLib.PDFDocument} pdfdoc
* @return {boolean} append mode or not
*/
addSignHolder(pdfdoc){
/** @const {number} */
@ -377,6 +566,28 @@ z.PdfSigner = class{
strmRef = signcrt.createEmptyField(pdfcont);
}
/** @type {Array<string>} */
var oldSigs = [];
/** @type {PDFLib.PDFAcroForm} */
var afrm = pdfdoc.catalog.getOrCreateAcroForm();
afrm.getAllFields().forEach(function(/** @type {PdfFieldInfo} */a_finf){
if(a_finf[0] instanceof PDFLib.PDFAcroSignature){
/** @type {PDFLib.PDFString|PDFLib.PDFHexString} */
var a_t = a_finf[0].T();
if(a_t instanceof PDFLib.PDFString){
oldSigs.push(a_t.asString());
}else if(a_t instanceof PDFLib.PDFHexString){
oldSigs.push(a_t.decodeText());
}
}
});
if(oldSigs.length > 0 && docMdp){
throw new Error("Since the pdf has been signed, can NOT sign with DocMDP. Because the signature field that contains DocMDP must be the first signed field in the document.");
}
/** @type {string} */
var signm = this.fixSigName(oldSigs, this.opt.signame);
/** @type {Date} */
var signdate = new Date();
if(this.opt.signdate instanceof Date && !this.tsainf){
@ -440,7 +651,7 @@ z.PdfSigner = class{
"FT": "Sig",
"Rect": signcrt.getSignRect(),
"V": signatureDictRef,
"T": this.convToPDFString(this.opt.signame ? this.opt.signame : "Signature1"),
"T": this.convToPDFString(signm),
"F": 132,
"P": page.ref,
};
@ -453,16 +664,19 @@ z.PdfSigner = class{
var widgetDictRef = pdfcont.register(pdfcont.obj(widgetObj));
// Add our signature widget to the page
page.node.set(PDFLib.PDFName.of("Annots"), pdfcont.obj([widgetDictRef]));
/** @type {PDFLib.PDFArray} */
var ans = page.node.Annots();
if(!ans){
ans = new PDFLib.PDFArray(pdfcont);
page.node.set(PDFLib.PDFName.Annots, ans);
}
ans.push(widgetDictRef);
if(!afrm.dict.lookup(PDFLib.PDFName.of("SigFlags"))){
afrm.dict.set(PDFLib.PDFName.of("SigFlags"), PDFLib.PDFNumber.of(3));
}
afrm.addField(widgetDictRef);
// Create an AcroForm object containing our signature widget
pdfdoc.catalog.set(
PDFLib.PDFName.of("AcroForm"),
pdfcont.obj({
"SigFlags": 3,
"Fields": [widgetDictRef],
}),
);
if(docMdp){
pdfdoc.catalog.set(
PDFLib.PDFName.of("Perms"),
@ -470,10 +684,34 @@ z.PdfSigner = class{
"DocMDP": signatureDictRef,
}),
);
return true;
}
return (oldSigs.length > 0);
}
/**
* @private
* @param {Array<string>} oldSigs
* @param {string=} signm
* @param {number=} idx
* @return {string}
*/
fixSigName(oldSigs, signm, idx){
if(!signm){
signm = "Signature";
idx = 1;
}
/** @type {string} */
var nm = signm;
if(idx){
nm += idx;
}else{
return false;
idx = 0;
}
if(oldSigs.indexOf(nm) >= 0){
return this.fixSigName(oldSigs, signm, idx+1);
}else{
return nm;
}
}
@ -895,14 +1133,13 @@ z.SignatureCreator = class{
this.rect = this.calcRect(pgrot.angle, areainf);
/** @type {PDFLib.PDFObject} */
var frmDict = pdfdoc.context.obj({
var frmDict = /** @type {PDFLib.PDFDict} */(pdfdoc.context.obj({
"Type": "XObject",
"Subtype": "Form",
"FormType": 1,
"BBox": [0, 0, areainf.w, areainf.h],
"Resources": rscObj,
});
}));
/** @type {PDFLib.PDFContentStream} */
var strm = PDFLib.PDFContentStream.of(frmDict, sigOprs, true);
return pdfdoc.context.register(strm);