diff --git a/.gitignore b/.gitignore index 516970e91..421e6f4a4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ tags .DS_Store Makefile node_modules/ +examples/node/svgdump/ diff --git a/examples/node/domstubs.js b/examples/node/domstubs.js new file mode 100644 index 000000000..dafc75832 --- /dev/null +++ b/examples/node/domstubs.js @@ -0,0 +1,140 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +var sheet = { + cssRules: [], + insertRule: function(rule) { + this.cssRules.push(rule); + }, +}; + +var style = { + sheet: sheet, +}; + +function xmlEncode(s){ + var i = 0, ch; + while (i < s.length && (ch = s[i]) !== '&' && ch !== '<' && + ch !== '\"' && ch !== '\n' && ch !== '\r' && ch !== '\t') { + i++; + } + if (i >= s.length) { + return s; + } + var buf = s.substring(0, i); + while (i < s.length) { + ch = s[i++]; + switch (ch) { + case '&': + buf += '&'; + break; + case '<': + buf += '<'; + break; + case '\"': + buf += '"'; + break; + case '\n': + buf += ' '; + break; + case '\r': + buf += ' '; + break; + case '\t': + buf += ' '; + break; + default: + buf += ch; + break; + } + } + return buf; +} + +global.btoa = function btoa(chars) { + var digits = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var buffer = ''; + var i, n; + for (i = 0, n = chars.length; i < n; i += 3) { + var b1 = chars.charCodeAt(i) & 0xFF; + var b2 = chars.charCodeAt(i + 1) & 0xFF; + var b3 = chars.charCodeAt(i + 2) & 0xFF; + var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4); + var d3 = i + 1 < n ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64; + var d4 = i + 2 < n ? (b3 & 0x3F) : 64; + buffer += (digits.charAt(d1) + digits.charAt(d2) + + digits.charAt(d3) + digits.charAt(d4)); + } + return buffer; +}; + +function DOMElement(name) { + this.nodeName = name; + this.childNodes = []; + this.attributes = {}; + this.textContent = ''; +} + +DOMElement.prototype = { + + setAttributeNS: function DOMElement_setAttributeNS(NS, name, value) { + value = value || ''; + value = xmlEncode(value); + this.attributes[name] = value; + }, + + appendChild: function DOMElement_appendChild(element) { + var childNodes = this.childNodes; + if (childNodes.indexOf(element) === -1) { + childNodes.push(element); + } + }, + + toString: function DOMElement_toString() { + var attrList = []; + for (i in this.attributes) { + attrList.push(i + '="' + xmlEncode(this.attributes[i]) + '"'); + } + + if (this.nodeName === 'svg:tspan') { + var encText = xmlEncode(this.textContent); + return '<' + this.nodeName + ' ' + attrList.join(' ') + '>' + + encText + ''; + } else if (this.nodeName === 'svg:svg') { + var ns = 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + + 'xmlns:svg="http://www.w3.org/2000/svg"' + return '<' + this.nodeName + ' ' + ns + ' ' + attrList.join(' ') + '>' + + this.childNodes.join('') + ''; + } else { + return '<' + this.nodeName + ' ' + attrList.join(' ') + '>' + + this.childNodes.join('') + ''; + } + }, + + cloneNode: function DOMElement_cloneNode() { + var newNode = new DOMElement(this.nodeName); + newNode.childNodes = this.childNodes; + newNode.attributes = this.attributes; + newNode.textContent = this.textContent; + return newNode; + }, +} + +global.document = { + childNodes : [], + + getElementById: function (id) { + if (id === 'PDFJS_FONT_STYLE_TAG') { + return style; + } + }, + + createElementNS: function (NS, element) { + var elObject = new DOMElement(element); + return elObject; + }, +}; + diff --git a/examples/node/pdf2svg.js b/examples/node/pdf2svg.js new file mode 100644 index 000000000..6da69b165 --- /dev/null +++ b/examples/node/pdf2svg.js @@ -0,0 +1,85 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// +// Node tool to dump SVG output into a file. +// + +var fs = require('fs'); + +// HACK few hacks to let PDF.js be loaded not as a module in global space. +global.window = global; +global.navigator = { userAgent: 'node' }; +global.PDFJS = {}; + +PDFJS.workerSrc = true; +require('../../build/singlefile/build/pdf.combined.js'); +require('./domstubs.js'); + +// Loading file from file system into typed array +var pdfPath = process.argv[2] || '../../web/compressed.tracemonkey-pldi-09.pdf'; +var data = new Uint8Array(fs.readFileSync(pdfPath)); + +// Dumps svg outputs to a folder called svgdump +function writeToFile(svgdump, pageNum) { + var name = getFileNameFromPath(pdfPath); + fs.mkdir('./svgdump/', function(err) { + if (!err || err.code === 'EEXIST') { + fs.writeFile('./svgdump/' + name + "-" + pageNum + '.svg', svgdump, + function(err) { + if (err) { + console.log('Error: ' + err); + } else { + console.log('Page: ' + pageNum); + } + }); + } + }); +} + +// Get filename from the path + +function getFileNameFromPath(path) { + var index = path.lastIndexOf('/'); + var extIndex = path.lastIndexOf('.'); + return path.substring(index , extIndex); +} + +// Will be using promises to load document, pages and misc data instead of +// callback. +PDFJS.getDocument(data).then(function (doc) { + var numPages = doc.numPages; + console.log('# Document Loaded'); + console.log('Number of Pages: ' + numPages); + console.log(); + + var lastPromise = Promise.resolve(); // will be used to chain promises + var loadPage = function (pageNum) { + return doc.getPage(pageNum).then(function (page) { + console.log('# Page ' + pageNum); + var viewport = page.getViewport(1.0 /* scale */); + console.log('Size: ' + viewport.width + 'x' + viewport.height); + console.log(); + + return page.getOperatorList().then(function (opList) { + var svgGfx = new PDFJS.SVGGraphics(page.commonObjs, page.objs); + return svgGfx.loadDependencies(opList).then(function (values) { + var svgDump = svgGfx.getSVG(viewport, pageNum, opList).toString(); + writeToFile(svgDump, pageNum); + }); + }); + }) + }; + + for (var i = 1; i <= numPages; i++) { + lastPromise = lastPromise.then(loadPage.bind(null, i)); + } + return lastPromise; +}).then(function () { + console.log('# End of Document'); +}, function (err) { + console.error('Error: ' + err); +}); +