Fast PNG Encoder/Decoder
fast-png is a performant JavaScript library for encoding and decoding PNG image data, built entirely in JavaScript without native dependencies. The current stable version is 8.0.0, released in December 2025. This package focuses on speed, demonstrated by its recent switch to the `fflate` library for compression in v8.0.0. Major versions are released periodically (roughly annually), often introducing significant breaking changes like the migration to ESM in v7.0.0. It differentiates itself by offering a pure JavaScript implementation suitable for both Node.js and browser environments, while providing granular control over encoding options and supporting various PNG features like `tEXt` chunks, `tRNS` fields, and `ICC` profiles.
Common errors
-
ERR_REQUIRE_ESM
cause Attempting to use `require()` to import `fast-png` in a CommonJS context after v7.0.0.fixChange `const { decode, encode } = require('fast-png');` to `import { decode, encode } from 'fast-png';`. Ensure your `package.json` has `"type": "module"` if running in Node.js, or use a bundler that handles ESM. -
TypeError: Cannot read properties of undefined (reading 'width')
cause The `encode` function received an `image` object that is missing required properties like `width`, `height`, or `data`.fixEnsure the object passed to `encode` has at least `width`, `height`, `data`, `channels`, and `depth` properties, as specified in the API documentation. -
Error: Invalid zlib options provided
cause Using old or incompatible `zlib` encoding options with the `encode` function after the v8.0.0 breaking change.fixRemove or update any `zlib` related options passed to `encode` as their structure or names may have changed with the switch to `fflate` in v8.0.0. Refer to the latest API documentation.
Warnings
- breaking The options for zlib encoding have been changed due to a switch from `pako` to `fflate` for performance improvements.
- breaking The package migrated to ECMAScript Modules (ESM) and no longer supports CommonJS `require()` syntax.
- breaking Support for Node.js versions 10 and 15 was removed. The library now targets more modern Node.js environments.
- breaking Acronyms in certain properties and methods were changed to use camelCase for consistency.
- gotcha The `decode` function's `checkCrc` option is `false` by default, meaning the library will not verify the integrity of chunks. Corrupt PNG files may be processed without error.
- gotcha When using the `text` option in the `encode` function for `tEXt` chunks, both keys and values must only contain characters from the Latin-1 charset (maximum code point 255), and keys must be less than 80 characters long.
Install
-
npm install fast-png -
yarn add fast-png -
pnpm add fast-png
Imports
- decode
const { decode } = require('fast-png');import { decode } from 'fast-png'; - encode
const { encode } = require('fast-png');import { encode } from 'fast-png'; - hasPngSignature
const { hasPngSignature } = require('fast-png');import { hasPngSignature } from 'fast-png';
Quickstart
import { decode, encode } from 'fast-png';
async function runPngExample() {
// 1. Define a simple 2x2 red image in RGBA format
const width = 2;
const height = 2;
const data = new Uint8Array([
255, 0, 0, 255, // Red pixel 1
255, 0, 0, 255, // Red pixel 2
255, 0, 0, 255, // Red pixel 3
255, 0, 0, 255 // Red pixel 4
]);
// 2. Encode the image into a PNG buffer
const encodedPngBuffer = encode({
width,
height,
data,
channels: 4, // RGBA
depth: 8, // 8 bits per channel
text: { title: 'Test Image', author: 'AI' } // Optional tEXt chunks
});
console.log(`Encoded PNG buffer size: ${encodedPngBuffer.length} bytes`);
// 3. Decode the PNG buffer back into an image object
// For Node.js, the buffer output by encode is compatible with decode.
// For browser, you might get an ArrayBuffer and need to wrap in Uint8Array.
const decodedImage = decode(encodedPngBuffer, { checkCrc: true });
console.log(`\n--- Decoded Image Information ---`);
console.log(`Width: ${decodedImage.width}`);
console.log(`Height: ${decodedImage.height}`);
console.log(`Channels: ${decodedImage.channels}`);
console.log(`Depth: ${decodedImage.depth}`);
console.log(`Data length: ${decodedImage.data.length}`);
console.log(`Text chunks:`, decodedImage.text);
// 4. Verify a pixel value from the decoded data
const firstPixelOffset = 0; // RGBA
const [r, g, b, a] = decodedImage.data.slice(firstPixelOffset, firstPixelOffset + 4);
console.log(`First pixel (R,G,B,A): (${r}, ${g}, ${b}, ${a})`);
if (r === 255 && g === 0 && b === 0 && a === 255) {
console.log('Successfully decoded the red pixel as expected!');
} else {
console.error('Decoded pixel color mismatch!');
}
}
runPngExample().catch(console.error);