@napi-rs/canvas 1.0.10 → 1.0.12

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.
package/load-image.js CHANGED
@@ -7,6 +7,9 @@ const { Image } = require('./js-binding')
7
7
  let http, https
8
8
 
9
9
  const MAX_REDIRECTS = 20
10
+ // Image fires onerror with an Event, as browsers do; the Error behind it is
11
+ // under this key.
12
+ const IMAGE_ERROR = Symbol.for('@napi-rs/canvas/image-error')
10
13
  const REDIRECT_STATUSES = new Set([301, 302])
11
14
 
12
15
  /**
@@ -26,17 +29,12 @@ module.exports = async function loadImage(source, options = {}) {
26
29
  if (isBufferLike(source)) return createImage(Buffer.from(source), options.alt)
27
30
  // if the source is Image instance, copy the image src to new image
28
31
  if (source instanceof Image) return createImage(source.src, options.alt)
29
- // if source is string and in data uri format, construct image using data uri
30
- if (typeof source === 'string' && source.trimStart().startsWith('data:')) {
31
- const commaIdx = source.indexOf(',')
32
- const encoding = source.lastIndexOf('base64', commaIdx) < 0 ? 'utf-8' : 'base64'
33
- const data = Buffer.from(source.slice(commaIdx + 1), encoding)
34
- // Empty payload would silently complete on Image (HTML spec) and the loadImage
35
- // promise would never settle; reject upfront instead.
36
- // See https://github.com/Brooooooklyn/canvas/issues/1255
37
- if (data.length === 0) throw new Error(`Invalid data URI: empty payload in ${source.slice(0, 64)}`)
38
- return createImage(data, options.alt)
39
- }
32
+ // A data: URL (the URL parser drops leading C0 controls and spaces) is
33
+ // the image's src, as in a browser: Image parses it with the Fetch data:
34
+ // URL processor. A URL object with the data: scheme too.
35
+ // An empty body fires onerror, so the promise settles (issue #1255).
36
+ if (typeof source === 'string' && isDataUrl(source)) return createImage(source, options.alt)
37
+ if (source instanceof URL && source.protocol === 'data:') return createImage(source.href, options.alt)
40
38
  // if source is a string or URL instance
41
39
  if (typeof source === 'string') {
42
40
  // if the source exists as a file, construct image from that file
@@ -141,11 +139,19 @@ async function createImage(src, alt) {
141
139
  .then(() => image.decode())
142
140
  .then(() => resolve(image), reject)
143
141
  }
144
- image.onerror = (e) => reject(e)
142
+ image.onerror = (event) => reject((event && event[IMAGE_ERROR]) || event)
145
143
  image.src = src
146
144
  })
147
145
  }
148
146
 
147
+ // The URL parser skips leading C0 controls and spaces; the scheme is
148
+ // ASCII case-insensitive.
149
+ function isDataUrl(src) {
150
+ let i = 0
151
+ while (i < src.length && src.charCodeAt(i) <= 0x20) i++
152
+ return src.slice(i, i + 5).toLowerCase() === 'data:'
153
+ }
154
+
149
155
  function isBufferLike(src) {
150
156
  return (src && src.type === 'Buffer') || Array.isArray(src)
151
157
  }
package/node-canvas.d.ts CHANGED
@@ -45,7 +45,12 @@ export interface PngConfig {
45
45
  palette?: Uint8ClampedArray
46
46
  /** Background color index for indexed PNGs. Not supported by Skia backend. */
47
47
  backgroundIndex?: number
48
- /** Pixels per inch. Accepted for compatibility. */
48
+ /**
49
+ * Pixels per inch, written as a PNG `pHYs` chunk with the bytes node-canvas
50
+ * writes, up to 54546055 ppi; a larger value writes 2147483647 px/m, the
51
+ * PNG maximum. The fraction is dropped. 0, a value below 1, NaN, the
52
+ * infinities and a non-number write none.
53
+ */
49
54
  resolution?: number
50
55
  }
51
56
 
package/node-canvas.js CHANGED
@@ -42,7 +42,7 @@ class PNGStream extends Readable {
42
42
  if (this._done) return
43
43
  this._done = true
44
44
  this._canvas
45
- .encode('png')
45
+ .encode('png', _pngOptions(this._options))
46
46
  .then((buf) => {
47
47
  this.push(buf)
48
48
  this.push(null)
@@ -109,6 +109,20 @@ function _extractQuality(mime, configOrQuality) {
109
109
  return NODE_CANVAS_DEFAULT_QUALITY
110
110
  }
111
111
 
112
+ /**
113
+ * The native PNG options for a node-canvas PngConfig: only `resolution`, the
114
+ * one member node-canvas writes (a pHYs chunk); undefined without a numeric
115
+ * one, so the native call stays a plain PNG encode.
116
+ *
117
+ * @param {object|undefined} config
118
+ * @returns {{ resolution: number }|undefined}
119
+ */
120
+ function _pngOptions(config) {
121
+ if (config === null || typeof config !== 'object') return undefined
122
+ const resolution = config.resolution
123
+ return typeof resolution === 'number' ? { resolution: resolution } : undefined
124
+ }
125
+
112
126
  // ---------------------------------------------------------------------------
113
127
  // Compat methods added to each canvas instance created via this module
114
128
  // ---------------------------------------------------------------------------
@@ -159,7 +173,8 @@ function _compatToBuffer(mimeOrCallback, configOrQuality) {
159
173
  return
160
174
  }
161
175
  const q = _extractQuality(mime, config)
162
- this.encode(format, q != null ? Math.round(q * 100) : undefined).then(
176
+ const options = format === 'png' ? _pngOptions(config) : q != null ? Math.round(q * 100) : undefined
177
+ this.encode(format, options).then(
163
178
  (buf) => callback(null, buf),
164
179
  (err) => callback(err),
165
180
  )
@@ -176,7 +191,11 @@ function _compatToBuffer(mimeOrCallback, configOrQuality) {
176
191
  return this.data()
177
192
  }
178
193
 
179
- // Sync: extract quality (0-1) and scale to 0-100 for native toBuffer
194
+ // Sync: PNG takes the resolution; JPEG / WebP a quality (0-1) scaled to
195
+ // 0-100 for native toBuffer
196
+ if (mimeOrCallback === 'image/png') {
197
+ return _origToBuffer.call(this, mimeOrCallback, _pngOptions(configOrQuality))
198
+ }
180
199
  const q = _extractQuality(mimeOrCallback, configOrQuality)
181
200
  return _origToBuffer.call(this, mimeOrCallback, q != null ? Math.round(q * 100) : undefined)
182
201
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@napi-rs/canvas",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Canvas for Node.js with skia backend",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -58,7 +58,6 @@
58
58
  },
59
59
  "scripts": {
60
60
  "artifacts": "napi artifacts",
61
- "bench": "node --import @oxc-node/core/register benchmark/bench.ts",
62
61
  "build": "napi build --platform --release --js js-binding.js",
63
62
  "build:debug": "napi build --platform --js js-binding.js",
64
63
  "example-lottie": "yarn oxnode ./example/lottie-to-video.ts",
@@ -103,14 +102,14 @@
103
102
  "npm-run-all2": "^9.0.0",
104
103
  "oxlint": "^1.34.0",
105
104
  "oxlint-tsgolint": "^7.0.0",
105
+ "pdfjs-dist": "6.4.299",
106
106
  "pinst": "^3.0.0",
107
107
  "png.js": "^0.2.1",
108
108
  "prettier": "^3.7.4",
109
109
  "pretty-bytes": "^7.1.0",
110
110
  "semver": "^7.7.3",
111
- "skia-canvas": "^3.0.8",
111
+ "smol-toml": "^1.9.0",
112
112
  "table": "^6.9.0",
113
- "tinybench": "^6.0.0",
114
113
  "typescript": "^7.0.0"
115
114
  },
116
115
  "lint-staged": {
@@ -156,25 +155,22 @@
156
155
  "dependenciesMeta": {
157
156
  "canvas": {
158
157
  "built": true
159
- },
160
- "skia-canvas": {
161
- "built": true
162
158
  }
163
159
  },
164
160
  "resolutions": {
165
161
  "@napi-rs/canvas": "workspace:"
166
162
  },
167
163
  "optionalDependencies": {
168
- "@napi-rs/canvas-linux-x64-gnu": "1.0.10",
169
- "@napi-rs/canvas-darwin-x64": "1.0.10",
170
- "@napi-rs/canvas-win32-x64-msvc": "1.0.10",
171
- "@napi-rs/canvas-win32-arm64-msvc": "1.0.10",
172
- "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.10",
173
- "@napi-rs/canvas-linux-x64-musl": "1.0.10",
174
- "@napi-rs/canvas-linux-arm64-gnu": "1.0.10",
175
- "@napi-rs/canvas-linux-arm64-musl": "1.0.10",
176
- "@napi-rs/canvas-darwin-arm64": "1.0.10",
177
- "@napi-rs/canvas-android-arm64": "1.0.10",
178
- "@napi-rs/canvas-linux-riscv64-gnu": "1.0.10"
164
+ "@napi-rs/canvas-linux-x64-gnu": "1.0.12",
165
+ "@napi-rs/canvas-darwin-x64": "1.0.12",
166
+ "@napi-rs/canvas-win32-x64-msvc": "1.0.12",
167
+ "@napi-rs/canvas-win32-arm64-msvc": "1.0.12",
168
+ "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.12",
169
+ "@napi-rs/canvas-linux-x64-musl": "1.0.12",
170
+ "@napi-rs/canvas-linux-arm64-gnu": "1.0.12",
171
+ "@napi-rs/canvas-linux-arm64-musl": "1.0.12",
172
+ "@napi-rs/canvas-darwin-arm64": "1.0.12",
173
+ "@napi-rs/canvas-android-arm64": "1.0.12",
174
+ "@napi-rs/canvas-linux-riscv64-gnu": "1.0.12"
179
175
  }
180
176
  }