skia-canvas 0.9.29 → 0.9.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/CHANGELOG.md +28 -1
- package/README.md +22 -7
- package/lib/browser.js +4 -3
- package/lib/index.d.ts +2 -0
- package/lib/index.js +23 -22
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- ## 🥚 ⟩ [Unreleased] -->
|
|
4
4
|
|
|
5
|
+
## 📦 ⟩ [v0.9.30] ⟩ Jun 7, 2022
|
|
6
|
+
|
|
7
|
+
### New Features
|
|
8
|
+
- Enhacements to the shared **FontLibrary** object:
|
|
9
|
+
- Added a [`reset()`][FontLibrary.reset] method to FontLibrary which uninstalls any fonts that had been dynamically installed via `FontLibrary.use()`
|
|
10
|
+
- The [`use()`][FontLibrary.use] method now checks for previously installed fonts with the same family name (or alias) and will replace them with the newly added font
|
|
11
|
+
- Added pre-compiled binaries for Alpine Linux on arm64
|
|
12
|
+
|
|
13
|
+
### Bugfixes
|
|
14
|
+
- Calling `clip` with an empty path (or one that does not intersect the current clipping mask) will now prevent drawing altogether
|
|
15
|
+
- Transformation (`translate`, `rotate`, etc.) and line-drawing methods (`moveTo`, `lineTo`, `ellipse`, etc.) are now silently ignored if called with `NaN`, `Infinity`, or non-**Number** values in the arguments rather than throwing an error
|
|
16
|
+
- applies to both the Context and Path2D versions of the drawing methods
|
|
17
|
+
- a **TypeError** is thrown only if the number of arguments is too low (mirroring browser behavior)
|
|
18
|
+
- [`conicCurveTo()`][conicCurveTo] now correctly reflects the canvas's transform state
|
|
19
|
+
- The browser-based version of [`loadImage()`][loadImage] now returns a **Promise** that correctly resolves to an **Image** object
|
|
20
|
+
- SVG exports no longer have an invisible, canvas-sized `<rect/>` as their first element
|
|
21
|
+
- Fixed an incompatibility on Alpine between the version of libstdc++ present on the `node:alpine` docker images and the version used when building the precompiled binaries
|
|
22
|
+
|
|
23
|
+
### Misc. Improvements
|
|
24
|
+
- Upgraded Skia to milestone 101
|
|
25
|
+
|
|
26
|
+
[conicCurveTo]: https://github.com/samizdatco/skia-canvas#coniccurvetocpx-cpy-x-y-weight
|
|
27
|
+
[FontLibrary.reset]: https://github.com/samizdatco/skia-canvas#reset
|
|
28
|
+
[FontLibrary.use]: https://github.com/samizdatco/skia-canvas#usefamilyname-fontpaths
|
|
29
|
+
[loadImage]: https://github.com/samizdatco/skia-canvas/#loadimage
|
|
30
|
+
|
|
5
31
|
## 📦 ⟩ [v0.9.29] ⟩ Feb 7, 2022
|
|
6
32
|
|
|
7
33
|
### New Features
|
|
@@ -202,7 +228,8 @@
|
|
|
202
228
|
|
|
203
229
|
**Initial public release** 🎉
|
|
204
230
|
|
|
205
|
-
[unreleased]: https://github.com/samizdatco/skia-canvas/compare/v0.9.
|
|
231
|
+
[unreleased]: https://github.com/samizdatco/skia-canvas/compare/v0.9.30...HEAD
|
|
232
|
+
[v0.9.30]: https://github.com/samizdatco/skia-canvas/compare/v0.9.29...v0.9.30
|
|
206
233
|
[v0.9.29]: https://github.com/samizdatco/skia-canvas/compare/v0.9.28...v0.9.29
|
|
207
234
|
[v0.9.28]: https://github.com/samizdatco/skia-canvas/compare/v0.9.27...v0.9.28
|
|
208
235
|
[v0.9.27]: https://github.com/samizdatco/skia-canvas/compare/v0.9.26...v0.9.27
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ In particular, Skia Canvas:
|
|
|
9
9
|
- is fast and compact since all the heavy lifting is done by native code written in Rust and C++
|
|
10
10
|
- can generate output in both raster (JPEG & PNG) and vector (PDF & SVG) image formats
|
|
11
11
|
- can save images to [files][saveAs], return them as [Buffers][toBuffer], or encode [dataURL][toDataURL_ext] strings
|
|
12
|
-
- uses native threads and [
|
|
12
|
+
- uses native threads and the Node [worker pool](https://github.com/neon-bindings/rfcs/pull/35) for asynchronous rendering and file I/O
|
|
13
13
|
- can create [multiple ‘pages’][newPage] on a given canvas and then [output][saveAs] them as a single, multi-page PDF or an image-sequence saved to multiple files
|
|
14
14
|
- can [simplify][p2d_simplify], [blunt][p2d_round], [combine][bool-ops], [excerpt][p2d_trim], and [atomize][p2d_points] bézier paths using [efficient](https://www.youtube.com/watch?v=OmfliNQsk88) boolean operations or point-by-point [interpolation][p2d_interpolate]
|
|
15
15
|
- can apply [3D perspective][createProjection()] transformations in addition to [scaling][scale()], [rotation][rotate()], and [translation][translate()]
|
|
@@ -52,9 +52,9 @@ Nearly everything you need is statically linked into the library. A notable exce
|
|
|
52
52
|
|
|
53
53
|
### Running in Docker
|
|
54
54
|
|
|
55
|
-
The library is compatible with Linux systems using [glibc](https://www.gnu.org/software/libc/) 2.24 or later as well as Alpine Linux (x64) and the [musl](https://musl.libc.org) C library it favors. In both cases, Fontconfig must be installed on the system for `skia-canvas` to operate correctly.
|
|
55
|
+
The library is compatible with Linux systems using [glibc](https://www.gnu.org/software/libc/) 2.24 or later as well as Alpine Linux (x64 & arm64) and the [musl](https://musl.libc.org) C library it favors. In both cases, Fontconfig must be installed on the system for `skia-canvas` to operate correctly.
|
|
56
56
|
|
|
57
|
-
If you are setting up a [Dockerfile](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/) that uses [`node`](https://hub.docker.com/_/node) as its basis, the simplest approach is to set your `FROM` image to one of the (Debian-derived) defaults like `node:16`, `node:14`, `node:12`, `node:
|
|
57
|
+
If you are setting up a [Dockerfile](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/) that uses [`node`](https://hub.docker.com/_/node) as its basis, the simplest approach is to set your `FROM` image to one of the (Debian-derived) defaults like `node:16`, `node:14`, `node:12`, `node:bullseye`, `node:buster`, or simply:
|
|
58
58
|
```dockerfile
|
|
59
59
|
FROM node
|
|
60
60
|
```
|
|
@@ -398,11 +398,11 @@ The geometry of the quadrilateral should be described as an Array of either 8 or
|
|
|
398
398
|
[left, top, right, bottom] // four edges of a rectangle
|
|
399
399
|
|
|
400
400
|
// internal arrays for grouping are also allowed
|
|
401
|
-
[[x1, y1], [x2, y2], [x3, y3], [x4, y4]]
|
|
401
|
+
[[x1, y1], [x2, y2], [x3, y3], [x4, y4]]
|
|
402
402
|
```
|
|
403
403
|
|
|
404
404
|
##### `basis`
|
|
405
|
-
|
|
405
|
+
|
|
406
406
|
The optional `basis` argument defines the **source** quadrilateral whose corners will be mapped to the positions defined by `quad`. If no `basis` is specified, the canvas's bounding box will be used (i.e., the rectangle from ⟨`0`, `0`⟩ to ⟨`canvas.width`, `canvas.height`⟩). Note that drawing commands that go outside of the `basis` region may well be visible—it only establishes the geometry of the projection, not the [clipping][clip()] path.
|
|
407
407
|
|
|
408
408
|
The `basis` polygon can be described using 2, 4, or 8 numbers, using the canvas dimensions to fill in the unspecified coordinates:
|
|
@@ -414,7 +414,7 @@ The `basis` polygon can be described using 2, 4, or 8 numbers, using the canvas
|
|
|
414
414
|
|
|
415
415
|
----
|
|
416
416
|
|
|
417
|
-
The projection matrix will apply to all types of drawing: shapes, images, and text. This example transforms a white box and red `"@"` character into a trapezoid bounded by the vertical midline of the canvas and its left and right edges. Since no `basis` argument is provided, it will default to using the current canvas bounds as the rectangle to be mapped onto that trapezoid.
|
|
417
|
+
The projection matrix will apply to all types of drawing: shapes, images, and text. This example transforms a white box and red `"@"` character into a trapezoid bounded by the vertical midline of the canvas and its left and right edges. Since no `basis` argument is provided, it will default to using the current canvas bounds as the rectangle to be mapped onto that trapezoid.
|
|
418
418
|
|
|
419
419
|
```js
|
|
420
420
|
let canvas = new Canvas(512, 512),
|
|
@@ -788,6 +788,13 @@ img.onload = function(){
|
|
|
788
788
|
img.src = 'https://example.com/icon.png'
|
|
789
789
|
```
|
|
790
790
|
|
|
791
|
+
```js
|
|
792
|
+
let img = new Image()
|
|
793
|
+
img.src = 'https://example.com/icon.png'
|
|
794
|
+
await img.decode()
|
|
795
|
+
ctx.drawImage(img, 100, 100)
|
|
796
|
+
```
|
|
797
|
+
|
|
791
798
|
```js
|
|
792
799
|
let img = await loadImage('https://example.com/icon.png')
|
|
793
800
|
ctx.drawImage(img, 100, 100)
|
|
@@ -821,6 +828,10 @@ Asking for details about an unknown family will return `undefined`.
|
|
|
821
828
|
|
|
822
829
|
Returns `true` if the family is installed on the system or has been added via `FontLibrary.use()`.
|
|
823
830
|
|
|
831
|
+
##### `reset()`
|
|
832
|
+
|
|
833
|
+
Uninstalls any dynamically loaded fonts that had been added via `FontLibrary.use()`.
|
|
834
|
+
|
|
824
835
|
##### `use(familyName, [...fontPaths])`
|
|
825
836
|
|
|
826
837
|
The `FontLibrary.use()` method allows you to dynamically load local font files and use them with your canvases. By default it will use whatever family name is in the font metadata, but this can be overridden by an alias you provide. Since font-wrangling can be messy, `use` can be called in a number of different ways:
|
|
@@ -844,6 +855,8 @@ FontLibrary.use("Grizwald", [
|
|
|
844
855
|
|
|
845
856
|
###### with a list of ‘glob’ patterns
|
|
846
857
|
|
|
858
|
+
> Note to Windows users: Due to recent changes to the [glob][glob] module, you must write paths using unix-style forward slashes. Backslashes are now used solely for escaping wildcard characters.
|
|
859
|
+
|
|
847
860
|
```js
|
|
848
861
|
// with default family name
|
|
849
862
|
FontLibrary.use(['fonts/Crimson_Pro/*.ttf'])
|
|
@@ -990,4 +1003,6 @@ Many thanks to the [`node-canvas`](https://github.com/Automattic/node-canvas) de
|
|
|
990
1003
|
[translate()]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/translate
|
|
991
1004
|
|
|
992
1005
|
[nonzero]: https://en.wikipedia.org/wiki/Nonzero-rule
|
|
993
|
-
[evenodd]: https://en.wikipedia.org/wiki/Even–odd_rule
|
|
1006
|
+
[evenodd]: https://en.wikipedia.org/wiki/Even–odd_rule
|
|
1007
|
+
|
|
1008
|
+
[glob]: https://github.com/isaacs/node-glob/blob/main/changelog.md#80
|
package/lib/browser.js
CHANGED
|
@@ -9,9 +9,10 @@ const {asBuffer, asDownload, asZipDownload, atScale, options} = require('./io')
|
|
|
9
9
|
|
|
10
10
|
const _toURL_ = Symbol.for("toDataURL")
|
|
11
11
|
|
|
12
|
-
const loadImage = src =>
|
|
13
|
-
Object.assign(new Image(), {crossOrigin:'Anonymous',
|
|
14
|
-
)
|
|
12
|
+
const loadImage = src => {
|
|
13
|
+
let img = Object.assign(new Image(), {crossOrigin:'Anonymous', src})
|
|
14
|
+
return img.decode().then(() => img)
|
|
15
|
+
}
|
|
15
16
|
|
|
16
17
|
class Canvas{
|
|
17
18
|
constructor(width, height){
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -51,7 +51,12 @@ class RustClass{
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
ƒ(fn, ...args){
|
|
54
|
-
|
|
54
|
+
try{
|
|
55
|
+
return this.native[fn](this[ø], ...args)
|
|
56
|
+
}catch(error){
|
|
57
|
+
Error.captureStackTrace(error, this.ƒ)
|
|
58
|
+
throw error
|
|
59
|
+
}
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
62
|
|
|
@@ -158,10 +163,8 @@ class Canvas extends RustClass{
|
|
|
158
163
|
|
|
159
164
|
opts = typeof opts=='number' ? {quality:opts} : opts
|
|
160
165
|
let {format, quality, pages, padding, pattern, density, outline, matte} = io.options(this.pages, {filename, ...opts}),
|
|
161
|
-
args = [pages.map(core), pattern, padding, format, quality, density, outline, matte]
|
|
162
|
-
|
|
163
|
-
this.ƒ("save", (result, msg) => worker.emit(result, msg), ...args)
|
|
164
|
-
return new Promise((res, rej) => worker.once('ok', res).once('err', msg => rej(new Error(msg))) )
|
|
166
|
+
args = [pages.map(core), pattern, padding, format, quality, density, outline, matte]
|
|
167
|
+
return this.ƒ("save", ...args)
|
|
165
168
|
}
|
|
166
169
|
|
|
167
170
|
saveAsSync(filename, opts={}){
|
|
@@ -175,10 +178,8 @@ class Canvas extends RustClass{
|
|
|
175
178
|
|
|
176
179
|
opts = typeof opts=='number' ? {quality:opts} : opts
|
|
177
180
|
let {format, quality, pages, density, outline, matte} = io.options(this.pages, {extension, ...opts}),
|
|
178
|
-
args = [pages.map(core), format, quality, density, outline, matte]
|
|
179
|
-
|
|
180
|
-
this.ƒ("toBuffer", (result, msg) => worker.emit(result, msg), ...args)
|
|
181
|
-
return new Promise((res, rej) => worker.once('ok', res).once('err', msg => rej(new Error(msg))) )
|
|
181
|
+
args = [pages.map(core), format, quality, density, outline, matte];
|
|
182
|
+
return this.ƒ("toBuffer", ...args)
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
toBufferSync(extension="png", opts={}){
|
|
@@ -292,10 +293,10 @@ class CanvasRenderingContext2D extends RustClass{
|
|
|
292
293
|
this.currentTransform = arguments.length > 1 ? [...arguments] : matrix
|
|
293
294
|
}
|
|
294
295
|
|
|
295
|
-
transform(
|
|
296
|
-
translate(x, y){ this.ƒ('translate',
|
|
297
|
-
scale(x, y){ this.ƒ('scale',
|
|
298
|
-
rotate(angle){ this.ƒ('rotate',
|
|
296
|
+
transform(a, b, c, d, e, f){ this.ƒ('transform', ...arguments)}
|
|
297
|
+
translate(x, y){ this.ƒ('translate', ...arguments)}
|
|
298
|
+
scale(x, y){ this.ƒ('scale', ...arguments)}
|
|
299
|
+
rotate(angle){ this.ƒ('rotate', ...arguments)}
|
|
299
300
|
|
|
300
301
|
createProjection(quad, basis){
|
|
301
302
|
return fromSkMatrix(this.ƒ("createProjection", [quad].flat(), [basis].flat()))
|
|
@@ -306,15 +307,15 @@ class CanvasRenderingContext2D extends RustClass{
|
|
|
306
307
|
rect(x, y, width, height){ this.ƒ('rect', ...arguments) }
|
|
307
308
|
arc(x, y, radius, startAngle, endAngle, isCCW){ this.ƒ('arc', ...arguments) }
|
|
308
309
|
ellipse(x, y, xRadius, yRadius, rotation, startAngle, endAngle, isCCW){ this.ƒ('ellipse', ...arguments) }
|
|
309
|
-
moveTo(x, y){ this.ƒ('moveTo',
|
|
310
|
-
lineTo(x, y){ this.ƒ('lineTo',
|
|
310
|
+
moveTo(x, y){ this.ƒ('moveTo', ...arguments) }
|
|
311
|
+
lineTo(x, y){ this.ƒ('lineTo', ...arguments) }
|
|
311
312
|
arcTo(x1, y1, x2, y2, radius){ this.ƒ('arcTo', ...arguments) }
|
|
312
313
|
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y){ this.ƒ('bezierCurveTo', ...arguments) }
|
|
313
314
|
quadraticCurveTo(cpx, cpy, x, y){ this.ƒ('quadraticCurveTo', ...arguments) }
|
|
314
315
|
conicCurveTo(cpx, cpy, x, y, weight){ this.ƒ("conicCurveTo", ...arguments) }
|
|
315
316
|
closePath(){ this.ƒ('closePath') }
|
|
316
|
-
isPointInPath(x, y){ return this.ƒ('isPointInPath',
|
|
317
|
-
isPointInStroke(x, y){ return this.ƒ('isPointInStroke',
|
|
317
|
+
isPointInPath(x, y){ return this.ƒ('isPointInPath', ...arguments) }
|
|
318
|
+
isPointInStroke(x, y){ return this.ƒ('isPointInStroke', ...arguments) }
|
|
318
319
|
|
|
319
320
|
// -- using paths -----------------------------------------------------------
|
|
320
321
|
fill(path, rule){
|
|
@@ -527,6 +528,8 @@ class FontLibrary extends RustClass {
|
|
|
527
528
|
throw new Error("Expected an array of file paths or an object mapping family names to font files")
|
|
528
529
|
}
|
|
529
530
|
}
|
|
531
|
+
|
|
532
|
+
reset(){ return this.ƒ('reset') }
|
|
530
533
|
}
|
|
531
534
|
|
|
532
535
|
class Image extends RustClass {
|
|
@@ -670,8 +673,8 @@ class Path2D extends RustClass{
|
|
|
670
673
|
}
|
|
671
674
|
|
|
672
675
|
// line segments
|
|
673
|
-
moveTo(x, y){ this.ƒ("moveTo",
|
|
674
|
-
lineTo(x, y){ this.ƒ("lineTo",
|
|
676
|
+
moveTo(x, y){ this.ƒ("moveTo", ...arguments) }
|
|
677
|
+
lineTo(x, y){ this.ƒ("lineTo", ...arguments) }
|
|
675
678
|
closePath(){ this.ƒ("closePath") }
|
|
676
679
|
arcTo(x1, y1, x2, y2, radius){ this.ƒ("arcTo", ...arguments) }
|
|
677
680
|
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y){ this.ƒ("bezierCurveTo", ...arguments) }
|
|
@@ -745,9 +748,7 @@ class TextMetrics{
|
|
|
745
748
|
}
|
|
746
749
|
}
|
|
747
750
|
|
|
748
|
-
const loadImage = src => new
|
|
749
|
-
Object.assign(new Image(), {onload, onerror, src})
|
|
750
|
-
)
|
|
751
|
+
const loadImage = src => Object.assign(new Image(), {src}).decode()
|
|
751
752
|
|
|
752
753
|
module.exports = {
|
|
753
754
|
Canvas, CanvasGradient, CanvasPattern, CanvasRenderingContext2D, CanvasTexture,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skia-canvas",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.30",
|
|
4
4
|
"description": "A canvas environment for Node",
|
|
5
5
|
"author": "Christian Swinehart <drafting@samizdat.co>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,21 +25,21 @@
|
|
|
25
25
|
"test": "jest"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@mapbox/node-pre-gyp": "^1.0.
|
|
28
|
+
"@mapbox/node-pre-gyp": "^1.0.9",
|
|
29
29
|
"cargo-cp-artifact": "^0.1",
|
|
30
|
-
"glob": "^
|
|
30
|
+
"glob": "^8.0.3",
|
|
31
31
|
"path-browserify": "^1.0.1",
|
|
32
32
|
"simple-get": "^4.0.1",
|
|
33
33
|
"string-split-by": "^1.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/jest": "^27.
|
|
37
|
-
"@types/node": "^17.0.
|
|
38
|
-
"aws-sdk": "^2.
|
|
39
|
-
"express": "^4.
|
|
40
|
-
"jest": "^
|
|
36
|
+
"@types/jest": "^27.5.1",
|
|
37
|
+
"@types/node": "^17.0.38",
|
|
38
|
+
"aws-sdk": "^2.1146.0",
|
|
39
|
+
"express": "^4.18.1",
|
|
40
|
+
"jest": "^28.1.0",
|
|
41
41
|
"lodash": "^4.17.21",
|
|
42
|
-
"nodemon": "^2.0.
|
|
42
|
+
"nodemon": "^2.0.16",
|
|
43
43
|
"tmp": "^0.2.1"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|