Working on text signature and placing on multiple pages.
parent
fd2b97d5b3
commit
0505fd1e0e
73
README.md
73
README.md
|
@ -14,7 +14,8 @@ And I use this name to hope the merits from this application will be dedicated t
|
||||||
## Main features
|
## Main features
|
||||||
|
|
||||||
* Sign a pdf with an invisible pkcs#7 signature.
|
* 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 with a visible pkcs#7 signature by drawing an image or a text or both.
|
||||||
|
* A visible signature can be placed on multiple pages. (In the same position)
|
||||||
* Sign a pdf and set [DocMDP](https://github.com/zboris12/zgapdfsigner/wiki/API#note).
|
* Sign a pdf and set [DocMDP](https://github.com/zboris12/zgapdfsigner/wiki/API#note).
|
||||||
* Add a new signature to a pdf if it has been signed already. (An incremental update)
|
* Add a new signature to a pdf if it has been signed already. (An incremental update)
|
||||||
* Add a document timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser)
|
* Add a document timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser)
|
||||||
|
@ -133,8 +134,10 @@ async function sign2(pdf, cert, pwd, imgdat, imgtyp){
|
||||||
w: 60, // width
|
w: 60, // width
|
||||||
h: 60, // height
|
h: 60, // height
|
||||||
},
|
},
|
||||||
imgData: imgdat,
|
imgInfo: {
|
||||||
imgType: imgtyp,
|
imgData: imgdat,
|
||||||
|
imgType: imgtyp,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
var signer = new Zga.PdfSigner(sopt);
|
var signer = new Zga.PdfSigner(sopt);
|
||||||
|
@ -143,10 +146,41 @@ async function sign2(pdf, cert, pwd, imgdat, imgtyp){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Sign with a visible signature of drawing a text.
|
Sign with a visible signature by drawing a text.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//TODO
|
/**
|
||||||
|
* @param {ArrayBuffer} pdf
|
||||||
|
* @param {ArrayBuffer} cert
|
||||||
|
* @param {string} pwd
|
||||||
|
* @param {string} txt
|
||||||
|
* @param {ArrayBuffer} fontdat
|
||||||
|
* @return {Promise<Blob>}
|
||||||
|
*/
|
||||||
|
async function sign3(pdf, cert, pwd, txt, fontdat){
|
||||||
|
/** @type {SignOption} */
|
||||||
|
var sopt = {
|
||||||
|
p12cert: cert,
|
||||||
|
pwd: pwd,
|
||||||
|
drawinf: {
|
||||||
|
area: {
|
||||||
|
x: 25, // left
|
||||||
|
y: 150, // top
|
||||||
|
w: 60, // width
|
||||||
|
h: 60, // height
|
||||||
|
},
|
||||||
|
textInfo: {
|
||||||
|
text: txt,
|
||||||
|
fontData: fontdat,
|
||||||
|
color: "#00f0f1",
|
||||||
|
size: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var signer = new Zga.PdfSigner(sopt);
|
||||||
|
var u8arr = await signer.sign(pdf);
|
||||||
|
return new Blob([u8arr], {"type" : "application/pdf"});
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Use it in [Google Apps Script](https://developers.google.com/apps-script)
|
Use it in [Google Apps Script](https://developers.google.com/apps-script)
|
||||||
|
@ -198,6 +232,10 @@ async function main(){
|
||||||
var ps = "";
|
var ps = "";
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var imgPath = m_path.join(__dirname, "_test.png");
|
var imgPath = m_path.join(__dirname, "_test.png");
|
||||||
|
/** @type {string} */
|
||||||
|
var txt = "I am a test string!";
|
||||||
|
/** @type {string} */
|
||||||
|
var fontPath = m_path.join(__dirname, "_test.ttf");
|
||||||
|
|
||||||
if(process.argv.length > 3){
|
if(process.argv.length > 3){
|
||||||
pfxPath = process.argv[2];
|
pfxPath = process.argv[2];
|
||||||
|
@ -226,6 +264,11 @@ async function main(){
|
||||||
img = m_fs.readFileSync(imgPath);
|
img = m_fs.readFileSync(imgPath);
|
||||||
imgType = m_path.extname(imgPath).slice(1);
|
imgType = m_path.extname(imgPath).slice(1);
|
||||||
}
|
}
|
||||||
|
/** @type {Buffer} */
|
||||||
|
var font = null;
|
||||||
|
if(fontPath){
|
||||||
|
font = m_fs.readFileSync(fontPath);
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {SignOption} */
|
/** @type {SignOption} */
|
||||||
var sopt = {
|
var sopt = {
|
||||||
|
@ -239,16 +282,24 @@ async function main(){
|
||||||
ltv: 1,
|
ltv: 1,
|
||||||
debug: true,
|
debug: true,
|
||||||
};
|
};
|
||||||
if(img){
|
if(img || txt){
|
||||||
sopt.drawinf = {
|
sopt.drawinf = {
|
||||||
area: {
|
area: {
|
||||||
x: 25, // left
|
x: 25, // left
|
||||||
y: 150, // top
|
y: 50, // top
|
||||||
w: 60,
|
w: txt ? undefined : 60,
|
||||||
h: 60,
|
h: txt ? undefined : 100,
|
||||||
},
|
},
|
||||||
imgData: img,
|
pageidx: "2-3", // Placed the signature on the 3rd page and the 4th page. (Indexes of pages start from 0)
|
||||||
imgType: imgType,
|
imgInfo: img ? {
|
||||||
|
imgData: img,
|
||||||
|
imgType: imgType,
|
||||||
|
} : undefined,
|
||||||
|
textInfo: txt ? {
|
||||||
|
text: txt,
|
||||||
|
fontData: font,
|
||||||
|
size: 16,
|
||||||
|
} : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
*/
|
*/
|
||||||
var PdfLoadOptions;
|
var PdfLoadOptions;
|
||||||
|
|
||||||
|
/** @const */
|
||||||
|
var fontkit = {};
|
||||||
|
|
||||||
/** @const */
|
/** @const */
|
||||||
var PDFLib = {};
|
var PDFLib = {};
|
||||||
|
|
||||||
|
@ -23,6 +26,21 @@ PDFLib.copyStringIntoBuffer = function(str, buffer, offset){};
|
||||||
* @return {Uint8Array}
|
* @return {Uint8Array}
|
||||||
*/
|
*/
|
||||||
PDFLib.toUint8Array = function(input){};
|
PDFLib.toUint8Array = function(input){};
|
||||||
|
/**
|
||||||
|
* @param {string} text
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
PDFLib.cleanText = function(text){};
|
||||||
|
/**
|
||||||
|
* @param {string} text
|
||||||
|
* @return {Array<string>}
|
||||||
|
*/
|
||||||
|
PDFLib.lineSplit = function(text){};
|
||||||
|
/**
|
||||||
|
* @param {string} text
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
PDFLib.isNewlineChar = function(text){};
|
||||||
|
|
||||||
/** @constructor */
|
/** @constructor */
|
||||||
PDFLib.PDFDocument = function(){};
|
PDFLib.PDFDocument = function(){};
|
||||||
|
@ -50,6 +68,10 @@ PDFLib.PDFDocument.prototype.save = function(options){};
|
||||||
* @returns {Array<PDFLib.PDFPage>}
|
* @returns {Array<PDFLib.PDFPage>}
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFDocument.prototype.getPages = function(){};
|
PDFLib.PDFDocument.prototype.getPages = function(){};
|
||||||
|
/**
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFDocument.prototype.getPageCount = function(){};
|
||||||
/**
|
/**
|
||||||
* @param {ArrayBuffer|Uint8Array|string} png
|
* @param {ArrayBuffer|Uint8Array|string} png
|
||||||
* @returns {Promise<PDFLib.PDFImage>}
|
* @returns {Promise<PDFLib.PDFImage>}
|
||||||
|
@ -82,6 +104,10 @@ PDFLib.PDFDocument.prototype.embedFont = function(font, options){};
|
||||||
* @returns {PDFLib.PDFFont}
|
* @returns {PDFLib.PDFFont}
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFDocument.prototype.embedStandardFont = function(font, customName){};
|
PDFLib.PDFDocument.prototype.embedStandardFont = function(font, customName){};
|
||||||
|
/**
|
||||||
|
* @lends {fontkit} fkt
|
||||||
|
*/
|
||||||
|
PDFLib.PDFDocument.prototype.registerFontkit = function(fkt){};
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<number>}
|
* @returns {Promise<number>}
|
||||||
*/
|
*/
|
||||||
|
@ -383,8 +409,23 @@ PDFLib.PDFFont = function(){};
|
||||||
PDFLib.PDFFont.prototype.ref;
|
PDFLib.PDFFont.prototype.ref;
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
PDFLib.PDFFont.prototype.name;
|
PDFLib.PDFFont.prototype.name;
|
||||||
/** @constructor */
|
/**
|
||||||
PDFLib.StandardFonts = function(){};
|
* @param {string} text
|
||||||
|
* @return {PDFLib.PDFHexString }
|
||||||
|
*/
|
||||||
|
PDFLib.PDFFont.prototype.encodeText = function(text){};
|
||||||
|
/**
|
||||||
|
* @param {number} size
|
||||||
|
* @param {Object<string, boolean>=} options
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFFont.prototype.heightAtSize = function(size, options){};
|
||||||
|
/**
|
||||||
|
* @param {string} text
|
||||||
|
* @param {number} size
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFFont.prototype.widthOfTextAtSize = function(text, size){};
|
||||||
|
|
||||||
PDFLib.RotationTypes = {};
|
PDFLib.RotationTypes = {};
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
|
@ -416,6 +457,7 @@ PDFLib.PDFOperator = function(){};
|
||||||
* rotate: (PDFLib.Rotation|undefined),
|
* rotate: (PDFLib.Rotation|undefined),
|
||||||
* xSkew: (PDFLib.Rotation|undefined),
|
* xSkew: (PDFLib.Rotation|undefined),
|
||||||
* ySkew: (PDFLib.Rotation|undefined),
|
* ySkew: (PDFLib.Rotation|undefined),
|
||||||
|
* graphicsState: (string|undefined),
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
var PdfDrawimgOption;
|
var PdfDrawimgOption;
|
||||||
|
|
|
@ -9,24 +9,74 @@
|
||||||
var TsaServiceInfo;
|
var TsaServiceInfo;
|
||||||
/**
|
/**
|
||||||
* the base point of x, y is top left corner.
|
* the base point of x, y is top left corner.
|
||||||
|
* wDraw, hDraw: Only for internal process.
|
||||||
* @typedef
|
* @typedef
|
||||||
* {{
|
* {{
|
||||||
* x: number,
|
* x: number,
|
||||||
* y: number,
|
* y: number,
|
||||||
* w: number,
|
* w: (number|undefined),
|
||||||
* h: number,
|
* h: (number|undefined),
|
||||||
|
* wDraw: (number|undefined),
|
||||||
|
* hDraw: (number|undefined),
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
var SignAreaInfo;
|
var SignAreaInfo;
|
||||||
/**
|
/**
|
||||||
|
* fontData: default: StandardFonts.Helvetica
|
||||||
|
* color: A Hex string of color. default: #000
|
||||||
|
* opacity: valid value is from 0 to 1. default: 1 // Not implemented
|
||||||
|
* blendMode: https://pdf-lib.js.org/docs/api/enums/blendmode // Not implemented
|
||||||
|
* lineHeight: default is the height of the font at the given size
|
||||||
|
* xOffset: An offset from SignAreaInfo's x
|
||||||
|
* yOffset: An offset from SignAreaInfo's y
|
||||||
|
* align: Text alignment: 0 left, 1 center, 2 right. default: 0
|
||||||
|
* noBreaks: A regular expression string that indicates which characters should not be used to break a word. default: [A-Za-z0-9]
|
||||||
|
*
|
||||||
|
* @typedef
|
||||||
|
* {{
|
||||||
|
* text: string,
|
||||||
|
* fontData: (Array<number>|Uint8Array|ArrayBuffer|string|undefined),
|
||||||
|
* color: (string|undefined),
|
||||||
|
* opacity: (number|undefined),
|
||||||
|
* blendMode: (string|undefined),
|
||||||
|
* lineHeight: (number|undefined),
|
||||||
|
* size: number,
|
||||||
|
* xOffset: (number|undefined),
|
||||||
|
* yOffset: (number|undefined),
|
||||||
|
* wMax: (number|undefined),
|
||||||
|
* align: (number|undefined),
|
||||||
|
* noBreaks: (string|undefined),
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
var SignTextInfo;
|
||||||
|
/**
|
||||||
|
* opacity: valid value is from 0 to 1. default: 1 // Not implemented
|
||||||
|
* blendMode: https://pdf-lib.js.org/docs/api/enums/blendmode // Not implemented
|
||||||
|
*
|
||||||
|
* @typedef
|
||||||
|
* {{
|
||||||
|
* imgData: (Array<number>|Uint8Array|ArrayBuffer|string|undefined),
|
||||||
|
* imgType: (string|undefined),
|
||||||
|
* opacity: (number|undefined),
|
||||||
|
* blendMode: (string|undefined),
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
var SignImageInfo;
|
||||||
|
/**
|
||||||
|
* The signature can be placed in the same position on multiple pages, but all pages must have the same size and rotation angle.
|
||||||
|
* pageidx: Can be a string to indicate placing the signature on multiple pages.
|
||||||
|
* For example: A pdf contains 17 pages and specify "-3,5-7,9,12,15-" means [0,1,2,3,5,6,7,9,12,15,16]
|
||||||
|
* imgData, imgType: Deprecated, use imgInfo instead.
|
||||||
|
* img, font: Only for internal process.
|
||||||
|
*
|
||||||
* @typedef
|
* @typedef
|
||||||
* {{
|
* {{
|
||||||
* area: SignAreaInfo,
|
* area: SignAreaInfo,
|
||||||
* pageidx: (number|undefined),
|
* pageidx: (number|string|undefined),
|
||||||
* imgData: (Array<number>|Uint8Array|ArrayBuffer|string|undefined),
|
* imgData: (Array<number>|Uint8Array|ArrayBuffer|string|undefined),
|
||||||
* imgType: (string|undefined),
|
* imgType: (string|undefined),
|
||||||
* text: (string|undefined),
|
* imgInfo: (SignImageInfo|undefined),
|
||||||
* fontData: (Array<number>|Uint8Array|ArrayBuffer|string|undefined),
|
* textInfo: (SignTextInfo|undefined),
|
||||||
* img: (PDFLib.PDFImage|undefined),
|
* img: (PDFLib.PDFImage|undefined),
|
||||||
* font: (PDFLib.PDFFont|undefined),
|
* font: (PDFLib.PDFFont|undefined),
|
||||||
* }}
|
* }}
|
||||||
|
|
|
@ -315,30 +315,40 @@ z.PdfSigner = class{
|
||||||
pdfdoc = await PDFLib.PDFDocument.load(_this.oriU8pdf);
|
pdfdoc = await PDFLib.PDFDocument.load(_this.oriU8pdf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_this.opt.drawinf && _this.opt.drawinf.imgData && !_this.opt.drawinf.img){
|
// For backward compatibility
|
||||||
|
if(_this.opt.drawinf && _this.opt.drawinf.imgData && !_this.opt.drawinf.imgInfo){
|
||||||
|
_this.opt.drawinf.imgInfo = {
|
||||||
|
imgData: _this.opt.drawinf.imgData,
|
||||||
|
imgType: _this.opt.drawinf.imgType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_this.opt.drawinf && _this.opt.drawinf.imgInfo && !_this.opt.drawinf.img){
|
||||||
/** @type {Uint8Array|ArrayBuffer|string} */
|
/** @type {Uint8Array|ArrayBuffer|string} */
|
||||||
var imgData2 = null;
|
var imgData2 = null;
|
||||||
if(Array.isArray(_this.opt.drawinf.imgData)){
|
if(Array.isArray(_this.opt.drawinf.imgInfo.imgData)){
|
||||||
imgData2 = new Uint8Array(_this.opt.drawinf.imgData);
|
imgData2 = new Uint8Array(_this.opt.drawinf.imgInfo.imgData);
|
||||||
}else{
|
}else{
|
||||||
imgData2 = _this.opt.drawinf.imgData;
|
imgData2 = _this.opt.drawinf.imgInfo.imgData;
|
||||||
}
|
}
|
||||||
if(_this.opt.drawinf.imgType == "png"){
|
if(_this.opt.drawinf.imgInfo.imgType == "png"){
|
||||||
_this.opt.drawinf.img = await pdfdoc.embedPng(imgData2);
|
_this.opt.drawinf.img = await pdfdoc.embedPng(imgData2);
|
||||||
}else if(_this.opt.drawinf.imgType == "jpg"){
|
}else if(_this.opt.drawinf.imgInfo.imgType == "jpg"){
|
||||||
_this.opt.drawinf.img = await pdfdoc.embedJpg(imgData2);
|
_this.opt.drawinf.img = await pdfdoc.embedJpg(imgData2);
|
||||||
}else{
|
}else{
|
||||||
throw new Error("Unkown image type. " + _this.opt.drawinf.imgType);
|
throw new Error("Unkown image type. " + _this.opt.drawinf.imgInfo.imgType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_this.opt.drawinf && _this.opt.drawinf.text && _this.opt.drawinf.fontData && !_this.opt.drawinf.font){
|
if(_this.opt.drawinf && _this.opt.drawinf.textInfo && !_this.opt.drawinf.font){
|
||||||
/** @type {Uint8Array|ArrayBuffer|string} */
|
/** @type {Uint8Array|ArrayBuffer|string} */
|
||||||
var fontData2 = null;
|
var fontData2 = null;
|
||||||
if(Array.isArray(_this.opt.drawinf.fontData)){
|
if(Array.isArray(_this.opt.drawinf.textInfo.fontData)){
|
||||||
fontData2 = new Uint8Array(_this.opt.drawinf.fontData);
|
fontData2 = new Uint8Array(_this.opt.drawinf.textInfo.fontData);
|
||||||
|
}else if(_this.opt.drawinf.textInfo.fontData){
|
||||||
|
fontData2 = _this.opt.drawinf.textInfo.fontData;
|
||||||
}else{
|
}else{
|
||||||
fontData2 = _this.opt.drawinf.fontData;
|
fontData2 = "Helvetica";
|
||||||
}
|
}
|
||||||
if(typeof fontData2 == "string"){
|
if(typeof fontData2 == "string"){
|
||||||
_this.opt.drawinf.font = pdfdoc.embedStandardFont(fontData2);
|
_this.opt.drawinf.font = pdfdoc.embedStandardFont(fontData2);
|
||||||
|
@ -719,14 +729,18 @@ z.PdfSigner = class{
|
||||||
/** @const {PDFLib.PDFContext} */
|
/** @const {PDFLib.PDFContext} */
|
||||||
const pdfcont = pdfdoc.context;
|
const pdfcont = pdfdoc.context;
|
||||||
/** @const {z.SignatureCreator} */
|
/** @const {z.SignatureCreator} */
|
||||||
const signcrt = new z.SignatureCreator(_this.opt.drawinf);
|
const signcrt = new z.SignatureCreator(_this.opt.drawinf, pdfdoc.getPageCount());
|
||||||
|
/** @type {Array<number>} */
|
||||||
|
var pgidxs = signcrt.getPageIndexes();
|
||||||
/** @const {PDFLib.PDFPage} */
|
/** @const {PDFLib.PDFPage} */
|
||||||
const page = pdfdoc.getPages()[signcrt.getPageIndex()];
|
const page = pdfdoc.getPages()[pgidxs[0]];
|
||||||
/** @type {PDFLib.PDFRef} */
|
/** @type {PDFLib.PDFRef} */
|
||||||
var strmRef = signcrt.createStream(pdfdoc, _this.opt.signame);
|
var strmRef = signcrt.createStream(pdfdoc, _this.opt.signame);
|
||||||
|
|
||||||
if(docMdp && !strmRef){
|
if(docMdp && !strmRef){
|
||||||
strmRef = signcrt.createEmptyField(pdfcont);
|
strmRef = signcrt.createEmptyField(pdfcont);
|
||||||
|
// For invisible signature, only place on one page.
|
||||||
|
pgidxs = [pgidxs[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {Array<string>} */
|
/** @type {Array<string>} */
|
||||||
|
@ -834,18 +848,22 @@ z.PdfSigner = class{
|
||||||
/** @type {PDFLib.PDFRef} */
|
/** @type {PDFLib.PDFRef} */
|
||||||
var widgetDictRef = pdfcont.register(pdfcont.obj(widgetObj));
|
var widgetDictRef = pdfcont.register(pdfcont.obj(widgetObj));
|
||||||
|
|
||||||
// Add our signature widget to the page
|
// Add our signature widget to the pages
|
||||||
/** @type {PDFLib.PDFArray} */
|
pgidxs.forEach(function(pi){
|
||||||
var ans = page.node.Annots();
|
/** @const {PDFLib.PDFPage} */
|
||||||
if(!ans){
|
var p = pdfdoc.getPages()[pi];
|
||||||
ans = new PDFLib.PDFArray(pdfcont);
|
/** @type {PDFLib.PDFArray} */
|
||||||
// if(docMdp){
|
var ans = p.node.Annots();
|
||||||
page.node.set(PDFLib.PDFName.Annots, ans);
|
if(!ans){
|
||||||
// }else{
|
ans = new PDFLib.PDFArray(pdfcont);
|
||||||
// page.node.set(PDFLib.PDFName.Annots, pdfcont.register(ans));
|
// if(docMdp){
|
||||||
// }
|
p.node.set(PDFLib.PDFName.Annots, ans);
|
||||||
}
|
// }else{
|
||||||
ans.push(widgetDictRef);
|
// p.node.set(PDFLib.PDFName.Annots, pdfcont.register(ans));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
ans.push(widgetDictRef);
|
||||||
|
});
|
||||||
|
|
||||||
if(!afrm.dict.lookup(PDFLib.PDFName.of("SigFlags"))){
|
if(!afrm.dict.lookup(PDFLib.PDFName.of("SigFlags"))){
|
||||||
afrm.dict.set(PDFLib.PDFName.of("SigFlags"), PDFLib.PDFNumber.of(3));
|
afrm.dict.set(PDFLib.PDFName.of("SigFlags"), PDFLib.PDFNumber.of(3));
|
||||||
|
@ -1233,10 +1251,11 @@ z.PdfSigner = class{
|
||||||
z.SignatureCreator = class{
|
z.SignatureCreator = class{
|
||||||
/**
|
/**
|
||||||
* @param {SignDrawInfo=} drawinf
|
* @param {SignDrawInfo=} drawinf
|
||||||
|
* @param {number=} pgcnt
|
||||||
*/
|
*/
|
||||||
constructor(drawinf){
|
constructor(drawinf, pgcnt){
|
||||||
/** @private @type {number} */
|
/** @private @type {Array<number>} */
|
||||||
this.pgidx = 0;
|
this.pgidxs = [];
|
||||||
/** @private @type {Array<number>} */
|
/** @private @type {Array<number>} */
|
||||||
this.rect = [0, 0, 0, 0];
|
this.rect = [0, 0, 0, 0];
|
||||||
/** @private @type {?SignDrawInfo} */
|
/** @private @type {?SignDrawInfo} */
|
||||||
|
@ -1244,18 +1263,40 @@ z.SignatureCreator = class{
|
||||||
|
|
||||||
if(drawinf){
|
if(drawinf){
|
||||||
this.drawinf = drawinf;
|
this.drawinf = drawinf;
|
||||||
if(this.drawinf.pageidx){
|
if(typeof this.drawinf.pageidx == "string"){
|
||||||
this.pgidx = this.drawinf.pageidx;
|
/** @type {Array<string>} */
|
||||||
|
var sarr = this.drawinf.pageidx.split(",");
|
||||||
|
/** @type {number} */
|
||||||
|
var i = 0;
|
||||||
|
for(i=0; i<sarr.length; i++){
|
||||||
|
if(sarr[i]){
|
||||||
|
/** @type {Array<string>} */
|
||||||
|
var sarr2 = sarr[i].split("-");
|
||||||
|
/** @type {number} */
|
||||||
|
var j = sarr2[0] ? parseInt(sarr2[0], 10) : 0;
|
||||||
|
/** @type {number} */
|
||||||
|
var ed = sarr2[sarr2.length - 1] ? parseInt(sarr2[sarr2.length - 1], 10) : (pgcnt ? pgcnt -1 : j);
|
||||||
|
while(j <= ed){
|
||||||
|
this.pgidxs.push(j);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if(this.drawinf.pageidx){
|
||||||
|
this.pgidxs = [/** @type {number} */(this.drawinf.pageidx)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(this.pgidxs.length == 0){
|
||||||
|
this.pgidxs = [0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
* @return {number}
|
* @return {Array<number>}
|
||||||
*/
|
*/
|
||||||
getPageIndex(){
|
getPageIndexes(){
|
||||||
return this.pgidx;
|
return this.pgidxs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1289,7 +1330,7 @@ z.SignatureCreator = class{
|
||||||
createStream(pdfdoc, signame){
|
createStream(pdfdoc, signame){
|
||||||
if(!this.drawinf){
|
if(!this.drawinf){
|
||||||
return null;
|
return null;
|
||||||
}else if(!(this.drawinf.img || this.drawinf.text)){
|
}else if(!(this.drawinf.img || this.drawinf.textInfo)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,8 +1338,8 @@ z.SignatureCreator = class{
|
||||||
var pages = pdfdoc.getPages();
|
var pages = pdfdoc.getPages();
|
||||||
/** @type {PDFLib.PDFPage} */
|
/** @type {PDFLib.PDFPage} */
|
||||||
var page = null;
|
var page = null;
|
||||||
if(this.pgidx < pages.length){
|
if(this.pgidxs[0] < pages.length){
|
||||||
page = pages[this.pgidx];
|
page = pages[this.pgidxs[0]];
|
||||||
}else{
|
}else{
|
||||||
throw new Error("Page index is overflow to pdf pages.");
|
throw new Error("Page index is overflow to pdf pages.");
|
||||||
}
|
}
|
||||||
|
@ -1309,59 +1350,46 @@ z.SignatureCreator = class{
|
||||||
/** @type {PdfSize} */
|
/** @type {PdfSize} */
|
||||||
var pgsz = page.getSize();
|
var pgsz = page.getSize();
|
||||||
/** @type {SignAreaInfo} */
|
/** @type {SignAreaInfo} */
|
||||||
var areainf = this.calcAreaInf(pgsz, pgrot.angle, this.drawinf.area);
|
var areainf = this.drawinf.area;
|
||||||
|
|
||||||
// resources object
|
// resources object
|
||||||
/** @type {Object<string, *>} */
|
/** @type {Object<string, *>} */
|
||||||
var rscObj = {};
|
var rscObj = {};
|
||||||
/** @type {Array<PDFLib.PDFOperator>} */
|
|
||||||
var sigOprs = [];
|
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var imgName = signame ? signame.concat("Img") : "SigImg";
|
var imgName = signame ? signame.concat("Img") : "SigImg";
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var fontName = signame ? signame.concat("Font") : "SigFont";
|
var fontName = signame ? signame.concat("Font") : "SigFont";
|
||||||
if(this.drawinf.img){
|
|
||||||
// Get scaled image size
|
|
||||||
/** @type {PdfSize} */
|
|
||||||
var imgsz = this.drawinf.img.size();
|
|
||||||
/** @type {number} */
|
|
||||||
var tmp = areainf.w * imgsz.height / imgsz.width;
|
|
||||||
if(tmp <= areainf.h){
|
|
||||||
areainf.h = tmp;
|
|
||||||
}else{
|
|
||||||
areainf.w = areainf.h * imgsz.width / imgsz.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/** @type {Array<PDFLib.PDFOperator>} */
|
||||||
|
var txtOprs = [];
|
||||||
|
if(this.drawinf.textInfo){
|
||||||
|
rscObj["Font"] = {
|
||||||
|
[fontName]: this.drawinf.font.ref,
|
||||||
|
};
|
||||||
|
txtOprs = this.createDrawTextOper(pdfdoc, pgrot, fontName, areainf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {Array<PDFLib.PDFOperator>} */
|
||||||
|
var imgOprs = [];
|
||||||
|
if(this.drawinf.img){
|
||||||
rscObj["XObject"] = {
|
rscObj["XObject"] = {
|
||||||
[imgName]: this.drawinf.img.ref,
|
[imgName]: this.drawinf.img.ref,
|
||||||
};
|
};
|
||||||
sigOprs = sigOprs.concat(PDFLib.drawImage(imgName, this.calcDrawImgInf(pgrot, areainf)));
|
imgOprs = PDFLib.drawImage(imgName, this.calcDrawImgInf(pgrot, this.drawinf.img.size(), areainf, txtOprs.length == 0));
|
||||||
}
|
|
||||||
if(this.drawinf.text){
|
|
||||||
/** @type {PDFLib.PDFHexString|undefined} */
|
|
||||||
var txt = undefined;
|
|
||||||
if(this.drawinf.font){
|
|
||||||
rscObj["Font"] = {
|
|
||||||
[fontName]: this.drawinf.font.ref,
|
|
||||||
};
|
|
||||||
txt = this.drawinf.font.encodeText(this.drawinf.text);
|
|
||||||
}else{
|
|
||||||
txt = PDFLib.PDFHexString.fromText(this.drawinf.text);
|
|
||||||
}
|
|
||||||
sigOprs = sigOprs.concat(PDFLib.drawLinesOfText([txt], this.calcDrawTextInf(pgrot, areainf, this.drawinf.font ? fontName : "Courier8")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
areainf = this.calcAreaInf(pgsz, pgrot.angle, areainf);
|
||||||
this.rect = this.calcRect(pgrot.angle, areainf);
|
this.rect = this.calcRect(pgrot.angle, areainf);
|
||||||
|
|
||||||
var frmDict = /** @type {PDFLib.PDFDict} */(pdfdoc.context.obj({
|
var frmDict = /** @type {PDFLib.PDFDict} */(pdfdoc.context.obj({
|
||||||
"Type": "XObject",
|
"Type": "XObject",
|
||||||
"Subtype": "Form",
|
"Subtype": "Form",
|
||||||
"FormType": 1,
|
"FormType": 1,
|
||||||
"BBox": [0, 0, areainf.w, areainf.h],
|
"BBox": [0, 0, areainf.wDraw, areainf.hDraw],
|
||||||
"Resources": rscObj,
|
"Resources": rscObj,
|
||||||
}));
|
}));
|
||||||
/** @type {PDFLib.PDFContentStream} */
|
/** @type {PDFLib.PDFContentStream} */
|
||||||
var strm = PDFLib.PDFContentStream.of(frmDict, sigOprs, true);
|
var strm = PDFLib.PDFContentStream.of(frmDict, imgOprs.concat(txtOprs), true);
|
||||||
return pdfdoc.context.register(strm);
|
return pdfdoc.context.register(strm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1379,25 +1407,25 @@ z.SignatureCreator = class{
|
||||||
// Calculate position after rotate
|
// Calculate position after rotate
|
||||||
switch(angle){
|
switch(angle){
|
||||||
case 90:
|
case 90:
|
||||||
ret.w = visinf.h;
|
ret.wDraw = visinf.hDraw;
|
||||||
ret.h = visinf.w;
|
ret.hDraw = visinf.wDraw;
|
||||||
ret.x = visinf.y + visinf.h;
|
ret.x = visinf.y + visinf.hDraw;
|
||||||
ret.y = visinf.x;
|
ret.y = visinf.x;
|
||||||
break;
|
break;
|
||||||
case 180:
|
case 180:
|
||||||
case -180:
|
case -180:
|
||||||
ret.x = pgsz.width - visinf.x;
|
ret.x = pgsz.width - visinf.x;
|
||||||
ret.y = visinf.y + visinf.h;
|
ret.y = visinf.y + visinf.hDraw;
|
||||||
break;
|
break;
|
||||||
case 270:
|
case 270:
|
||||||
case -90:
|
case -90:
|
||||||
ret.w = visinf.h;
|
ret.wDraw = visinf.hDraw;
|
||||||
ret.h = visinf.w;
|
ret.hDraw = visinf.wDraw;
|
||||||
ret.x = pgsz.width - visinf.y - visinf.h;
|
ret.x = pgsz.width - visinf.y - visinf.hDraw;
|
||||||
ret.y = pgsz.height - visinf.x;
|
ret.y = pgsz.height - visinf.x;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret.y = pgsz.height - visinf.y - visinf.h;
|
ret.y = pgsz.height - visinf.y - visinf.hDraw;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1405,7 +1433,7 @@ z.SignatureCreator = class{
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {number} angle
|
* @param {number} angle
|
||||||
* @param {SignAreaInfo} areainf // { x, y, w, h }
|
* @param {SignAreaInfo} areainf
|
||||||
* @return {Array<number>}
|
* @return {Array<number>}
|
||||||
*/
|
*/
|
||||||
calcRect(angle, areainf){
|
calcRect(angle, areainf){
|
||||||
|
@ -1415,22 +1443,22 @@ z.SignatureCreator = class{
|
||||||
rect[1] = areainf.y;
|
rect[1] = areainf.y;
|
||||||
switch(angle){
|
switch(angle){
|
||||||
case 90:
|
case 90:
|
||||||
rect[2] = areainf.x - areainf.h;
|
rect[2] = areainf.x - areainf.wDraw;
|
||||||
rect[3] = areainf.y + areainf.w;
|
rect[3] = areainf.y + areainf.hDraw;
|
||||||
break;
|
break;
|
||||||
case 180:
|
case 180:
|
||||||
case -180:
|
case -180:
|
||||||
rect[2] = areainf.x - areainf.w;
|
rect[2] = areainf.x - areainf.wDraw;
|
||||||
rect[3] = areainf.y - areainf.h;
|
rect[3] = areainf.y - areainf.hDraw;
|
||||||
break;
|
break;
|
||||||
case 270:
|
case 270:
|
||||||
case -90:
|
case -90:
|
||||||
rect[2] = areainf.x + areainf.h;
|
rect[2] = areainf.x + areainf.wDraw;
|
||||||
rect[3] = areainf.y - areainf.w;
|
rect[3] = areainf.y - areainf.hDraw;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rect[2] = areainf.x + areainf.w;
|
rect[2] = areainf.x + areainf.wDraw;
|
||||||
rect[3] = areainf.y + areainf.h;
|
rect[3] = areainf.y + areainf.hDraw;
|
||||||
}
|
}
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
@ -1440,78 +1468,310 @@ z.SignatureCreator = class{
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {PDFLib.Rotation} rot
|
* @param {PDFLib.Rotation} rot
|
||||||
* @param {SignAreaInfo} areainf // { x, y, w, h }
|
* @param {PdfSize} imgsz
|
||||||
|
* @param {SignAreaInfo} areainf
|
||||||
|
* @param {boolean} canResize
|
||||||
* @return {PdfDrawimgOption}
|
* @return {PdfDrawimgOption}
|
||||||
*/
|
*/
|
||||||
calcDrawImgInf(rot, areainf){
|
calcDrawImgInf(rot, imgsz, areainf, canResize){
|
||||||
|
if(!areainf.wDraw){
|
||||||
|
if(areainf.w){
|
||||||
|
areainf.wDraw = areainf.w;
|
||||||
|
}else{
|
||||||
|
areainf.wDraw = imgsz.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!areainf.hDraw){
|
||||||
|
if(areainf.h){
|
||||||
|
areainf.hDraw = areainf.h;
|
||||||
|
}else{
|
||||||
|
areainf.hDraw = imgsz.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** @type {number} */
|
||||||
|
var wImg = areainf.wDraw;
|
||||||
|
/** @type {number} */
|
||||||
|
var hImg = areainf.hDraw;
|
||||||
|
if(wImg != imgsz.width && hImg != imgsz.height){
|
||||||
|
/** @type {number} */
|
||||||
|
var tmp = wImg * imgsz.height / imgsz.width;
|
||||||
|
if(tmp <= hImg){
|
||||||
|
hImg = tmp;
|
||||||
|
}else{
|
||||||
|
wImg = hImg * imgsz.width / imgsz.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(canResize){
|
||||||
|
areainf.wDraw = wImg;
|
||||||
|
areainf.hDraw = hImg;
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {PdfDrawimgOption} */
|
/** @type {PdfDrawimgOption} */
|
||||||
var ret = {
|
var ret = {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"width": areainf.w,
|
"width": wImg,
|
||||||
"height": areainf.h,
|
"height": hImg,
|
||||||
"rotate": rot,
|
"rotate": rot,
|
||||||
"xSkew": PDFLib.degrees(0),
|
"xSkew": PDFLib.degrees(0),
|
||||||
"ySkew": PDFLib.degrees(0),
|
"ySkew": PDFLib.degrees(0),
|
||||||
|
// "graphicsState": "",
|
||||||
};
|
};
|
||||||
switch(rot.angle){
|
switch(rot.angle){
|
||||||
|
case 0:
|
||||||
|
ret["y"] = areainf.hDraw - hImg - ret["y"];
|
||||||
|
break;
|
||||||
case 90:
|
case 90:
|
||||||
ret["x"] = areainf.w;
|
ret["x"] += hImg;
|
||||||
ret["width"] = areainf.h;
|
|
||||||
ret["height"] = areainf.w;
|
|
||||||
break;
|
break;
|
||||||
case 180:
|
case 180:
|
||||||
case -180:
|
case -180:
|
||||||
ret["x"] = areainf.w;
|
ret["x"] = areainf.wDraw - ret["x"];
|
||||||
ret["y"] = areainf.h;
|
ret["y"] += hImg;
|
||||||
break;
|
break;
|
||||||
case 270:
|
case 270:
|
||||||
case -90:
|
case -90:
|
||||||
ret["y"] = areainf.h;
|
ret["x"] = areainf.hDraw - hImg - ret["x"];
|
||||||
ret["width"] = areainf.h;
|
ret["y"] = areainf.wDraw - ret["y"];
|
||||||
ret["height"] = areainf.w;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate informations for drawing text after rotate
|
* Create operations for drawing text after rotate
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
|
* @param {PDFLib.PDFDocument} pdfdoc
|
||||||
* @param {PDFLib.Rotation} rot
|
* @param {PDFLib.Rotation} rot
|
||||||
* @param {SignAreaInfo} areainf // { x, y, w, h }
|
* @param {string} fontName
|
||||||
* @param {string=} font
|
* @param {SignAreaInfo} areainf
|
||||||
* @return {DrawLinesOfTextOptions}
|
* @return {Array<PDFLib.PDFOperator>}
|
||||||
*/
|
*/
|
||||||
calcDrawTextInf(rot, areainf, font){
|
createDrawTextOper(pdfdoc, rot, fontName, areainf){
|
||||||
|
/** @const {z.SignatureCreator} */
|
||||||
|
const _this = this;
|
||||||
|
var txtInf = /** @type {SignTextInfo} */(_this.drawinf.textInfo);
|
||||||
|
var font = /** @type {!PDFLib.PDFFont} */(_this.drawinf.font);
|
||||||
/** @type {DrawLinesOfTextOptions} */
|
/** @type {DrawLinesOfTextOptions} */
|
||||||
var ret = {
|
var opts = {
|
||||||
"x": 0,
|
"x": txtInf.xOffset || 0,
|
||||||
"y": 10,
|
"y": txtInf.yOffset || 0,
|
||||||
"color": PDFLib.rgb(0, 0, 0),
|
"color": _this.hexToColor(txtInf.color),
|
||||||
"font": font,
|
"font": fontName,
|
||||||
"lineHeight": 35,
|
"lineHeight": txtInf.lineHeight || font.heightAtSize(txtInf.size, {descender: true}),
|
||||||
"size": 35,
|
"size": txtInf.size,
|
||||||
"rotate": rot,
|
"rotate": rot,
|
||||||
"xSkew": PDFLib.degrees(0),
|
"xSkew": PDFLib.degrees(0),
|
||||||
"ySkew": PDFLib.degrees(0),
|
"ySkew": PDFLib.degrees(0),
|
||||||
|
// "graphicsState": "",
|
||||||
};
|
};
|
||||||
switch(rot.angle){
|
/**
|
||||||
|
* @param {string} t
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
var calcTextWidth = function(t){
|
||||||
|
return font.widthOfTextAtSize(t, txtInf.size);
|
||||||
|
};
|
||||||
|
/** @type {Array<string>} */
|
||||||
|
var txts = [];
|
||||||
|
/** @type {boolean} */
|
||||||
|
var needW = false;
|
||||||
|
/** @type {number} */
|
||||||
|
var w = txtInf.wMax || areainf.w || 0;
|
||||||
|
if(w){
|
||||||
|
txts = _this.breakTextIntoLines(txtInf.text, w, calcTextWidth, txtInf.noBreaks);
|
||||||
|
}else{
|
||||||
|
txts = PDFLib.lineSplit(PDFLib.cleanText(txtInf.text));
|
||||||
|
needW = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {Array<number>} */
|
||||||
|
var wids = [];
|
||||||
|
/** @type {Array<PDFLib.PDFHexString>} */
|
||||||
|
var enctxts = txts.map(function(t2){
|
||||||
|
/** @type {number} */
|
||||||
|
var cw = 0;
|
||||||
|
t2 = t2.trim();
|
||||||
|
if(needW || txtInf.align){
|
||||||
|
cw = calcTextWidth(t2);
|
||||||
|
wids.push(cw);
|
||||||
|
}
|
||||||
|
if(needW){
|
||||||
|
w = Math.max(w, cw);
|
||||||
|
}
|
||||||
|
return font.encodeText(t2);
|
||||||
|
});
|
||||||
|
if(areainf.w){
|
||||||
|
areainf.wDraw = areainf.w;
|
||||||
|
}else{
|
||||||
|
areainf.wDraw = w + opts["x"];
|
||||||
|
}
|
||||||
|
if(areainf.h){
|
||||||
|
areainf.hDraw = areainf.h;
|
||||||
|
}else{
|
||||||
|
areainf.hDraw = txts.length * opts["lineHeight"] + opts["y"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {Array<PDFLib.PDFOperator>} */
|
||||||
|
var ret = [];
|
||||||
|
/** @type {Array<number>} */
|
||||||
|
var pos = null;
|
||||||
|
if(txtInf.align){
|
||||||
|
wids.forEach(function(w1, i1){
|
||||||
|
/** @type {number} */
|
||||||
|
var x = opts["x"];
|
||||||
|
if(txtInf.align == 1){
|
||||||
|
// center alignment
|
||||||
|
x = (w - w1) / 2 + opts["x"];
|
||||||
|
}else{
|
||||||
|
// right alignment
|
||||||
|
x = (w - w1) + opts["x"];
|
||||||
|
}
|
||||||
|
ret = ret.concat(PDFLib.drawLinesOfText([enctxts[i1]], _this.calcTextPos(opts, areainf.wDraw, areainf.hDraw, i1, x)));
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
ret = PDFLib.drawLinesOfText(enctxts, _this.calcTextPos(opts, areainf.wDraw, areainf.hDraw));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert hex string to Color
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string=} hex
|
||||||
|
* @return {PDFLib.Color}
|
||||||
|
*/
|
||||||
|
hexToColor(hex){
|
||||||
|
/** @type {Array<number>} */
|
||||||
|
var rgb = [0,0,0];
|
||||||
|
if(hex){
|
||||||
|
if(hex.charAt(0) == "#"){
|
||||||
|
hex = hex.substring(1);
|
||||||
|
}
|
||||||
|
if(hex.length == 3){
|
||||||
|
rgb[0] = parseInt(hex.charAt(0)+hex.charAt(0), 16);
|
||||||
|
rgb[1] = parseInt(hex.charAt(1)+hex.charAt(1), 16);
|
||||||
|
rgb[2] = parseInt(hex.charAt(2)+hex.charAt(2), 16);
|
||||||
|
}else if(hex.length == 6){
|
||||||
|
rgb[0] = parseInt(hex.substring(0, 2), 16);
|
||||||
|
rgb[1] = parseInt(hex.substring(2, 4), 16);
|
||||||
|
rgb[2] = parseInt(hex.substring(4, 6), 16);
|
||||||
|
}else{
|
||||||
|
throw new Error("The hex string is not a valid color.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PDFLib.rgb(rgb[0]/255, rgb[1]/255, rgb[2]/255);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {string} text
|
||||||
|
* @param {number} maxWidth
|
||||||
|
* @param {function(string):number} computeWidthOfText
|
||||||
|
* @param {string=} noBreakRx
|
||||||
|
* @return {Array<string>}
|
||||||
|
*/
|
||||||
|
breakTextIntoLines(text, maxWidth, computeWidthOfText, noBreakRx){
|
||||||
|
/** @type {string} */
|
||||||
|
var ctxt = PDFLib.cleanText(text);
|
||||||
|
/** @type {string} */
|
||||||
|
var currLine = "";
|
||||||
|
/** @type {number} */
|
||||||
|
var currWidth = 0;
|
||||||
|
/** @type {Array<string>} */
|
||||||
|
var lines = [];
|
||||||
|
|
||||||
|
var nwRegexp = new RegExp(noBreakRx || "[A-Za-z0-9]");
|
||||||
|
/** @type {Array<string>} */
|
||||||
|
var words = [];
|
||||||
|
/** @type {number} */
|
||||||
|
var idx = 0;
|
||||||
|
/** @type {number} */
|
||||||
|
var len = ctxt.length;
|
||||||
|
while(idx < len){
|
||||||
|
/** @type {string} */
|
||||||
|
var c = ctxt.charAt(idx);
|
||||||
|
if(nwRegexp.test(c)){
|
||||||
|
currLine += c;
|
||||||
|
}else{
|
||||||
|
if(currLine)words.push(currLine);
|
||||||
|
currLine = "";
|
||||||
|
words.push(c);
|
||||||
|
}
|
||||||
|
if(c == "\r" && idx + 1 < len && ctxt.charAt(idx + 1) == "\n"){
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
if(currLine)words.push(currLine);
|
||||||
|
|
||||||
|
currLine = "";
|
||||||
|
idx = 0;
|
||||||
|
len = words.length;
|
||||||
|
while(idx < len){
|
||||||
|
/** @type {string} */
|
||||||
|
var word = words[idx];
|
||||||
|
if(PDFLib.isNewlineChar(word)){
|
||||||
|
lines.push(currLine);
|
||||||
|
currLine = "";
|
||||||
|
currWidth = 0;
|
||||||
|
}else{
|
||||||
|
/** @type {number} */
|
||||||
|
var width = computeWidthOfText(word);
|
||||||
|
if(currWidth + width > maxWidth){
|
||||||
|
lines.push(currLine);
|
||||||
|
currLine = "";
|
||||||
|
currWidth = 0;
|
||||||
|
}
|
||||||
|
currLine += word;
|
||||||
|
currWidth += width;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
if(currLine)lines.push(currLine);
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {DrawLinesOfTextOptions} opts
|
||||||
|
* @param {number=} w // It must not be undefined, but need to suppress warning of mismatch
|
||||||
|
* @param {number=} h // It must not be undefined, but need to suppress warning of mismatch
|
||||||
|
* @param {number=} idx // line index
|
||||||
|
* @param {number=} aX // x of alignment
|
||||||
|
* @return {DrawLinesOfTextOptions} // A copy of opts, and x, y are calculated.
|
||||||
|
*/
|
||||||
|
calcTextPos(opts, w, h, idx, aX){
|
||||||
|
var newopts = /** @type {DrawLinesOfTextOptions} */(Object.assign({}, opts));
|
||||||
|
/** @type {number} */
|
||||||
|
var i = idx || 0;
|
||||||
|
/** @type {number} */
|
||||||
|
var x = aX || opts["x"];
|
||||||
|
switch(opts["rotate"].angle){
|
||||||
|
case 0:
|
||||||
|
newopts["x"] = x;
|
||||||
|
newopts["y"] = h - opts["lineHeight"] - opts["y"] - (opts["lineHeight"] * i);
|
||||||
|
break;
|
||||||
case 90:
|
case 90:
|
||||||
ret["x"] = areainf.w;
|
newopts["x"] = opts["lineHeight"] + opts["y"] + (opts["lineHeight"] * i);
|
||||||
|
newopts["y"] = x;
|
||||||
break;
|
break;
|
||||||
case 180:
|
case 180:
|
||||||
case -180:
|
case -180:
|
||||||
ret["x"] = areainf.w;
|
newopts["x"] = w - x;
|
||||||
ret["y"] = areainf.h;
|
newopts["y"] = opts["lineHeight"] + opts["y"] + (opts["lineHeight"] * i);
|
||||||
break;
|
break;
|
||||||
case 270:
|
case 270:
|
||||||
case -90:
|
case -90:
|
||||||
ret["y"] = areainf.h;
|
newopts["x"] = h - opts["lineHeight"] - opts["y"] - (opts["lineHeight"] * i);
|
||||||
|
newopts["y"] = w - x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return newopts;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
61
test4node.js
61
test4node.js
|
@ -10,9 +10,11 @@ const workpath = "test/";
|
||||||
* @param {string} ps
|
* @param {string} ps
|
||||||
* @param {number} perm
|
* @param {number} perm
|
||||||
* @param {string=} imgPath
|
* @param {string=} imgPath
|
||||||
|
* @param {string=} txt
|
||||||
|
* @param {string=} fontPath
|
||||||
* @return {Promise<string>} output path
|
* @return {Promise<string>} output path
|
||||||
*/
|
*/
|
||||||
async function sign_protect(pdfPath, pfxPath, ps, perm, imgPath){
|
async function sign_protect(pdfPath, pfxPath, ps, perm, imgPath, txt, fontPath){
|
||||||
/** @type {Buffer} */
|
/** @type {Buffer} */
|
||||||
var pdf = m_fs.readFileSync(pdfPath);
|
var pdf = m_fs.readFileSync(pdfPath);
|
||||||
/** @type {Buffer} */
|
/** @type {Buffer} */
|
||||||
|
@ -21,6 +23,8 @@ async function sign_protect(pdfPath, pfxPath, ps, perm, imgPath){
|
||||||
var img = null;
|
var img = null;
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var imgType = "";
|
var imgType = "";
|
||||||
|
/** @type {Buffer} */
|
||||||
|
var font = null;
|
||||||
|
|
||||||
if(perm == 1){
|
if(perm == 1){
|
||||||
console.log("\nTest signing pdf with full protection. (permission 1 and password encryption)");
|
console.log("\nTest signing pdf with full protection. (permission 1 and password encryption)");
|
||||||
|
@ -32,6 +36,9 @@ async function sign_protect(pdfPath, pfxPath, ps, perm, imgPath){
|
||||||
img = m_fs.readFileSync(imgPath);
|
img = m_fs.readFileSync(imgPath);
|
||||||
imgType = m_path.extname(imgPath).slice(1);
|
imgType = m_path.extname(imgPath).slice(1);
|
||||||
}
|
}
|
||||||
|
if(fontPath){
|
||||||
|
font = m_fs.readFileSync(fontPath);
|
||||||
|
}
|
||||||
/** @type {SignOption} */
|
/** @type {SignOption} */
|
||||||
var sopt = {
|
var sopt = {
|
||||||
p12cert: pfx,
|
p12cert: pfx,
|
||||||
|
@ -44,16 +51,31 @@ async function sign_protect(pdfPath, pfxPath, ps, perm, imgPath){
|
||||||
ltv: 1,
|
ltv: 1,
|
||||||
debug: true,
|
debug: true,
|
||||||
};
|
};
|
||||||
if(img){
|
if(img || txt){
|
||||||
sopt.drawinf = {
|
sopt.drawinf = {
|
||||||
area: {
|
area: {
|
||||||
x: 25, // left
|
x: 25, // left
|
||||||
y: 150, // top
|
y: 50, // top
|
||||||
w: 60,
|
w: txt ? undefined : 60,
|
||||||
h: 60,
|
h: txt ? undefined : 100,
|
||||||
},
|
},
|
||||||
imgData: img,
|
pageidx: "-",
|
||||||
imgType: imgType,
|
imgInfo: img ? {
|
||||||
|
imgData: img,
|
||||||
|
imgType: imgType,
|
||||||
|
} : undefined,
|
||||||
|
textInfo: txt ? {
|
||||||
|
text: txt,
|
||||||
|
fontData: font,
|
||||||
|
color: "00f0f1",
|
||||||
|
lineHeight: 20,
|
||||||
|
size: 16,
|
||||||
|
align: 1,
|
||||||
|
wMax: 80,
|
||||||
|
yOffset: 10,
|
||||||
|
xOffset: 20,
|
||||||
|
noBreaks: "[あいうえおA-Za-z0-9]",
|
||||||
|
} : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +95,7 @@ async function sign_protect(pdfPath, pfxPath, ps, perm, imgPath){
|
||||||
var u8dat = await ser.sign(pdf, eopt);
|
var u8dat = await ser.sign(pdf, eopt);
|
||||||
if(u8dat){
|
if(u8dat){
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var outPath = m_path.join(__dirname, workpath+"test_perm"+perm+".pdf");
|
var outPath = m_path.join(__dirname, workpath+"test_perm"+perm+m_path.basename(pdfPath));
|
||||||
m_fs.writeFileSync(outPath, u8dat);
|
m_fs.writeFileSync(outPath, u8dat);
|
||||||
console.log("Output file: " + outPath);
|
console.log("Output file: " + outPath);
|
||||||
}
|
}
|
||||||
|
@ -109,15 +131,20 @@ async function addtsa(pdfPath){
|
||||||
return outPath;
|
return outPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main(){
|
/**
|
||||||
|
* @param {number} angle
|
||||||
|
*/
|
||||||
|
async function main1(angle){
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var pdfPath = m_path.join(__dirname, workpath+"_test.pdf");
|
var pdfPath = m_path.join(__dirname, workpath+"_test"+(angle ? "_"+angle : "")+".pdf");
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var pfxPath = m_path.join(__dirname, workpath+"_test.pfx");
|
var pfxPath = m_path.join(__dirname, workpath+"_test.pfx");
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var ps = "";
|
var ps = "";
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var imgPath = m_path.join(__dirname, workpath+"_test.png");
|
var imgPath = m_path.join(__dirname, workpath+"_test.png");
|
||||||
|
/** @type {string} */
|
||||||
|
var fontPath = m_path.join(__dirname, workpath+"_test.ttf");
|
||||||
|
|
||||||
if(process.argv.length > 3){
|
if(process.argv.length > 3){
|
||||||
pfxPath = process.argv[2];
|
pfxPath = process.argv[2];
|
||||||
|
@ -132,8 +159,8 @@ async function main(){
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pfxPath){
|
if(pfxPath){
|
||||||
await sign_protect(pdfPath, pfxPath, ps, 1, imgPath);
|
await sign_protect(pdfPath, pfxPath, ps, 1, imgPath, "あいうえおか\r\n\nThis is a test of text!\n", fontPath);
|
||||||
pdfPath = await sign_protect(pdfPath, pfxPath, ps, 2, imgPath);
|
pdfPath = await sign_protect(pdfPath, pfxPath, ps, 2, undefined, "ありがとうご\r\n\nThis is an another test of text!\n", fontPath);
|
||||||
await addtsa(pdfPath);
|
await addtsa(pdfPath);
|
||||||
}else{
|
}else{
|
||||||
await addtsa(pdfPath);
|
await addtsa(pdfPath);
|
||||||
|
@ -142,4 +169,14 @@ async function main(){
|
||||||
console.log("Done");
|
console.log("Done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function main(){
|
||||||
|
/** @type {Array<number>} */
|
||||||
|
var arr = [0, 90, 180, 270];
|
||||||
|
/** @type {number} */
|
||||||
|
for(var i=0; i<arr.length; i++){
|
||||||
|
await main1(arr[i]);
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
Loading…
Reference in New Issue