function PdfParser(context, needRawText) { //call constructor for super class stream.Transform.call(this, {objectMode: true, bufferSize: 64 * 1024}); // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = () => _id; this.get_name = () => _name + _id; // service context object, only used in Web Service project; null in command line this.context = context; this.pdfFilePath = null; //current PDF file to load and parse, null means loading/parsing not started this.data = null; //if file read success, data is PDF content; if failed, data is "err" object this.PDFJS = new PDFJS(needRawText); this.processFieldInfoXML = false;//disable additional _fieldInfo.xml parsing and merging this.chunks = []; this.flushCallback = null; }
n/a
p2jcmd = function () { this.inputCount = 0; this.successCount = 0; this.failedCount = 0; this.warningCount = 0; this.p2j = null; }
n/a
pdf = function (needRawText) { nodeEvents.EventEmitter.call(this); // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = () => _id; this.get_name = () => _name + _id; // public, this instance copies this.pdfDocument = null; this.pages = []; this.pageWidth = 0; this.rawTextContents = []; this.needRawText = needRawText; }
n/a
pdfanno = function (field, viewport, Fields, Boxsets) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function () { return _id; }; this.get_name = function () { return _name + _id; }; }
n/a
function CanvasRenderingContext2D_(canvasTarget, scaledWidth, scaledHeight) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.m_ = createMatrixIdentity(); this.mStack_ = []; this.aStack_ = []; this.currentPath_ = []; // Canvas context properties this.strokeStyle = '#000'; this.fillStyle = '#000'; this.lineWidth = 1; this.lineJoin = 'miter'; this.lineCap = 'butt'; this.dashArray = []; this.miterLimit = 1; this.globalAlpha = 1; if (!_.has(canvasTarget, "HLines") || !_.isArray(canvasTarget.HLines)) canvasTarget.HLines = []; if (!_.has(canvasTarget, "VLines") || !_.isArray(canvasTarget.VLines)) canvasTarget.VLines = []; if (!_.has(canvasTarget, "Fills") || !_.isArray(canvasTarget.Fills)) canvasTarget.Fills = []; if (!_.has(canvasTarget, "Texts") || !_.isArray(canvasTarget.Texts)) canvasTarget.Texts = []; this.canvas = canvasTarget; this.width = scaledWidth; this.height = scaledHeight; this.arcScaleX_ = 1; this.arcScaleY_ = 1; this.lineScale_ = 1; this.currentFont = null; }
n/a
pdffield = function (field, viewport, Fields, Boxsets) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.field = field; this.viewport = viewport; this.Fields = Fields; this.Boxsets = Boxsets; }
n/a
pdffill = function (x, y, width, height, color) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.x = x; this.y = y; this.width = width; this.height = height; this.color = color; }
n/a
pdffont = function (fontObj) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.fontObj = fontObj; let typeName = (fontObj.name || fontObj.fallbackName); if (!typeName) { typeName = _kFontFaces[0]; //default font family name } typeName = typeName.toLowerCase(); this.typeName = typeName; let subType = typeName; let nameArray = typeName.split('+'); if (_.isArray(nameArray) && nameArray.length > 1) { subType = nameArray[1].split("-"); if (_.isArray(subType) && subType.length > 1) { if (!this.bold) { let subName = subType[1].toLowerCase(); this.bold = _boldSubNames.indexOf(subName) >= 0; } subType = subType[0]; } } this.subType = subType; this.isSymbol = typeName.indexOf("symbol") > 0 || _kFontFaces[2].indexOf(this.subType) >= 0; if (this.fontObj.isSymbolicFont) { let mFonts = _stdFonts.filter( (oneName) => (typeName.indexOf(oneName) >= 0) ); if (mFonts.length > 0) { this.fontObj.isSymbolicFont = false; //lots of Arial-based font is detected as symbol in VA forms (301, 76-c, etc.) reset the flag for now nodeUtil.p2jinfo("Reset: isSymbolicFont (false) for " + this.fontObj.name); } } else { if (this.isSymbol) { this.fontObj.isSymbolicFont = true; //text pdf: va_ind_760c nodeUtil.p2jinfo("Reset: isSymbolicFont (true) for " + this.fontObj.name); } } this.fontSize = 1; this.faceIdx = 0; this.bold = false; this.italic = false; this.fontStyleId = -1; this.spaceWidth = fontObj.spaceWidth; if (!this.spaceWidth) { var spaceId = Array.isArray(fontObj.toFontChar) ? fontObj.toFontChar.indexOf(32) : -1; this.spaceWidth = (spaceId >= 0 && Array.isArray(fontObj.widths)) ? fontObj.widths[spaceId] : 250; } this.spaceWidth = PDFUnit.toFormX(this.spaceWidth) / 32; }
n/a
pdfline = function (x1, y1, x2, y2, lineWidth, color, dashed) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.lineWidth = lineWidth || 1.0; this.color = color; this.dashed = dashed; }
n/a
pdfunit = function () { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; }
n/a
ptixmlinject = function () { }
n/a
function Transform(options) { if (!(this instanceof Transform)) return new Transform(options); Duplex.call(this, options); this._transformState = new TransformState(this); var stream = this; // start out asking for a readable event once data is transformed. this._readableState.needReadable = true; // we have implemented the _read method, and done the other things // that Readable wants before the first _read call, so unset the // sync guard flag. this._readableState.sync = false; if (options) { if (typeof options.transform === 'function') this._transform = options.transform; if (typeof options.flush === 'function') this._flush = options.flush; } // When the writable side finishes, then flush out anything remaining. this.once('prefinish', function() { if (typeof this._flush === 'function') this._flush(function(er) { done(stream, er); }); else done(stream); }); }
n/a
p2jcmd = function () { this.inputCount = 0; this.successCount = 0; this.failedCount = 0; this.warningCount = 0; this.p2j = null; }
n/a
complete = function (err) { let statusMsg = "\n%d input files\t%d success\t%d fail\t%d warning."; console.log(statusMsg, this.inputCount, this.successCount, this.failedCount, this.warningCount); process.nextTick( () => { console.timeEnd(_PRO_TIMER); //let exitCode = (this.inputCount === this.successCount) ? 0 : 1; process.exit(0); }); }
...
cls.prototype.processOneFile = function () {
let inputDir = path.dirname(argv.f);
let inputFile = path.basename(argv.f);
this.inputCount = 1;
this.p2j = new PDF2JSONUtil(inputDir, inputFile, this);
this.p2j.processFile( data => this.complete(data) );
};
cls.prototype.processFiles = function(inputDir, files) {
let fId = 0;
this.p2j = new PDF2JSONUtil(inputDir, files[fId], this);
this.p2j.processFile( function processPDFFile(err) {
if (err) {
...
initialize = function (){ console.time(_PRO_TIMER); let retVal = true; try { if (_.has(argv, 'v')) { console.log(pkInfo.version); retVal = false; } else if (_.has(argv, 'h')) { optimist.showHelp(); retVal = false; } else if (!_.has(argv, 'f')) { optimist.showHelp(); console.log("-f is required to specify input directory or file."); retVal = false; } } catch(e) { console.log("Exception: " + e.message); retVal = false; } return retVal; }
...
console.log("Exception: " + e.message);
retVal = false;
}
return retVal;
};
cls.prototype.start = function(){
if (!this.initialize()) {
console.timeEnd(_PRO_TIMER);
return;
}
try {
console.log("\n" + _PRO_TIMER);
...
processFiles = function (inputDir, files) { let fId = 0; this.p2j = new PDF2JSONUtil(inputDir, files[fId], this); this.p2j.processFile( function processPDFFile(err) { if (err) { this.complete(err); } else { fId++; if (fId >= this.inputCount) { this.complete(null); } else { if (this.p2j) { this.p2j.destroy(); this.p2j = null; } this.p2j = new PDF2JSONUtil(inputDir, files[fId], this); this.p2j.processFile(processPDFFile.bind(this)); } } }.bind(this)); }
...
fs.readdir(inputDir, (err, files) => {
let _iChars = "!@#$%^&*()+=[]\\\';,/{}|\":<>?~`.-_ ";
let pdfFiles = files.filter( file => file.substr(-4).toLowerCase() === '.pdf' && _iChars.indexOf
(file.substr(0,1)) < 0 );
this.inputCount = pdfFiles.length;
if (this.inputCount > 0) {
this.processFiles(inputDir, pdfFiles);
}
else {
console.log("No PDF files found. [" + inputDir + "].");
this.complete(null);
}
});
};
...
processOneDirectory = function () { let inputDir = path.normalize(argv.f); fs.readdir(inputDir, (err, files) => { let _iChars = "!@#$%^&*()+=[]\\\';,/{}|\":<>?~`.-_ "; let pdfFiles = files.filter( file => file.substr(-4).toLowerCase() === '.pdf' && _iChars.indexOf(file.substr(0,1)) < 0 ); this.inputCount = pdfFiles.length; if (this.inputCount > 0) { this.processFiles(inputDir, pdfFiles); } else { console.log("No PDF files found. [" + inputDir + "]."); this.complete(null); } }); }
...
let inputStatus = fs.statSync(argv.f);
if (inputStatus.isFile()) {
this.processOneFile();
}
else if (inputStatus.isDirectory()) {
this.processOneDirectory();
}
}
catch(e) {
console.error("Exception: " + e.message);
console.timeEnd(_PRO_TIMER);
}
};
...
processOneFile = function () { let inputDir = path.dirname(argv.f); let inputFile = path.basename(argv.f); this.inputCount = 1; this.p2j = new PDF2JSONUtil(inputDir, inputFile, this); this.p2j.processFile( data => this.complete(data) ); }
...
try {
console.log("\n" + _PRO_TIMER);
let inputStatus = fs.statSync(argv.f);
if (inputStatus.isFile()) {
this.processOneFile();
}
else if (inputStatus.isDirectory()) {
this.processOneDirectory();
}
}
catch(e) {
console.error("Exception: " + e.message);
...
start = function (){ if (!this.initialize()) { console.timeEnd(_PRO_TIMER); return; } try { console.log("\n" + _PRO_TIMER); let inputStatus = fs.statSync(argv.f); if (inputStatus.isFile()) { this.processOneFile(); } else if (inputStatus.isDirectory()) { this.processOneDirectory(); } } catch(e) { console.error("Exception: " + e.message); console.timeEnd(_PRO_TIMER); } }
...
'use strict';
var P2JCMD = require('./lib/p2jcmd');
new P2JCMD().start();
...
pdf = function (needRawText) { nodeEvents.EventEmitter.call(this); // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = () => _id; this.get_name = () => _name + _id; // public, this instance copies this.pdfDocument = null; this.pages = []; this.pageWidth = 0; this.rawTextContents = []; this.needRawText = needRawText; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
destroy = function () { this.removeAllListeners(); if (this.pdfDocument) this.pdfDocument.destroy(); this.pdfDocument = null; this.pages = null; this.rawTextContents = null; }
...
PdfParser.prototype.getMergedTextBlocksStream = function() { return _createContentStream(this.getMergedTextBlocksIfNeeded()); };
PdfParser.prototype.destroy = function() {
this.removeAllListeners();
//context object will be set in Web Service project, but not in command line utility
if (this.context) {
this.context.destroy();
this.context = null;
}
this.pdfFilePath = null;
this.data = null;
this.chunks = null;
...
getAllFieldsTypes = function () { return PDFField.getAllFieldsTypes({Pages:this.pages || [], Width: this.pageWidth}); }
...
PdfParser.prototype.parseBuffer = function(pdfBuffer) {
_startParsingPDF.call(this, pdfBuffer);
};
PdfParser.prototype.getRawTextContent = function() { return this.PDFJS.getRawTextContent(); };
PdfParser.prototype.getRawTextContentStream = function() { return _createContentStream(this.getRawTextContent()); };
PdfParser.prototype.getAllFieldsTypes = function() { return this.PDFJS.getAllFieldsTypes(); };
PdfParser.prototype.getAllFieldsTypesStream = function() { return _createContentStream(this.getAllFieldsTypes()); };
PdfParser.prototype.getMergedTextBlocksIfNeeded = function() { return {"formImage": this.PDFJS.getMergedTextBlocksIfNeeded
()}; };
PdfParser.prototype.getMergedTextBlocksStream = function() { return _createContentStream(this.getMergedTextBlocksIfNeeded()); };
PdfParser.prototype.destroy = function() {
this.removeAllListeners();
...
getMergedTextBlocksIfNeeded = function () { for (let p = 0; p < this.pages.length; p++) { let prevText = null; let page = this.pages[p]; page.Texts.sort(PDFFont.compareBlockPos); page.Texts = page.Texts.filter( (t, j) => { let isDup = (j > 0) && PDFFont.areDuplicateBlocks(page.Texts[j-1], t); if (isDup) { nodeUtil.p2jinfo("skipped: dup text block: " + decodeURIComponent(t.R[0].T)); } return !isDup; }); for (let i = 0; i < page.Texts.length; i++) { let text = page.Texts[i]; if (prevText) { if (PDFFont.areAdjacentBlocks(prevText, text) && PDFFont.haveSameStyle(prevText, text)) { let preT = decodeURIComponent(prevText.R[0].T); let curT = decodeURIComponent(text.R[0].T); prevText.R[0].T += text.R[0].T; prevText.w += text.w; text.merged = true; let mergedText = decodeURIComponent(prevText.R[0].T); nodeUtil.p2jinfo(`merged text block: ${preT} + ${curT} => ${mergedText}`); prevText = null; //yeah, only merge two blocks for now } else { prevText = text; } } else { prevText = text; } } page.Texts = page.Texts.filter( t => !t.merged); } return {Pages:this.pages, Width: this.pageWidth}; }
...
PdfParser.prototype.getRawTextContent = function() { return this.PDFJS.getRawTextContent(); };
PdfParser.prototype.getRawTextContentStream = function() { return _createContentStream(this.getRawTextContent()); };
PdfParser.prototype.getAllFieldsTypes = function() { return this.PDFJS.getAllFieldsTypes(); };
PdfParser.prototype.getAllFieldsTypesStream = function() { return _createContentStream(this.getAllFieldsTypes()); };
PdfParser.prototype.getMergedTextBlocksIfNeeded = function() { return {"formImage": this.PDFJS.getMergedTextBlocksIfNeeded()}; };
PdfParser.prototype.getMergedTextBlocksStream = function() { return _createContentStream(this.getMergedTextBlocksIfNeeded()); };
PdfParser.prototype.destroy = function() {
this.removeAllListeners();
//context object will be set in Web Service project, but not in command line utility
if (this.context) {
...
getRawTextContent = function () { let retVal = ""; if (!this.needRawText) return retVal; _.each(this.rawTextContents, function(textContent, index) { let prevText = null; _.each(textContent.bidiTexts, function(textObj, idx) { if (prevText) { if (Math.abs(textObj.y - prevText.y) <= 9) { prevText.str += textObj.str; } else { retVal += prevText.str + "\r\n"; prevText = textObj; } } else { prevText = textObj; } }); if (prevText) { retVal += prevText.str; } retVal += "\r\n----------------Page (" + index + ") Break----------------\r\n"; }); return retVal; }
...
};
// Introduce a way to directly process buffers without the need to write it to a temporary file
PdfParser.prototype.parseBuffer = function(pdfBuffer) {
_startParsingPDF.call(this, pdfBuffer);
};
PdfParser.prototype.getRawTextContent = function() { return this.PDFJS.getRawTextContent(); };
PdfParser.prototype.getRawTextContentStream = function() { return _createContentStream(this.getRawTextContent()); };
PdfParser.prototype.getAllFieldsTypes = function() { return this.PDFJS.getAllFieldsTypes(); };
PdfParser.prototype.getAllFieldsTypesStream = function() { return _createContentStream(this.getAllFieldsTypes()); };
PdfParser.prototype.getMergedTextBlocksIfNeeded = function() { return {"formImage": this.PDFJS.getMergedTextBlocksIfNeeded
()}; };
PdfParser.prototype.getMergedTextBlocksStream = function() { return _createContentStream(this.getMergedTextBlocksIfNeeded()); };
...
load = function (pdfDocument, scale) { this.pdfDocument = pdfDocument; return this.loadMetaData().then( () => this.loadPages(), error => this.raiseErrorEvent("loadMetaData error: " + error) ); }
...
cls.prototype.parsePDFData = function(arrayBuffer) {
this.pdfDocument = null;
let parameters = {password: '', data: arrayBuffer};
PDFJS.getDocument(parameters).then(
pdfDocument => this.load(pdfDocument, 1),
error => this.raiseErrorEvent("An error occurred while parsing the PDF: " + error)
);
};
cls.prototype.tryLoadFieldInfoXML = function(pdfFilePath) {
let fieldInfoXMLPath = pdfFilePath.replace(".pdf", _sufInfo);
if ((fieldInfoXMLPath.indexOf(_sufInfo) < 1) || (!fs.existsSync(fieldInfoXMLPath))) {
...
loadMetaData = function () { return this.pdfDocument.getMetadata().then( data => { this.documentInfo = data.info; this.metadata = data.metadata; this.parseMetaData(); }, error => this.raiseErrorEvent("pdfDocument.getMetadata error: " + error) ); }
...
}
});
};
cls.prototype.load = function(pdfDocument, scale) {
this.pdfDocument = pdfDocument;
return this.loadMetaData().then(
() => this.loadPages(),
error => this.raiseErrorEvent("loadMetaData error: " + error)
);
};
cls.prototype.loadMetaData = function() {
return this.pdfDocument.getMetadata().then(
...
loadPages = function () { let pagesCount = this.pdfDocument.numPages; let pagePromises = []; for (let i = 1; i <= pagesCount; i++) pagePromises.push(this.pdfDocument.getPage(i)); let pagesPromise = PDFJS.Promise.all(pagePromises); nodeUtil.p2jinfo("PDF loaded. pagesCount = " + pagesCount); return pagesPromise.then( promisedPages => this.parsePage(promisedPages, 0, 1.5), error => this.raiseErrorEvent("pagesPromise error: " + error) ); }
...
});
};
cls.prototype.load = function(pdfDocument, scale) {
this.pdfDocument = pdfDocument;
return this.loadMetaData().then(
() => this.loadPages(),
error => this.raiseErrorEvent("loadMetaData error: " + error)
);
};
cls.prototype.loadMetaData = function() {
return this.pdfDocument.getMetadata().then(
data => {
...
parseMetaData = function () { let info = this.documentInfo; let metadata = this.metadata; let pdfTile = ""; if (metadata && metadata.has('dc:title')) { pdfTile = metadata.get('dc:title'); } else if (info && info['Title']) pdfTile = info['Title']; let formAttr = {AgencyId:"", Name: "", MC: false, Max: 1, Parent:""}; if (metadata) { formAttr.AgencyId = _getMetaDataString(metadata, 'pdfx:agencyid'); if (formAttr.AgencyId != "unknown") pdfTile = formAttr.AgencyId; formAttr.Name = _getMetaDataString(metadata, 'pdfx:name'); formAttr.MC = _getMetaDataString(metadata, 'pdfx:mc') === 'true'; formAttr.Max = _getMetaDataInt(metadata, 'pdfx:max'); formAttr.Parent = _getMetaDataInt(metadata, 'pdfx:parent'); } this.raiseReadyEvent({Transcoder: _PARSER_SIG, Agency:pdfTile, Id: formAttr}); }
...
};
cls.prototype.loadMetaData = function() {
return this.pdfDocument.getMetadata().then(
data => {
this.documentInfo = data.info;
this.metadata = data.metadata;
this.parseMetaData();
},
error => this.raiseErrorEvent("pdfDocument.getMetadata error: " + error)
);
};
cls.prototype.parseMetaData = function() {
let info = this.documentInfo;
...
parsePDFData = function (arrayBuffer) { this.pdfDocument = null; let parameters = {password: '', data: arrayBuffer}; PDFJS.getDocument(parameters).then( pdfDocument => this.load(pdfDocument, 1), error => this.raiseErrorEvent("An error occurred while parsing the PDF: " + error) ); }
...
let _startParsingPDF = function(buffer) {
this.data = {};
this.PDFJS.on("pdfjs_parseDataReady", _onPDFJSParseDataReady.bind(this));
this.PDFJS.on("pdfjs_parseDataError", _onPDFJSParserDataError.bind(this));
this.PDFJS.parsePDFData(buffer || _binBuffer[this.pdfFilePath]);
};
let _processBinaryCache = function() {
if (_.has(_binBuffer, this.pdfFilePath)) {
_startParsingPDF.call(this);
return true;
}
...
parsePage = function (promisedPages, id, scale) { nodeUtil.p2jinfo("start to parse page:" + (id+1)); let pdfPage = promisedPages[id]; let pageParser = new PDFPageParser(pdfPage, id, scale, this.ptiParser); function continueOnNextPage() { nodeUtil.p2jinfo("complete parsing page:" + (id+1)); if (id === (this.pdfDocument.numPages - 1) ) { this.raiseReadyEvent({Pages:this.pages, Width: this.pageWidth}); //v1.1.2: signal end of parsed data with null process.nextTick(() => this.raiseReadyEvent(null)); } else { process.nextTick(() => this.parsePage(promisedPages, ++id, scale)); } } pageParser.parsePage( data => { if (!this.pageWidth) //get PDF width this.pageWidth = pageParser.width; let page = {Height: pageParser.height, HLines: pageParser.HLines, VLines: pageParser.VLines, Fills:pageParser.Fills, //needs to keep current default output format, text content will output to a separate file if '-c' command line argument is set // Content:pdfPage.getTextContent(), Texts: pageParser.Texts, Fields: pageParser.Fields, Boxsets: pageParser.Boxsets }; this.pages.push(page); if (this.needRawText) { pdfPage.getTextContent().then( textContent => { this.rawTextContents.push(textContent); nodeUtil.p2jinfo("complete parsing raw text content:" + (id+1)); continueOnNextPage.call(this); }, error => this.raiseErrorEvent("pdfPage.getTextContent error: " + error) ); } else { continueOnNextPage.call(this); } }, errMsg => this.raiseErrorEvent("parsePage error:" + errMsg) ); }
...
pagePromises.push(this.pdfDocument.getPage(i));
let pagesPromise = PDFJS.Promise.all(pagePromises);
nodeUtil.p2jinfo("PDF loaded. pagesCount = " + pagesCount);
return pagesPromise.then(
promisedPages => this.parsePage(promisedPages, 0, 1.5),
error => this.raiseErrorEvent("pagesPromise error: " + error)
);
};
cls.prototype.parsePage = function(promisedPages, id, scale) {
nodeUtil.p2jinfo("start to parse page:" + (id+1));
...
raiseErrorEvent = function (errMsg) { console.error(errMsg); process.nextTick( () => this.emit("pdfjs_parseDataError", errMsg)); return errMsg; }
...
cls.prototype.parsePDFData = function(arrayBuffer) {
this.pdfDocument = null;
let parameters = {password: '', data: arrayBuffer};
PDFJS.getDocument(parameters).then(
pdfDocument => this.load(pdfDocument, 1),
error => this.raiseErrorEvent("An error occurred while parsing the
PDF: " + error)
);
};
cls.prototype.tryLoadFieldInfoXML = function(pdfFilePath) {
let fieldInfoXMLPath = pdfFilePath.replace(".pdf", _sufInfo);
if ((fieldInfoXMLPath.indexOf(_sufInfo) < 1) || (!fs.existsSync(fieldInfoXMLPath))) {
return;
...
raiseReadyEvent = function (data) { process.nextTick( () => this.emit("pdfjs_parseDataReady", data) ); return data; }
...
formAttr.Name = _getMetaDataString(metadata, 'pdfx:name');
formAttr.MC = _getMetaDataString(metadata, 'pdfx:mc') === 'true';
formAttr.Max = _getMetaDataInt(metadata, 'pdfx:max');
formAttr.Parent = _getMetaDataInt(metadata, 'pdfx:parent');
}
this.raiseReadyEvent({Transcoder: _PARSER_SIG, Agency:pdfTile, Id: formAttr});
};
cls.prototype.loadPages = function() {
let pagesCount = this.pdfDocument.numPages;
let pagePromises = [];
for (let i = 1; i <= pagesCount; i++)
pagePromises.push(this.pdfDocument.getPage(i));
...
tryLoadFieldInfoXML = function (pdfFilePath) { let fieldInfoXMLPath = pdfFilePath.replace(".pdf", _sufInfo); if ((fieldInfoXMLPath.indexOf(_sufInfo) < 1) || (!fs.existsSync(fieldInfoXMLPath))) { return; } nodeUtil.p2jinfo("About to load fieldInfo XML : " + fieldInfoXMLPath); let PTIXmlParser = require('./ptixmlinject'); this.ptiParser = new PTIXmlParser(); this.ptiParser.parseXml(fieldInfoXMLPath, err => { if (err) { nodeUtil.p2jwarn("fieldInfo XML Error: " + JSON.stringify(err)); this.ptiParser = null; } else { nodeUtil.p2jinfo("fieldInfo XML loaded."); } }); }
...
PdfParser.prototype.loadPDF = function(pdfFilePath, verbosity) {
this.setVerbosity(verbosity);
nodeUtil.p2jinfo("about to load PDF file " + pdfFilePath);
this.pdfFilePath = pdfFilePath;
if (this.processFieldInfoXML) {
this.PDFJS.tryLoadFieldInfoXML(pdfFilePath);
}
if (_processBinaryCache.call(this))
return;
this.fq.push({path: pdfFilePath}, _processPDFContent.bind(this));
};
...
pdfanno = function (field, viewport, Fields, Boxsets) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function () { return _id; }; this.get_name = function () { return _name + _id; }; }
n/a
processAnnotation = function (annotation, item) { if (item.fieldType == 'Btn') { //PDF Spec p.675 if (item.fieldFlags & 32768) { setupRadioButton(annotation, item); } else if (item.fieldFlags & 65536) { setupPushButton(annotation, item); } else { setupCheckBox(annotation, item); } } else if (item.fieldType == 'Ch') { setupDropDown(annotation, item); } else if (item.fieldType == 'Tx') { setupFieldAttributes(annotation, item); } }
...
//END:MQZ. Sep.19.2012. comment out the fullname routin, replace it with getInheritableProperty('T') //PDF Spec P.689
//It matches a sequence of at least one period or space, which is then replaced by a single underscore
var itemNameStr = stringToPDFString(Util.getInheritableProperty(dict, 'T') || '');
itemNameStr = itemNameStr.replace(/[.\s\W]+/g, '_'); //replace spaces and non-word character (not [^a-zA-Z0-9_]) with
_
data.fullName = itemNameStr.replace(/^[\s_,:.;\/\\]+/, ''); //replace starting punctuation
PDFAnno.processAnnotation(dict, data);
}
var parent = Annotation.prototype;
Util.inherit(WidgetAnnotation, Annotation, {
isViewable: function WidgetAnnotation_isViewable() {
if (this.data.fieldType === 'Sig') {
TODO('unimplemented annotation type: Widget signature');
...
clean = function () { delete this.get_id; delete this.get_name; }
...
console.warn("to be implemented: contextPrototype.measureText - ", text);
let chars = text.length || 1;
return {width: chars * (this.currentFont.spaceWidth || 5)};
};
contextPrototype.setFont = function(fontObj) {
if ((!!this.currentFont) && _.isFunction(this.currentFont.clean)) {
this.currentFont.clean();
this.currentFont = null;
}
this.currentFont = new PDFFont(fontObj);
};
contextPrototype.clearRect = function () {
...
function CanvasRenderingContext2D_(canvasTarget, scaledWidth, scaledHeight) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.m_ = createMatrixIdentity(); this.mStack_ = []; this.aStack_ = []; this.currentPath_ = []; // Canvas context properties this.strokeStyle = '#000'; this.fillStyle = '#000'; this.lineWidth = 1; this.lineJoin = 'miter'; this.lineCap = 'butt'; this.dashArray = []; this.miterLimit = 1; this.globalAlpha = 1; if (!_.has(canvasTarget, "HLines") || !_.isArray(canvasTarget.HLines)) canvasTarget.HLines = []; if (!_.has(canvasTarget, "VLines") || !_.isArray(canvasTarget.VLines)) canvasTarget.VLines = []; if (!_.has(canvasTarget, "Fills") || !_.isArray(canvasTarget.Fills)) canvasTarget.Fills = []; if (!_.has(canvasTarget, "Texts") || !_.isArray(canvasTarget.Texts)) canvasTarget.Texts = []; this.canvas = canvasTarget; this.width = scaledWidth; this.height = scaledHeight; this.arcScaleX_ = 1; this.arcScaleY_ = 1; this.lineScale_ = 1; this.currentFont = null; }
n/a
arc = function (aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) { let arcType = aClockwise ? 'at' : 'wa'; let xStart = aX + mc(aStartAngle) * aRadius; let yStart = aY + ms(aStartAngle) * aRadius; let xEnd = aX + mc(aEndAngle) * aRadius; let yEnd = aY + ms(aEndAngle) * aRadius; // IE won't render arches drawn counter clockwise if xStart == xEnd. if (xStart == xEnd && !aClockwise) { xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something // that can be represented in binary } let p = this.getCoords_(aX, aY); let pStart = this.getCoords_(xStart, yStart); let pEnd = this.getCoords_(xEnd, yEnd); this.currentPath_.push({type:arcType, x:p.x, y:p.y, radius:aRadius, xStart:pStart.x, yStart:pStart.y, xEnd:pEnd.x, yEnd:pEnd.y}); }
n/a
arcTo = function () { // TODO: Implement }
n/a
beginPath = function () { // TODO: Branch current matrix so that save/restore has no effect // as per safari docs. this.currentPath_ = []; }
...
contextPrototype.strokeRect = function (aX, aY, aWidth, aHeight) {
if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) {
return;//try to remove the rectangle behind radio buttons and checkboxes
}
let oldPath = this.currentPath_;
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
...
bezierCurveTo = function (aCP1x, aCP1y, aCP2x, aCP2y, aX, aY) { let p = this.getCoords_(aX, aY); let cp1 = this.getCoords_(aCP1x, aCP1y); let cp2 = this.getCoords_(aCP2x, aCP2y); bezierCurveTo(this, cp1, cp2, p); }
...
function moveTo(x, y) {
js.push('c.moveTo(' + x + ',' + y + ');');
}
function lineTo(x, y) {
js.push('c.lineTo(' + x + ',' + y + ');');
}
function bezierCurveTo(x1, y1, x2, y2, x, y) {
js.push('c.bezierCurveTo(' + x1 + ',' + y1 + ',' + x2
+ ',' + y2 + ',' +
x + ',' + y + ');');
}
function parse(code) {
var i = 0;
while (i < code.length) {
var stackClean = false;
...
clearRect = function () { }
...
// blend modes can look wrong since we'd be blending with a white
// backdrop. The problem with a transparent backdrop though is we then
// don't get sub pixel anti aliasing on text, so we fill with white if
// we can.
var width = this.ctx.canvas.width;
var height = this.ctx.canvas.height;
if (transparency) {
this.ctx.clearRect(0, 0, width, height);
} else {
this.ctx.mozOpaque = true;
this.ctx.save();
this.ctx.fillStyle = 'rgb(255, 255, 255)';
this.ctx.fillRect(0, 0, width, height);
this.ctx.restore();
}
...
clip = function () { // TODO: Implement }
...
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
ctx.setTransform.apply(ctx, path.transform);
ctx.translate(path.x, path.y);
path.addToPath(ctx, path.fontSize);
}
ctx.restore();
ctx.clip();
ctx.beginPath();
delete this.pendingTextPaths;
},
setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
this.current.charSpacing = spacing;
},
setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) {
...
closePath = function () { this.currentPath_.push({type:'close'}); }
...
return;//try to remove the rectangle behind radio buttons and checkboxes
}
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
contextPrototype.strokeRect = function (aX, aY, aWidth, aHeight) {
if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) {
return;//try to remove the rectangle behind radio buttons and checkboxes
}
...
createLinearGradient = function (aX0, aY0, aX1, aY1) { let gradient = new CanvasGradient_('gradient'); gradient.x0_ = aX0; gradient.y0_ = aY0; gradient.x1_ = aX1; gradient.y1_ = aY1; return gradient; }
...
var r0 = raw[5];
var r1 = raw[6];
return {
type: 'Pattern',
getPattern: function RadialAxial_getPattern(ctx) {
var grad;
if (type == PatternType.AXIAL)
grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
else if (type == PatternType.RADIAL)
grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
for (var i = 0, ii = colorStops.length; i < ii; ++i) {
var c = colorStops[i];
grad.addColorStop(c[0], c[1]);
}
...
createPattern = function () { return new CanvasPattern_; }
...
var temporaryPatternCanvas = this.createPatternCanvas(owner);
var ctx = this.ctx;
ctx.setTransform.apply(ctx, this.baseTransform);
ctx.transform.apply(ctx, this.matrix);
this.scaleToContext();
return ctx.createPattern(temporaryPatternCanvas, 'repeat');
}
};
return TilingPattern;
})();
...
createRadialGradient = function (aX0, aY0, aR0, aX1, aY1, aR1) { let gradient = new CanvasGradient_('gradientradial'); gradient.x0_ = aX0; gradient.y0_ = aY0; gradient.r0_ = aR0; gradient.x1_ = aX1; gradient.y1_ = aY1; gradient.r1_ = aR1; return gradient; }
...
return {
type: 'Pattern',
getPattern: function RadialAxial_getPattern(ctx) {
var grad;
if (type == PatternType.AXIAL)
grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
else if (type == PatternType.RADIAL)
grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
for (var i = 0, ii = colorStops.length; i < ii; ++i) {
var c = colorStops[i];
grad.addColorStop(c[0], c[1]);
}
return grad;
}
...
drawImage = function (image, var_args) { //MQZ. no image drawing support for now }
...
var width = img.width;
var height = img.height;
var size = width * height;
var rgbaLength = size * 4;
var buf = new Uint8Array(size * components);
var tmpCanvas = createScratchCanvas(width, height);
var tmpCtx = tmpCanvas.getContext('2d');
tmpCtx.drawImage(img, 0, 0);
var data = tmpCtx.getImageData(0, 0, width, height).data;
if (components == 3) {
for (var i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
buf[j] = data[i];
buf[j + 1] = data[i + 1];
buf[j + 2] = data[i + 2];
...
fill = function () { this.stroke(true); }
...
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.fill();
this.currentPath_ = oldPath;
};
contextPrototype.createLinearGradient = function (aX0, aY0, aX1, aY1) {
let gradient = new CanvasGradient_('gradient');
gradient.x0_ = aX0;
...
fillRect = function (aX, aY, aWidth, aHeight) { if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) { return;//try to remove the rectangle behind radio buttons and checkboxes } let oldPath = this.currentPath_; this.beginPath(); this.moveTo(aX, aY); this.lineTo(aX + aWidth, aY); this.lineTo(aX + aWidth, aY + aHeight); this.lineTo(aX, aY + aHeight); this.closePath(); this.fill(); this.currentPath_ = oldPath; }
...
var height = this.ctx.canvas.height;
if (transparency) {
this.ctx.clearRect(0, 0, width, height);
} else {
this.ctx.mozOpaque = true;
this.ctx.save();
this.ctx.fillStyle = 'rgb(255, 255, 255)';
this.ctx.fillRect(0, 0, width, height);
this.ctx.restore();
}
var transform = viewport.transform;
this.baseTransform = transform.slice();
this.ctx.save();
this.ctx.transform.apply(this.ctx, transform);
...
fillText = function (text, x, y, maxWidth, fontSize) { if (!text || text.trim().length < 1) return; let p = this.getCoords_(x, y); let a = processStyle(this.fillStyle || this.strokeStyle); let color = (!!a) ? a.color : '#000000'; this.currentFont.processText(p, text, maxWidth, color, fontSize, this.canvas, this.m_); }
...
let color = (!!a) ? a.color : '#000000';
this.currentFont.processText(p, text, maxWidth, color, fontSize, this.canvas, this.m_);
};
contextPrototype.strokeText = function(text, x, y, maxWidth) {
//MQZ. 10/23/2012, yeah, no hollow text for now
this.fillText(text, x, y, maxWidth);
};
contextPrototype.measureText = function(text) {
console.warn("to be implemented: contextPrototype.measureText - ", text);
let chars = text.length || 1;
return {width: chars * (this.currentFont.spaceWidth || 5)};
};
...
getContext = function (ctxType) { return (ctxType === "2d") ? this : null; }
...
cls.prototype.parsePage = function(callback, errorCallBack) {
if (this.renderingState !== RenderingStates.INITIAL)
error('Must be in new state before drawing');
this.renderingState = RenderingStates.RUNNING;
let canvas = createScratchCanvas(1, 1);
let ctx = canvas.getContext('2d');
function pageViewDrawCallback(error) {
this.renderingState = RenderingStates.FINISHED;
if (error) {
let errMsg = 'An error occurred while rendering the page ' + (this.id + 1) +
':\n' + error.message +
...
getCoords_ = function (aX, aY) { let m = this.m_; return { x: (aX * m[0][0] + aY * m[1][0] + m[2][0]), y: (aX * m[0][1] + aY * m[1][1] + m[2][1]) }; }
...
contextPrototype.getLineDash= function() {
return this.dashArray;
};
contextPrototype.fillText = function(text, x, y, maxWidth, fontSize) {
if (!text || text.trim().length < 1)
return;
let p = this.getCoords_(x, y);
let a = processStyle(this.fillStyle || this.strokeStyle);
let color = (!!a) ? a.color : '#000000';
this.currentFont.processText(p, text, maxWidth, color, fontSize, this.canvas, this.m_);
};
...
getImageData = function (x, y, w, h) { //MQZ. returns empty data buffer for now return { width:w, height:h, data:new Uint8Array(w * h * 4) }; }
...
var SMALL_IMAGE_DIMENSIONS = 200;
// Inlining small images into the queue as RGB data
if (inline && !softMask && !mask &&
!(image instanceof JpegStream) &&
(w + h) < SMALL_IMAGE_DIMENSIONS) {
var imageObj = new PDFImage(this.xref, resources, image,
inline, null, null);
var imgData = imageObj.getImageData();
operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
return;
}
// If there is no imageMask, create the PDFImage and a lot
// of image processing can be done here.
var uniquePrefix = this.uniquePrefix || '';
...
getLineDash = function () { return this.dashArray; }
...
for (var i = 0, ii = properties.length; i < ii; i++) {
var property = properties[i];
if (property in sourceCtx) {
destCtx[property] = sourceCtx[property];
}
}
if ('setLineDash' in sourceCtx) {
destCtx.setLineDash(sourceCtx.getLineDash());
destCtx.lineDashOffset = sourceCtx.lineDashOffset;
} else if ('mozDash' in sourceCtx) {
destCtx.mozDash = sourceCtx.mozDash;
destCtx.mozDashOffset = sourceCtx.mozDashOffset;
}
}
...
lineTo = function (aX, aY) { let p = this.getCoords_(aX, aY); this.currentPath_.push({type:'lineTo', x:p.x, y:p.y}); this.currentX_ = p.x; this.currentY_ = p.y; }
...
contextPrototype.rect = function (aX, aY, aWidth, aHeight) {
if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) {
return;//try to remove the rectangle behind radio buttons and checkboxes
}
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
contextPrototype.strokeRect = function (aX, aY, aWidth, aHeight) {
if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) {
...
measureText = function (text) { console.warn("to be implemented: contextPrototype.measureText - ", text); let chars = text.length || 1; return {width: chars * (this.currentFont.spaceWidth || 5)}; }
...
scaledX = x / fontSizeScale;
scaledY = 0;
}
if (font.remeasure && width > 0) {
// some standard fonts may not have the exact width, trying to
// rescale per character
var measuredWidth = ctx.measureText(character).width * 1000 /
current.fontSize * current.fontSizeScale;
var characterScaleX = width / measuredWidth;
restoreNeeded = true;
ctx.save();
ctx.scale(characterScaleX, 1);
scaledX /= characterScaleX;
...
moveTo = function (aX, aY) { let p = this.getCoords_(aX, aY); this.currentPath_.push({type:'moveTo', x:p.x, y:p.y}); this.currentX_ = p.x; this.currentY_ = p.y; }
...
};
contextPrototype.rect = function (aX, aY, aWidth, aHeight) {
if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) {
return;//try to remove the rectangle behind radio buttons and checkboxes
}
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
contextPrototype.strokeRect = function (aX, aY, aWidth, aHeight) {
...
quadraticCurveTo = function (aCPx, aCPy, aX, aY) { // the following is lifted almost directly from // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes let cp = this.getCoords_(aCPx, aCPy); let p = this.getCoords_(aX, aY); let cp1 = { x:this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_), y:this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_) }; let cp2 = { x:cp1.x + (p.x - this.currentX_) / 3.0, y:cp1.y + (p.y - this.currentY_) / 3.0 }; bezierCurveTo(this, cp1, cp2, p); }
...
function moveTo(x, y) {
js.push('c.moveTo(' + x + ',' + y + ');');
}
function lineTo(x, y) {
js.push('c.lineTo(' + x + ',' + y + ');');
}
function quadraticCurveTo(xa, ya, x, y) {
js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' +
x + ',' + y + ');');
}
var i = 0;
var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
var xMin = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
var yMin = ((code[i + 4] << 24) | (code[i + 5] << 16)) >> 16;
...
rect = function (aX, aY, aWidth, aHeight) { if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) { return;//try to remove the rectangle behind radio buttons and checkboxes } this.moveTo(aX, aY); this.lineTo(aX + aWidth, aY); this.lineTo(aX + aWidth, aY + aHeight); this.lineTo(aX, aY + aHeight); this.closePath(); }
...
this.curveTo(x1, y1, x3, y3, x3, y3);
this.current.setCurrentPoint(x3, y3);
},
closePath: function CanvasGraphics_closePath() {
this.ctx.closePath();
},
rectangle: function CanvasGraphics_rectangle(x, y, width, height) {
this.ctx.rect(x, y, width, height);
},
stroke: function CanvasGraphics_stroke(consumePath) {
consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
var ctx = this.ctx;
var strokeColor = this.current.strokeColor;
if (this.current.lineWidth === 0)
ctx.lineWidth = this.getSinglePixelWidth();
...
restore = function () { copyState(this.aStack_.pop(), this); this.m_ = this.mStack_.pop(); }
...
}
var subglyph = font.glyphs[glyphIndex];
if (subglyph) {
js.push('c.save();');
js.push('c.transform(' + scaleX + ',' + scale01 + ',' +
scale10 + ',' + scaleY + ',' + x + ',' + y + ');');
compileGlyf(subglyph, js, font);
js.push('c.restore();');
}
} while ((flags & 0x20));
} else {
// simple glyph
var endPtsOfContours = [];
for (var j = 0; j < numberOfContours; j++) {
endPtsOfContours.push((code[i] << 8) | code[i + 1]);
...
rotate = function (aRot) { let c = mc(aRot); let s = ms(aRot); let m1 = [ [c, s, 0], [-s, c, 0], [0, 0, 1] ]; setM(this, matrixMultiply(m1, this.m_), false); }
n/a
save = function () { let o = {}; copyState(this, o); this.aStack_.push(o); this.mStack_.push(this.m_); this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); }
...
scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;
scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;
i += 8;
}
var subglyph = font.glyphs[glyphIndex];
if (subglyph) {
js.push('c.save();');
js.push('c.transform(' + scaleX + ',' + scale01 + ',' +
scale10 + ',' + scaleY + ',' + x + ',' + y + ');');
compileGlyf(subglyph, js, font);
js.push('c.restore();');
}
} while ((flags & 0x20));
} else {
...
scale = function (aX, aY) { this.arcScaleX_ *= aX; this.arcScaleY_ *= aY; let m1 = [ [aX, 0, 0], [0, aY, 0], [0, 0, 1] ]; setM(this, matrixMultiply(m1, this.m_), true); }
...
if (!code || code.length === 0 || code[0] === 14) {
return noop;
}
var js = [];
js.push('c.save();');
js.push('c.transform(' + this.fontMatrix.join(',') + ');');
js.push('c.scale(size, -size);');
this.compileGlyphImpl(code, js);
js.push('c.restore();');
return js.join('\n');
},
...
setFont = function (fontObj) { if ((!!this.currentFont) && _.isFunction(this.currentFont.clean)) { this.currentFont.clean(); this.currentFont = null; } this.currentFont = new PDFFont(fontObj); }
...
case 'RI':
this.setRenderingIntent(value);
break;
case 'FL':
this.setFlatness(value);
break;
case 'Font':
this.setFont(value[0], value[1]);
break;
case 'CA':
this.current.strokeAlpha = state[1];
break;
case 'ca':
this.current.fillAlpha = state[1];
this.ctx.globalAlpha = state[1];
...
setLineDash = function (lineDash) { this.dashArray = lineDash; }
...
for (var i = 0, ii = properties.length; i < ii; i++) {
var property = properties[i];
if (property in sourceCtx) {
destCtx[property] = sourceCtx[property];
}
}
if ('setLineDash' in sourceCtx) {
destCtx.setLineDash(sourceCtx.getLineDash());
destCtx.lineDashOffset = sourceCtx.lineDashOffset;
} else if ('mozDash' in sourceCtx) {
destCtx.mozDash = sourceCtx.mozDash;
destCtx.mozDashOffset = sourceCtx.mozDashOffset;
}
}
...
setTransform = function (m11, m12, m21, m22, dx, dy) { let m = [ [m11, m12, 0], [m21, m22, 0], [dx, dy, 1] ]; setM(this, m, true); }
...
trackTransform) {
var canvasEntry;
if (id in cache) {
canvasEntry = cache[id];
canvasEntry.canvas.width = width;
canvasEntry.canvas.height = height;
// reset canvas transform for emulated mozCurrentTransform, if needed
canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);
} else {
var canvas = createScratchCanvas(width, height);
var ctx = canvas.getContext('2d');
if (trackTransform) {
addContextCurrentTransform(ctx);
}
cache[id] = canvasEntry = {canvas: canvas, context: ctx};
...
stroke = function (aFill) { if (this.currentPath_.length < 2) { return; } let a = processStyle(aFill ? this.fillStyle : this.strokeStyle); let color = a.color; // let opacity = a.alpha * this.globalAlpha; let lineWidth = this.lineScale_ * this.lineWidth; let min = {x:null, y:null}; let max = {x:null, y:null}; for (let i = 0; i < this.currentPath_.length; i++) { let p = this.currentPath_[i]; switch (p.type) { case 'moveTo': break; case 'lineTo': if (!aFill) { //lines if (i > 0) { _drawPDFLine.call(this, this.currentPath_[i-1], p, lineWidth, color); } } break; case 'close': if (!aFill) { //lines if (i > 0) { _drawPDFLine.call(this, this.currentPath_[i-1], this.currentPath_[0], lineWidth, color); } } p = null; break; case 'bezierCurveTo': break; case 'at': case 'wa': break; } // Figure out dimensions so we can set fills' coordinates correctly if (aFill && p) { if (min.x == null || p.x < min.x) { min.x = p.x; } if (max.x == null || p.x > max.x) { max.x = p.x; } if (min.y == null || p.y < min.y) { min.y = p.y; } if (max.y == null || p.y > max.y) { max.y = p.y; } } } if (aFill) { //fill _drawPDFFill.call(this, min, min, max, color); } }
...
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
this.currentPath_ = oldPath;
};
contextPrototype.fillRect = function (aX, aY, aWidth, aHeight) {
if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) {
return;//try to remove the rectangle behind radio buttons and checkboxes
...
strokeRect = function (aX, aY, aWidth, aHeight) { if (_needRemoveRect.call(this, aX, aY, aWidth, aHeight)) { return;//try to remove the rectangle behind radio buttons and checkboxes } let oldPath = this.currentPath_; this.beginPath(); this.moveTo(aX, aY); this.lineTo(aX + aWidth, aY); this.lineTo(aX + aWidth, aY + aHeight); this.lineTo(aX, aY + aHeight); this.closePath(); this.stroke(); this.currentPath_ = oldPath; }
n/a
strokeText = function (text, x, y, maxWidth) { //MQZ. 10/23/2012, yeah, no hollow text for now this.fillText(text, x, y, maxWidth); }
...
} else {
if (fillStrokeMode === TextRenderingMode.FILL ||
fillStrokeMode === TextRenderingMode.FILL_STROKE) {
ctx.fillText(character, x, y);
}
if (fillStrokeMode === TextRenderingMode.STROKE ||
fillStrokeMode === TextRenderingMode.FILL_STROKE) {
ctx.strokeText(character, x, y);
}
}
if (isAddToPathSet) {
var paths = this.pendingTextPaths || (this.pendingTextPaths = []);
paths.push({
transform: ctx.mozCurrentTransform,
...
transform = function (m11, m12, m21, m22, dx, dy) { let m1 = [ [m11, m12, 0], [m21, m22, 0], [dx, dy, 1] ]; setM(this, matrixMultiply(m1, this.m_), true); }
...
scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;
scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;
i += 8;
}
var subglyph = font.glyphs[glyphIndex];
if (subglyph) {
js.push('c.save();');
js.push('c.transform(' + scaleX + ',' + scale01 + ',
x27; +
scale10 + ',' + scaleY + ',' + x + ',' + y + ');');
compileGlyf(subglyph, js, font);
js.push('c.restore();');
}
} while ((flags & 0x20));
} else {
// simple glyph
...
translate = function (aX, aY) { let m1 = [ [1, 0, 0], [0, 1, 0], [aX, aY, 1] ]; setM(this, matrixMultiply(m1, this.m_), false); }
...
case 14: // endchar
if (stack.length >= 4) {
var achar = stack.pop();
var bchar = stack.pop();
y = stack.pop();
x = stack.pop();
js.push('c.save();');
js.push('c.translate('+ x + ',' + y + ');');
var gid = lookupCmap(font.cmap, String.fromCharCode(
font.glyphNameMap[Encodings.StandardEncoding[achar]]));
compileCharString(font.glyphs[gid], js, font);
js.push('c.restore();');
gid = lookupCmap(font.cmap, String.fromCharCode(
font.glyphNameMap[Encodings.StandardEncoding[bchar]]));
...
pdffield = function (field, viewport, Fields, Boxsets) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.field = field; this.viewport = viewport; this.Fields = Fields; this.Boxsets = Boxsets; }
n/a
getAllFieldsTypes = function (data) { function isFieldReadOnly(field) { return (field.AM & kFBANotOverridable) ? true : false; } function getFieldBase(field) { return {id: field.id.Id, type: field.T.Name, calc: isFieldReadOnly(field), value: field.V || ""}; } let retVal = []; _.each(data.Pages, function(page) { _.each(page.Boxsets, function(boxsets) { if (boxsets.boxes.length > 1) { //radio button _.each(boxsets.boxes, function(box) { retVal.push({id: boxsets.id.Id, type: "radio", calc: isFieldReadOnly(box), value: box.id.Id}); }); } else { //checkbox retVal.push(getFieldBase(boxsets.boxes[0])); } }); _.each(page.Fields, function(field){ retVal.push(getFieldBase(field)); }); }); return retVal; }
...
PdfParser.prototype.parseBuffer = function(pdfBuffer) {
_startParsingPDF.call(this, pdfBuffer);
};
PdfParser.prototype.getRawTextContent = function() { return this.PDFJS.getRawTextContent(); };
PdfParser.prototype.getRawTextContentStream = function() { return _createContentStream(this.getRawTextContent()); };
PdfParser.prototype.getAllFieldsTypes = function() { return this.PDFJS.getAllFieldsTypes(); };
PdfParser.prototype.getAllFieldsTypesStream = function() { return _createContentStream(this.getAllFieldsTypes()); };
PdfParser.prototype.getMergedTextBlocksIfNeeded = function() { return {"formImage": this.PDFJS.getMergedTextBlocksIfNeeded
()}; };
PdfParser.prototype.getMergedTextBlocksStream = function() { return _createContentStream(this.getMergedTextBlocksIfNeeded()); };
PdfParser.prototype.destroy = function() {
this.removeAllListeners();
...
isFormElement = function (field) { let retVal = false; switch(field.subtype) { case 'Widget': retVal = cls.isWidgetSupported(field); break; default: nodeUtil.p2jwarn("Unsupported: field.type of " + field.subtype); break; } return retVal; }
...
INITIAL: 0,
RUNNING: 1,
PAUSED: 2,
FINISHED: 3
};
let _addField = function(field) {
if (!PDFField.isFormElement(field))
return;
let oneField = new PDFField(field, this.viewport, this.Fields, this.Boxsets);
oneField.processField();
};
// constructor
...
isWidgetSupported = function (field) { let retVal = false; switch(field.fieldType) { case 'Tx': retVal = true; break; //text input case 'Btn': if (field.fieldFlags & 32768) { field.fieldType = 'Rd'; //radio button } else if (field.fieldFlags & 65536) { field.fieldType = 'Btn'; //push button } else { field.fieldType = 'Cb'; //checkbox } retVal = true; break; case 'Ch': retVal = true; break; //drop down default: nodeUtil.p2jwarn("Unsupported: field.fieldType of " + field.fieldType); break; } return retVal; }
...
return retVal;
};
cls.isFormElement = function(field) {
let retVal = false;
switch(field.subtype) {
case 'Widget': retVal = cls.isWidgetSupported(field); break;
default:
nodeUtil.p2jwarn("Unsupported: field.type of " + field.subtype);
break;
}
return retVal;
};
...
clean = function () { delete this.get_id; delete this.get_name; delete this.field; delete this.viewport; delete this.Fields; delete this.Boxsets; }
...
console.warn("to be implemented: contextPrototype.measureText - ", text);
let chars = text.length || 1;
return {width: chars * (this.currentFont.spaceWidth || 5)};
};
contextPrototype.setFont = function(fontObj) {
if ((!!this.currentFont) && _.isFunction(this.currentFont.clean)) {
this.currentFont.clean();
this.currentFont = null;
}
this.currentFont = new PDFFont(fontObj);
};
contextPrototype.clearRect = function () {
...
processField = function () { this.field.TI = _tabIndex++; switch(this.field.fieldType) { case 'Tx': _addAlpha.call(this, this.field); break; case 'Cb': _addCheckBox.call(this, this.field); break; case 'Rd': _addRadioButton.call(this, this.field);break; case 'Btn':_addLinkButton.call(this, this.field); break; case 'Ch': _addSelect.call(this, this.field); break; } this.clean(); }
...
};
let _addField = function(field) {
if (!PDFField.isFormElement(field))
return;
let oneField = new PDFField(field, this.viewport, this.Fields, this.Boxsets);
oneField.processField();
};
// constructor
let cls = function (pdfPage, id, scale, ptiParser) {
nodeEvents.EventEmitter.call(this);
// private
let _id = _nextId++;
...
pdffill = function (x, y, width, height, color) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.x = x; this.y = y; this.width = width; this.height = height; this.color = color; }
n/a
processFill = function (targetData) { let clrId = PDFUnit.findColorIndex(this.color); let oneFill = {x:PDFUnit.toFormX(this.x), y:PDFUnit.toFormY(this.y), w:PDFUnit.toFormX(this.width), h:PDFUnit.toFormY(this.height), clr: clrId}; //MQZ.07/29/2013: when color is not in color dictionary, set the original color (oc) if (clrId < 0) { oneFill = _.extend({oc: this.color}, oneFill); } targetData.Fills.push(oneFill); }
...
pL.processLine(this.canvas);
};
let _drawPDFFill = function(cp, min, max, color) {
let width = max.x - min.x;
let height = max.y - min.y;
let pF = new PDFFill(cp.x, cp.y, width, height, color);
pF.processFill(this.canvas);
};
let _needRemoveRect = function(x, y, w, h) {
let retVal = (Math.abs(w - Math.abs(h)) < 1 && w < 13);
if (retVal) {
nodeUtil.p2jinfo("Skipped: tiny rect: w=" + w + ", h=" + h);
}
...
pdffont = function (fontObj) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.fontObj = fontObj; let typeName = (fontObj.name || fontObj.fallbackName); if (!typeName) { typeName = _kFontFaces[0]; //default font family name } typeName = typeName.toLowerCase(); this.typeName = typeName; let subType = typeName; let nameArray = typeName.split('+'); if (_.isArray(nameArray) && nameArray.length > 1) { subType = nameArray[1].split("-"); if (_.isArray(subType) && subType.length > 1) { if (!this.bold) { let subName = subType[1].toLowerCase(); this.bold = _boldSubNames.indexOf(subName) >= 0; } subType = subType[0]; } } this.subType = subType; this.isSymbol = typeName.indexOf("symbol") > 0 || _kFontFaces[2].indexOf(this.subType) >= 0; if (this.fontObj.isSymbolicFont) { let mFonts = _stdFonts.filter( (oneName) => (typeName.indexOf(oneName) >= 0) ); if (mFonts.length > 0) { this.fontObj.isSymbolicFont = false; //lots of Arial-based font is detected as symbol in VA forms (301, 76-c, etc.) reset the flag for now nodeUtil.p2jinfo("Reset: isSymbolicFont (false) for " + this.fontObj.name); } } else { if (this.isSymbol) { this.fontObj.isSymbolicFont = true; //text pdf: va_ind_760c nodeUtil.p2jinfo("Reset: isSymbolicFont (true) for " + this.fontObj.name); } } this.fontSize = 1; this.faceIdx = 0; this.bold = false; this.italic = false; this.fontStyleId = -1; this.spaceWidth = fontObj.spaceWidth; if (!this.spaceWidth) { var spaceId = Array.isArray(fontObj.toFontChar) ? fontObj.toFontChar.indexOf(32) : -1; this.spaceWidth = (spaceId >= 0 && Array.isArray(fontObj.widths)) ? fontObj.widths[spaceId] : 250; } this.spaceWidth = PDFUnit.toFormX(this.spaceWidth) / 32; }
n/a
areAdjacentBlocks = function (t1, t2) { let isInSameLine = Math.abs(t1.y - t2.y) <= DISTANCE_DELTA; let isDistanceSmallerThanASpace = ((t2.x - t1.x - t1.w) < cls.getSpaceThreshHold(t1)); return isInSameLine && isDistanceSmallerThanASpace; }
...
return !isDup;
});
for (let i = 0; i < page.Texts.length; i++) {
let text = page.Texts[i];
if (prevText) {
if (PDFFont.areAdjacentBlocks(prevText, text) && PDFFont.haveSameStyle
(prevText, text)) {
let preT = decodeURIComponent(prevText.R[0].T);
let curT = decodeURIComponent(text.R[0].T);
prevText.R[0].T += text.R[0].T;
prevText.w += text.w;
text.merged = true;
...
areDuplicateBlocks = function (t1, t2) { return t1.x == t2.x && t1.y == t2.y && t1.R[0].T == t2.R[0].T && cls.haveSameStyle(t1, t2); }
...
cls.prototype.getMergedTextBlocksIfNeeded = function() {
for (let p = 0; p < this.pages.length; p++) {
let prevText = null;
let page = this.pages[p];
page.Texts.sort(PDFFont.compareBlockPos);
page.Texts = page.Texts.filter( (t, j) => {
let isDup = (j > 0) && PDFFont.areDuplicateBlocks(page.Texts[j-1],
t);
if (isDup) {
nodeUtil.p2jinfo("skipped: dup text block: " + decodeURIComponent(t.R[0].T));
}
return !isDup;
});
for (let i = 0; i < page.Texts.length; i++) {
...
compareBlockPos = function (t1, t2) { if (t1.y < t2.y - DISTANCE_DELTA) { return -1; } if (Math.abs(t1.y - t2.y) <= DISTANCE_DELTA) { if (t1.x < t2.x - DISTANCE_DELTA) { return -1; } if (Math.abs(t1.x - t2.x) <= DISTANCE_DELTA) { return 0; } } return 1; }
n/a
getFontSize = function (textBlock) { let sId = textBlock.R[0].S; return (sId < 0) ? textBlock.R[0].TS[1] : _kFontStyles[sId][1]; }
...
retVal = (typeof t1.R[0].RA === 'undefined') && (typeof t2.R[0].RA === 'undefined');
}
return retVal;
};
cls.getSpaceThreshHold = function(t1) {
return (PDFFont.getFontSize(t1)/12) * t1.sw;
};
cls.areAdjacentBlocks = function(t1, t2) {
let isInSameLine = Math.abs(t1.y - t2.y) <= DISTANCE_DELTA;
let isDistanceSmallerThanASpace = ((t2.x - t1.x - t1.w) < cls.getSpaceThreshHold(t1));
return isInSameLine && isDistanceSmallerThanASpace;
...
getSpaceThreshHold = function (t1) { return (PDFFont.getFontSize(t1)/12) * t1.sw; }
...
cls.getSpaceThreshHold = function(t1) {
return (PDFFont.getFontSize(t1)/12) * t1.sw;
};
cls.areAdjacentBlocks = function(t1, t2) {
let isInSameLine = Math.abs(t1.y - t2.y) <= DISTANCE_DELTA;
let isDistanceSmallerThanASpace = ((t2.x - t1.x - t1.w) < cls.getSpaceThreshHold
(t1));
return isInSameLine && isDistanceSmallerThanASpace;
};
cls.getFontSize = function(textBlock) {
let sId = textBlock.R[0].S;
return (sId < 0) ? textBlock.R[0].TS[1] : _kFontStyles[sId][1];
...
haveSameStyle = function (t1, t2) { let retVal = t1.R[0].S === t2.R[0].S; if (retVal && t1.R[0].S < 0) { for (let i = 0; i < t1.R[0].TS.length; i++) { if (t1.R[0].TS[i] !== t2.R[0].TS[i]) { retVal = false; break; } } } if (retVal) { // make sure both block are not rotated retVal = (typeof t1.R[0].RA === 'undefined') && (typeof t2.R[0].RA === 'undefined'); } return retVal; }
...
cls.getFontSize = function(textBlock) {
let sId = textBlock.R[0].S;
return (sId < 0) ? textBlock.R[0].TS[1] : _kFontStyles[sId][1];
};
cls.areDuplicateBlocks = function(t1, t2) {
return t1.x == t2.x && t1.y == t2.y && t1.R[0].T == t2.R[0].T && cls.haveSameStyle(t1, t2);
};
// private
let _setFaceIndex = function() {
let fontObj = this.fontObj;
this.bold = fontObj.bold;
...
clean = function () { this.fontObj = null; delete this.fontObj; }
...
console.warn("to be implemented: contextPrototype.measureText - ", text);
let chars = text.length || 1;
return {width: chars * (this.currentFont.spaceWidth || 5)};
};
contextPrototype.setFont = function(fontObj) {
if ((!!this.currentFont) && _.isFunction(this.currentFont.clean)) {
this.currentFont.clean();
this.currentFont = null;
}
this.currentFont = new PDFFont(fontObj);
};
contextPrototype.clearRect = function () {
...
flash_encode = function (str) { let retVal = encodeURIComponent(str); retVal = retVal.replace("%C2%96", "-"); retVal = retVal.replace("%C2%91", "%27"); retVal = retVal.replace("%C2%92", "%27"); retVal = retVal.replace("%C2%82", "%27"); retVal = retVal.replace("%C2%93", "%22"); retVal = retVal.replace("%C2%94", "%22"); retVal = retVal.replace("%C2%84", "%22"); retVal = retVal.replace("%C2%8B", "%C2%AB"); retVal = retVal.replace("%C2%9B", "%C2%BB"); return retVal; }
...
let oneText = {x: PDFUnit.toFormX(p.x) - 0.25,
y: PDFUnit.toFormY(p.y) - 0.75,
w: PDFUnit.toFixedFloat(maxWidth),
sw: this.spaceWidth, //font space width, use to merge adjacent text blocks
clr: clrId,
A: "left",
R: [{
T: this.flash_encode(text),
S: this.fontStyleId,
TS: TS
}]
};
//MQZ.07/29/2013: when color is not in color dictionary, set the original color (oc)
if (clrId < 0) {
...
processText = function (p, str, maxWidth, color, fontSize, targetData, matrix2D) { let text = _processSymbolicFont.call(this, str); if (!text) { return; } this.fontStyleId = _getFontStyleIndex.call(this, fontSize); // when this.fontStyleId === -1, it means the text style doesn't match any entry in the dictionary // adding TS to better describe text style [fontFaceId, fontSize, 1/0 for bold, 1/0 for italic]; let TS = [this.faceIdx, this.fontSize, this.bold?1:0, this.italic?1:0]; let clrId = PDFUnit.findColorIndex(color); let oneText = {x: PDFUnit.toFormX(p.x) - 0.25, y: PDFUnit.toFormY(p.y) - 0.75, w: PDFUnit.toFixedFloat(maxWidth), sw: this.spaceWidth, //font space width, use to merge adjacent text blocks clr: clrId, A: "left", R: [{ T: this.flash_encode(text), S: this.fontStyleId, TS: TS }] }; //MQZ.07/29/2013: when color is not in color dictionary, set the original color (oc) if (clrId < 0) { oneText = _.extend({oc: color}, oneText); } let rAngle = _textRotationAngle.call(this, matrix2D); if (rAngle != 0) { nodeUtil.p2jinfo(str + ": rotated " + rAngle + " degree."); _.extend(oneText.R[0], {RA: rAngle}); } targetData.Texts.push(oneText); }
...
if (!text || text.trim().length < 1)
return;
let p = this.getCoords_(x, y);
let a = processStyle(this.fillStyle || this.strokeStyle);
let color = (!!a) ? a.color : '#000000';
this.currentFont.processText(p, text, maxWidth, color, fontSize, this.canvas, this
.m_);
};
contextPrototype.strokeText = function(text, x, y, maxWidth) {
//MQZ. 10/23/2012, yeah, no hollow text for now
this.fillText(text, x, y, maxWidth);
};
...
pdfline = function (x1, y1, x2, y2, lineWidth, color, dashed) { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.lineWidth = lineWidth || 1.0; this.color = color; this.dashed = dashed; }
n/a
processLine = function (targetData) { let xDelta = Math.abs(this.x2 - this.x1); let yDelta = Math.abs(this.y2 - this.y1); let minDelta = this.lineWidth; let oneLine = {x:0, y:0, w: PDFUnit.toFixedFloat(this.lineWidth), l:0}; //MQZ Aug.28.2013, adding color support, using color dictionary and default to black let clrId = PDFUnit.findColorIndex(this.color); if (clrId < 0) { oneLine = _.extend({oc: this.color}, oneLine); } else if (clrId > 0 && clrId < (PDFUnit.colorCount() - 1)) { oneLine = _.extend({clr: clrId}, oneLine); } //MQZ Aug.29 dashed line support if (this.dashed) { oneLine = _.extend({dsh: 1}, oneLine); } if ((yDelta < this.lineWidth) && (xDelta > minDelta)) { //HLine if (this.lineWidth < 4 && (xDelta / this.lineWidth < 4)) { nodeUtil.p2jinfo("Skipped: short thick HLine: lineWidth = " + this.lineWidth + ", xDelta = " + xDelta); return; //skip short thick lines, like PA SPP lines behinds checkbox } oneLine.l = PDFUnit.toFormX(xDelta); if (this.x1 > this.x2) _setStartPoint.call(this, oneLine, this.x2, this.y2); else _setStartPoint.call(this, oneLine, this.x1, this.y1); targetData.HLines.push(oneLine); } else if ((xDelta < this.lineWidth) && (yDelta > minDelta)) {//VLine if (this.lineWidth < 4 && (yDelta / this.lineWidth < 4)) { nodeUtil.p2jinfo("Skipped: short thick VLine: lineWidth = " + this.lineWidth + ", yDelta = " + yDelta); return; //skip short think lines, like PA SPP lines behinds checkbox } oneLine.l = PDFUnit.toFormY(yDelta); if (this.y1 > this.y2) _setStartPoint.call(this, oneLine, this.x2, this.y2); else _setStartPoint.call(this, oneLine, this.x1, this.y1); targetData.VLines.push(oneLine); } }
...
this.currentFont = null;
}
//private helper methods
let _drawPDFLine = function(p1, p2, lineWidth, color) {
let dashedLine = _.isArray(this.dashArray) && (this.dashArray.length > 1);
let pL = new PDFLine(p1.x, p1.y, p2.x, p2.y, lineWidth, color, dashedLine);
pL.processLine(this.canvas);
};
let _drawPDFFill = function(cp, min, max, color) {
let width = max.x - min.x;
let height = max.y - min.y;
let pF = new PDFFill(cp.x, cp.y, width, height, color);
pF.processFill(this.canvas);
...
pdfunit = function () { // private let _id = _nextId++; // public (every instance will have their own copy of these methods, needs to be lightweight) this.get_id = function() { return _id; }; this.get_name = function() { return _name + _id; }; }
n/a
colorCount = function () { return kColors.length; }
...
let oneLine = {x:0, y:0, w: PDFUnit.toFixedFloat(this.lineWidth), l:0};
//MQZ Aug.28.2013, adding color support, using color dictionary and default to black
let clrId = PDFUnit.findColorIndex(this.color);
if (clrId < 0) {
oneLine = _.extend({oc: this.color}, oneLine);
}
else if (clrId > 0 && clrId < (PDFUnit.colorCount() - 1)) {
oneLine = _.extend({clr: clrId}, oneLine);
}
//MQZ Aug.29 dashed line support
if (this.dashed) {
oneLine = _.extend({dsh: 1}, oneLine);
}
...
findColorIndex = function (color) { if (color.length === 4) color += "000"; //MQZ. 07/29/2013: if color is not in dictionary, just return -1. The caller (pdffont, pdffill) will set the actual color return kColors.indexOf(color); }
...
this.width = width;
this.height = height;
this.color = color;
};
// public (every instance will share the same method, but has no access to private fields defined in constructor)
cls.prototype.processFill = function (targetData) {
let clrId = PDFUnit.findColorIndex(this.color);
let oneFill = {x:PDFUnit.toFormX(this.x),
y:PDFUnit.toFormY(this.y),
w:PDFUnit.toFormX(this.width),
h:PDFUnit.toFormY(this.height),
clr: clrId};
...
getColorByIndex = function (clrId) { return kColors[clrId]; }
n/a
pointToPixel = function (point) {// Point unit (1/72 an inch) to pixel units return point * _pixelPerPoint; }
n/a
toFixedFloat = function (fNum) { return parseFloat(fNum.toFixed(3)); }
...
// adding TS to better describe text style [fontFaceId, fontSize, 1/0 for bold, 1/0 for italic];
let TS = [this.faceIdx, this.fontSize, this.bold?1:0, this.italic?1:0];
let clrId = PDFUnit.findColorIndex(color);
let oneText = {x: PDFUnit.toFormX(p.x) - 0.25,
y: PDFUnit.toFormY(p.y) - 0.75,
w: PDFUnit.toFixedFloat(maxWidth),
sw: this.spaceWidth, //font space width, use to merge adjacent text blocks
clr: clrId,
A: "left",
R: [{
T: this.flash_encode(text),
S: this.fontStyleId,
TS: TS
...
toFormPoint = function (viewportX, viewportY) { return [(viewportX / _pixelXPerGrid), (viewportY / _pixelYPerGrid)]; }
n/a
toFormX = function (viewportX) { return cls.toFixedFloat(viewportX / _pixelXPerGrid); }
...
else if (field.fieldType !== 'Ch') { //checkbox, radio button, and link button
rect[1] -= 3;
}
height = (height >= kMinHeight) ? height : kMinHeight;
return {
x: PDFUnit.toFormX(rect[0]),
y: PDFUnit.toFormY(rect[1]),
w: PDFUnit.toFormX(rect[2] - rect[0]),
h: PDFUnit.toFormY(height)
};
};
let _getFieldBaseData = function(field) {
...
toFormY = function (viewportY) { return cls.toFixedFloat(viewportY / _pixelYPerGrid); }
...
rect[1] -= 3;
}
height = (height >= kMinHeight) ? height : kMinHeight;
return {
x: PDFUnit.toFormX(rect[0]),
y: PDFUnit.toFormY(rect[1]),
w: PDFUnit.toFormX(rect[2] - rect[0]),
h: PDFUnit.toFormY(height)
};
};
let _getFieldBaseData = function(field) {
let attributeMask = 0;
...
toPixelX = function (formX) { return Math.round(formX * _pixelXPerGrid); }
n/a
toPixelY = function (formY) { return Math.round(formY * _pixelYPerGrid); }
n/a
ptixmlinject = function () { }
n/a
getFields = function (pageNum) { return ptiPageArray[pageNum]; }
...
let errMsg = 'An error occurred while rendering the page ' + (this.id + 1) +
':\n' + error.message +
':\n' + error.stack;
errorCallBack(errMsg);
}
else {
if (this.ptiParser) {
let extraFields = this.ptiParser.getFields(parseInt(this.id) + 1);
_.each(extraFields, _.bind(_addField, this));
}
_.extend(this, ctx.canvas);
this.stats = this.pdfPage.stats;
nodeUtil.p2jinfo('page ' + (this.id + 1) + ' is rendered successfully.');
...
parseXml = function (filePath, callback) { fs.readFile(filePath, 'utf8', function (err,data) { if (err) { callback(err); } else { xmlData = data; var parser = new DOMParser(); var dom = parser.parseFromString(xmlData); var root = dom.documentElement; var xmlFields = root.getElementsByTagName("field"); var fields = []; for(var i=0;i<xmlFields.length;i++){ var id = xmlFields[i].getAttribute('id'); var xPos = xmlFields[i].getAttribute('x'); var yPos = xmlFields[i].getAttribute('y'); var width = xmlFields[i].getAttribute('width'); var height = xmlFields[i].getAttribute('height'); var type = xmlFields[i].getAttribute('xsi:type'); var page = xmlFields[i].getAttribute('page'); var fontName = xmlFields[i].getAttribute('fontName'); var fontSize = xmlFields[i].getAttribute('fontSize'); var item = {}; var rectLeft = parseInt(xPos) - 21; //was 23.5 var rectTop = parseInt(yPos) - 20;//was 23 var rectRight = parseInt(rectLeft) + parseInt(width) - 4; var rectBottom = parseInt(rectTop) + parseInt(height) - 4; item.fieldType="Tx"; if (type == "Boolean") { item.fieldType="Btn"; } else if (type=="SSN" || type=="Phone" || type=="zip") { item.TName = type.toLowerCase(); } item.alternativeText = ""; item.fullName = id; item.fontSize = fontSize; item.subtype = "Widget"; item.rect = [rectLeft, rectTop, rectRight, rectBottom];; fields.push(item); ptiPageArray[parseInt(page)]=fields; } } callback(); }); }
...
if ((fieldInfoXMLPath.indexOf(_sufInfo) < 1) || (!fs.existsSync(fieldInfoXMLPath))) {
return;
}
nodeUtil.p2jinfo("About to load fieldInfo XML : " + fieldInfoXMLPath);
let PTIXmlParser = require('./ptixmlinject');
this.ptiParser = new PTIXmlParser();
this.ptiParser.parseXml(fieldInfoXMLPath, err => {
if (err) {
nodeUtil.p2jwarn("fieldInfo XML Error: " + JSON.stringify(err));
this.ptiParser = null;
}
else {
nodeUtil.p2jinfo("fieldInfo XML loaded.");
}
...