1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 06:38:07 +02:00

[api-minor] Replace the canvas package with @napi-rs/canvas

The `@napi-rs/canvas` package has fewer dependencies, which should *hopefully* make installing and using it easier for `pdfjs-dist` end-users. (Over the years we've seen, repeatedly, that `canvas` can be difficult to install successfully.)
Furthermore, this package includes more functionality (such as `Path2D`) which reduces the overall number of dependencies in the PDF.js project.

One point to note is that `@napi-rs/canvas` is a fair bit newer than `canvas`, and has a lot fewer users, however looking at the commit history it does seem to be actively maintained.

Note that I've successfully tested the [Node.js examples](https://github.com/mozilla/pdf.js/tree/master/examples/node), in particular the `pdf2png` one, with this patch applied and things appear to work fine.

Please see:
 - https://www.npmjs.com/package/@napi-rs/canvas
 - https://github.com/Brooooooklyn/canvas
This commit is contained in:
Jonas Jenwald 2024-11-08 11:29:24 +01:00
parent bff6738966
commit 86f943ca03
7 changed files with 188 additions and 104 deletions

View file

@ -57,9 +57,6 @@ all dependencies for PDF.js:
$ npm install
> [!NOTE]
> On MacOS M1/M2 you may see some `node-gyp`-related errors when running `npm install`. This is because one of our dependencies, `"canvas"`, does not provide pre-built binaries for this platform and instead `npm` will try to build it from source. Please make sure to first install the necessary native dependencies using `brew`: https://github.com/Automattic/node-canvas#compiling.
Finally, you need to start a local web server as some browsers do not allow opening
PDF files using a `file://` URL. Run:

View file

@ -9,9 +9,7 @@ Install the dependencies and build the PDF.js library:
$ npm install
$ gulp dist-install
Install the Node canvas library and run the example to convert the first page of a
PDF file to a PNG image:
Run the example to convert the first page of a PDF file to a PNG image:
$ npm install canvas
$ cd examples/node/pdf2png
$ node pdf2png.js
$ node pdf2png.mjs

View file

@ -57,7 +57,7 @@ try {
const renderTask = page.render(renderContext);
await renderTask.promise;
// Convert the canvas to an image buffer.
const image = canvasAndContext.canvas.toBuffer();
const image = canvasAndContext.canvas.toBuffer("image/png");
fs.writeFile("output.png", image, function (error) {
if (error) {
console.error("Error: " + error);

View file

@ -2256,8 +2256,7 @@ function packageJson() {
bugs: DIST_BUGS_URL,
license: DIST_LICENSE,
optionalDependencies: {
canvas: "^3.0.0-rc2",
path2d: "^0.2.1",
"@napi-rs/canvas": "^0.1.60",
},
browser: {
canvas: false,

238
package-lock.json generated
View file

@ -15,11 +15,11 @@
"@jazzer.js/core": "^2.1.0",
"@metalsmith/layouts": "^2.7.0",
"@metalsmith/markdown": "^1.10.0",
"@napi-rs/canvas": "^0.1.60",
"@types/node": "^22.8.7",
"autoprefixer": "^10.4.20",
"babel-loader": "^9.2.1",
"caniuse-lite": "^1.0.30001677",
"canvas": "^3.0.0-rc2",
"core-js": "^3.39.0",
"eslint": "^8.57.1",
"eslint-plugin-import": "^2.31.0",
@ -42,7 +42,6 @@
"metalsmith": "^2.6.3",
"metalsmith-html-relative": "^2.0.5",
"ordered-read-streams": "^2.0.0",
"path2d": "^0.2.1",
"pngjs": "^7.0.0",
"postcss": "^8.4.47",
"postcss-dark-theme-class": "^1.3.0",
@ -2286,6 +2285,180 @@
"metalsmith": "^2.5.0"
}
},
"node_modules/@napi-rs/canvas": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.60.tgz",
"integrity": "sha512-2a/8ynCHVXu9JVTeT/RLrZy6kro3VHnxDqy7SyHIdzCUUwJoKuKNmDzXjD6bqE0W/07j1lFW7OVIAYSr1GiWuA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
"@napi-rs/canvas-android-arm64": "0.1.60",
"@napi-rs/canvas-darwin-arm64": "0.1.60",
"@napi-rs/canvas-darwin-x64": "0.1.60",
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.60",
"@napi-rs/canvas-linux-arm64-gnu": "0.1.60",
"@napi-rs/canvas-linux-arm64-musl": "0.1.60",
"@napi-rs/canvas-linux-x64-gnu": "0.1.60",
"@napi-rs/canvas-linux-x64-musl": "0.1.60",
"@napi-rs/canvas-win32-x64-msvc": "0.1.60"
}
},
"node_modules/@napi-rs/canvas-android-arm64": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.60.tgz",
"integrity": "sha512-KNOBYH3BUfUl5mo5wvrA2C+tJk0RnF4InkbsCoHdsxjhLjbriJKmu5DCFLaiG/c6WPfTcLRz73bGcP7boVeb6A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-darwin-arm64": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.60.tgz",
"integrity": "sha512-j6PA7RwRcx0409Jk3zz6beq3EtvwEgvN46FyKgFnSnzoV0ey2kM+KI2XTpG3tE/v4+fTnQenR+ysUBEgtWuUuA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-darwin-x64": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.60.tgz",
"integrity": "sha512-k0uBuShNK7QnOJlLhzxSsnSdJMkiU8VexqvuTEi0qABqKkHrYzD0ezUgtyvaVLOOoqxwGy1Hh5ZoEze5s9H/6g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-arm-gnueabihf": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.60.tgz",
"integrity": "sha512-X2cQ6MIDZn5dMsy9jakASM6tvo2PGd3dq25gqrUzJeQIngQhLIWZtaYWza3md3M6HoQ4b/6W81OVQhgL/8uTkA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-arm64-gnu": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.60.tgz",
"integrity": "sha512-Ch02kQsetlXA4tfHfSJ63oyq9EbYB00yy/6hZ0/VYh60pLnopvsMt682+cM+rGBbgm14G+Heh3rDzJ6zBiiocw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-arm64-musl": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.60.tgz",
"integrity": "sha512-7TpSJM4RnhHnAMrA/bDXitNVx9TV8ZLQ/47QHsNhdZ77yCgcEyLBRgUGvjsmnUpWIHhTOWTHDlGY47zHcQDfhA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-x64-gnu": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.60.tgz",
"integrity": "sha512-46yi+fIUQ5SRg0Qs3L04zh67kk0uFJa2elWt/cS/7kEydu06uhjbJwW3123J9KShu2PKLlaZEqxJPksYpowoeA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-linux-x64-musl": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.60.tgz",
"integrity": "sha512-lTKiv5VnccFyZAd27AL6t69djDXQlfUgVE03PTM5HZUUy0h7sQKnrGh2mSMq58E3/vA0k65IFDqVqxyLjCpvlw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/canvas-win32-x64-msvc": {
"version": "0.1.60",
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.60.tgz",
"integrity": "sha512-b7VjNQ3V/7G6VQqB8KvG9A06ENFZhxFMe4areUduipFwuJ0w35PGgOmYZHd0+iY9Nh7niECjgPRNDcrzpDlWXg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -3739,22 +3912,6 @@
],
"license": "CC-BY-4.0"
},
"node_modules/canvas": {
"version": "3.0.0-rc2",
"resolved": "https://registry.npmjs.org/canvas/-/canvas-3.0.0-rc2.tgz",
"integrity": "sha512-esx4bYDznnqgRX4G8kaEaf0W3q8xIc51WpmrIitDzmcoEgwnv9wSKdzT6UxWZ4wkVu5+ileofppX0TpyviJRdQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"node-addon-api": "^7.0.0",
"prebuild-install": "^7.1.1",
"simple-get": "^3.0.3"
},
"engines": {
"node": "^18.12.0 || >= 20.9.0"
}
},
"node_modules/catharsis": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
@ -4525,18 +4682,6 @@
"node": ">=0.10.0"
}
},
"node_modules/decompress-response": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
"dev": true,
"dependencies": {
"mimic-response": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@ -9381,18 +9526,6 @@
"node": ">=6"
}
},
"node_modules/mimic-response": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
"dev": true,
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@ -10143,16 +10276,6 @@
"node": ">=8"
}
},
"node_modules/path2d": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.1.tgz",
"integrity": "sha512-Fl2z/BHvkTNvkuBzYTpTuirHZg6wW9z8+4SND/3mDTEcYbbNKWAy21dz9D3ePNNwrrK8pqZO5vLPZ1hLF6T7XA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@ -11671,17 +11794,6 @@
}
]
},
"node_modules/simple-get": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
"dev": true,
"dependencies": {
"decompress-response": "^4.2.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",

View file

@ -10,11 +10,11 @@
"@jazzer.js/core": "^2.1.0",
"@metalsmith/layouts": "^2.7.0",
"@metalsmith/markdown": "^1.10.0",
"@napi-rs/canvas": "^0.1.60",
"@types/node": "^22.8.7",
"autoprefixer": "^10.4.20",
"babel-loader": "^9.2.1",
"caniuse-lite": "^1.0.30001677",
"canvas": "^3.0.0-rc2",
"core-js": "^3.39.0",
"eslint": "^8.57.1",
"eslint-plugin-import": "^2.31.0",
@ -37,7 +37,6 @@
"metalsmith": "^2.6.3",
"metalsmith-html-relative": "^2.0.5",
"ordered-read-streams": "^2.0.0",
"path2d": "^0.2.1",
"pngjs": "^7.0.0",
"postcss": "^8.4.47",
"postcss-dark-theme-class": "^1.3.0",

View file

@ -31,50 +31,29 @@ if (
!PDFJSDev.test("SKIP_BABEL") &&
isNodeJS
) {
let canvas, path2d;
let canvas;
try {
const require = process
.getBuiltinModule("module")
.createRequire(import.meta.url);
try {
canvas = require("canvas");
canvas = require("@napi-rs/canvas");
} catch (ex) {
warn(`Cannot load "canvas" package: "${ex}".`);
}
try {
path2d = require("path2d");
} catch (ex) {
warn(`Cannot load "path2d" package: "${ex}".`);
warn(`Cannot load "@napi-rs/canvas" package: "${ex}".`);
}
} catch {}
if (!globalThis.DOMMatrix) {
const DOMMatrix = canvas?.DOMMatrix;
if (DOMMatrix) {
globalThis.DOMMatrix = DOMMatrix;
if (canvas?.DOMMatrix) {
globalThis.DOMMatrix = canvas.DOMMatrix;
} else {
warn("Cannot polyfill `DOMMatrix`, rendering may be broken.");
}
}
if (!globalThis.Path2D) {
const CanvasRenderingContext2D = canvas?.CanvasRenderingContext2D;
const applyPath2DToCanvasRenderingContext =
path2d?.applyPath2DToCanvasRenderingContext;
const Path2D = path2d?.Path2D;
if (
CanvasRenderingContext2D &&
applyPath2DToCanvasRenderingContext &&
Path2D
) {
try {
applyPath2DToCanvasRenderingContext(CanvasRenderingContext2D);
} catch (ex) {
warn(`applyPath2DToCanvasRenderingContext: "${ex}".`);
}
globalThis.Path2D = Path2D;
if (canvas?.Path2D) {
globalThis.Path2D = canvas.Path2D;
} else {
warn("Cannot polyfill `Path2D`, rendering may be broken.");
}
@ -97,7 +76,7 @@ class NodeCanvasFactory extends BaseCanvasFactory {
const require = process
.getBuiltinModule("module")
.createRequire(import.meta.url);
const canvas = require("canvas");
const canvas = require("@napi-rs/canvas");
return canvas.createCanvas(width, height);
}
}