@napi-rs/canvas 0.1.23 → 0.1.26
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 +1 -1
- package/index.d.ts +18 -5
- package/index.js +13 -60
- package/load-image.js +94 -0
- package/package.json +22 -17
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
|
|
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,7 +356,7 @@ 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
|
|
@@ -362,29 +364,40 @@ export const enum PathOp {
|
|
|
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,
|
|
388
390
|
}
|
|
389
391
|
|
|
390
392
|
export function convertSVGTextToPath(svg: Buffer | string): Buffer
|
|
393
|
+
|
|
394
|
+
export interface LoadImageOptions {
|
|
395
|
+
alt?: string
|
|
396
|
+
maxRedirects?: number
|
|
397
|
+
requestOptions?: import('http').RequestOptions
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function loadImage(
|
|
401
|
+
source: string | URL | Buffer | ArrayBufferLike | Uint8Array | Image | import('stream').Readable,
|
|
402
|
+
options?: LoadImageOptions,
|
|
403
|
+
): Promise<Image>
|
package/index.js
CHANGED
|
@@ -16,6 +16,8 @@ const {
|
|
|
16
16
|
|
|
17
17
|
const { DOMPoint, DOMMatrix, DOMRect } = require('./geometry')
|
|
18
18
|
|
|
19
|
+
const loadImage = require('./load-image')
|
|
20
|
+
|
|
19
21
|
const StrokeJoin = {
|
|
20
22
|
Miter: 0,
|
|
21
23
|
Round: 1,
|
|
@@ -211,87 +213,37 @@ function createCanvas(width, height, flag) {
|
|
|
211
213
|
toDataURLAsync: canvasToDataURLAsync,
|
|
212
214
|
} = Object.getPrototypeOf(canvasElement)
|
|
213
215
|
|
|
214
|
-
|
|
215
|
-
const avifDefaultQuality = 80
|
|
216
|
-
const avifConfig = {
|
|
217
|
-
// 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.
|
|
218
|
-
quality: avifDefaultQuality,
|
|
219
|
-
|
|
220
|
-
// Calculate alphaQuality, this is consistent with cavif.
|
|
221
|
-
// https://github.com/kornelski/cavif-rs/blob/37847b95bb81d4cf90e36b7fab2c7fbbcf95abe2/src/main.rs#L97
|
|
222
|
-
alphaQuality: Math.min((avifDefaultQuality + 100) / 2, avifDefaultQuality + avifDefaultQuality / 4 + 2),
|
|
223
|
-
threads: 0,
|
|
224
|
-
|
|
225
|
-
// 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.
|
|
226
|
-
speed: 4,
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
canvasElement.encode = function encode(type, qualityOrConfig) {
|
|
216
|
+
canvasElement.encode = function encode(type, qualityOrConfig = {}) {
|
|
230
217
|
if (type === 'avif') {
|
|
231
|
-
return canvasEncode.call(
|
|
232
|
-
this,
|
|
233
|
-
type,
|
|
234
|
-
JSON.stringify({
|
|
235
|
-
...avifConfig,
|
|
236
|
-
...(qualityOrConfig || {}),
|
|
237
|
-
}),
|
|
238
|
-
)
|
|
218
|
+
return canvasEncode.call(this, type, JSON.stringify(qualityOrConfig))
|
|
239
219
|
}
|
|
240
220
|
return canvasEncode.call(this, type, qualityOrConfig)
|
|
241
221
|
}
|
|
242
222
|
|
|
243
|
-
canvasElement.encodeSync = function encodeSync(type, qualityOrConfig) {
|
|
223
|
+
canvasElement.encodeSync = function encodeSync(type, qualityOrConfig = {}) {
|
|
244
224
|
if (type === 'avif') {
|
|
245
|
-
return canvasEncodeSync.call(
|
|
246
|
-
this,
|
|
247
|
-
type,
|
|
248
|
-
JSON.stringify({
|
|
249
|
-
...avifConfig,
|
|
250
|
-
...(qualityOrConfig || {}),
|
|
251
|
-
}),
|
|
252
|
-
)
|
|
225
|
+
return canvasEncodeSync.call(this, type, JSON.stringify(qualityOrConfig))
|
|
253
226
|
}
|
|
254
227
|
return canvasEncodeSync.call(this, type, qualityOrConfig)
|
|
255
228
|
}
|
|
256
229
|
|
|
257
|
-
canvasElement.toBuffer = function toBuffer(type = 'image/png', qualityOrConfig) {
|
|
230
|
+
canvasElement.toBuffer = function toBuffer(type = 'image/png', qualityOrConfig = {}) {
|
|
258
231
|
if (type === 'avif') {
|
|
259
|
-
return canvasToBuffer.call(
|
|
260
|
-
this,
|
|
261
|
-
type,
|
|
262
|
-
JSON.stringify({
|
|
263
|
-
...avifConfig,
|
|
264
|
-
...(qualityOrConfig || {}),
|
|
265
|
-
}),
|
|
266
|
-
)
|
|
232
|
+
return canvasToBuffer.call(this, type, JSON.stringify(qualityOrConfig))
|
|
267
233
|
}
|
|
268
234
|
return canvasToBuffer.call(this, type, qualityOrConfig)
|
|
269
235
|
}
|
|
270
236
|
|
|
271
|
-
canvasElement.toDataURL = function toDataURL(type = 'image/png', qualityOrConfig) {
|
|
237
|
+
canvasElement.toDataURL = function toDataURL(type = 'image/png', qualityOrConfig = {}) {
|
|
272
238
|
if (type === 'avif') {
|
|
273
|
-
return canvasToDataURL.call(
|
|
274
|
-
this,
|
|
275
|
-
type,
|
|
276
|
-
JSON.stringify({
|
|
277
|
-
...avifConfig,
|
|
278
|
-
...(qualityOrConfig || {}),
|
|
279
|
-
}),
|
|
280
|
-
)
|
|
239
|
+
return canvasToDataURL.call(this, type, JSON.stringify(qualityOrConfig))
|
|
281
240
|
}
|
|
282
241
|
return canvasToDataURL.call(this, type, qualityOrConfig)
|
|
283
242
|
}
|
|
284
243
|
|
|
285
|
-
canvasElement.toDataURLAsync = function toDataURLAsync(type = 'image/png', qualityOrConfig) {
|
|
244
|
+
canvasElement.toDataURLAsync = function toDataURLAsync(type = 'image/png', qualityOrConfig = {}) {
|
|
286
245
|
if (type === 'avif') {
|
|
287
|
-
return canvasToDataURLAsync.call(
|
|
288
|
-
this,
|
|
289
|
-
type,
|
|
290
|
-
JSON.stringify({
|
|
291
|
-
...avifConfig,
|
|
292
|
-
...(qualityOrConfig || {}),
|
|
293
|
-
}),
|
|
294
|
-
)
|
|
246
|
+
return canvasToDataURLAsync.call(this, type, JSON.stringify(qualityOrConfig))
|
|
295
247
|
}
|
|
296
248
|
return canvasToDataURLAsync.call(this, type, qualityOrConfig)
|
|
297
249
|
}
|
|
@@ -344,4 +296,5 @@ module.exports = {
|
|
|
344
296
|
DOMPoint,
|
|
345
297
|
DOMMatrix,
|
|
346
298
|
DOMRect,
|
|
299
|
+
loadImage,
|
|
347
300
|
}
|
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.26",
|
|
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.14.0",
|
|
86
87
|
"husky": "^8.0.1",
|
|
87
88
|
"lint-staged": "^13.0.0",
|
|
88
89
|
"lodash": "^4.17.21",
|
|
@@ -90,11 +91,11 @@
|
|
|
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": {
|
|
97
|
-
"*.@(js|ts|tsx|yml|yaml|md|json)": [
|
|
98
|
+
"*.@(js|ts|tsx|yml|yaml|md|json|html)": [
|
|
98
99
|
"prettier --write"
|
|
99
100
|
],
|
|
100
101
|
"*.@(js|ts|tsx)": [
|
|
@@ -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.26",
|
|
134
|
+
"@napi-rs/canvas-darwin-x64": "0.1.26",
|
|
135
|
+
"@napi-rs/canvas-linux-x64-gnu": "0.1.26",
|
|
136
|
+
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.26",
|
|
137
|
+
"@napi-rs/canvas-linux-x64-musl": "0.1.26",
|
|
138
|
+
"@napi-rs/canvas-linux-arm64-gnu": "0.1.26",
|
|
139
|
+
"@napi-rs/canvas-linux-arm64-musl": "0.1.26",
|
|
140
|
+
"@napi-rs/canvas-darwin-arm64": "0.1.26",
|
|
141
|
+
"@napi-rs/canvas-android-arm64": "0.1.26"
|
|
137
142
|
}
|
|
138
143
|
}
|