mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-19 06:38:07 +02:00
[api-major] Remove the SVG back-end (PR 15173 follow-up)
This has been deprecated since version `2.15.349`, which is a year ago. Removing this will also simplify some upcoming changes, specifically outputting of JavaScript modules in the builds.
This commit is contained in:
parent
be53c7d6f5
commit
3ced0dec1b
16 changed files with 1 additions and 2302 deletions
|
@ -1,285 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function xmlEncode(s) {
|
||||
let i = 0,
|
||||
ch;
|
||||
s = String(s);
|
||||
while (
|
||||
i < s.length &&
|
||||
(ch = s[i]) !== "&" &&
|
||||
ch !== "<" &&
|
||||
ch !== '"' &&
|
||||
ch !== "\n" &&
|
||||
ch !== "\r" &&
|
||||
ch !== "\t"
|
||||
) {
|
||||
i++;
|
||||
}
|
||||
if (i >= s.length) {
|
||||
return s;
|
||||
}
|
||||
let 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;
|
||||
}
|
||||
|
||||
function DOMElement(name) {
|
||||
this.nodeName = name;
|
||||
this.childNodes = [];
|
||||
this.attributes = {};
|
||||
this.textContent = "";
|
||||
|
||||
if (name === "style") {
|
||||
this.sheet = {
|
||||
cssRules: [],
|
||||
insertRule(rule) {
|
||||
this.cssRules.push(rule);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
DOMElement.prototype = {
|
||||
getAttribute: function DOMElement_getAttribute(name) {
|
||||
if (name in this.attributes) {
|
||||
return this.attributes[name];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
getAttributeNS: function DOMElement_getAttributeNS(NS, name) {
|
||||
// Fast path
|
||||
if (name in this.attributes) {
|
||||
return this.attributes[name];
|
||||
}
|
||||
// Slow path - used by test/unit/display_svg_spec.js
|
||||
// Assuming that there is only one matching attribute for a given name,
|
||||
// across all namespaces.
|
||||
if (NS) {
|
||||
const suffix = ":" + name;
|
||||
for (const fullName in this.attributes) {
|
||||
if (fullName.slice(-suffix.length) === suffix) {
|
||||
return this.attributes[fullName];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
setAttribute: function DOMElement_setAttribute(name, value) {
|
||||
this.attributes[name] = value || "";
|
||||
},
|
||||
|
||||
setAttributeNS: function DOMElement_setAttributeNS(NS, name, value) {
|
||||
this.setAttribute(name, value);
|
||||
},
|
||||
|
||||
append: function DOMElement_append(...elements) {
|
||||
const childNodes = this.childNodes;
|
||||
for (const element of elements) {
|
||||
if (!childNodes.includes(element)) {
|
||||
childNodes.push(element);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
appendChild: function DOMElement_appendChild(element) {
|
||||
const childNodes = this.childNodes;
|
||||
if (!childNodes.includes(element)) {
|
||||
childNodes.push(element);
|
||||
}
|
||||
},
|
||||
|
||||
hasChildNodes: function DOMElement_hasChildNodes() {
|
||||
return this.childNodes.length !== 0;
|
||||
},
|
||||
|
||||
cloneNode: function DOMElement_cloneNode() {
|
||||
const newNode = new DOMElement(this.nodeName);
|
||||
newNode.childNodes = this.childNodes;
|
||||
newNode.attributes = this.attributes;
|
||||
newNode.textContent = this.textContent;
|
||||
return newNode;
|
||||
},
|
||||
|
||||
// This method is offered for convenience. It is recommended to directly use
|
||||
// getSerializer because that allows you to process the chunks as they come
|
||||
// instead of requiring the whole image to fit in memory.
|
||||
toString: function DOMElement_toString() {
|
||||
const buf = [];
|
||||
const serializer = this.getSerializer();
|
||||
let chunk;
|
||||
while ((chunk = serializer.getNext()) !== null) {
|
||||
buf.push(chunk);
|
||||
}
|
||||
return buf.join("");
|
||||
},
|
||||
|
||||
getSerializer: function DOMElement_getSerializer() {
|
||||
return new DOMElementSerializer(this);
|
||||
},
|
||||
};
|
||||
|
||||
function DOMElementSerializer(node) {
|
||||
this._node = node;
|
||||
this._state = 0;
|
||||
this._loopIndex = 0;
|
||||
this._attributeKeys = null;
|
||||
this._childSerializer = null;
|
||||
}
|
||||
DOMElementSerializer.prototype = {
|
||||
/**
|
||||
* Yields the next chunk in the serialization of the element.
|
||||
*
|
||||
* @returns {string|null} null if the element has fully been serialized.
|
||||
*/
|
||||
getNext: function DOMElementSerializer_getNext() {
|
||||
const node = this._node;
|
||||
switch (this._state) {
|
||||
case 0: // Start opening tag.
|
||||
++this._state;
|
||||
return "<" + node.nodeName;
|
||||
case 1: // Add SVG namespace if this is the root element.
|
||||
++this._state;
|
||||
if (node.nodeName === "svg:svg") {
|
||||
return (
|
||||
' xmlns:xlink="http://www.w3.org/1999/xlink"' +
|
||||
' xmlns:svg="http://www.w3.org/2000/svg"'
|
||||
);
|
||||
}
|
||||
/* falls through */
|
||||
case 2: // Initialize variables for looping over attributes.
|
||||
++this._state;
|
||||
this._loopIndex = 0;
|
||||
this._attributeKeys = Object.keys(node.attributes);
|
||||
/* falls through */
|
||||
case 3: // Serialize any attributes and end opening tag.
|
||||
if (this._loopIndex < this._attributeKeys.length) {
|
||||
const name = this._attributeKeys[this._loopIndex++];
|
||||
return " " + name + '="' + xmlEncode(node.attributes[name]) + '"';
|
||||
}
|
||||
++this._state;
|
||||
return ">";
|
||||
case 4: // Serialize textContent for tspan/style elements.
|
||||
if (node.nodeName === "svg:tspan" || node.nodeName === "svg:style") {
|
||||
this._state = 6;
|
||||
return xmlEncode(node.textContent);
|
||||
}
|
||||
++this._state;
|
||||
this._loopIndex = 0;
|
||||
/* falls through */
|
||||
case 5: // Serialize child nodes (only for non-tspan/style elements).
|
||||
while (true) {
|
||||
const value =
|
||||
this._childSerializer && this._childSerializer.getNext();
|
||||
if (value !== null) {
|
||||
return value;
|
||||
}
|
||||
const nextChild = node.childNodes[this._loopIndex++];
|
||||
if (nextChild) {
|
||||
this._childSerializer = new DOMElementSerializer(nextChild);
|
||||
} else {
|
||||
this._childSerializer = null;
|
||||
++this._state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* falls through */
|
||||
case 6: // Ending tag.
|
||||
++this._state;
|
||||
return "</" + node.nodeName + ">";
|
||||
case 7: // Done.
|
||||
return null;
|
||||
default:
|
||||
throw new Error("Unexpected serialization state: " + this._state);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const document = {
|
||||
childNodes: [],
|
||||
|
||||
get currentScript() {
|
||||
return { src: "" };
|
||||
},
|
||||
|
||||
get documentElement() {
|
||||
return this;
|
||||
},
|
||||
|
||||
createElementNS(NS, element) {
|
||||
const elObject = new DOMElement(element);
|
||||
return elObject;
|
||||
},
|
||||
|
||||
createElement(element) {
|
||||
return this.createElementNS("", element);
|
||||
},
|
||||
|
||||
getElementsByTagName(element) {
|
||||
if (element === "head") {
|
||||
return [this.head || (this.head = new DOMElement("head"))];
|
||||
}
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
||||
function Image() {
|
||||
this._src = null;
|
||||
this.onload = null;
|
||||
}
|
||||
Image.prototype = {
|
||||
get src() {
|
||||
return this._src;
|
||||
},
|
||||
set src(value) {
|
||||
this._src = value;
|
||||
if (this.onload) {
|
||||
this.onload();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
exports.document = document;
|
||||
exports.Image = Image;
|
||||
|
||||
const exported_symbols = Object.keys(exports);
|
||||
|
||||
exports.setStubs = function (namespace) {
|
||||
exported_symbols.forEach(function (key) {
|
||||
console.assert(!(key in namespace), "property should not be set: " + key);
|
||||
namespace[key] = exports[key];
|
||||
});
|
||||
};
|
||||
exports.unsetStubs = function (namespace) {
|
||||
exported_symbols.forEach(function (key) {
|
||||
console.assert(key in namespace, "property should be set: " + key);
|
||||
delete namespace[key];
|
||||
});
|
||||
};
|
|
@ -1,128 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
//
|
||||
// Node tool to dump SVG output into a file.
|
||||
//
|
||||
|
||||
const fs = require("fs");
|
||||
const util = require("util");
|
||||
const path = require("path");
|
||||
const stream = require("stream");
|
||||
|
||||
// HACK few hacks to let PDF.js be loaded not as a module in global space.
|
||||
require("./domstubs.js").setStubs(global);
|
||||
|
||||
// Run `gulp dist-install` to generate 'pdfjs-dist' npm package files.
|
||||
const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js");
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
||||
const CMAP_PACKED = true;
|
||||
|
||||
// Loading file from file system into typed array
|
||||
const pdfPath =
|
||||
process.argv[2] || "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
const data = new Uint8Array(fs.readFileSync(pdfPath));
|
||||
|
||||
const outputDirectory = "./svgdump";
|
||||
|
||||
try {
|
||||
// Note: This creates a directory only one level deep. If you want to create
|
||||
// multiple subdirectories on the fly, use the mkdirp module from npm.
|
||||
fs.mkdirSync(outputDirectory);
|
||||
} catch (e) {
|
||||
if (e.code !== "EEXIST") {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Dumps svg outputs to a folder called svgdump
|
||||
function getFilePathForPage(pageNum) {
|
||||
const name = path.basename(pdfPath, path.extname(pdfPath));
|
||||
return path.join(outputDirectory, `${name}-${pageNum}.svg`);
|
||||
}
|
||||
|
||||
/**
|
||||
* A readable stream which offers a stream representing the serialization of a
|
||||
* given DOM element (as defined by domstubs.js).
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {DOMElement} options.svgElement The element to serialize
|
||||
*/
|
||||
function ReadableSVGStream(options) {
|
||||
if (!(this instanceof ReadableSVGStream)) {
|
||||
return new ReadableSVGStream(options);
|
||||
}
|
||||
stream.Readable.call(this, options);
|
||||
this.serializer = options.svgElement.getSerializer();
|
||||
}
|
||||
util.inherits(ReadableSVGStream, stream.Readable);
|
||||
// Implements https://nodejs.org/api/stream.html#stream_readable_read_size_1
|
||||
ReadableSVGStream.prototype._read = function () {
|
||||
let chunk;
|
||||
while ((chunk = this.serializer.getNext()) !== null) {
|
||||
if (!this.push(chunk)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.push(null);
|
||||
};
|
||||
|
||||
// Streams the SVG element to the given file path.
|
||||
function writeSvgToFile(svgElement, filePath) {
|
||||
let readableSvgStream = new ReadableSVGStream({
|
||||
svgElement,
|
||||
});
|
||||
const writableStream = fs.createWriteStream(filePath);
|
||||
return new Promise(function (resolve, reject) {
|
||||
readableSvgStream.once("error", reject);
|
||||
writableStream.once("error", reject);
|
||||
writableStream.once("finish", resolve);
|
||||
readableSvgStream.pipe(writableStream);
|
||||
}).catch(function (err) {
|
||||
readableSvgStream = null; // Explicitly null because of v8 bug 6512.
|
||||
writableStream.end();
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
// Will be using async/await to load document, pages and misc data.
|
||||
const loadingTask = pdfjsLib.getDocument({
|
||||
data,
|
||||
cMapUrl: CMAP_URL,
|
||||
cMapPacked: CMAP_PACKED,
|
||||
fontExtraProperties: true,
|
||||
});
|
||||
(async function () {
|
||||
const doc = await loadingTask.promise;
|
||||
const numPages = doc.numPages;
|
||||
console.log("# Document Loaded");
|
||||
console.log(`Number of Pages: ${numPages}`);
|
||||
console.log();
|
||||
|
||||
for (let pageNum = 1; pageNum <= numPages; pageNum++) {
|
||||
try {
|
||||
const page = await doc.getPage(pageNum);
|
||||
console.log(`# Page ${pageNum}`);
|
||||
const viewport = page.getViewport({ scale: 1.0 });
|
||||
console.log(`Size: ${viewport.width}x${viewport.height}`);
|
||||
console.log();
|
||||
|
||||
const opList = await page.getOperatorList();
|
||||
const svgGfx = new pdfjsLib.SVGGraphics(
|
||||
page.commonObjs,
|
||||
page.objs,
|
||||
/* forceDataSchema = */ true
|
||||
);
|
||||
svgGfx.embedFonts = true;
|
||||
const svg = await svgGfx.getSVG(opList, viewport);
|
||||
await writeSvgToFile(svg, getFilePathForPage(pageNum));
|
||||
// Release page resources.
|
||||
page.cleanup();
|
||||
} catch (err) {
|
||||
console.log(`Error: ${err}`);
|
||||
}
|
||||
}
|
||||
console.log("# End of Document");
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue