# node-canvas
**Repository Path**: mirrors_addons/node-canvas
## Basic Information
- **Project Name**: node-canvas
- **Description**: Node canvas is a Cairo backed Canvas implementation for NodeJS.
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-27
- **Last Updated**: 2026-09-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# node-canvas

[](http://badge.fury.io/js/canvas)
node-canvas is a [Cairo](http://cairographics.org/)-backed Canvas implementation for [Node.js](http://nodejs.org).
## Installation
The latest version of node-canvas is v4. It fixes a plethora of font related issues, adds support for worker threads, reduces binary size, removes the post install script, expands the platforms that binaries support, and more. It is still in the pre-release phase. We appreciate any feedback.
```bash
$ npm install canvas@next
```
To get v3:
```bash
$ npm install canvas
```
The minimum version of Node.js required is **22**.
Binaries will be installed for the following platforms:
- macOS x64/arm64
- Linux x64/x86/arm64 (glibc or musl)
- Linux arm/riscv64 (glibc)
- Windows x64/x86/arm64
If you want to install for a more exotic system, CD into the package and run
`zig build`. You may need to tweak build.zig. PRs are welcome.
## Quick Example
```javascript
const { createCanvas, loadImage } = require('canvas')
const canvas = createCanvas(200, 200)
const ctx = canvas.getContext('2d')
// Write "Awesome!"
ctx.font = '30px Impact'
ctx.rotate(0.1)
ctx.fillText('Awesome!', 50, 100)
// Draw line under text
var text = ctx.measureText('Awesome!')
ctx.strokeStyle = 'rgba(0,0,0,0.5)'
ctx.beginPath()
ctx.lineTo(50, 102)
ctx.lineTo(50 + text.width, 102)
ctx.stroke()
// Draw cat with lime helmet
loadImage('examples/images/lime-cat.jpg').then((image) => {
ctx.drawImage(image, 50, 0, 70, 70)
console.log('
')
})
```
## Documentation
This project is an implementation of the Web Canvas API and implements that API as closely as possible. For API documentation, please visit [Mozilla Web Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API). (See [Compatibility Status](https://github.com/Automattic/node-canvas/wiki/Compatibility-Status) for the current API compliance.) All utility methods and non-standard APIs are documented below.
### Utility methods
* [createCanvas()](#createcanvas)
* [createImageData()](#createimagedata)
* [loadImage()](#loadimage)
### Font API
* [FontFace](#fontface)
* [fonts](#fonts)
### Non-standard APIs
* [Image#src](#imagesrc)
* [Image#dataMode](#imagedatamode)
* [Canvas#toBuffer()](#canvastobuffer)
* [Canvas#createPNGStream()](#canvascreatepngstream)
* [Canvas#createJPEGStream()](#canvascreatejpegstream)
* [Canvas#createPDFStream()](#canvascreatepdfstream)
* [Canvas#toDataURL()](#canvastodataurl)
* [CanvasRenderingContext2D#patternQuality](#canvasrenderingcontext2dpatternquality)
* [CanvasRenderingContext2D#quality](#canvasrenderingcontext2dquality)
* [CanvasRenderingContext2D#textDrawingMode](#canvasrenderingcontext2dtextdrawingmode)
* [CanvasRenderingContext2D#globalCompositeOperation = 'saturate'](#canvasrenderingcontext2dglobalcompositeoperation--saturate)
* [CanvasRenderingContext2D#antialias](#canvasrenderingcontext2dantialias)
### createCanvas()
> ```ts
> createCanvas(width: number, height: number, type?: 'PDF'|'SVG') => Canvas
> ```
Creates a Canvas instance. This method works in both Node.js and Web browsers, where there is no Canvas constructor. (See `browser.js` for the implementation that runs in browsers.)
```js
const { createCanvas } = require('canvas')
const mycanvas = createCanvas(200, 200)
const myPDFcanvas = createCanvas(600, 800, 'pdf') // see "PDF Support" section
```
### createImageData()
> ```ts
> createImageData(width: number, height: number) => ImageData
> createImageData(data: Uint8ClampedArray, width: number, height?: number) => ImageData
> // for alternative pixel formats:
> createImageData(data: Uint16Array, width: number, height?: number) => ImageData
> ```
Creates an ImageData instance. This method works in both Node.js and Web browsers.
```js
const { createImageData } = require('canvas')
const width = 20, height = 20
const arraySize = width * height * 4
const mydata = createImageData(new Uint8ClampedArray(arraySize), width)
```
### loadImage()
> ```ts
> loadImage() => Promise
> ```
Convenience method for loading images. This method works in both Node.js and Web browsers.
```js
const { loadImage } = require('canvas')
const myimg = loadImage('http://server.com/image.png')
myimg.then(() => {
// do something with image
}).catch(err => {
console.log('oh no!', err)
})
// or with async/await:
const myimg = await loadImage('http://server.com/image.png')
// do something with image
```
### FontFace
> ```ts
>
> interface FontFaceDescriptors {
> weight?: string | number;
> style?: string;
> }
>
> class FontFace {
> constructor(
> family: string,
> source: string | ArrayBuffer | Uint8Array,
> descriptors?: FontFaceDescriptors
> )
>
> family: string;
> style: string;
> weight: string;
> status: 'loaded' | 'unloaded' | 'error';
> }
>
> ```
To use your own font file, create a `FontFace` with the file path and add it to [`fonts`](#fonts). `fonts` is just like the browser's `document.fonts`, but with a slightly more limited API.
```js
const { createCanvas, FontFace, fonts } = require('canvas')
fonts.add(new FontFace('Comic Sans', '/home/you/comicsans.ttf'))
const canvas = createCanvas(500, 500)
const ctx = canvas.getContext('2d')
ctx.font = '12px "Comic Sans"'
ctx.fillText('Everyone hates this font :(', 250, 10)
```
The second argument can either be a path to the font file or a buffer in TrueType format. The third argument is an object with properties that resemble the CSS properties that are specified in `@font-face` rules. You must specify at least `family`. `weight` and `style` are optional and default to `'normal'`.
### fonts
> ```ts
>
> class FontFaceSet {
> add(face: FontFace): void;
> has(face: FontFace): boolean;
> clear(): void;
> delete(face: FontFace): boolean;
> [Symbol.iterator](): Iterator;
> size: number;
> }
>
> fonts: FontFaceSet
> ```
`fonts` implements a subset of the browser's `document.fonts`. Use `fonts.delete()` to unregister an individual font, or `fonts.clear()` to remove all registered fonts. This is useful when you want to remove all registered fonts, such as when using the canvas in tests.
```ts
const { registerFont, createCanvas, fonts, FontFace } = require('canvas')
describe('text rendering', () => {
afterEach(() => {
fonts.clear()
})
it('should render text with Comic Sans', () => {
fonts.add(new FontFace('Comic Sans', '/home/you/comicsans.ttf'))
const canvas = createCanvas(500, 500)
const ctx = canvas.getContext('2d')
ctx.font = '12px "Comic Sans"'
ctx.fillText('Everyone loves this font :)', 250, 10)
// assertScreenshot()
})
})
```
### Image#src
> ```ts
> img.src: string|Buffer
> ```
As in browsers, `img.src` can be set to a `data:` URI or a remote URL. In addition, node-canvas allows setting `src` to a local file path or `Buffer` instance.
```javascript
const { Image } = require('canvas')
// From a buffer:
fs.readFile('images/squid.png', (err, squid) => {
if (err) throw err
const img = new Image()
img.onload = () => ctx.drawImage(img, 0, 0)
img.onerror = err => { throw err }
img.src = squid
})
// From a local file path:
const img = new Image()
img.onload = () => ctx.drawImage(img, 0, 0)
img.onerror = err => { throw err }
img.src = 'images/squid.png'
// From a remote URL:
img.src = 'http://picsum.photos/200/300'
// ... as above
// From a `data:` URI:
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='
// ... as above
```
*Note: In some cases, `img.src=` is currently synchronous. However, you should always use `img.onload` and `img.onerror`, as we intend to make `img.src=` always asynchronous as it is in browsers. See https://github.com/Automattic/node-canvas/issues/1007.*
### Image#dataMode
> ```ts
> img.dataMode: number
> ```
Applies to JPEG images drawn to PDF canvases only.
Setting `img.dataMode = Image.MODE_MIME` or `Image.MODE_MIME|Image.MODE_IMAGE` enables MIME data tracking of images. When MIME data is tracked, PDF canvases can embed JPEGs directly into the output, rather than re-encoding into PNG. This can drastically reduce filesize and speed up rendering.
```javascript
const { Image, createCanvas } = require('canvas')
const canvas = createCanvas(w, h, 'pdf')
const img = new Image()
img.dataMode = Image.MODE_IMAGE // Only image data tracked
img.dataMode = Image.MODE_MIME // Only mime data tracked
img.dataMode = Image.MODE_MIME | Image.MODE_IMAGE // Both are tracked
```
If working with a non-PDF canvas, image data *must* be tracked; otherwise the output will be junk.
Enabling mime data tracking has no benefits (only a slow down) unless you are generating a PDF.
### Canvas#toBuffer()
> ```ts
> canvas.toBuffer((err: Error|null, result: Buffer) => void, mimeType?: string, config?: any) => void
> canvas.toBuffer(mimeType?: string, config?: any) => Buffer
> ```
Creates a [`Buffer`](https://nodejs.org/api/buffer.html) object representing the image contained in the canvas.
* **callback** If provided, the buffer will be provided in the callback instead of being returned by the function. Invoked with an error as the first argument if encoding failed, or the resulting buffer as the second argument if it succeeded. Not supported for mimeType `raw` or for PDF or SVG canvases.
* **mimeType** A string indicating the image format. Valid options are `image/png`, `image/jpeg`, `raw` (unencoded data in BGRA order on little-endian (most) systems, ARGB on big-endian systems; top-to-bottom), `application/pdf` (for PDF canvases) and `image/svg+xml` (for SVG canvases). Defaults to `image/png` for image canvases, or the corresponding type for PDF or SVG canvas.
* **config**
* For `image/jpeg`, an object specifying the quality (0 to 1), if progressive compression should be used and/or if chroma subsampling should be used: `{quality: 0.75, progressive: false, chromaSubsampling: true}`. All properties are optional.
* For `image/png`, an object specifying the ZLIB compression level (between 0 and 9), the compression filter(s), the palette (indexed PNGs only), the the background palette index (indexed PNGs only) and/or the resolution (ppi): `{compressionLevel: 6, filters: canvas.PNG_ALL_FILTERS, palette: undefined, backgroundIndex: 0, resolution: undefined}`. All properties are optional.
Note that the PNG format encodes the resolution in pixels per meter, so if you specify `96`, the file will encode 3780 ppm (~96.01 ppi). The resolution is undefined by default to match common browser behavior.
* For `application/pdf`, an object specifying optional document metadata: `{title: string, author: string, subject: string, keywords: string, creator: string, creationDate: Date, modDate: Date}`. All properties are optional and default to `undefined`, except for `creationDate`, which defaults to the current date.
For a description of these properties, see page 550 of [PDF 32000-1:2008](https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf).
Note that there is no standard separator for `keywords`. A space is recommended because it is in common use by other applications, and Cairo will enclose the list of keywords in quotes if a comma or semicolon is used.
**Return value**
If no callback is provided, a [`Buffer`](https://nodejs.org/api/buffer.html). If a callback is provided, none.
#### Examples
```js
// Default: buf contains a PNG-encoded image
const buf = canvas.toBuffer()
// PNG-encoded, zlib compression level 3 for faster compression but bigger files, no filtering
const buf2 = canvas.toBuffer('image/png', { compressionLevel: 3, filters: canvas.PNG_FILTER_NONE })
// JPEG-encoded, 50% quality
const buf3 = canvas.toBuffer('image/jpeg', { quality: 0.5 })
// Asynchronous PNG
canvas.toBuffer((err, buf) => {
if (err) throw err // encoding failed
// buf is PNG-encoded image
})
canvas.toBuffer((err, buf) => {
if (err) throw err // encoding failed
// buf is JPEG-encoded image at 95% quality
}, 'image/jpeg', { quality: 0.95 })
// BGRA pixel values, native-endian
const buf4 = canvas.toBuffer('raw')
const { stride, width } = canvas
// In memory, this is `canvas.height * canvas.stride` bytes long.
// The top row of pixels, in BGRA order on little-endian hardware,
// left-to-right, is:
const topPixelsBGRALeftToRight = buf4.slice(0, width * 4)
// And the third row is:
const row3 = buf4.slice(2 * stride, 2 * stride + width * 4)
// SVG and PDF canvases
const myCanvas = createCanvas(w, h, 'pdf')
myCanvas.toBuffer() // returns a buffer containing a PDF-encoded canvas
// With optional metadata:
myCanvas.toBuffer('application/pdf', {
title: 'my picture',
keywords: 'node.js demo cairo',
creationDate: new Date()
})
```
### Canvas#createPNGStream()
> ```ts
> canvas.createPNGStream(config?: any) => ReadableStream
> ```
Creates a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) that emits PNG-encoded data.
* `config` An object specifying the ZLIB compression level (between 0 and 9), the compression filter(s), the palette (indexed PNGs only) and/or the background palette index (indexed PNGs only): `{compressionLevel: 6, filters: canvas.PNG_ALL_FILTERS, palette: undefined, backgroundIndex: 0, resolution: undefined}`. All properties are optional.
#### Examples
```javascript
const fs = require('fs')
const out = fs.createWriteStream(__dirname + '/test.png')
const stream = canvas.createPNGStream()
stream.pipe(out)
out.on('finish', () => console.log('The PNG file was created.'))
```
To encode indexed PNGs from canvases with `pixelFormat: 'A8'` or `'A1'`, provide an options object:
```js
const palette = new Uint8ClampedArray([
//r g b a
0, 50, 50, 255, // index 1
10, 90, 90, 255, // index 2
127, 127, 255, 255
// ...
])
canvas.createPNGStream({
palette: palette,
backgroundIndex: 0 // optional, defaults to 0
})
```
### Canvas#createJPEGStream()
> ```ts
> canvas.createJPEGStream(config?: any) => ReadableStream
> ```
Creates a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) that emits JPEG-encoded data.
*Note: At the moment, `createJPEGStream()` is synchronous under the hood. That is, it runs in the main thread, not in the libuv threadpool.*
* `config` an object specifying the quality (0 to 1), if progressive compression should be used and/or if chroma subsampling should be used: `{quality: 0.75, progressive: false, chromaSubsampling: true}`. All properties are optional.
#### Examples
```javascript
const fs = require('fs')
const out = fs.createWriteStream(__dirname + '/test.jpeg')
const stream = canvas.createJPEGStream()
stream.pipe(out)
out.on('finish', () => console.log('The JPEG file was created.'))
// Disable 2x2 chromaSubsampling for deeper colors and use a higher quality
const stream = canvas.createJPEGStream({
quality: 0.95,
chromaSubsampling: false
})
```
### Canvas#createPDFStream()
> ```ts
> canvas.createPDFStream(config?: any) => ReadableStream
> ```
* `config` an object specifying optional document metadata: `{title: string, author: string, subject: string, keywords: string, creator: string, creationDate: Date, modDate: Date}`. See `toBuffer()` for more information.
Applies to PDF canvases only. Creates a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) that emits the encoded PDF. `canvas.toBuffer()` also produces an encoded PDF, but `createPDFStream()` can be used to reduce memory usage.
### Canvas#toDataURL()
This is a standard API, but several non-standard calls are supported. The full list of supported calls is:
```js
dataUrl = canvas.toDataURL() // defaults to PNG
dataUrl = canvas.toDataURL('image/png')
dataUrl = canvas.toDataURL('image/jpeg')
dataUrl = canvas.toDataURL('image/jpeg', quality) // quality from 0 to 1
canvas.toDataURL((err, png) => { }) // defaults to PNG
canvas.toDataURL('image/png', (err, png) => { })
canvas.toDataURL('image/jpeg', (err, jpeg) => { }) // sync JPEG is not supported
canvas.toDataURL('image/jpeg', {...opts}, (err, jpeg) => { }) // see Canvas#createJPEGStream for valid options
canvas.toDataURL('image/jpeg', quality, (err, jpeg) => { }) // spec-following; quality from 0 to 1
```
### CanvasRenderingContext2D#patternQuality
> ```ts
> context.patternQuality: 'fast'|'good'|'best'|'nearest'|'bilinear'
> ```
Defaults to `'good'`. Affects pattern (gradient, image, etc.) rendering quality.
### CanvasRenderingContext2D#quality
> ```ts
> context.quality: 'fast'|'good'|'best'|'nearest'|'bilinear'
> ```
Defaults to `'good'`. Like `patternQuality`, but applies to transformations affecting more than just patterns.
### CanvasRenderingContext2D#textDrawingMode
> ```ts
> context.textDrawingMode: 'path'|'glyph'
> ```
Defaults to `'path'`. The effect depends on the canvas type:
* **Standard (image)** `glyph` and `path` both result in rasterized text. Glyph mode is faster than `path`, but may result in lower-quality text, especially when rotated or translated.
* **PDF** `glyph` will embed text instead of paths into the PDF. This is faster to encode, faster to open with PDF viewers, yields a smaller file size and makes the text selectable. The subset of the font needed to render the glyphs will be embedded in the PDF. This is usually the mode you want to use with PDF canvases.
* **SVG** `glyph` does *not* cause `` elements to be produced as one might expect ([cairo bug](https://gitlab.freedesktop.org/cairo/cairo/issues/253)). Rather, `glyph` will create a `` section with a `` for each glyph, then those glyphs be reused via `