node-canvas README

The project's README from github.com/Automattic/node-canvas. As one markdown file: README.md.

node-canvas

Test NPM version

node-canvas is a Cairo-backed Canvas implementation for Node.js.

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.

$ npm install canvas@next

To get v3:

$ npm install canvas

The minimum version of Node.js required is 22.

Binaries will be installed for the following platforms:

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

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('<img src="' + canvas.toDataURL() + '" />')
})

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. (See Compatibility Status for the current API compliance.) All utility methods and non-standard APIs are documented below.

Utility methods

Font API

Non-standard APIs

createCanvas()

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.)

const { createCanvas } = require('canvas')
const mycanvas = createCanvas(200, 200)
const myPDFcanvas = createCanvas(600, 800, 'pdf') // see "PDF Support" section

createImageData()

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.

const { createImageData } = require('canvas')
const width = 20, height = 20
const arraySize = width * height * 4
const mydata = createImageData(new Uint8ClampedArray(arraySize), width)

loadImage()

loadImage() => Promise<Image>

Convenience method for loading images. This method works in both Node.js and Web browsers.

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


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 is just like the browser's document.fonts, but with a slightly more limited API.

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


class FontFaceSet {
  add(face: FontFace): void;
  has(face: FontFace): boolean;
  clear(): void;
  delete(face: FontFace): boolean;
  [Symbol.iterator](): Iterator<FontFace>;
  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.

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

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.

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

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.

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()

canvas.toBuffer((err: Error|null, result: Buffer) => void, mimeType?: string, config?: any) => void
canvas.toBuffer(mimeType?: string, config?: any) => Buffer

Creates a Buffer object representing the image contained in the canvas.

Return value

If no callback is provided, a Buffer. If a callback is provided, none.

Examples

// 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()

canvas.createPNGStream(config?: any) => ReadableStream

Creates a ReadableStream that emits PNG-encoded data.

Examples

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:

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()

canvas.createJPEGStream(config?: any) => ReadableStream

Creates a ReadableStream 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.

Examples

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()

canvas.createPDFStream(config?: any) => ReadableStream

Applies to PDF canvases only. Creates a ReadableStream 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:

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

context.patternQuality: 'fast'|'good'|'best'|'nearest'|'bilinear'

Defaults to 'good'. Affects pattern (gradient, image, etc.) rendering quality.

CanvasRenderingContext2D#quality

context.quality: 'fast'|'good'|'best'|'nearest'|'bilinear'

Defaults to 'good'. Like patternQuality, but applies to transformations affecting more than just patterns.

CanvasRenderingContext2D#textDrawingMode

context.textDrawingMode: 'path'|'glyph'

Defaults to 'path'. The effect depends on the canvas type:

In glyph mode, ctx.strokeText() and ctx.fillText() behave the same (aside from using the stroke and fill style, respectively).

This property is tracked as part of the canvas state in save/restore.

CanvasRenderingContext2D#globalCompositeOperation = 'saturate'

In addition to all of the standard global composite operations defined by the Canvas specification, the 'saturate' operation is also available.

CanvasRenderingContext2D#antialias

context.antialias: 'default'|'none'|'gray'|'subpixel'

Sets the anti-aliasing mode.

PDF Output Support

node-canvas can create PDF documents instead of images. The canvas type must be set when creating the canvas as follows:

const canvas = createCanvas(200, 500, 'pdf')

An additional method .addPage() is then available to create multiple page PDFs:

// On first page
ctx.font = '22px Helvetica'
ctx.fillText('Hello World', 50, 80)

ctx.addPage()
// Now on second page
ctx.font = '22px Helvetica'
ctx.fillText('Hello World 2', 50, 80)

canvas.toBuffer() // returns a PDF file
canvas.createPDFStream() // returns a ReadableStream that emits a PDF
// With optional document metadata:
canvas.toBuffer('application/pdf', {
  title: 'my picture',
  keywords: 'node.js demo cairo',
  creationDate: new Date()
})

It is also possible to create pages with different sizes by passing width and height to the .addPage() method:

ctx.font = '22px Helvetica'
ctx.fillText('Hello World', 50, 80)
ctx.addPage(400, 800)

ctx.fillText('Hello World 2', 50, 80)

It is possible to add hyperlinks using .beginTag() and .endTag():

ctx.beginTag('Link', "uri='https://google.com'")
ctx.font = '22px Helvetica'
ctx.fillText('Hello World', 50, 80)
ctx.endTag('Link')

Or with a defined rectangle:

ctx.beginTag('Link', "uri='https://google.com' rect=[50 80 100 20]")
ctx.endTag('Link')

Note that the syntax for attributes is unique to Cairo. See cairo_tag_begin for the full documentation.

You can create areas on the canvas using the "cairo.dest" tag, and then link to them using the "Link" tag with the dest= attribute. You can also define PDF structure for accessibility by using tag names like "P", "H1", and "TABLE". The standard tags are defined in §14.8.4 of the PDF 1.7 specification.

See also:

SVG Output Support

node-canvas can create SVG documents instead of images. The canvas type must be set when creating the canvas as follows:

const canvas = createCanvas(200, 500, 'svg')
// Use the normal primitives.
fs.writeFileSync('out.svg', canvas.toBuffer())

SVG Image Support

If librsvg is available when node-canvas is installed, node-canvas can render SVG images to your canvas context. This currently works by rasterizing the SVG image (i.e. drawing an SVG image to an SVG canvas will not preserve the SVG data).

const img = new Image()
img.onload = () => ctx.drawImage(img, 0, 0)
img.onerror = err => { throw err }
img.src = './example.svg'

Image pixel formats (experimental)

node-canvas has experimental support for additional pixel formats, roughly following the Canvas color space proposal.

const canvas = createCanvas(200, 200)
const ctx = canvas.getContext('2d', { pixelFormat: 'A8' })

By default, canvases are created in the RGBA32 format, which corresponds to the native HTML Canvas behavior. Each pixel is 32 bits. The JavaScript APIs that involve pixel data (getImageData, putImageData) store the colors in the order {red, green, blue, alpha} without alpha pre-multiplication. (The C++ API stores the colors in the order {alpha, red, green, blue} in native-endian ordering, with alpha pre-multiplication.)

These additional pixel formats have experimental support:

Notes and caveats:

Local Development and Testing

To set up node-canvas for local develoment, use the --force argument (until npm/cli#6138 is fixed):

npm install --force

For visual tests: npm run test-server and point your browser to http://localhost:4000.

For unit tests: npm run test.

Benchmarks

Benchmarks live in the benchmarks directory.

Examples

Examples line in the examples directory. Most produce a png image of the same name, and others such as live-clock.js launch an HTTP server to be viewed in the browser.

Original Authors

License

node-canvas

(The MIT License)

Copyright (c) 2010 LearnBoost, and contributors <[email protected]>

Copyright (c) 2014 Automattic, Inc and contributors <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

BMP parser

See license

node-canvas (Automattic/node-canvas)

Searching Database…

Что это такое?node-canvas — это реализация HTML5 Canvas API для Node.js на основе Cairo. Она позволяет рисовать фигуры, изображения и текст на сервере и экспортировать результат в PNG, JPEG, PDF или SVG.
Это библиотека, которую я подключаю в проект, или отдельное приложение?Это библиотека для Node.js (устанавливается через npm), которая максимально точно повторяет Web Canvas API из браузера. Она предоставляет такие функции, как createCanvas(), createImageData() и loadImage().
Как добавить её в проект на Node?Добавьте её как зависимость npm. Пакет содержит готовые нативные бинарники для поддерживаемых платформ, поэтому обычно не требуется локальная сборка Cairo. Текущий основной релиз — v4 (предварительный), а если нужна стабильная версия, доступна v3.
Можно ли использовать текущую версию в продакшене?v4 пока находится на стадии предварительного релиза: она добавляет поддержку worker-потоков и уменьшает размер бинарников, но ещё дорабатывается. Если нужна надёжность для продакшена, выбирайте v3 — это проверенная и стабильная версия. В любом случае требуется Node.js 22+.
Для каких сочетаний ОС и процессора есть готовые бинарники?Готовые бинарники есть для macOS x64/arm64, Linux x64/x86/arm64 (glibc или musl), Linux arm/riscv64 (glibc) и Windows x64/x86/arm64.
Можно ли экспортировать canvas в формат, отличный от PNG?Да. Canvas может выдавать JPEG и необработанные буферы через toBuffer(), потоковые JPEG/PNG через createJPEGStream() и createPNGStream(), а также полные документы PDF или SVG, если при создании указать тип canvas pdf или svg.
Можно ли использовать свои шрифты?Да, через FontFace API и реестр шрифтов, который повторяет document.fonts из браузера. Вы регистрируете файл TrueType (по пути или буфером) с именем семейства, а затем рисуете текст им так же, как системным шрифтом.
Можно ли выводить SVG-изображения на canvas?Только если librsvg был доступен при установке node-canvas. В этом случае SVG-изображения растризуются на canvas, а не сохраняются как векторные данные.
Зачем использовать экспериментальные форматы пикселей, например A8 или RGB16565?Они меняют стандартный RGBA32 на экономию памяти или скорость: RGB24 не хранит альфа-канал и быстрее выводит непрозрачное изображение, A8 даёт оттенки серого или индексированный PNG, а RGB16565 соответствует некоторым аппаратным буферам кадров.
Creator
Automattic
Size
5.3 MB
Stars
10.7K
Age
16y
Commits · 90 Days