@napi-rs/canvas 0.1.28 → 0.1.30
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/README.md +8 -4
- package/index.d.ts +49 -2
- package/index.js +2 -122
- package/js-binding.js +65 -38
- package/load-image.js +19 -10
- package/package.json +28 -28
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# `skr canvas`
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|
[](https://packagephobia.com/result?p=@napi-rs/canvas)
|
|
6
6
|
[](https://npmcharts.com/compare/@napi-rs/canvas?minimal=true)
|
|
7
7
|
|
|
@@ -41,12 +41,16 @@ npm install @napi-rs/canvas
|
|
|
41
41
|
|
|
42
42
|
[**_cortex-a57_**](https://en.wikipedia.org/wiki/ARM_Cortex-A57) or newer CPU architecture on **Linux**.
|
|
43
43
|
|
|
44
|
-
All
|
|
44
|
+
All Apple M chips on **macOS**.
|
|
45
45
|
|
|
46
46
|
### `armv7`
|
|
47
47
|
|
|
48
48
|
[**_cortex-a7_**](https://en.wikipedia.org/wiki/ARM_Cortex-A7) or newer CPU architecture.
|
|
49
49
|
|
|
50
|
+
### glibc
|
|
51
|
+
|
|
52
|
+
Since Skia relies on the [glibc](https://www.gnu.org/software/libc/) 2.18 API, you need to have at least glibc version >= 2.18 on your system.
|
|
53
|
+
|
|
50
54
|
# Usage
|
|
51
55
|
|
|
52
56
|
```js
|
|
@@ -92,7 +96,7 @@ main()
|
|
|
92
96
|
const { writeFileSync } = require('fs')
|
|
93
97
|
const { join } = require('path')
|
|
94
98
|
|
|
95
|
-
const { createCanvas, GlobalFonts } = require('
|
|
99
|
+
const { createCanvas, GlobalFonts } = require('@napi-rs/canvas')
|
|
96
100
|
|
|
97
101
|
GlobalFonts.registerFromPath(join(__dirname, '..', 'fonts', 'AppleColorEmoji@2x.ttf'), 'Apple Emoji')
|
|
98
102
|
GlobalFonts.registerFromPath(join(__dirname, '..', '__test__', 'fonts', 'COLRv1.ttf'), 'COLRv1')
|
|
@@ -324,7 +328,7 @@ $ node scripts/build-skia.js
|
|
|
324
328
|
|
|
325
329
|
# Install NPM packages, build the Node.js addon:
|
|
326
330
|
$ npm install -g yarn
|
|
327
|
-
$ yarn install --mode=skip
|
|
331
|
+
$ yarn install --mode=skip-build # Here are modules that are used for benchmarking and are hard to install, you can skip it by specifying `--mode=skip-build`
|
|
328
332
|
$ sudo dnf install clang # https://fedora.pkgs.org/34/fedora-x86_64/clang-12.0.0-0.3.rc1.fc34.x86_64.rpm.html
|
|
329
333
|
$ yarn build
|
|
330
334
|
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/// <reference lib="dom" />
|
|
2
|
-
|
|
3
1
|
// Clear all type of caches in Skia
|
|
4
2
|
export function clearAllCache(): void
|
|
5
3
|
|
|
@@ -302,9 +300,58 @@ export interface SvgCanvas {
|
|
|
302
300
|
}
|
|
303
301
|
|
|
304
302
|
export interface AvifConfig {
|
|
303
|
+
/** 0-100 scale, 100 is lossless */
|
|
305
304
|
quality?: number
|
|
305
|
+
/** 0-100 scale */
|
|
306
|
+
alphaQuality?: number
|
|
307
|
+
/** rav1e preset 1 (slow) 10 (fast but crappy), default is 4 */
|
|
306
308
|
speed?: number
|
|
309
|
+
/** How many threads should be used (0 = match core count) */
|
|
307
310
|
threads?: number
|
|
311
|
+
/** set to '4:2:0' to use chroma subsampling, default '4:4:4' */
|
|
312
|
+
chromaSubsampling?: ChromaSubsampling
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* https://en.wikipedia.org/wiki/Chroma_subsampling#Types_of_sampling_and_subsampling
|
|
316
|
+
* https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_concepts
|
|
317
|
+
*/
|
|
318
|
+
export enum ChromaSubsampling {
|
|
319
|
+
/**
|
|
320
|
+
* Each of the three Y'CbCr components has the same sample rate, thus there is no chroma subsampling. This scheme is sometimes used in high-end film scanners and cinematic post-production.
|
|
321
|
+
* Note that "4:4:4" may instead be wrongly referring to R'G'B' color space, which implicitly also does not have any chroma subsampling (except in JPEG R'G'B' can be subsampled).
|
|
322
|
+
* Formats such as HDCAM SR can record 4:4:4 R'G'B' over dual-link HD-SDI.
|
|
323
|
+
*/
|
|
324
|
+
Yuv444 = 0,
|
|
325
|
+
/**
|
|
326
|
+
* The two chroma components are sampled at half the horizontal sample rate of luma: the horizontal chroma resolution is halved. This reduces the bandwidth of an uncompressed video signal by one-third.
|
|
327
|
+
* Many high-end digital video formats and interfaces use this scheme:
|
|
328
|
+
* - [AVC-Intra 100](https://en.wikipedia.org/wiki/AVC-Intra)
|
|
329
|
+
* - [Digital Betacam](https://en.wikipedia.org/wiki/Betacam#Digital_Betacam)
|
|
330
|
+
* - [Betacam SX](https://en.wikipedia.org/wiki/Betacam#Betacam_SX)
|
|
331
|
+
* - [DVCPRO50](https://en.wikipedia.org/wiki/DV#DVCPRO) and [DVCPRO HD](https://en.wikipedia.org/wiki/DV#DVCPRO_HD)
|
|
332
|
+
* - [Digital-S](https://en.wikipedia.org/wiki/Digital-S)
|
|
333
|
+
* - [CCIR 601](https://en.wikipedia.org/wiki/Rec._601) / [Serial Digital Interface](https://en.wikipedia.org/wiki/Serial_digital_interface) / [D1](https://en.wikipedia.org/wiki/D-1_(Sony))
|
|
334
|
+
* - [ProRes (HQ, 422, LT, and Proxy)](https://en.wikipedia.org/wiki/Apple_ProRes)
|
|
335
|
+
* - [XDCAM HD422](https://en.wikipedia.org/wiki/XDCAM)
|
|
336
|
+
* - [Canon MXF HD422](https://en.wikipedia.org/wiki/Canon_XF-300)
|
|
337
|
+
*/
|
|
338
|
+
Yuv422 = 1,
|
|
339
|
+
/**
|
|
340
|
+
* n 4:2:0, the horizontal sampling is doubled compared to 4:1:1,
|
|
341
|
+
* but as the **Cb** and **Cr** channels are only sampled on each alternate line in this scheme, the vertical resolution is halved.
|
|
342
|
+
* The data rate is thus the same.
|
|
343
|
+
* This fits reasonably well with the PAL color encoding system, since this has only half the vertical chrominance resolution of [NTSC](https://en.wikipedia.org/wiki/NTSC).
|
|
344
|
+
* It would also fit extremely well with the [SECAM](https://en.wikipedia.org/wiki/SECAM) color encoding system,
|
|
345
|
+
* since like that format, 4:2:0 only stores and transmits one color channel per line (the other channel being recovered from the previous line).
|
|
346
|
+
* However, little equipment has actually been produced that outputs a SECAM analogue video signal.
|
|
347
|
+
* In general, SECAM territories either have to use a PAL-capable display or a [transcoder](https://en.wikipedia.org/wiki/Transcoding) to convert the PAL signal to SECAM for display.
|
|
348
|
+
*/
|
|
349
|
+
Yuv420 = 2,
|
|
350
|
+
/**
|
|
351
|
+
* What if the chroma subsampling model is 4:0:0?
|
|
352
|
+
* That says to use every pixel of luma data, but that each row has 0 chroma samples applied to it. The resulting image, then, is comprised solely of the luminance data—a greyscale image.
|
|
353
|
+
*/
|
|
354
|
+
Yuv400 = 3,
|
|
308
355
|
}
|
|
309
356
|
|
|
310
357
|
export class Canvas {
|
package/index.js
CHANGED
|
@@ -5,9 +5,8 @@ const {
|
|
|
5
5
|
clearAllCache,
|
|
6
6
|
CanvasRenderingContext2D,
|
|
7
7
|
CanvasElement,
|
|
8
|
-
createContext,
|
|
9
8
|
SVGCanvas,
|
|
10
|
-
Path2D,
|
|
9
|
+
Path: Path2D,
|
|
11
10
|
ImageData,
|
|
12
11
|
Image,
|
|
13
12
|
CanvasPattern,
|
|
@@ -47,128 +46,9 @@ Object.defineProperty(GlobalFonts, 'has', {
|
|
|
47
46
|
writable: false,
|
|
48
47
|
})
|
|
49
48
|
|
|
50
|
-
CanvasRenderingContext2D.prototype.createPattern = function createPattern(image, repetition) {
|
|
51
|
-
if (image instanceof ImageData) {
|
|
52
|
-
const pattern = new CanvasPattern(image, repetition, 0)
|
|
53
|
-
Object.defineProperty(pattern, '_imageData', {
|
|
54
|
-
writable: true,
|
|
55
|
-
configurable: false,
|
|
56
|
-
enumerable: false,
|
|
57
|
-
value: null,
|
|
58
|
-
})
|
|
59
|
-
return pattern
|
|
60
|
-
} else if (image instanceof Image) {
|
|
61
|
-
return new CanvasPattern(image, repetition, 1)
|
|
62
|
-
} else if (image instanceof CanvasElement || image instanceof SVGCanvas) {
|
|
63
|
-
return new CanvasPattern(image, repetition, 2)
|
|
64
|
-
}
|
|
65
|
-
throw TypeError('Image should be instance of ImageData or Image')
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
CanvasRenderingContext2D.prototype.getImageData = function getImageData(x, y, w, h) {
|
|
69
|
-
const data = this._getImageData(x, y, w, h)
|
|
70
|
-
return new ImageData(data, w, h)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
49
|
function createCanvas(width, height, flag) {
|
|
74
50
|
const isSvgBackend = typeof flag !== 'undefined'
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
let ctx
|
|
78
|
-
canvasElement.getContext = function getContext(type, attr = {}) {
|
|
79
|
-
if (type !== '2d') {
|
|
80
|
-
throw new Error('Unsupported type')
|
|
81
|
-
}
|
|
82
|
-
const attrs = { alpha: true, colorSpace: 'srgb', ...attr }
|
|
83
|
-
ctx = ctx
|
|
84
|
-
? ctx
|
|
85
|
-
: isSvgBackend
|
|
86
|
-
? new CanvasRenderingContext2D(this.width, this.height, attrs.colorSpace, flag)
|
|
87
|
-
: new CanvasRenderingContext2D(this.width, this.height, attrs.colorSpace)
|
|
88
|
-
createContext(ctx, this.width, this.height, attrs)
|
|
89
|
-
|
|
90
|
-
// napi can not define writable: true but enumerable: false property
|
|
91
|
-
Object.defineProperty(ctx, '_fillStyle', {
|
|
92
|
-
value: '#000',
|
|
93
|
-
configurable: false,
|
|
94
|
-
enumerable: false,
|
|
95
|
-
writable: true,
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
Object.defineProperty(ctx, '_strokeStyle', {
|
|
99
|
-
value: '#000',
|
|
100
|
-
configurable: false,
|
|
101
|
-
enumerable: false,
|
|
102
|
-
writable: true,
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
Object.defineProperty(ctx, 'createImageData', {
|
|
106
|
-
value: function createImageData(widthOrImage, height, attrs = {}) {
|
|
107
|
-
if (widthOrImage instanceof ImageData) {
|
|
108
|
-
return new ImageData(widthOrImage.data, widthOrImage.width, widthOrImage.height)
|
|
109
|
-
}
|
|
110
|
-
return new ImageData(widthOrImage, height, { colorSpace: 'srgb', ...attrs })
|
|
111
|
-
},
|
|
112
|
-
configurable: true,
|
|
113
|
-
enumerable: false,
|
|
114
|
-
writable: true,
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
Object.defineProperty(canvasElement, 'ctx', {
|
|
118
|
-
value: ctx,
|
|
119
|
-
enumerable: false,
|
|
120
|
-
configurable: false,
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
ctx.canvas = canvasElement
|
|
124
|
-
|
|
125
|
-
return ctx
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const {
|
|
129
|
-
encode: canvasEncode,
|
|
130
|
-
encodeSync: canvasEncodeSync,
|
|
131
|
-
toBuffer: canvasToBuffer,
|
|
132
|
-
toDataURL: canvasToDataURL,
|
|
133
|
-
toDataURLAsync: canvasToDataURLAsync,
|
|
134
|
-
} = Object.getPrototypeOf(canvasElement)
|
|
135
|
-
|
|
136
|
-
canvasElement.encode = function encode(type, qualityOrConfig = {}) {
|
|
137
|
-
if (type === 'avif') {
|
|
138
|
-
return canvasEncode.call(this, type, JSON.stringify(qualityOrConfig))
|
|
139
|
-
}
|
|
140
|
-
return canvasEncode.call(this, type, qualityOrConfig)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
canvasElement.encodeSync = function encodeSync(type, qualityOrConfig = {}) {
|
|
144
|
-
if (type === 'avif') {
|
|
145
|
-
return canvasEncodeSync.call(this, type, JSON.stringify(qualityOrConfig))
|
|
146
|
-
}
|
|
147
|
-
return canvasEncodeSync.call(this, type, qualityOrConfig)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
canvasElement.toBuffer = function toBuffer(type = 'image/png', qualityOrConfig = {}) {
|
|
151
|
-
if (type === 'avif') {
|
|
152
|
-
return canvasToBuffer.call(this, type, JSON.stringify(qualityOrConfig))
|
|
153
|
-
}
|
|
154
|
-
return canvasToBuffer.call(this, type, qualityOrConfig)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
canvasElement.toDataURL = function toDataURL(type = 'image/png', qualityOrConfig = {}) {
|
|
158
|
-
if (type === 'avif') {
|
|
159
|
-
return canvasToDataURL.call(this, type, JSON.stringify(qualityOrConfig))
|
|
160
|
-
}
|
|
161
|
-
return canvasToDataURL.call(this, type, qualityOrConfig)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
canvasElement.toDataURLAsync = function toDataURLAsync(type = 'image/png', qualityOrConfig = {}) {
|
|
165
|
-
if (type === 'avif') {
|
|
166
|
-
return canvasToDataURLAsync.call(this, type, JSON.stringify(qualityOrConfig))
|
|
167
|
-
}
|
|
168
|
-
return canvasToDataURLAsync.call(this, type, qualityOrConfig)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return canvasElement
|
|
51
|
+
return isSvgBackend ? new SVGCanvas(width, height, flag) : new CanvasElement(width, height)
|
|
172
52
|
}
|
|
173
53
|
|
|
174
54
|
class Canvas {
|
package/js-binding.js
CHANGED
|
@@ -5,27 +5,54 @@ const { platform, arch } = process
|
|
|
5
5
|
|
|
6
6
|
let nativeBinding = null
|
|
7
7
|
let localFileExisted = false
|
|
8
|
-
let isMusl = false
|
|
9
8
|
let loadError = null
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
15
|
-
}
|
|
16
|
-
localFileExisted = existsSync(join(__dirname, 'skia.android-arm64.node'))
|
|
10
|
+
function isMusl() {
|
|
11
|
+
// For Node 10
|
|
12
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
17
13
|
try {
|
|
18
|
-
|
|
19
|
-
nativeBinding = require('./skia.android-arm64.node')
|
|
20
|
-
} else {
|
|
21
|
-
nativeBinding = require('@napi-rs/canvas-android-arm64')
|
|
22
|
-
}
|
|
14
|
+
return readFileSync('/usr/bin/ldd', 'utf8').includes('musl')
|
|
23
15
|
} catch (e) {
|
|
24
|
-
|
|
16
|
+
return true
|
|
17
|
+
}
|
|
18
|
+
} else {
|
|
19
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
20
|
+
return !glibcVersionRuntime
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
switch (platform) {
|
|
25
|
+
case 'android':
|
|
26
|
+
switch (arch) {
|
|
27
|
+
case 'arm64':
|
|
28
|
+
localFileExisted = existsSync(join(__dirname, 'skia.android-arm64.node'))
|
|
29
|
+
try {
|
|
30
|
+
if (localFileExisted) {
|
|
31
|
+
nativeBinding = require('./skia.android-arm64.node')
|
|
32
|
+
} else {
|
|
33
|
+
nativeBinding = require('@napi-rs/canvas-android-arm64')
|
|
34
|
+
}
|
|
35
|
+
} catch (e) {
|
|
36
|
+
loadError = e
|
|
37
|
+
}
|
|
38
|
+
break
|
|
39
|
+
case 'arm':
|
|
40
|
+
localFileExisted = existsSync(join(__dirname, 'skia.android-arm-eabi.node'))
|
|
41
|
+
try {
|
|
42
|
+
if (localFileExisted) {
|
|
43
|
+
nativeBinding = require('./skia.android-arm-eabi.node')
|
|
44
|
+
} else {
|
|
45
|
+
nativeBinding = require('@napi-rs/canvas-android-arm-eabi')
|
|
46
|
+
}
|
|
47
|
+
} catch (e) {
|
|
48
|
+
loadError = e
|
|
49
|
+
}
|
|
50
|
+
break
|
|
51
|
+
default:
|
|
52
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
25
53
|
}
|
|
26
54
|
break
|
|
27
55
|
case 'win32':
|
|
28
|
-
// eslint-disable-next-line sonarjs/no-nested-switch
|
|
29
56
|
switch (arch) {
|
|
30
57
|
case 'x64':
|
|
31
58
|
localFileExisted = existsSync(join(__dirname, 'skia.win32-x64-msvc.node'))
|
|
@@ -68,7 +95,6 @@ switch (platform) {
|
|
|
68
95
|
}
|
|
69
96
|
break
|
|
70
97
|
case 'darwin':
|
|
71
|
-
// eslint-disable-next-line sonarjs/no-nested-switch
|
|
72
98
|
switch (arch) {
|
|
73
99
|
case 'x64':
|
|
74
100
|
localFileExisted = existsSync(join(__dirname, 'skia.darwin-x64.node'))
|
|
@@ -114,11 +140,9 @@ switch (platform) {
|
|
|
114
140
|
}
|
|
115
141
|
break
|
|
116
142
|
case 'linux':
|
|
117
|
-
// eslint-disable-next-line sonarjs/no-nested-switch
|
|
118
143
|
switch (arch) {
|
|
119
144
|
case 'x64':
|
|
120
|
-
|
|
121
|
-
if (isMusl) {
|
|
145
|
+
if (isMusl()) {
|
|
122
146
|
localFileExisted = existsSync(join(__dirname, 'skia.linux-x64-musl.node'))
|
|
123
147
|
try {
|
|
124
148
|
if (localFileExisted) {
|
|
@@ -143,8 +167,7 @@ switch (platform) {
|
|
|
143
167
|
}
|
|
144
168
|
break
|
|
145
169
|
case 'arm64':
|
|
146
|
-
|
|
147
|
-
if (isMusl) {
|
|
170
|
+
if (isMusl()) {
|
|
148
171
|
localFileExisted = existsSync(join(__dirname, 'skia.linux-arm64-musl.node'))
|
|
149
172
|
try {
|
|
150
173
|
if (localFileExisted) {
|
|
@@ -196,35 +219,39 @@ if (!nativeBinding) {
|
|
|
196
219
|
}
|
|
197
220
|
|
|
198
221
|
const {
|
|
199
|
-
|
|
222
|
+
ChromaSubsampling,
|
|
223
|
+
SvgExportFlag,
|
|
200
224
|
CanvasRenderingContext2D,
|
|
201
|
-
|
|
202
|
-
createContext,
|
|
203
|
-
SVGCanvas,
|
|
204
|
-
Path,
|
|
225
|
+
CanvasGradient,
|
|
205
226
|
ImageData,
|
|
206
227
|
Image,
|
|
207
|
-
CanvasPattern,
|
|
208
|
-
GlobalFonts,
|
|
209
|
-
convertSVGTextToPath,
|
|
210
228
|
PathOp,
|
|
211
229
|
FillType,
|
|
212
|
-
StrokeJoin,
|
|
213
230
|
StrokeCap,
|
|
231
|
+
StrokeJoin,
|
|
232
|
+
Path,
|
|
233
|
+
CanvasPattern,
|
|
234
|
+
convertSVGTextToPath,
|
|
235
|
+
CanvasElement,
|
|
236
|
+
SVGCanvas,
|
|
237
|
+
clearAllCache,
|
|
238
|
+
GlobalFonts,
|
|
214
239
|
} = nativeBinding
|
|
215
240
|
|
|
216
|
-
module.exports.
|
|
241
|
+
module.exports.ChromaSubsampling = ChromaSubsampling
|
|
242
|
+
module.exports.SvgExportFlag = SvgExportFlag
|
|
217
243
|
module.exports.CanvasRenderingContext2D = CanvasRenderingContext2D
|
|
218
|
-
module.exports.
|
|
219
|
-
module.exports.createContext = createContext
|
|
220
|
-
module.exports.SVGCanvas = SVGCanvas
|
|
221
|
-
module.exports.Path2D = Path
|
|
244
|
+
module.exports.CanvasGradient = CanvasGradient
|
|
222
245
|
module.exports.ImageData = ImageData
|
|
223
246
|
module.exports.Image = Image
|
|
224
|
-
module.exports.CanvasPattern = CanvasPattern
|
|
225
|
-
module.exports.GlobalFonts = GlobalFonts
|
|
226
|
-
module.exports.convertSVGTextToPath = convertSVGTextToPath
|
|
227
247
|
module.exports.PathOp = PathOp
|
|
228
248
|
module.exports.FillType = FillType
|
|
229
|
-
module.exports.StrokeJoin = StrokeJoin
|
|
230
249
|
module.exports.StrokeCap = StrokeCap
|
|
250
|
+
module.exports.StrokeJoin = StrokeJoin
|
|
251
|
+
module.exports.Path = Path
|
|
252
|
+
module.exports.CanvasPattern = CanvasPattern
|
|
253
|
+
module.exports.convertSVGTextToPath = convertSVGTextToPath
|
|
254
|
+
module.exports.CanvasElement = CanvasElement
|
|
255
|
+
module.exports.SVGCanvas = SVGCanvas
|
|
256
|
+
module.exports.clearAllCache = clearAllCache
|
|
257
|
+
module.exports.GlobalFonts = GlobalFonts
|
package/load-image.js
CHANGED
|
@@ -39,7 +39,13 @@ module.exports = async function loadImage(source, options = {}) {
|
|
|
39
39
|
source = !(source instanceof URL) ? new URL(source) : source
|
|
40
40
|
// attempt to download the remote source and construct image
|
|
41
41
|
const data = await new Promise((resolve, reject) =>
|
|
42
|
-
makeRequest(
|
|
42
|
+
makeRequest(
|
|
43
|
+
source,
|
|
44
|
+
resolve,
|
|
45
|
+
reject,
|
|
46
|
+
typeof options.maxRedirects === 'number' && options.maxRedirects >= 0 ? options.maxRedirects : MAX_REDIRECTS,
|
|
47
|
+
options.requestOptions,
|
|
48
|
+
),
|
|
43
49
|
)
|
|
44
50
|
return createImage(data, options.alt)
|
|
45
51
|
}
|
|
@@ -54,16 +60,18 @@ function makeRequest(url, resolve, reject, redirectCount, requestOptions) {
|
|
|
54
60
|
// lazy load the lib
|
|
55
61
|
const lib = isHttps ? (!https ? (https = require('https')) : https) : !http ? (http = require('http')) : http
|
|
56
62
|
|
|
57
|
-
lib
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
lib
|
|
64
|
+
.get(url, requestOptions || {}, (res) => {
|
|
65
|
+
const shouldRedirect = REDIRECT_STATUSES.has(res.statusCode) && typeof res.headers.location === 'string'
|
|
66
|
+
if (shouldRedirect && redirectCount > 0)
|
|
67
|
+
return makeRequest(new URL(res.headers.location), resolve, reject, redirectCount - 1, requestOptions)
|
|
68
|
+
if (typeof res.statusCode === 'number' && (res.statusCode < 200 || res.statusCode >= 300)) {
|
|
69
|
+
return reject(new Error(`remote source rejected with status code ${res.statusCode}`))
|
|
70
|
+
}
|
|
64
71
|
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
consumeStream(res).then(resolve, reject)
|
|
73
|
+
})
|
|
74
|
+
.on('error', reject)
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
// use stream/consumers in the future?
|
|
@@ -86,6 +94,7 @@ function createImage(src, alt) {
|
|
|
86
94
|
|
|
87
95
|
function isBufferLike(src) {
|
|
88
96
|
return (
|
|
97
|
+
(src && src.type === 'Buffer') ||
|
|
89
98
|
Array.isArray(src) ||
|
|
90
99
|
src instanceof ArrayBuffer ||
|
|
91
100
|
src instanceof SharedArrayBuffer ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@napi-rs/canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"description": "Canvas for Node.js with skia backend",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": "https://github.com/Brooooooklyn/canvas.git",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"scripts": {
|
|
50
50
|
"artifacts": "napi artifacts",
|
|
51
51
|
"bench": "node -r @swc-node/register benchmark/bench.ts",
|
|
52
|
-
"build": "napi build --platform --release",
|
|
53
|
-
"build:debug": "napi build --platform",
|
|
52
|
+
"build": "napi build --platform --release --js js-binding.js",
|
|
53
|
+
"build:debug": "napi build --platform --js js-binding.js",
|
|
54
54
|
"format": "run-p format:source format:rs",
|
|
55
55
|
"format:rs": "cargo fmt",
|
|
56
56
|
"format:source": "prettier . -w",
|
|
@@ -65,36 +65,36 @@
|
|
|
65
65
|
"@jimp/custom": "^0.16.1",
|
|
66
66
|
"@jimp/jpeg": "^0.16.1",
|
|
67
67
|
"@jimp/png": "^0.16.1",
|
|
68
|
-
"@napi-rs/cli": "^2.
|
|
69
|
-
"@octokit/rest": "^19.0.
|
|
68
|
+
"@napi-rs/cli": "^2.11.4",
|
|
69
|
+
"@octokit/rest": "^19.0.4",
|
|
70
70
|
"@swc-node/register": "^1.5.1",
|
|
71
|
-
"@types/lodash": "^4.14.
|
|
72
|
-
"@types/node": "^
|
|
73
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
74
|
-
"@typescript-eslint/parser": "^5.
|
|
75
|
-
"ava": "^4.
|
|
71
|
+
"@types/lodash": "^4.14.184",
|
|
72
|
+
"@types/node": "^18.7.13",
|
|
73
|
+
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
|
74
|
+
"@typescript-eslint/parser": "^5.35.1",
|
|
75
|
+
"ava": "^4.3.3",
|
|
76
76
|
"benny": "^3.7.1",
|
|
77
|
-
"canvas": "^2.9.
|
|
78
|
-
"canvaskit-wasm": "^0.
|
|
77
|
+
"canvas": "^2.9.3",
|
|
78
|
+
"canvaskit-wasm": "^0.37.0",
|
|
79
79
|
"colorette": "^2.0.19",
|
|
80
80
|
"conventional-changelog-cli": "^2.2.2",
|
|
81
|
-
"echarts": "^5.3.
|
|
82
|
-
"eslint": "^8.
|
|
81
|
+
"echarts": "^5.3.3",
|
|
82
|
+
"eslint": "^8.22.0",
|
|
83
83
|
"eslint-config-prettier": "^8.5.0",
|
|
84
84
|
"eslint-plugin-import": "^2.26.0",
|
|
85
|
-
"eslint-plugin-prettier": "^4.
|
|
85
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
86
86
|
"eslint-plugin-sonarjs": "^0.15.0",
|
|
87
87
|
"husky": "^8.0.1",
|
|
88
|
-
"lint-staged": "^13.0.
|
|
88
|
+
"lint-staged": "^13.0.3",
|
|
89
89
|
"lodash": "^4.17.21",
|
|
90
90
|
"npm-run-all": "^4.1.5",
|
|
91
91
|
"pinst": "^3.0.0",
|
|
92
92
|
"png.js": "^0.2.1",
|
|
93
|
-
"prettier": "^2.
|
|
93
|
+
"prettier": "^2.7.1",
|
|
94
94
|
"pretty-bytes": "^6.0.0",
|
|
95
95
|
"skia-canvas": "^1.0.0",
|
|
96
96
|
"table": "^6.8.0",
|
|
97
|
-
"typescript": "^4.7.
|
|
97
|
+
"typescript": "^4.7.4"
|
|
98
98
|
},
|
|
99
99
|
"lint-staged": {
|
|
100
100
|
"*.@(js|ts|tsx|yml|yaml|md|json|html)": [
|
|
@@ -130,16 +130,16 @@
|
|
|
130
130
|
"singleQuote": true,
|
|
131
131
|
"arrowParens": "always"
|
|
132
132
|
},
|
|
133
|
-
"packageManager": "yarn@3.2.
|
|
133
|
+
"packageManager": "yarn@3.2.3",
|
|
134
134
|
"optionalDependencies": {
|
|
135
|
-
"@napi-rs/canvas-win32-x64-msvc": "0.1.
|
|
136
|
-
"@napi-rs/canvas-darwin-x64": "0.1.
|
|
137
|
-
"@napi-rs/canvas-linux-x64-gnu": "0.1.
|
|
138
|
-
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.
|
|
139
|
-
"@napi-rs/canvas-linux-x64-musl": "0.1.
|
|
140
|
-
"@napi-rs/canvas-linux-arm64-gnu": "0.1.
|
|
141
|
-
"@napi-rs/canvas-linux-arm64-musl": "0.1.
|
|
142
|
-
"@napi-rs/canvas-darwin-arm64": "0.1.
|
|
143
|
-
"@napi-rs/canvas-android-arm64": "0.1.
|
|
135
|
+
"@napi-rs/canvas-win32-x64-msvc": "0.1.30",
|
|
136
|
+
"@napi-rs/canvas-darwin-x64": "0.1.30",
|
|
137
|
+
"@napi-rs/canvas-linux-x64-gnu": "0.1.30",
|
|
138
|
+
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.30",
|
|
139
|
+
"@napi-rs/canvas-linux-x64-musl": "0.1.30",
|
|
140
|
+
"@napi-rs/canvas-linux-arm64-gnu": "0.1.30",
|
|
141
|
+
"@napi-rs/canvas-linux-arm64-musl": "0.1.30",
|
|
142
|
+
"@napi-rs/canvas-darwin-arm64": "0.1.30",
|
|
143
|
+
"@napi-rs/canvas-android-arm64": "0.1.30"
|
|
144
144
|
}
|
|
145
145
|
}
|