@portable/png
Functions
Png.decode
Decodes a PNG file to 8-bit RGBA pixels. Decompresses with DecompressionStream unless you pass inflate.
async function decode(
bytes: Uint8Array,
options: decode.Options = {},
): Promise<Decoded>;| Option | Type | Default | Description |
|---|---|---|---|
checkCrc | boolean | true | Verify the CRC of every chunk. |
maxPixels | number | Infinity | The most pixels (width * height) to decode. A larger image throws MaxPixelsError before anything is decompressed or allocated. |
inflate | ((data: Uint8Array) => Uint8Array | Promise<Uint8Array>) | DecompressionStream('deflate') | Decompresses zlib data. |
signal | AbortSignal | Rejects with signal.reason when aborted, and stops decompressing. |
Throws
MaxPixelsErrorWhenwidth * heightis more thanmaxPixels.
import * as Png from '@portable/png';
const response = await fetch('https://example.com/image.png');
const { width, height, data } = await Png.decode(
await response.bytes(),
);Png.decodeSync
Decodes a PNG file to 8-bit RGBA pixels synchronously, with the inflate function you pass.
function decodeSync(
bytes: Uint8Array,
options: decodeSync.Options,
): Decoded;| Option | Type | Default | Description |
|---|---|---|---|
checkCrc | boolean | true | Verify the CRC of every chunk. |
maxPixels | number | Infinity | The most pixels (width * height) to decode. A larger image throws MaxPixelsError before anything is decompressed or allocated. |
inflate | (data: Uint8Array) => Uint8Array | Decompresses zlib data, such as unzlibSync from fflate. |
Throws
MaxPixelsErrorWhenwidth * heightis more thanmaxPixels.
import * as Png from '@portable/png';
import { unzlibSync } from 'fflate';
const { width, height, data } = Png.decodeSync(bytes, {
inflate: unzlibSync,
});Png.encode
Encodes 8-bit RGBA pixels as a PNG file. Compresses with CompressionStream unless you pass deflate.
async function encode(
image: RgbaImage,
options: encode.Options = {},
): Promise<Uint8Array<ArrayBuffer>>;| Option | Type | Default | Description |
|---|---|---|---|
colorType | 0 | 2 | 4 | 6 | 6 | Color type to write: 0 grayscale, 2 RGB, 4 grayscale with alpha, 6 RGBA. Gray is the BT.709 luma of each pixel. |
filter | FilterType | readonly FilterType[] | [0, 1, 2, 3, 4] | Filter for every row, or the filters to choose from per row. With more than one, each row gets the filter whose output has the smallest sum of absolute values. |
background | { red: number; green: number; blue: number; } | white | Color to blend transparent pixels onto when colorType has no alpha. |
deflate | ((data: Uint8Array) => Uint8Array | Promise<Uint8Array>) | CompressionStream('deflate') | Compresses to zlib format. Set it to choose a compression level. |
signal | AbortSignal | Rejects with signal.reason when aborted, and stops compressing. |
import * as Png from '@portable/png';
const data = new Uint8Array(16 * 16 * 4).fill(255);
const bytes = await Png.encode({ width: 16, height: 16, data });
return new Response(bytes, {
headers: { 'content-type': 'image/png' },
});Png.encodeSync
Encodes 8-bit RGBA pixels as a PNG file synchronously, with the deflate function you pass.
function encodeSync(
image: RgbaImage,
options: encodeSync.Options,
): Uint8Array<ArrayBuffer>;| Option | Type | Default | Description |
|---|---|---|---|
colorType | 0 | 2 | 4 | 6 | 6 | Color type to write: 0 grayscale, 2 RGB, 4 grayscale with alpha, 6 RGBA. Gray is the BT.709 luma of each pixel. |
filter | FilterType | readonly FilterType[] | [0, 1, 2, 3, 4] | Filter for every row, or the filters to choose from per row. With more than one, each row gets the filter whose output has the smallest sum of absolute values. |
background | { red: number; green: number; blue: number; } | white | Color to blend transparent pixels onto when colorType has no alpha. |
deflate | (data: Uint8Array) => Uint8Array | Compresses to zlib format, such as zlibSync from fflate. |
import * as Png from '@portable/png';
import { zlibSync } from 'fflate';
const bytes = Png.encodeSync(
{ width, height, data },
{ deflate: (raw) => zlibSync(raw, { level: 9 }) },
);Errors
Png.InvalidInputError
Thrown when the input is malformed: a bad signature, a CRC mismatch, an invalid header, corrupt
image data, or (from encode) pixel data that doesn't match the size.
class InvalidInputError extends Errors.InvalidInputError {
readonly kind: string;
}import * as Png from '@portable/png';
try {
await Png.decode(new TextEncoder().encode('not a png'));
} catch (error) {
if (error instanceof Png.InvalidInputError) {
console.log(error.message);
}
}Png.MaxPixelsError
Thrown by decode and decodeSync when the image has more pixels (width * height) than
maxPixels. The check runs on the IHDR chunk, before any image data is decompressed or
allocated.
class MaxPixelsError extends Errors.BaseError {
constructor(
options: ErrorOptions & {
maxPixels: number;
},
);
readonly kind: string;
readonly maxPixels: number;
}import * as Png from '@portable/png';
try {
await Png.decode(upload, { maxPixels: 50_000_000 });
} catch (error) {
if (error instanceof Png.MaxPixelsError) {
return new Response('Image too large', { status: 413 });
}
throw error;
}Png.TruncatedError
Thrown by decode when the file ends early: before IEND, inside a chunk, or with less image data than the image needs.
class TruncatedError extends Errors.TruncatedError {
readonly kind: string;
}import * as Png from '@portable/png';
try {
await Png.decode(bytes.subarray(0, 100));
} catch (error) {
if (error instanceof Png.TruncatedError) {
console.log('incomplete download');
}
}Png.UnsupportedError
Thrown by decode for a valid file that uses something this package doesn't handle: an unknown
critical chunk, or a compression, filter or interlace method other than the ones PNG defines.
class UnsupportedError extends Errors.UnsupportedError {
readonly kind: string;
}import * as Png from '@portable/png';
try {
await Png.decode(bytes);
} catch (error) {
if (error instanceof Png.UnsupportedError) {
console.log(error.message);
}
}Types
Png.BitDepth
Bits per sample (per palette index for color type 3).
type BitDepth = | | | | ;Png.ColorType
PNG color type: 0 grayscale, 2 RGB, 3 palette, 4 grayscale with alpha, 6 RGBA.
type ColorType = | | | | ;Png.Decoded
A decoded image. data holds 8-bit RGBA, four bytes per pixel, row by row from the top left.
type Decoded = {
width: number;
height: number;
data: Uint8Array<ArrayBuffer>;
depth: BitDepth;
colorType: ColorType;
interlace: boolean;
alpha: boolean;
gamma: number | undefined;
};Png.RgbaImage
8-bit RGBA pixels, four bytes per pixel, row by row from the top left. A decoded image or a canvas ImageData fits.
type RgbaImage = {
width: number;
height: number;
data: Uint8Array | Uint8ClampedArray;
gamma?: number | undefined;
};Png.FilterType
PNG scanline filter: 0 none, 1 sub, 2 up, 3 average, 4 Paeth.
type FilterType = | | | | ;