@napi-rs/canvas 0.1.24 → 0.1.27
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 +2 -2
- package/index.d.ts +11 -9
- package/index.js +27 -163
- package/js-binding.js +10 -2
- package/load-image.js +94 -0
- package/package.json +21 -16
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
|
|
|
@@ -76,7 +76,7 @@ ctx.closePath()
|
|
|
76
76
|
ctx.stroke()
|
|
77
77
|
|
|
78
78
|
async function main() {
|
|
79
|
-
const pngData = await canvas.encode('png') // JPEG and WebP
|
|
79
|
+
const pngData = await canvas.encode('png') // JPEG, AVIF and WebP are also supported
|
|
80
80
|
// encoding in libuv thread pool, non-blocking
|
|
81
81
|
await promises.writeFile(join(__dirname, 'simple.png'), pngData)
|
|
82
82
|
}
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
|
|
1
3
|
export interface DOMMatrix2DInit {
|
|
2
4
|
a: number
|
|
3
5
|
b: number
|
|
@@ -354,34 +356,34 @@ interface IGlobalFonts {
|
|
|
354
356
|
|
|
355
357
|
export const GlobalFonts: IGlobalFonts
|
|
356
358
|
|
|
357
|
-
export
|
|
359
|
+
export enum PathOp {
|
|
358
360
|
Difference = 0, // subtract the op path from the first path
|
|
359
361
|
Intersect = 1, // intersect the two paths
|
|
360
362
|
Union = 2, // union (inclusive-or) the two paths
|
|
361
|
-
|
|
363
|
+
Xor = 3, // exclusive-or the two paths
|
|
362
364
|
ReverseDifference = 4, // subtract the first path from the op path
|
|
363
365
|
}
|
|
364
366
|
|
|
365
|
-
export
|
|
367
|
+
export enum FillType {
|
|
366
368
|
Winding = 0,
|
|
367
369
|
EvenOdd = 1,
|
|
368
370
|
InverseWinding = 2,
|
|
369
371
|
InverseEvenOdd = 3,
|
|
370
372
|
}
|
|
371
373
|
|
|
372
|
-
export
|
|
374
|
+
export enum StrokeJoin {
|
|
373
375
|
Miter = 0,
|
|
374
376
|
Round = 1,
|
|
375
377
|
Bevel = 2,
|
|
376
378
|
}
|
|
377
379
|
|
|
378
|
-
export
|
|
380
|
+
export enum StrokeCap {
|
|
379
381
|
Butt = 0,
|
|
380
382
|
Round = 1,
|
|
381
383
|
Square = 2,
|
|
382
384
|
}
|
|
383
385
|
|
|
384
|
-
export
|
|
386
|
+
export enum SvgExportFlag {
|
|
385
387
|
ConvertTextToPaths = 0x01,
|
|
386
388
|
NoPrettyXML = 0x02,
|
|
387
389
|
RelativePathEncoding = 0x04,
|
|
@@ -390,9 +392,9 @@ export const enum SvgExportFlag {
|
|
|
390
392
|
export function convertSVGTextToPath(svg: Buffer | string): Buffer
|
|
391
393
|
|
|
392
394
|
export interface LoadImageOptions {
|
|
393
|
-
alt?: string
|
|
394
|
-
maxRedirects?: number
|
|
395
|
-
requestOptions?: import('http').RequestOptions
|
|
395
|
+
alt?: string
|
|
396
|
+
maxRedirects?: number
|
|
397
|
+
requestOptions?: import('http').RequestOptions
|
|
396
398
|
}
|
|
397
399
|
|
|
398
400
|
export function loadImage(
|
package/index.js
CHANGED
|
@@ -11,95 +11,35 @@ const {
|
|
|
11
11
|
Image,
|
|
12
12
|
CanvasPattern,
|
|
13
13
|
GlobalFonts,
|
|
14
|
-
|
|
14
|
+
PathOp,
|
|
15
|
+
FillType,
|
|
16
|
+
StrokeJoin,
|
|
17
|
+
StrokeCap,
|
|
18
|
+
convertSVGTextToPath,
|
|
15
19
|
} = require('./js-binding')
|
|
16
20
|
|
|
17
21
|
const { DOMPoint, DOMMatrix, DOMRect } = require('./geometry')
|
|
18
22
|
|
|
19
23
|
const loadImage = require('./load-image')
|
|
20
24
|
|
|
21
|
-
const StrokeJoin = {
|
|
22
|
-
Miter: 0,
|
|
23
|
-
Round: 1,
|
|
24
|
-
Bevel: 2,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const StrokeCap = {
|
|
28
|
-
Butt: 0,
|
|
29
|
-
Round: 1,
|
|
30
|
-
Square: 2,
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const PathOp = {
|
|
34
|
-
Difference: 0, // subtract the op path from the first path
|
|
35
|
-
Intersect: 1, // intersect the two paths
|
|
36
|
-
Union: 2, // union (inclusive-or) the two paths
|
|
37
|
-
XOR: 3, // exclusive-or the two paths
|
|
38
|
-
ReverseDifference: 4, // subtract the first path from the op path
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const FillType = {
|
|
42
|
-
Winding: 0,
|
|
43
|
-
EvenOdd: 1,
|
|
44
|
-
InverseWinding: 2,
|
|
45
|
-
InverseEvenOdd: 3,
|
|
46
|
-
}
|
|
47
|
-
|
|
48
25
|
const SvgExportFlag = {
|
|
49
26
|
ConvertTextToPaths: 0x01,
|
|
50
27
|
NoPrettyXML: 0x02,
|
|
51
28
|
RelativePathEncoding: 0x04,
|
|
52
29
|
}
|
|
53
30
|
|
|
54
|
-
const GlobalFontsSingleton = new GlobalFonts()
|
|
55
|
-
let FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
|
|
56
|
-
|
|
57
31
|
// eslint-disable-next-line sonarjs/no-unused-collection
|
|
58
32
|
const Fonts = []
|
|
59
33
|
|
|
60
|
-
Object.defineProperty(
|
|
61
|
-
value: function register(fontData, nameAlias = '') {
|
|
62
|
-
const result = GlobalFontsSingleton._register(fontData, nameAlias)
|
|
63
|
-
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
|
|
64
|
-
Fonts.push(fontData)
|
|
65
|
-
return result
|
|
66
|
-
},
|
|
67
|
-
configurable: false,
|
|
68
|
-
enumerable: false,
|
|
69
|
-
writable: false,
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
Object.defineProperty(GlobalFontsSingleton, 'registerFromPath', {
|
|
73
|
-
value: function registerFromPath(path, nameAlias = '') {
|
|
74
|
-
const result = GlobalFontsSingleton._registerFromPath(path, nameAlias)
|
|
75
|
-
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
|
|
76
|
-
return result
|
|
77
|
-
},
|
|
78
|
-
configurable: false,
|
|
79
|
-
enumerable: false,
|
|
80
|
-
writable: false,
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
Object.defineProperty(GlobalFontsSingleton, 'loadFontsFromDir', {
|
|
84
|
-
value: function loadFontsFromDir(path) {
|
|
85
|
-
const result = GlobalFontsSingleton._loadFontsFromDir(path)
|
|
86
|
-
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
|
|
87
|
-
return result
|
|
88
|
-
},
|
|
89
|
-
configurable: false,
|
|
90
|
-
enumerable: false,
|
|
91
|
-
writable: false,
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
Object.defineProperty(GlobalFontsSingleton, 'families', {
|
|
34
|
+
Object.defineProperty(GlobalFonts, 'families', {
|
|
95
35
|
get: function () {
|
|
96
|
-
return
|
|
36
|
+
return JSON.parse(GlobalFonts.getFamilies())
|
|
97
37
|
},
|
|
98
38
|
})
|
|
99
39
|
|
|
100
|
-
Object.defineProperty(
|
|
40
|
+
Object.defineProperty(GlobalFonts, 'has', {
|
|
101
41
|
value: function has(name) {
|
|
102
|
-
return !!
|
|
42
|
+
return !!JSON.parse(GlobalFonts.getFamilies()).find(({ family }) => family === name)
|
|
103
43
|
},
|
|
104
44
|
configurable: false,
|
|
105
45
|
enumerable: false,
|
|
@@ -129,27 +69,6 @@ CanvasRenderingContext2D.prototype.getImageData = function getImageData(x, y, w,
|
|
|
129
69
|
return new ImageData(data, w, h)
|
|
130
70
|
}
|
|
131
71
|
|
|
132
|
-
Path2D.prototype.stroke = function stroke(strokeOptions = {}) {
|
|
133
|
-
const width = typeof strokeOptions.width === 'undefined' ? 1 : strokeOptions.width
|
|
134
|
-
const miterLimit = typeof strokeOptions.miterLimit === 'undefined' ? 4 : strokeOptions.miterLimit
|
|
135
|
-
const join = typeof strokeOptions.join === 'undefined' ? StrokeJoin.Miter : strokeOptions.join
|
|
136
|
-
const cap = typeof strokeOptions.cap === 'undefined' ? StrokeCap.Butt : strokeOptions.cap
|
|
137
|
-
|
|
138
|
-
return this._stroke(width, miterLimit, join, cap)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
Path2D.prototype.getFillTypeString = function getFillTypeString() {
|
|
142
|
-
const fillType = this.getFillType()
|
|
143
|
-
|
|
144
|
-
if (fillType === FillType.Winding) {
|
|
145
|
-
return 'nonzero'
|
|
146
|
-
} else if (fillType === FillType.EvenOdd) {
|
|
147
|
-
return 'evenodd'
|
|
148
|
-
} else {
|
|
149
|
-
return 'nonzero' // default
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
72
|
function createCanvas(width, height, flag) {
|
|
154
73
|
const isSvgBackend = typeof flag !== 'undefined'
|
|
155
74
|
const canvasElement = isSvgBackend ? new SVGCanvas(width, height) : new CanvasElement(width, height)
|
|
@@ -163,8 +82,8 @@ function createCanvas(width, height, flag) {
|
|
|
163
82
|
ctx = ctx
|
|
164
83
|
? ctx
|
|
165
84
|
: isSvgBackend
|
|
166
|
-
? new CanvasRenderingContext2D(this.width, this.height,
|
|
167
|
-
: new CanvasRenderingContext2D(this.width, this.height,
|
|
85
|
+
? new CanvasRenderingContext2D(this.width, this.height, attrs.colorSpace, flag)
|
|
86
|
+
: new CanvasRenderingContext2D(this.width, this.height, attrs.colorSpace)
|
|
168
87
|
createContext(ctx, this.width, this.height, attrs)
|
|
169
88
|
|
|
170
89
|
// napi can not define writable: true but enumerable: false property
|
|
@@ -213,87 +132,37 @@ function createCanvas(width, height, flag) {
|
|
|
213
132
|
toDataURLAsync: canvasToDataURLAsync,
|
|
214
133
|
} = Object.getPrototypeOf(canvasElement)
|
|
215
134
|
|
|
216
|
-
|
|
217
|
-
const avifDefaultQuality = 80
|
|
218
|
-
const avifConfig = {
|
|
219
|
-
// Quality from 1 (worst) to 100 (best), the default value is 80. The numbers have different meaning than JPEG's quality scale. Beware when comparing codecs. There is no lossless compression support.
|
|
220
|
-
quality: avifDefaultQuality,
|
|
221
|
-
|
|
222
|
-
// Calculate alphaQuality, this is consistent with cavif.
|
|
223
|
-
// https://github.com/kornelski/cavif-rs/blob/37847b95bb81d4cf90e36b7fab2c7fbbcf95abe2/src/main.rs#L97
|
|
224
|
-
alphaQuality: Math.min((avifDefaultQuality + 100) / 2, avifDefaultQuality + avifDefaultQuality / 4 + 2),
|
|
225
|
-
threads: 0,
|
|
226
|
-
|
|
227
|
-
// Encoding speed between 1 (best, but slowest) and 10 (fastest, but a blurry mess), the default value is 4. Speeds 1 and 2 are unbelievably slow, but make files ~3-5% smaller. Speeds 7 and above degrade compression significantly, and are not recommended.
|
|
228
|
-
speed: 4,
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
canvasElement.encode = function encode(type, qualityOrConfig) {
|
|
135
|
+
canvasElement.encode = function encode(type, qualityOrConfig = {}) {
|
|
232
136
|
if (type === 'avif') {
|
|
233
|
-
return canvasEncode.call(
|
|
234
|
-
this,
|
|
235
|
-
type,
|
|
236
|
-
JSON.stringify({
|
|
237
|
-
...avifConfig,
|
|
238
|
-
...(qualityOrConfig || {}),
|
|
239
|
-
}),
|
|
240
|
-
)
|
|
137
|
+
return canvasEncode.call(this, type, JSON.stringify(qualityOrConfig))
|
|
241
138
|
}
|
|
242
139
|
return canvasEncode.call(this, type, qualityOrConfig)
|
|
243
140
|
}
|
|
244
141
|
|
|
245
|
-
canvasElement.encodeSync = function encodeSync(type, qualityOrConfig) {
|
|
142
|
+
canvasElement.encodeSync = function encodeSync(type, qualityOrConfig = {}) {
|
|
246
143
|
if (type === 'avif') {
|
|
247
|
-
return canvasEncodeSync.call(
|
|
248
|
-
this,
|
|
249
|
-
type,
|
|
250
|
-
JSON.stringify({
|
|
251
|
-
...avifConfig,
|
|
252
|
-
...(qualityOrConfig || {}),
|
|
253
|
-
}),
|
|
254
|
-
)
|
|
144
|
+
return canvasEncodeSync.call(this, type, JSON.stringify(qualityOrConfig))
|
|
255
145
|
}
|
|
256
146
|
return canvasEncodeSync.call(this, type, qualityOrConfig)
|
|
257
147
|
}
|
|
258
148
|
|
|
259
|
-
canvasElement.toBuffer = function toBuffer(type = 'image/png', qualityOrConfig) {
|
|
149
|
+
canvasElement.toBuffer = function toBuffer(type = 'image/png', qualityOrConfig = {}) {
|
|
260
150
|
if (type === 'avif') {
|
|
261
|
-
return canvasToBuffer.call(
|
|
262
|
-
this,
|
|
263
|
-
type,
|
|
264
|
-
JSON.stringify({
|
|
265
|
-
...avifConfig,
|
|
266
|
-
...(qualityOrConfig || {}),
|
|
267
|
-
}),
|
|
268
|
-
)
|
|
151
|
+
return canvasToBuffer.call(this, type, JSON.stringify(qualityOrConfig))
|
|
269
152
|
}
|
|
270
153
|
return canvasToBuffer.call(this, type, qualityOrConfig)
|
|
271
154
|
}
|
|
272
155
|
|
|
273
|
-
canvasElement.toDataURL = function toDataURL(type = 'image/png', qualityOrConfig) {
|
|
156
|
+
canvasElement.toDataURL = function toDataURL(type = 'image/png', qualityOrConfig = {}) {
|
|
274
157
|
if (type === 'avif') {
|
|
275
|
-
return canvasToDataURL.call(
|
|
276
|
-
this,
|
|
277
|
-
type,
|
|
278
|
-
JSON.stringify({
|
|
279
|
-
...avifConfig,
|
|
280
|
-
...(qualityOrConfig || {}),
|
|
281
|
-
}),
|
|
282
|
-
)
|
|
158
|
+
return canvasToDataURL.call(this, type, JSON.stringify(qualityOrConfig))
|
|
283
159
|
}
|
|
284
160
|
return canvasToDataURL.call(this, type, qualityOrConfig)
|
|
285
161
|
}
|
|
286
162
|
|
|
287
|
-
canvasElement.toDataURLAsync = function toDataURLAsync(type = 'image/png', qualityOrConfig) {
|
|
163
|
+
canvasElement.toDataURLAsync = function toDataURLAsync(type = 'image/png', qualityOrConfig = {}) {
|
|
288
164
|
if (type === 'avif') {
|
|
289
|
-
return canvasToDataURLAsync.call(
|
|
290
|
-
this,
|
|
291
|
-
type,
|
|
292
|
-
JSON.stringify({
|
|
293
|
-
...avifConfig,
|
|
294
|
-
...(qualityOrConfig || {}),
|
|
295
|
-
}),
|
|
296
|
-
)
|
|
165
|
+
return canvasToDataURLAsync.call(this, type, JSON.stringify(qualityOrConfig))
|
|
297
166
|
}
|
|
298
167
|
return canvasToDataURLAsync.call(this, type, qualityOrConfig)
|
|
299
168
|
}
|
|
@@ -308,26 +177,21 @@ class Canvas {
|
|
|
308
177
|
}
|
|
309
178
|
|
|
310
179
|
if (!process.env.DISABLE_SYSTEM_FONTS_LOAD) {
|
|
311
|
-
|
|
180
|
+
GlobalFonts.loadSystemFonts()
|
|
312
181
|
const platformName = platform()
|
|
313
182
|
const homedirPath = homedir()
|
|
314
183
|
switch (platformName) {
|
|
315
184
|
case 'win32':
|
|
316
|
-
|
|
185
|
+
GlobalFonts.loadFontsFromDir(join(homedirPath, 'AppData', 'Local', 'Microsoft', 'Windows', 'Fonts'))
|
|
317
186
|
break
|
|
318
187
|
case 'darwin':
|
|
319
|
-
|
|
188
|
+
GlobalFonts.loadFontsFromDir(join(homedirPath, 'Library', 'Fonts'))
|
|
320
189
|
break
|
|
321
190
|
case 'linux':
|
|
322
|
-
|
|
323
|
-
|
|
191
|
+
GlobalFonts.loadFontsFromDir(join('usr', 'local', 'share', 'fonts'))
|
|
192
|
+
GlobalFonts.loadFontsFromDir(join(homedirPath, '.fonts'))
|
|
324
193
|
break
|
|
325
194
|
}
|
|
326
|
-
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
function convertSVGTextToPath(input) {
|
|
330
|
-
return _convertSVGTextToPath(Buffer.isBuffer(input) ? input : Buffer.from(input), GlobalFontsSingleton)
|
|
331
195
|
}
|
|
332
196
|
|
|
333
197
|
module.exports = {
|
|
@@ -341,7 +205,7 @@ module.exports = {
|
|
|
341
205
|
StrokeCap,
|
|
342
206
|
StrokeJoin,
|
|
343
207
|
SvgExportFlag,
|
|
344
|
-
GlobalFonts:
|
|
208
|
+
GlobalFonts: GlobalFonts,
|
|
345
209
|
convertSVGTextToPath,
|
|
346
210
|
DOMPoint,
|
|
347
211
|
DOMMatrix,
|
package/js-binding.js
CHANGED
|
@@ -200,21 +200,29 @@ const {
|
|
|
200
200
|
CanvasElement,
|
|
201
201
|
createContext,
|
|
202
202
|
SVGCanvas,
|
|
203
|
-
|
|
203
|
+
Path,
|
|
204
204
|
ImageData,
|
|
205
205
|
Image,
|
|
206
206
|
CanvasPattern,
|
|
207
207
|
GlobalFonts,
|
|
208
208
|
convertSVGTextToPath,
|
|
209
|
+
PathOp,
|
|
210
|
+
FillType,
|
|
211
|
+
StrokeJoin,
|
|
212
|
+
StrokeCap,
|
|
209
213
|
} = nativeBinding
|
|
210
214
|
|
|
211
215
|
module.exports.CanvasRenderingContext2D = CanvasRenderingContext2D
|
|
212
216
|
module.exports.CanvasElement = CanvasElement
|
|
213
217
|
module.exports.createContext = createContext
|
|
214
218
|
module.exports.SVGCanvas = SVGCanvas
|
|
215
|
-
module.exports.Path2D =
|
|
219
|
+
module.exports.Path2D = Path
|
|
216
220
|
module.exports.ImageData = ImageData
|
|
217
221
|
module.exports.Image = Image
|
|
218
222
|
module.exports.CanvasPattern = CanvasPattern
|
|
219
223
|
module.exports.GlobalFonts = GlobalFonts
|
|
220
224
|
module.exports.convertSVGTextToPath = convertSVGTextToPath
|
|
225
|
+
module.exports.PathOp = PathOp
|
|
226
|
+
module.exports.FillType = FillType
|
|
227
|
+
module.exports.StrokeJoin = StrokeJoin
|
|
228
|
+
module.exports.StrokeCap = StrokeCap
|
package/load-image.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const { Image } = require('./js-binding')
|
|
3
|
+
const { Readable } = require('stream')
|
|
4
|
+
|
|
5
|
+
let http, https
|
|
6
|
+
|
|
7
|
+
const MAX_REDIRECTS = 20,
|
|
8
|
+
REDIRECT_STATUSES = new Set([301, 302]),
|
|
9
|
+
DATA_URI = /^\s*data:/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Loads the given source into canvas Image
|
|
13
|
+
* @param {string|URL|Image|Buffer} source The image source to be loaded
|
|
14
|
+
* @param {object} options Options passed to the loader
|
|
15
|
+
*/
|
|
16
|
+
module.exports = async function loadImage(source, options = {}) {
|
|
17
|
+
// load readable stream as image
|
|
18
|
+
if (source instanceof Readable) return createImage(await consumeStream(source), options.alt)
|
|
19
|
+
// use the same buffer without copying if the source is a buffer
|
|
20
|
+
if (Buffer.isBuffer(source)) return createImage(source, options.alt)
|
|
21
|
+
// construct a buffer if the source is buffer-like
|
|
22
|
+
if (isBufferLike(source)) return createImage(Buffer.from(source), options.alt)
|
|
23
|
+
// if the source is Image instance, copy the image src to new image
|
|
24
|
+
if (source instanceof Image) return createImage(source.src, options.alt)
|
|
25
|
+
// if source is string and in data uri format, construct image using data uri
|
|
26
|
+
if (typeof source === 'string' && DATA_URI.test(source)) {
|
|
27
|
+
const commaIdx = source.indexOf(',')
|
|
28
|
+
const encoding = source.lastIndexOf('base64', commaIdx) < 0 ? 'utf-8' : 'base64'
|
|
29
|
+
const data = Buffer.from(source.slice(commaIdx + 1), encoding)
|
|
30
|
+
return createImage(data, options.alt)
|
|
31
|
+
}
|
|
32
|
+
// if source is a string or URL instance
|
|
33
|
+
if (typeof source === 'string' || source instanceof URL) {
|
|
34
|
+
// if the source exists as a file, construct image from that file
|
|
35
|
+
if (fs.existsSync(source)) {
|
|
36
|
+
return createImage(await fs.promises.readFile(source), options.alt)
|
|
37
|
+
} else {
|
|
38
|
+
// the source is a remote url here
|
|
39
|
+
source = !(source instanceof URL) ? new URL(source) : source
|
|
40
|
+
// attempt to download the remote source and construct image
|
|
41
|
+
const data = await new Promise((resolve, reject) =>
|
|
42
|
+
makeRequest(source, resolve, reject, options.maxRedirects ?? MAX_REDIRECTS, options.requestOptions),
|
|
43
|
+
)
|
|
44
|
+
return createImage(data, options.alt)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// throw error as dont support that source
|
|
49
|
+
throw new TypeError('unsupported image source')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function makeRequest(url, resolve, reject, redirectCount, requestOptions) {
|
|
53
|
+
const isHttps = url.protocol === 'https:'
|
|
54
|
+
// lazy load the lib
|
|
55
|
+
const lib = isHttps ? (!https ? (https = require('https')) : https) : !http ? (http = require('http')) : http
|
|
56
|
+
|
|
57
|
+
lib.get(url, requestOptions ?? {}, (res) => {
|
|
58
|
+
const shouldRedirect = REDIRECT_STATUSES.has(res.statusCode) && typeof res.headers.location === 'string'
|
|
59
|
+
if (shouldRedirect && redirectCount > 0)
|
|
60
|
+
return makeRequest(new URL(res.headers.location), resolve, reject, redirectCount - 1, requestOptions)
|
|
61
|
+
if (typeof res.statusCode === 'number' && (res.statusCode < 200 || res.statusCode >= 300)) {
|
|
62
|
+
return reject(new Error(`remote source rejected with status code ${res.statusCode}`))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
consumeStream(res).then(resolve, reject)
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// use stream/consumers in the future?
|
|
70
|
+
function consumeStream(res) {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const chunks = []
|
|
73
|
+
|
|
74
|
+
res.on('data', (chunk) => chunks.push(chunk))
|
|
75
|
+
res.on('end', () => resolve(Buffer.concat(chunks)))
|
|
76
|
+
res.on('error', reject)
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createImage(src, alt) {
|
|
81
|
+
const image = new Image()
|
|
82
|
+
image.src = src
|
|
83
|
+
if (typeof alt === 'string') image.alt = alt
|
|
84
|
+
return image
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function isBufferLike(src) {
|
|
88
|
+
return (
|
|
89
|
+
Array.isArray(src) ||
|
|
90
|
+
src instanceof ArrayBuffer ||
|
|
91
|
+
src instanceof SharedArrayBuffer ||
|
|
92
|
+
src instanceof Object.getPrototypeOf(Uint8Array)
|
|
93
|
+
)
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@napi-rs/canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"description": "Canvas for Node.js with skia backend",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": "https://github.com/Brooooooklyn/canvas.git",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"index.d.ts",
|
|
23
23
|
"index.js",
|
|
24
24
|
"geometry.js",
|
|
25
|
-
"js-binding.js"
|
|
25
|
+
"js-binding.js",
|
|
26
|
+
"load-image.js"
|
|
26
27
|
],
|
|
27
28
|
"napi": {
|
|
28
29
|
"name": "skia",
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
"@jimp/jpeg": "^0.16.1",
|
|
66
67
|
"@jimp/png": "^0.16.1",
|
|
67
68
|
"@napi-rs/cli": "^2.9.0",
|
|
68
|
-
"@octokit/rest": "^
|
|
69
|
+
"@octokit/rest": "^19.0.0",
|
|
69
70
|
"@swc-node/register": "^1.5.1",
|
|
70
71
|
"@types/lodash": "^4.14.182",
|
|
71
72
|
"@types/node": "^17.0.35",
|
|
@@ -74,7 +75,7 @@
|
|
|
74
75
|
"ava": "^4.2.0",
|
|
75
76
|
"benny": "^3.7.1",
|
|
76
77
|
"canvas": "^2.9.1",
|
|
77
|
-
"canvaskit-wasm": "^0.
|
|
78
|
+
"canvaskit-wasm": "^0.35.0",
|
|
78
79
|
"colorette": "^2.0.16",
|
|
79
80
|
"conventional-changelog-cli": "^2.2.2",
|
|
80
81
|
"echarts": "^5.3.2",
|
|
@@ -82,7 +83,7 @@
|
|
|
82
83
|
"eslint-config-prettier": "^8.5.0",
|
|
83
84
|
"eslint-plugin-import": "^2.26.0",
|
|
84
85
|
"eslint-plugin-prettier": "^4.0.0",
|
|
85
|
-
"eslint-plugin-sonarjs": "^0.
|
|
86
|
+
"eslint-plugin-sonarjs": "^0.15.0",
|
|
86
87
|
"husky": "^8.0.1",
|
|
87
88
|
"lint-staged": "^13.0.0",
|
|
88
89
|
"lodash": "^4.17.21",
|
|
@@ -90,7 +91,7 @@
|
|
|
90
91
|
"pinst": "^3.0.0",
|
|
91
92
|
"png.js": "^0.2.1",
|
|
92
93
|
"prettier": "^2.6.2",
|
|
93
|
-
"skia-canvas": "^0.
|
|
94
|
+
"skia-canvas": "^1.0.0",
|
|
94
95
|
"typescript": "^4.7.2"
|
|
95
96
|
},
|
|
96
97
|
"lint-staged": {
|
|
@@ -108,6 +109,10 @@
|
|
|
108
109
|
"extensions": [
|
|
109
110
|
"ts"
|
|
110
111
|
],
|
|
112
|
+
"files": [
|
|
113
|
+
"__test__/**/*.spec.ts",
|
|
114
|
+
"scripts/__test__/**/*.spec.ts"
|
|
115
|
+
],
|
|
111
116
|
"workerThreads": false,
|
|
112
117
|
"cache": false,
|
|
113
118
|
"timeout": "3m",
|
|
@@ -123,16 +128,16 @@
|
|
|
123
128
|
"singleQuote": true,
|
|
124
129
|
"arrowParens": "always"
|
|
125
130
|
},
|
|
126
|
-
"packageManager": "yarn@3.2.
|
|
131
|
+
"packageManager": "yarn@3.2.2",
|
|
127
132
|
"optionalDependencies": {
|
|
128
|
-
"@napi-rs/canvas-win32-x64-msvc": "0.1.
|
|
129
|
-
"@napi-rs/canvas-darwin-x64": "0.1.
|
|
130
|
-
"@napi-rs/canvas-linux-x64-gnu": "0.1.
|
|
131
|
-
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.
|
|
132
|
-
"@napi-rs/canvas-linux-x64-musl": "0.1.
|
|
133
|
-
"@napi-rs/canvas-linux-arm64-gnu": "0.1.
|
|
134
|
-
"@napi-rs/canvas-linux-arm64-musl": "0.1.
|
|
135
|
-
"@napi-rs/canvas-darwin-arm64": "0.1.
|
|
136
|
-
"@napi-rs/canvas-android-arm64": "0.1.
|
|
133
|
+
"@napi-rs/canvas-win32-x64-msvc": "0.1.27",
|
|
134
|
+
"@napi-rs/canvas-darwin-x64": "0.1.27",
|
|
135
|
+
"@napi-rs/canvas-linux-x64-gnu": "0.1.27",
|
|
136
|
+
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.27",
|
|
137
|
+
"@napi-rs/canvas-linux-x64-musl": "0.1.27",
|
|
138
|
+
"@napi-rs/canvas-linux-arm64-gnu": "0.1.27",
|
|
139
|
+
"@napi-rs/canvas-linux-arm64-musl": "0.1.27",
|
|
140
|
+
"@napi-rs/canvas-darwin-arm64": "0.1.27",
|
|
141
|
+
"@napi-rs/canvas-android-arm64": "0.1.27"
|
|
137
142
|
}
|
|
138
143
|
}
|