@napi-rs/canvas 0.1.22 → 0.1.25

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # `skr canvas`
2
2
 
3
3
  ![CI](https://github.com/Brooooooklyn/canvas/workflows/CI/badge.svg)
4
- ![Skia Version](https://img.shields.io/badge/Skia-chrome%2Fm103-hotpink)
4
+ ![Skia Version](https://img.shields.io/badge/Skia-chrome%2Fm104-hotpink)
5
5
  [![install size](https://packagephobia.com/badge?p=@napi-rs/canvas)](https://packagephobia.com/result?p=@napi-rs/canvas)
6
6
  [![Downloads](https://img.shields.io/npm/dm/@napi-rs/canvas.svg?sanitize=true)](https://npmcharts.com/compare/@napi-rs/canvas?minimal=true)
7
7
 
package/index.d.ts CHANGED
@@ -388,3 +388,14 @@ export const enum SvgExportFlag {
388
388
  }
389
389
 
390
390
  export function convertSVGTextToPath(svg: Buffer | string): Buffer
391
+
392
+ export interface LoadImageOptions {
393
+ alt?: string,
394
+ maxRedirects?: number,
395
+ requestOptions?: import('http').RequestOptions,
396
+ }
397
+
398
+ export function loadImage(
399
+ source: string | URL | Buffer | ArrayBufferLike | Uint8Array | Image | import('stream').Readable,
400
+ options?: LoadImageOptions,
401
+ ): 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,
@@ -344,4 +346,5 @@ module.exports = {
344
346
  DOMPoint,
345
347
  DOMMatrix,
346
348
  DOMRect,
349
+ loadImage,
347
350
  }
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(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.22",
3
+ "version": "0.1.25",
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",
@@ -94,7 +95,7 @@
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)": [
@@ -125,14 +126,14 @@
125
126
  },
126
127
  "packageManager": "yarn@3.2.1",
127
128
  "optionalDependencies": {
128
- "@napi-rs/canvas-win32-x64-msvc": "0.1.22",
129
- "@napi-rs/canvas-darwin-x64": "0.1.22",
130
- "@napi-rs/canvas-linux-x64-gnu": "0.1.22",
131
- "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.22",
132
- "@napi-rs/canvas-linux-x64-musl": "0.1.22",
133
- "@napi-rs/canvas-linux-arm64-gnu": "0.1.22",
134
- "@napi-rs/canvas-linux-arm64-musl": "0.1.22",
135
- "@napi-rs/canvas-darwin-arm64": "0.1.22",
136
- "@napi-rs/canvas-android-arm64": "0.1.22"
129
+ "@napi-rs/canvas-win32-x64-msvc": "0.1.25",
130
+ "@napi-rs/canvas-darwin-x64": "0.1.25",
131
+ "@napi-rs/canvas-linux-x64-gnu": "0.1.25",
132
+ "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.25",
133
+ "@napi-rs/canvas-linux-x64-musl": "0.1.25",
134
+ "@napi-rs/canvas-linux-arm64-gnu": "0.1.25",
135
+ "@napi-rs/canvas-linux-arm64-musl": "0.1.25",
136
+ "@napi-rs/canvas-darwin-arm64": "0.1.25",
137
+ "@napi-rs/canvas-android-arm64": "0.1.25"
137
138
  }
138
139
  }