Wraps a native surface.
One argument, where there were three. The other two were a filesystem,
injected so this class could be tested without a disk. They cannot survive
the encode moving into the file: toFile no longer produces a buffer for
anyone to write, so a caller supplying a writer would have been passing
something nothing could call — a documented capability that silently did
nothing.
The seam did not go, it moved. A test substitutes a NativeCanvas,
which is where encode was always mocked anyway, and a host without
node:fs supplies one too. One injection point instead of two.
toBuffer('apng'). Every page as a frame, with PNG's colour and alpha.
toBuffer('avif'). Smaller again, and slower to encode.
toBuffer('bmp'). Uncompressed, and rarely what is wanted.
Which rasteriser drew the pages: 'gpu' or 'cpu'.
The outcome rather than the request, and they disagree: a build with no GPU
backend compiled, a driver that declines, and a float colorType all
rasterise on the CPU whatever gpu says. v1 reports both for this reason,
and without it a caller who asks for the GPU and gets the CPU has no way to
find out — the same shape of invisibility that hid a missing build feature
from this project for a session.
toBuffer('gif'). Every page as a frame, at 256 colours.
Whether the GPU was asked for.
Asking is not getting — compare Canvas.engine. This is what
Root was told, and it is true when nothing was said, because that is
the renderer's own default.
toBuffer('ico'). The Windows icon container.
toBuffer('jpg'). Lossy and opaque — no alpha channel.
How many pages were painted.
What a page means is the format's answer: a frame for GIF and APNG, a sheet for PDF and TIFF, one size of the same icon for ICO.
toBuffer('pdf'). Vector, and every page a page.
toBuffer('png'). Lossless, and the format to reach for without a reason not to.
toBuffer('raw'). The pixels, unencoded.
Whether the surface is still there.
The device-pixel multiplier the pages were drawn at.
Layout always solves at one, so this is resolution rather than anything about where things sit.
toBuffer('svg'). Vector, so text stays text.
toBuffer('tiff'). Lossless, and what a print pipeline usually asks for.
toBuffer('webp'). Smaller than PNG at the same quality, and takes every page as an animation.
Frees the Skia surface now rather than at the next collection.
Optional. The surface is freed when this canvas is collected either way; this only makes it sooner, which a server rendering thousands of images wants and a script does not need. Calling it twice is not an error, and every other method throws afterwards rather than reading freed memory.
Encodes the canvas on a worker thread and resolves with the bytes.
This is where the pixels are allocated, because painting recorded a drawing rather than a bitmap. So this is what costs time in proportion to the canvas area — about 11 ms at 800×800, 65 ms at 2000×2000 and 256 ms at 4000×4000 on one machine — and this is what throws when the area is more than the host can allocate, however long ago the size was chosen.
That time is not spent on the event loop. It used to be: this method
returned a promise that was already settled, having blocked every other
request in the process for the whole encode, so await bought a tick and
nothing else. What crosses to the worker is the recorded pages, not the
scene — the drawing is already shaped, so the worker consults no font and
cannot substitute one.
The remaining loop time is the half of an export that needs the canvas, which is small and does not grow with area the way the encode does.
See Canvas.toBufferSync for why the type is Buffer.
Optionalformat: FormatOptionaloptions: EncodeOptionsEncodes the canvas and returns the bytes.
The same bytes Canvas.toBuffer resolves with, produced on the calling thread instead of a worker. A genuine choice rather than the same call twice: this one blocks the event loop for the whole encode, which is what a script wants and what a server does not.
Buffer and not Uint8ArrayBecause a Buffer is what already came back. The addon returns a
Neon JsBuffer and always has; the declaration said Uint8Array, which
was a false statement about the value. Buffer extends Uint8Array, so
this narrows the type without changing a byte, and every caller that
wanted either is satisfied.
It is not a fix for sharp. sharp accepts a plain Uint8Array — its
SharpInput names the type, and 0.34.5, 0.35.3 and 0.35.4 each read one
back to png 410x140 when measured. Whatever a caller hit handing this to
sharp, this was not it, and the type being honest is worth having on its
own.
Optionalformat: FormatOptionaloptions: EncodeOptionsThe HTMLCanvasElement spelling of Canvas.toURLSync.
Synchronous and taking a quality rather than an options object, because the DOM method it is named after is both. v1 has it for the same reason.
Optionalformat: FormatOptionalquality: numberEncodes the canvas on a worker and writes it to path.
The bytes never come back through JavaScript. They used to: this
encoded to a Buffer, resolved it here, and handed it to a write — so a
three-hundred-frame animation had to exist whole in memory before any of
it reached the disk. The file is now written where it is encoded, and a
spanning format streams into it page by page.
That is also why the filesystem injected into the constructor is not on this path any more. It cannot be: the point is that no buffer crosses back for anyone to write.
Optionaloptions: EncodeOptionsEncodes the canvas and writes it to path, blocking.
The same call on the calling thread. It asks the format question once, on this side, and everything after that is the one decision made in one place — see NativeCanvas.write.
Optionaloptions: EncodeOptionsEncodes the canvas on a worker and resolves with a data: URL.
The base64 runs on the calling thread, which is where it has to: it is a string, and a string cannot cross to a worker without being copied twice. It is also the cheap end — a 4000×4000 PNG is tens of kilobytes by the time it is bytes, against the hundred milliseconds that made it.
Optionalformat: FormatOptionaloptions: EncodeOptionsEncodes the canvas and returns a data: URL.
Optionalformat: FormatOptionaloptions: EncodeOptions
A painted canvas, and the ways to read it back.
Constructed by
Root; a caller never builds one. It holds the native surface and nothing else, so every method here is an encode of work already done.