@shqld/canvas 3.2.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/Readme.md +654 -0
  2. package/binding.gyp +229 -0
  3. package/browser.js +31 -0
  4. package/index.d.ts +507 -0
  5. package/index.js +94 -0
  6. package/lib/DOMMatrix.js +678 -0
  7. package/lib/bindings.js +113 -0
  8. package/lib/canvas.js +113 -0
  9. package/lib/context2d.js +11 -0
  10. package/lib/image.js +97 -0
  11. package/lib/jpegstream.js +41 -0
  12. package/lib/pattern.js +15 -0
  13. package/lib/pdfstream.js +35 -0
  14. package/lib/pngstream.js +42 -0
  15. package/package.json +77 -0
  16. package/scripts/install.js +19 -0
  17. package/src/Backends.h +9 -0
  18. package/src/Canvas.cc +1026 -0
  19. package/src/Canvas.h +128 -0
  20. package/src/CanvasError.h +37 -0
  21. package/src/CanvasGradient.cc +113 -0
  22. package/src/CanvasGradient.h +20 -0
  23. package/src/CanvasPattern.cc +129 -0
  24. package/src/CanvasPattern.h +33 -0
  25. package/src/CanvasRenderingContext2d.cc +3527 -0
  26. package/src/CanvasRenderingContext2d.h +238 -0
  27. package/src/CharData.h +233 -0
  28. package/src/FontParser.cc +605 -0
  29. package/src/FontParser.h +115 -0
  30. package/src/Image.cc +1719 -0
  31. package/src/Image.h +146 -0
  32. package/src/ImageData.cc +138 -0
  33. package/src/ImageData.h +26 -0
  34. package/src/InstanceData.h +12 -0
  35. package/src/JPEGStream.h +157 -0
  36. package/src/PNG.h +292 -0
  37. package/src/Point.h +11 -0
  38. package/src/Util.h +9 -0
  39. package/src/bmp/BMPParser.cc +459 -0
  40. package/src/bmp/BMPParser.h +60 -0
  41. package/src/bmp/LICENSE.md +24 -0
  42. package/src/closure.cc +52 -0
  43. package/src/closure.h +98 -0
  44. package/src/color.cc +796 -0
  45. package/src/color.h +30 -0
  46. package/src/dll_visibility.h +20 -0
  47. package/src/init.cc +114 -0
  48. package/src/register_font.cc +352 -0
  49. package/src/register_font.h +7 -0
  50. package/util/has_lib.js +119 -0
  51. package/util/win_jpeg_lookup.js +21 -0
@@ -0,0 +1,113 @@
1
+ 'use strict'
2
+
3
+ const path = require('path')
4
+
5
+ const PLATFORMS = {
6
+ 'darwin-arm64': '@shqld/canvas-darwin-arm64',
7
+ 'darwin-x64': '@shqld/canvas-darwin-x64',
8
+ 'linux-arm64-gnu': '@shqld/canvas-linux-arm64-gnu',
9
+ 'linux-arm64-musl': '@shqld/canvas-linux-arm64-musl',
10
+ 'linux-x64-gnu': '@shqld/canvas-linux-x64-gnu',
11
+ 'linux-x64-musl': '@shqld/canvas-linux-x64-musl',
12
+ 'win32-x64': '@shqld/canvas-win32-x64'
13
+ }
14
+
15
+ function getPlatformKey () {
16
+ const platform = process.platform
17
+ const arch = process.arch
18
+ let key = `${platform}-${arch}`
19
+ if (platform === 'linux') {
20
+ key += isMuslLinux() ? '-musl' : '-gnu'
21
+ }
22
+ return key
23
+ }
24
+
25
+ function isMuslLinux () {
26
+ try {
27
+ const { execFileSync } = require('child_process')
28
+ const output = execFileSync('ldd', ['--version'], {
29
+ encoding: 'utf8',
30
+ stdio: ['pipe', 'pipe', 'pipe']
31
+ })
32
+ return output.includes('musl')
33
+ } catch (e) {
34
+ // ldd --version exits non-zero on musl and prints to stderr
35
+ return e.stderr ? e.stderr.includes('musl') : false
36
+ }
37
+ }
38
+
39
+ function loadBinding () {
40
+ const key = getPlatformKey()
41
+ const packageName = PLATFORMS[key]
42
+
43
+ if (packageName) {
44
+ try {
45
+ // Windows: DLLs are next to canvas.node, add to search path
46
+ if (process.platform === 'win32') {
47
+ const pkgDir = path.dirname(require.resolve(`${packageName}/package.json`))
48
+ process.env.PATH = pkgDir + path.delimiter + process.env.PATH
49
+ }
50
+ return require(packageName)
51
+ } catch (_) {
52
+ // fall through to build-from-source fallback
53
+ }
54
+ }
55
+
56
+ // Fallback: locally built binary
57
+ try {
58
+ const localPath = path.resolve(__dirname, '..', 'build', 'Release')
59
+ if (process.platform === 'win32') {
60
+ process.env.PATH = localPath + path.delimiter + process.env.PATH
61
+ }
62
+ return require(path.join(localPath, 'canvas.node'))
63
+ } catch (_) {
64
+ const supported = Object.keys(PLATFORMS).join(', ')
65
+ throw new Error(
66
+ `No prebuilt canvas binary found for ${key}. ` +
67
+ `Supported platforms: ${supported}. ` +
68
+ 'To build from source: npm rebuild canvas --build-from-source'
69
+ )
70
+ }
71
+ }
72
+
73
+ const bindings = loadBinding()
74
+
75
+ module.exports = bindings
76
+
77
+ Object.defineProperty(bindings.Canvas.prototype, Symbol.toStringTag, {
78
+ value: 'HTMLCanvasElement',
79
+ configurable: true
80
+ })
81
+
82
+ Object.defineProperty(bindings.Image.prototype, Symbol.toStringTag, {
83
+ value: 'HTMLImageElement',
84
+ configurable: true
85
+ })
86
+
87
+ bindings.ImageData.prototype.toString = function () {
88
+ return '[object ImageData]'
89
+ }
90
+
91
+ Object.defineProperty(bindings.ImageData.prototype, Symbol.toStringTag, {
92
+ value: 'ImageData',
93
+ configurable: true
94
+ })
95
+
96
+ bindings.CanvasGradient.prototype.toString = function () {
97
+ return '[object CanvasGradient]'
98
+ }
99
+
100
+ Object.defineProperty(bindings.CanvasGradient.prototype, Symbol.toStringTag, {
101
+ value: 'CanvasGradient',
102
+ configurable: true
103
+ })
104
+
105
+ Object.defineProperty(bindings.CanvasPattern.prototype, Symbol.toStringTag, {
106
+ value: 'CanvasPattern',
107
+ configurable: true
108
+ })
109
+
110
+ Object.defineProperty(bindings.CanvasRenderingContext2d.prototype, Symbol.toStringTag, {
111
+ value: 'CanvasRenderingContext2d',
112
+ configurable: true
113
+ })
package/lib/canvas.js ADDED
@@ -0,0 +1,113 @@
1
+ 'use strict'
2
+
3
+ /*!
4
+ * Canvas
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+ const bindings = require('./bindings')
10
+ const Canvas = module.exports = bindings.Canvas
11
+ const Context2d = require('./context2d')
12
+ const PNGStream = require('./pngstream')
13
+ const PDFStream = require('./pdfstream')
14
+ const JPEGStream = require('./jpegstream')
15
+ const FORMATS = ['image/png', 'image/jpeg']
16
+ const util = require('util')
17
+
18
+ // TODO || is for Node.js pre-v6.6.0
19
+ Canvas.prototype[util.inspect.custom || 'inspect'] = function () {
20
+ return `[Canvas ${this.width}x${this.height}]`
21
+ }
22
+
23
+ Canvas.prototype.getContext = function (contextType, contextAttributes) {
24
+ if (contextType == '2d') {
25
+ const ctx = this._context2d || (this._context2d = new Context2d(this, contextAttributes))
26
+ this.context = ctx
27
+ ctx.canvas = this
28
+ return ctx
29
+ }
30
+ }
31
+
32
+ Canvas.prototype.pngStream =
33
+ Canvas.prototype.createPNGStream = function (options) {
34
+ return new PNGStream(this, options)
35
+ }
36
+
37
+ Canvas.prototype.pdfStream =
38
+ Canvas.prototype.createPDFStream = function (options) {
39
+ return new PDFStream(this, options)
40
+ }
41
+
42
+ Canvas.prototype.jpegStream =
43
+ Canvas.prototype.createJPEGStream = function (options) {
44
+ return new JPEGStream(this, options)
45
+ }
46
+
47
+ Canvas.prototype.toDataURL = function (a1, a2, a3) {
48
+ // valid arg patterns (args -> [type, opts, fn]):
49
+ // [] -> ['image/png', null, null]
50
+ // [qual] -> ['image/png', null, null]
51
+ // [undefined] -> ['image/png', null, null]
52
+ // ['image/png'] -> ['image/png', null, null]
53
+ // ['image/png', qual] -> ['image/png', null, null]
54
+ // [fn] -> ['image/png', null, fn]
55
+ // [type, fn] -> [type, null, fn]
56
+ // [undefined, fn] -> ['image/png', null, fn]
57
+ // ['image/png', qual, fn] -> ['image/png', null, fn]
58
+ // ['image/jpeg', fn] -> ['image/jpeg', null, fn]
59
+ // ['image/jpeg', opts, fn] -> ['image/jpeg', opts, fn]
60
+ // ['image/jpeg', qual, fn] -> ['image/jpeg', {quality: qual}, fn]
61
+ // ['image/jpeg', undefined, fn] -> ['image/jpeg', null, fn]
62
+ // ['image/jpeg'] -> ['image/jpeg', null, fn]
63
+ // ['image/jpeg', opts] -> ['image/jpeg', opts, fn]
64
+ // ['image/jpeg', qual] -> ['image/jpeg', {quality: qual}, fn]
65
+
66
+ let type = 'image/png'
67
+ let opts = {}
68
+ let fn
69
+
70
+ if (typeof a1 === 'function') {
71
+ fn = a1
72
+ } else {
73
+ if (typeof a1 === 'string' && FORMATS.includes(a1.toLowerCase())) {
74
+ type = a1.toLowerCase()
75
+ }
76
+
77
+ if (typeof a2 === 'function') {
78
+ fn = a2
79
+ } else {
80
+ if (typeof a2 === 'object') {
81
+ opts = a2
82
+ } else if (typeof a2 === 'number') {
83
+ opts = { quality: Math.max(0, Math.min(1, a2)) }
84
+ }
85
+
86
+ if (typeof a3 === 'function') {
87
+ fn = a3
88
+ } else if (undefined !== a3) {
89
+ throw new TypeError(`${typeof a3} is not a function`)
90
+ }
91
+ }
92
+ }
93
+
94
+ if (this.width === 0 || this.height === 0) {
95
+ // Per spec, if the bitmap has no pixels, return this string:
96
+ const str = 'data:,'
97
+ if (fn) {
98
+ setTimeout(() => fn(null, str))
99
+ return
100
+ } else {
101
+ return str
102
+ }
103
+ }
104
+
105
+ if (fn) {
106
+ this.toBuffer((err, buf) => {
107
+ if (err) return fn(err)
108
+ fn(null, `data:${type};base64,${buf.toString('base64')}`)
109
+ }, type, opts)
110
+ } else {
111
+ return `data:${type};base64,${this.toBuffer(type, opts).toString('base64')}`
112
+ }
113
+ }
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ /*!
4
+ * Canvas - Context2d
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+ const bindings = require('./bindings')
10
+
11
+ module.exports = bindings.CanvasRenderingContext2d
package/lib/image.js ADDED
@@ -0,0 +1,97 @@
1
+ 'use strict'
2
+
3
+ /*!
4
+ * Canvas - Image
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+ /**
10
+ * Module dependencies.
11
+ */
12
+
13
+ const bindings = require('./bindings')
14
+ const Image = module.exports = bindings.Image
15
+ const util = require('util')
16
+
17
+ const { GetSource, SetSource } = bindings
18
+
19
+ Object.defineProperty(Image.prototype, 'src', {
20
+ /**
21
+ * src setter. Valid values:
22
+ * * `data:` URI
23
+ * * Local file path
24
+ * * HTTP or HTTPS URL
25
+ * * Buffer containing image data (i.e. not a `data:` URI stored in a Buffer)
26
+ *
27
+ * @param {String|Buffer} val filename, buffer, data URI, URL
28
+ * @api public
29
+ */
30
+ set (val) {
31
+ if (typeof val === 'string') {
32
+ if (/^\s*data:/.test(val)) { // data: URI
33
+ const commaI = val.indexOf(',')
34
+ // 'base64' must come before the comma
35
+ const isBase64 = val.lastIndexOf('base64', commaI) !== -1
36
+ const content = val.slice(commaI + 1)
37
+ setSource(this, Buffer.from(content, isBase64 ? 'base64' : 'utf8'), val)
38
+ } else if (/^\s*https?:\/\//.test(val)) { // remote URL
39
+ const onerror = err => {
40
+ if (typeof this.onerror === 'function') {
41
+ this.onerror(err)
42
+ } else {
43
+ throw err
44
+ }
45
+ }
46
+
47
+ fetch(val, {
48
+ method: 'GET',
49
+ headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36' }
50
+ })
51
+ .then(res => {
52
+ if (!res.ok) {
53
+ throw new Error(`Server responded with ${res.status}`)
54
+ }
55
+ return res.arrayBuffer()
56
+ })
57
+ .then(data => {
58
+ setSource(this, Buffer.from(data))
59
+ })
60
+ .catch(onerror)
61
+ } else { // local file path assumed
62
+ setSource(this, val)
63
+ }
64
+ } else if (Buffer.isBuffer(val)) {
65
+ setSource(this, val)
66
+ } else {
67
+ const err = new Error("Invalid image source")
68
+ if (typeof this.onerror === 'function') this.onerror(err)
69
+ else throw err
70
+ }
71
+ },
72
+
73
+ get () {
74
+ // TODO https://github.com/Automattic/node-canvas/issues/118
75
+ return getSource(this)
76
+ },
77
+
78
+ configurable: true
79
+ })
80
+
81
+ // TODO || is for Node.js pre-v6.6.0
82
+ Image.prototype[util.inspect.custom || 'inspect'] = function () {
83
+ return '[Image' +
84
+ (this.complete ? ':' + this.width + 'x' + this.height : '') +
85
+ (this.src ? ' ' + this.src : '') +
86
+ (this.complete ? ' complete' : '') +
87
+ ']'
88
+ }
89
+
90
+ function getSource (img) {
91
+ return img._originalSource || GetSource.call(img)
92
+ }
93
+
94
+ function setSource (img, src, origSrc) {
95
+ SetSource.call(img, src)
96
+ img._originalSource = origSrc
97
+ }
@@ -0,0 +1,41 @@
1
+ 'use strict'
2
+
3
+ /*!
4
+ * Canvas - JPEGStream
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+ const { Readable } = require('stream')
10
+ function noop () {}
11
+
12
+ class JPEGStream extends Readable {
13
+ constructor (canvas, options) {
14
+ super()
15
+
16
+ if (canvas.streamJPEGSync === undefined) {
17
+ throw new Error('node-canvas was built without JPEG support.')
18
+ }
19
+
20
+ this.options = options
21
+ this.canvas = canvas
22
+ }
23
+
24
+ _read () {
25
+ // For now we're not controlling the c++ code's data emission, so we only
26
+ // call canvas.streamJPEGSync once and let it emit data at will.
27
+ this._read = noop
28
+
29
+ this.canvas.streamJPEGSync(this.options, (err, chunk) => {
30
+ if (err) {
31
+ this.emit('error', err)
32
+ } else if (chunk) {
33
+ this.push(chunk)
34
+ } else {
35
+ this.push(null)
36
+ }
37
+ })
38
+ }
39
+ };
40
+
41
+ module.exports = JPEGStream
package/lib/pattern.js ADDED
@@ -0,0 +1,15 @@
1
+ 'use strict'
2
+
3
+ /*!
4
+ * Canvas - CanvasPattern
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+ const bindings = require('./bindings')
10
+
11
+ module.exports = bindings.CanvasPattern
12
+
13
+ bindings.CanvasPattern.prototype.toString = function () {
14
+ return '[object CanvasPattern]'
15
+ }
@@ -0,0 +1,35 @@
1
+ 'use strict'
2
+
3
+ /*!
4
+ * Canvas - PDFStream
5
+ */
6
+
7
+ const { Readable } = require('stream')
8
+ function noop () {}
9
+
10
+ class PDFStream extends Readable {
11
+ constructor (canvas, options) {
12
+ super()
13
+
14
+ this.canvas = canvas
15
+ this.options = options
16
+ }
17
+
18
+ _read () {
19
+ // For now we're not controlling the c++ code's data emission, so we only
20
+ // call canvas.streamPDFSync once and let it emit data at will.
21
+ this._read = noop
22
+
23
+ this.canvas.streamPDFSync((err, chunk, len) => {
24
+ if (err) {
25
+ this.emit('error', err)
26
+ } else if (len) {
27
+ this.push(chunk)
28
+ } else {
29
+ this.push(null)
30
+ }
31
+ }, this.options)
32
+ }
33
+ }
34
+
35
+ module.exports = PDFStream
@@ -0,0 +1,42 @@
1
+ 'use strict'
2
+
3
+ /*!
4
+ * Canvas - PNGStream
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+ const { Readable } = require('stream')
10
+ function noop () {}
11
+
12
+ class PNGStream extends Readable {
13
+ constructor (canvas, options) {
14
+ super()
15
+
16
+ if (options &&
17
+ options.palette instanceof Uint8ClampedArray &&
18
+ options.palette.length % 4 !== 0) {
19
+ throw new Error('Palette length must be a multiple of 4.')
20
+ }
21
+ this.canvas = canvas
22
+ this.options = options || {}
23
+ }
24
+
25
+ _read () {
26
+ // For now we're not controlling the c++ code's data emission, so we only
27
+ // call canvas.streamPNGSync once and let it emit data at will.
28
+ this._read = noop
29
+
30
+ this.canvas.streamPNGSync((err, chunk, len) => {
31
+ if (err) {
32
+ this.emit('error', err)
33
+ } else if (len) {
34
+ this.push(chunk)
35
+ } else {
36
+ this.push(null)
37
+ }
38
+ }, this.options)
39
+ }
40
+ }
41
+
42
+ module.exports = PNGStream
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@shqld/canvas",
3
+ "description": "Canvas graphics API backed by Cairo",
4
+ "version": "3.2.2-rc.1",
5
+ "author": "TJ Holowaychuk <tj@learnboost.com>",
6
+ "main": "index.js",
7
+ "browser": "browser.js",
8
+ "types": "index.d.ts",
9
+ "contributors": [
10
+ "Nathan Rajlich <nathan@tootallnate.net>",
11
+ "Rod Vagg <r@va.gg>",
12
+ "Juriy Zaytsev <kangax@gmail.com>"
13
+ ],
14
+ "keywords": [
15
+ "canvas",
16
+ "graphic",
17
+ "graphics",
18
+ "pixman",
19
+ "cairo",
20
+ "image",
21
+ "images",
22
+ "pdf"
23
+ ],
24
+ "homepage": "https://github.com/Automattic/node-canvas",
25
+ "repository": "git://github.com/Automattic/node-canvas.git",
26
+ "scripts": {
27
+ "prebenchmark": "node-gyp build",
28
+ "benchmark": "node benchmarks/run.js",
29
+ "lint": "standard examples/*.js test/server.js test/public/*.js benchmarks/run.js lib/context2d.js util/has_lib.js browser.js index.js",
30
+ "test": "mocha test/*.test.js",
31
+ "pretest-server": "node-gyp build",
32
+ "test-server": "node test/server.js",
33
+ "generate-wpt": "node ./test/wpt/generate.js",
34
+ "test-wpt": "mocha test/wpt/generated/*.js",
35
+ "install": "node scripts/install.js",
36
+ "tsd": "tsd"
37
+ },
38
+ "files": [
39
+ "binding.gyp",
40
+ "browser.js",
41
+ "index.d.ts",
42
+ "index.js",
43
+ "lib/",
44
+ "scripts/",
45
+ "src/",
46
+ "util/"
47
+ ],
48
+ "dependencies": {},
49
+ "optionalDependencies": {
50
+ "@shqld/canvas-darwin-arm64": "3.2.2-rc.1",
51
+ "@shqld/canvas-darwin-x64": "3.2.2-rc.1",
52
+ "@shqld/canvas-linux-arm64-gnu": "3.2.2-rc.1",
53
+ "@shqld/canvas-linux-x64-gnu": "3.2.2-rc.1",
54
+ "@shqld/canvas-win32-x64": "3.2.2-rc.1"
55
+ },
56
+ "devDependencies": {
57
+ "node-addon-api": "^7.0.0",
58
+ "@types/node": "^10.12.18",
59
+ "assert-rejects": "^1.0.0",
60
+ "express": "^4.16.3",
61
+ "js-yaml": "^4.1.0",
62
+ "mocha": "^5.2.0",
63
+ "pixelmatch": "^4.0.2",
64
+ "standard": "^12.0.1",
65
+ "tsd": "^0.29.0",
66
+ "typescript": "^4.2.2"
67
+ },
68
+ "engines": {
69
+ "node": "^18.12.0 || >= 20.9.0"
70
+ },
71
+ "binary": {
72
+ "napi_versions": [
73
+ 7
74
+ ]
75
+ },
76
+ "license": "MIT"
77
+ }
@@ -0,0 +1,19 @@
1
+ 'use strict'
2
+
3
+ // If a prebuilt binary is available, skip node-gyp entirely.
4
+ // Otherwise, fall back to building from source.
5
+
6
+ try {
7
+ require('../lib/bindings')
8
+ process.exit(0)
9
+ } catch (_) {
10
+ const { execSync } = require('child_process')
11
+ try {
12
+ execSync('node-gyp rebuild', { stdio: 'inherit', cwd: require('path').resolve(__dirname, '..') })
13
+ } catch (e) {
14
+ console.error('Failed to build canvas from source.')
15
+ console.error('Please install the required system dependencies:')
16
+ console.error(' https://github.com/Automattic/node-canvas#compiling')
17
+ process.exit(1)
18
+ }
19
+ }
package/src/Backends.h ADDED
@@ -0,0 +1,9 @@
1
+ #pragma once
2
+
3
+ #include "backend/Backend.h"
4
+ #include <napi.h>
5
+
6
+ class Backends : public Napi::ObjectWrap<Backends> {
7
+ public:
8
+ static void Initialize(Napi::Env env, Napi::Object exports);
9
+ };