High performance Skia canvas implementation. Zero system dependencies.
High performance Skia canvas implementation. Zero system dependencies.
skr canvasHelp me to become a full-time open-source developer by sponsoring me on Github
Google Skia binding to Node.js via Node-API, 0 System dependencies!
yarn add @napi-rs/canvas
npm install @napi-rs/canvasarm64cortex-a57 or newer CPU architecture on Linux.
All Apple M chips on macOS.
armv7cortex-a7 or newer CPU architecture.
Since Skia relies on the glibc 2.18 API, you need to have at least glibc version >= 2.18 on your system.
To use this library on Lambda you will need to use a Lambda layer.
You can simply attach a lambda layer by getting an ARN from Canvas-Lambda-Layer
Make sure to exclude
@napi-rs/canvaswhile bundling your Lambda.
……See benchmark for benchmark code.
Hardware info:
……new Path2D()
new Path2D(path: Path2D)
// new Path2D('M108.956,403.826c0,0,0.178,3.344-1.276,3.311 c-1.455-0.033-30.507-84.917-66.752-80.957C40.928,326.18,72.326,313.197,108.956,403.826z')
new Path2D(path: string)…PathKit is a toolset for manipulating Path in Skia, supporting quadratic beziers, cubic beziers and conics.
The main features are.
.op(path, PathOp)
const pathOne = new Path2D(
'M8 50H92C96.4183 50 100 53.5817 100 58V142C100 146.418 96.4183 150 92 150H8C3.58172 150 0 146.418 0 142V58C0 53.5817 3.58172 50 8 50Z',
)
const pathTwo = new Path2D(
'"M58 0H142C146.418 0 150 3.58172 150 8V92C150 96.4183 146.418 100 142 100H58C53.5817 100 50 96.4183 50 92V8C50 3.58172 53.5817 0 58 0Z',
)
pathOne.op(pathTwo, PathOp.Intersect).toSVGString()
// => "M100 100L58 100C53.5817 100 50 96.4183 50 92L50 50L92 50C96.4183 50 100 53.5817 100 58L100 100Z"FillType in Path.asWinding()
You can convert fill-rule="evenodd" to fill-rule="nonzero" in SVG.
This is useful for OpenType font-related tools, as fill-rule="nonzero" is only supported in OpenType fonts.
….simplify()
Set the path to the same non-overlapping contour as the original path area, which means that it can also remove overlapping paths.
SVG with overlapping paths (Left)
…Render Lottie animations using Skia's Skottie module.
const { LottieAnimation } = require('@napi-rs/canvas')
// Load from file
const animation = LottieAnimation.loadFromFile('animation.json')
// Load from JSON string with resource path for external assets
const animation = LottieAnimation.loadFromData(jsonString, {
resourcePath: '/path/to/assets',
})animation.duration // Total duration in seconds
animation.fps // Frames per second
animation.frames // Total frame count
animation.width // Animation width
animation.height // Animation height
animation.version // Lottie format versionanimation.seekFrame(30) // Seek to frame 30
animation.seek(1.5) // Seek to 1.5 secondsconst { createCanvas, LottieAnimation } = require('@napi-rs/canvas')
const animation = LottieAnimation.loadFromFile('animation.json')
const canvas = createCanvas(animation.width, animation.height)
const ctx = canvas.getContext('2d')
// Render at original size
animation.render(ctx)
// Render with custom destination rect
animation.render(ctx, { x: 0, y: 0, width: 800, height: 600 })data:image/png;base64,...)resourcePath directory.lottie ZIP files at runtime (see example)See example/lottie-to-video.ts for encoding Lottie animations to MP4 using @napi-rs/webcodecs.
import { createCanvas, LottieAnimation } from '@napi-rs/canvas'
import {
VideoEncoder,
VideoFrame,
Mp4Muxer,
type EncodedVideoChunk,
type EncodedVideoChunkMetadata,
} from '@napi-rs/webcodecs'
const animation = LottieAnimation.loadFromFile('animation.json')
const canvas = createCanvas(animation.width, animation.height)
const ctx = canvas.getContext('2d')
for (let frame = 0; frame < animation.frames; frame++) {
animation.seekFrame(frame)
ctx.fillStyle = '#ffffff'
ctx.fillRect(0, 0, canvas.width, canvas.height)
animation.render(ctx)
// Encode frame to video...
}The tiger.json was serialized from gojs/samples/tiger
node example/anime-girl.js| SVG | PNG |
|---|---|
CC-BY-SA 3.0 by Niabot |
CC-BY-SA 3.0 by Niabot |
You can build this project from source, the system requirements are here: https://skia.org/docs/user/build
# Clone the code:
$ git clone --recurse-submodules https://github.com/Brooooooklyn/canvas.git
$ cd canvas
# Build Skia:
$ node scripts/build-skia.js
# Install NPM packages, build the Node.js addon:
$ npm install -g yarn
$ 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`
$ sudo dnf install clang # https://fedora.pkgs.org/34/fedora-x86_64/clang-12.0.0-0.3.rc1.fc34.x86_64.rpm.html
$ yarn build
# All done! Run test cases or examples now:
$ yarn test
$ node example/tiger.jsYou can pull skia pre-build binaries if you just care the Rust part:
# Clone the code:
$ git clone --recurse-submodules https://github.com/Brooooooklyn/canvas.git
$ cd canvas
# Download Skia binaries:
# It will pull the binaries match the git hash in `./skia` submodule
$ node scripts/release-skia-binary.mjs --download
# Install NPM packages, build the Node.js addon:
$ npm install -g yarn
$ yarn install --mode=skip-build
$ sudo dnf install clang # https://fedora.pkgs.org/34/fedora-x86_64/clang-12.0.0-0.3.rc1.fc34.x86_64.rpm.html
$ yarn build
# All done! Run test cases or examples now:
$ yarn test
$ node example/tiger.jsNo open issues yet, or sync has not completed.