{"id":13446128,"url":"https://github.com/samizdatco/skia-canvas","last_synced_at":"2025-04-23T20:56:31.431Z","repository":{"id":41062314,"uuid":"285112082","full_name":"samizdatco/skia-canvas","owner":"samizdatco","description":"A GPU-accelerated 2D graphics environment for Node.js","archived":false,"fork":false,"pushed_at":"2025-01-28T03:37:42.000Z","size":4401,"stargazers_count":2291,"open_issues_count":34,"forks_count":81,"subscribers_count":18,"default_branch":"main","last_synced_at":"2025-04-23T20:56:12.643Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/samizdatco.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-04T22:12:53.000Z","updated_at":"2025-04-22T15:09:52.000Z","dependencies_parsed_at":"2024-02-04T07:43:27.706Z","dependency_job_id":"09b2597a-697d-491b-ab22-0c6096bca078","html_url":"https://github.com/samizdatco/skia-canvas","commit_stats":{"total_commits":1084,"total_committers":11,"mean_commits":98.54545454545455,"dds":"0.023062730627306238","last_synced_commit":"f125bcb10f09bc59a26cf8ffbbad758215273abe"},"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samizdatco%2Fskia-canvas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samizdatco%2Fskia-canvas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samizdatco%2Fskia-canvas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samizdatco%2Fskia-canvas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samizdatco","download_url":"https://codeload.github.com/samizdatco/skia-canvas/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250514767,"owners_count":21443208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T05:00:46.423Z","updated_at":"2025-04-23T20:56:31.406Z","avatar_url":"https://github.com/samizdatco.png","language":"Rust","funding_links":[],"categories":["Libraries","Rust","Repository","JavaScript","Packages","Uncategorized"],"sub_categories":["Runtime","Canvas","Uncategorized"],"readme":"\u003ca href=\"https://skia-canvas.org\"\u003e\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/assets/hero-dark@2x.png\"\u003e\n  \u003cimg alt=\"Skia Canvas\" src=\"docs/assets/hero@2x.png\"\u003e\n\u003c/picture\u003e\n\n\u003c/a\u003e\n\n---\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"http://skia-canvas.org/getting-started\"\u003eGetting Started\u003c/a\u003e \u003cspan\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003c/span\u003e\n  \u003ca href=\"http://skia-canvas.org/api\"\u003eDocumentation\u003c/a\u003e \u003cspan\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003c/span\u003e\n  \u003ca href=\"http://skia-canvas.org/releases\"\u003eRelease Notes\u003c/a\u003e  \u003cspan\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003c/span\u003e\n  \u003ca href=\"https://github.com/samizdatco/skia-canvas/discussions\"\u003eDiscussion Forum\u003c/a\u003e\n\u003c/div\u003e\n\n---\n\nSkia Canvas is a browser-less implementation of the HTML Canvas drawing API for Node.js. It is based on Google’s [Skia](https://skia.org) graphics engine and, accordingly, produces very similar results to Chrome’s `\u003ccanvas\u003e` element. The library is well suited for use on desktop machines where you can render hardware-accelerated graphics to a window and on the server where it can output a variety of image formats.\n\nWhile the primary goal of this project is to provide a reliable emulation of the [standard API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) according to the [spec](https://html.spec.whatwg.org/multipage/canvas.html), it also extends it in a number of areas to take greater advantage of Skia's advanced graphical features and provide a more expressive coding environment.\n\nIn particular, Skia Canvas:\n\n  - is fast and compact since rendering takes place on the GPU and all the heavy lifting is done by native code written in Rust and C++\n  - can render to [windows][window] using an OS-native graphics pipeline and provides a browser-like [UI event][win_bind] framework\n  - generates images in both raster (JPEG, PNG, \u0026 WEBP) and vector (PDF \u0026 SVG) formats\n  - can save images to [files][saveAs], return them as [Buffers][toBuffer], or encode [dataURL][toDataURL_ext] strings\n  - uses native threads in a [user-configurable][multithreading] worker pool for asynchronous rendering and file I/O\n  - 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\n  - 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]\n  - provides [3D perspective][createProjection()] transformations in addition to [scaling][scale()], [rotation][rotate()], and [translation][translate()]\n  - can fill shapes with vector-based [Textures][createTexture()] in addition to bitmap-based [Patterns][createPattern()] and supports line-drawing with custom [markers][lineDashMarker]\n  - supports the full set of [CSS filter][filter] image processing operators\n  - offers rich typographic control including:\n    - multi-line, [word-wrapped][textwrap] text\n    - line-by-line [text metrics][c2d_measuretext]\n    - small-caps, ligatures, and other opentype features accessible using standard [font-variant][fontvariant] syntax\n    - proportional [letter-spacing][letterSpacing], [word-spacing][wordSpacing], and [leading][c2d_font]\n    - support for [variable fonts][VariableFonts] and transparent mapping of weight values\n    - use of non-system fonts [loaded][fontlibrary-use] from local files\n\n## Installation\n\nIf you’re running on a supported platform, installation should be as simple as:\n```bash\nnpm install skia-canvas\n```\n\nThis will download a pre-compiled library from the project’s most recent [release](https://github.com/samizdatco/skia-canvas/releases).\n\n## Platform Support\n\nThe underlying Rust library uses [N-API][node_napi] v8 which allows it to run on Node.js versions:\n  - v12.22+\n  - v14.17+\n  - v15.12+\n  - v16.0.0 and later\n\nPre-compiled binaries are available for:\n\n  - Linux (x64 \u0026 arm64)\n  - macOS (x64 \u0026 Apple silicon)\n  - Windows (x64)\n\nNearly everything you need is statically linked into the library. A notable exception is the [Fontconfig](https://www.freedesktop.org/wiki/Software/fontconfig/) library which must be installed separately if you’re running on Linux.\n\n## Running in Docker\n\nThe library is compatible with Linux systems using [glibc](https://www.gnu.org/software/libc/) 2.28 or later as well as Alpine Linux (x64 \u0026 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.\n\nIf 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:lts`, `node:18`, `node:16`, `node:14-buster`, `node:12-buster`, `node:bullseye`, `node:buster`, or simply:\n```dockerfile\nFROM node\n```\n\nYou can also use the ‘slim’ image if you manually install fontconfig:\n\n```dockerfile\nFROM node:slim\nRUN apt-get update \u0026\u0026 apt-get install -y -q --no-install-recommends libfontconfig1\n```\n\nIf you wish to use Alpine as the underlying distribution, you can start with something along the lines of:\n\n```dockerfile\nFROM node:alpine\nRUN apk update \u0026\u0026 apk add fontconfig\n```\n\n## Compiling from Source\n\nIf prebuilt binaries aren’t available for your system you’ll need to compile the portions of this library that directly interface with Skia.\n\nStart by installing:\n\n  1. The [Rust compiler](https://www.rust-lang.org/tools/install) and cargo package manager using [`rustup`](https://rust-lang.github.io/rustup/)\n  2. A C compiler toolchain (either LLVM/Clang or MSVC)\n  4. Python 3 (used by Skia's [build process](https://skia.org/docs/user/build/))\n  3. The [Ninja](https://ninja-build.org) build system\n  5. On Linux: Fontconfig and OpenSSL\n\n[Detailed instructions](https://github.com/rust-skia/rust-skia#building) for setting up these dependencies on different operating systems can be found in the ‘Building’ section of the Rust Skia documentation. Once all the necessary compilers and libraries are present, running `npm run build` will give you a usable library (after a fairly lengthy compilation process).\n\n## Multithreading\n\nWhen rendering canvases in the background (e.g., by using the asynchronous [saveAs][saveAs] or [toBuffer][toBuffer] methods), tasks are spawned in a thread pool managed by the [rayon][rayon] library. By default it will create up to as many threads as your CPU has cores. You can see this default value by inspecting any [Canvas][canvas] object's [`engine.threads`][engine] property. If you wish to override this default, you can set the `SKIA_CANVAS_THREADS` environment variable to your preferred value.\n\nFor example, you can limit your asynchronous processing to two simultaneous tasks by running your script with:\n```bash\nSKIA_CANVAS_THREADS=2 node my-canvas-script.js\n```\n\n## Example Usage\n\n### Generating image files\n\n```js\nimport {Canvas} from 'skia-canvas'\n\nlet canvas = new Canvas(400, 400),\n    ctx = canvas.getContext(\"2d\"),\n    {width, height} = canvas;\n\nlet sweep = ctx.createConicGradient(Math.PI * 1.2, width/2, height/2)\nsweep.addColorStop(0, \"red\")\nsweep.addColorStop(0.25, \"orange\")\nsweep.addColorStop(0.5, \"yellow\")\nsweep.addColorStop(0.75, \"green\")\nsweep.addColorStop(1, \"red\")\nctx.strokeStyle = sweep\nctx.lineWidth = 100\nctx.strokeRect(100,100, 200,200)\n\n// render to multiple destinations using a background thread\nasync function render(){\n  // save a ‘retina’ image...\n  await canvas.saveAs(\"rainbox.png\", {density:2})\n  // ...or use a shorthand for canvas.toBuffer(\"png\")\n  let pngData = await canvas.png\n  // ...or embed it in a string\n  let pngEmbed = `\u003cimg src=\"${await canvas.toDataURL(\"png\")}\"\u003e`\n}\nrender()\n\n// ...or save the file synchronously from the main thread\ncanvas.saveAsSync(\"rainbox.pdf\")\n```\n\n### Multi-page sequences\n\n```js\nimport {Canvas} from 'skia-canvas'\n\nlet canvas = new Canvas(400, 400),\n    ctx = canvas.getContext(\"2d\"),\n    {width, height} = canvas\n\nfor (const color of ['orange', 'yellow', 'green', 'skyblue', 'purple']){\n  ctx = canvas.newPage()\n  ctx.fillStyle = color\n  ctx.fillRect(0,0, width, height)\n  ctx.fillStyle = 'white'\n  ctx.arc(width/2, height/2, 40, 0, 2 * Math.PI)\n  ctx.fill()\n}\n\nasync function render(){\n  // save to a multi-page PDF file\n  await canvas.saveAs(\"all-pages.pdf\")\n\n  // save to files named `page-01.png`, `page-02.png`, etc.\n  await canvas.saveAs(\"page-{2}.png\")\n}\nrender()\n```\n\n### Rendering to a window\n\n```js\nimport {Window} from 'skia-canvas'\n\nlet win = new Window(300, 300)\nwin.title = \"Canvas Window\"\nwin.on(\"draw\", e =\u003e {\n  let ctx = e.target.canvas.getContext(\"2d\")\n  ctx.lineWidth = 25 + 25 * Math.cos(e.frame / 10)\n  ctx.beginPath()\n  ctx.arc(150, 150, 50, 0, 2 * Math.PI)\n  ctx.stroke()\n\n  ctx.beginPath()\n  ctx.arc(150, 150, 10, 0, 2 * Math.PI)\n  ctx.stroke()\n  ctx.fill()\n})\n```\n## Acknowledgements\n\nThis project is deeply indebted to the work of the [Rust Skia project](https://github.com/rust-skia/rust-skia) whose Skia bindings provide a safe and idiomatic interface to the mess of C++ that lies underneath. Many thanks to the developers of [node-canvas](https://github.com/Automattic/node-canvas) for their terrific set of unit tests. In the absence of an [Acid Test](https://www.acidtests.org) for canvas, these routines were invaluable.\n\n\n### Notable contributors\n\n- [@mpaparno](https://github.com/mpaparno) contributed support for SVG rendering, raw image-buffer handling, WEBP import/export and numerous bugfixes\n- [@Salmondx](https://github.com/Salmondx) developed the initial Raw image loading \u0026 rendering routines\n- [@lucasmerlin](https://github.com/lucasmerlin) helped get GPU rendering working on Vulkan\n- [@cprecioso](https://github.com/cprecioso) \u0026 [@saantonandre](https://github.com/saantonandre) corrected and expanded upon the TypeScript type definitions\n- [@meihuanyu](https://github.com/meihuanyu) contributed filter \u0026 path rendering fixes\n\n## Copyright\n© 2020–2025 [Samizdat Drafting Co.](https://samizdat.co)\n\n[bool-ops]: https://skia-canvas.org/api/path2d#complement-difference-intersect-union-and-xor\n[c2d_font]: https://skia-canvas.org/api/context#font\n[c2d_measuretext]: https://skia-canvas.org/api/context#measuretext\n[canvas]: https://skia-canvas.org/api/canvas\n[createProjection()]: https://skia-canvas.org/api/context#createprojection\n[createTexture()]: https://skia-canvas.org/api/context#createtexture\n[engine]: https://skia-canvas.org/api/canvas#engine\n[fontlibrary-use]: https://skia-canvas.org/api/font-library#use\n[fontvariant]: https://skia-canvas.org/api/context#fontvariant\n[lineDashMarker]: https://skia-canvas.org/api/context#linedashmarker\n[newPage]: https://skia-canvas.org/api/canvas#newpage\n[p2d_interpolate]: https://skia-canvas.org/api/path2d#interpolate\n[p2d_points]: https://skia-canvas.org/api/path2d#points\n[p2d_round]: https://skia-canvas.org/api/path2d#round\n[p2d_simplify]: https://skia-canvas.org/api/path2d#simplify\n[p2d_trim]: https://skia-canvas.org/api/path2d#trim\n[saveAs]: https://skia-canvas.org/api/canvas#saveas\n[textwrap]: https://skia-canvas.org/api/context#textwrap\n[toBuffer]: https://skia-canvas.org/api/canvas#tobuffer\n[toDataURL_ext]: https://skia-canvas.org/api/canvas#todataurl\n[win_bind]: https://skia-canvas.org/api/window#on--off--once\n[window]: https://skia-canvas.org/api/window\n[multithreading]: https://skia-canvas.org/getting-started#multithreading\n[node_napi]: https://nodejs.org/api/n-api.html#node-api-version-matrix\n[rayon]: https://crates.io/crates/rayon\n[VariableFonts]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide\n[filter]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter\n[letterSpacing]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/letterSpacing\n[wordSpacing]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/wordSpacing\n[createPattern()]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createPattern\n[rotate()]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/rotate\n[scale()]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/scale\n[translate()]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/translate\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamizdatco%2Fskia-canvas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamizdatco%2Fskia-canvas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamizdatco%2Fskia-canvas/lists"}