PNGQuant Stream Wrapper
The `pngquant` package provides a Node.js readable/writable stream wrapper for the `pngquant` command-line utility. It allows developers to optimize PNG images by reducing their color palette directly within a Node.js stream pipeline, making it suitable for processing images from HTTP requests, file uploads, or other stream sources without requiring temporary files. Currently at version 4.2.0, its release cadence is not explicitly stated in the provided information, but it appears actively maintained given recent version bumps and project activity. Key differentiators include its efficient stream-based API, direct integration with the powerful `pngquant` CLI for high-quality optimization, and robust TypeScript type definitions for enhanced developer experience. This design simplifies image optimization workflows in server-side applications and microservices.
Common errors
-
spawn pngquant ENOENT
cause The `pngquant` executable is not found in the system's PATH environment variable.fixEnsure the `pngquant` command-line utility is installed and its location is included in your system's PATH. Verify installation by running `pngquant --version` in your terminal. -
Error: PngQuant exited with code 98
cause The underlying `pngquant` binary encountered an error during image processing, often due to invalid input (e.g., corrupted PNG) or incompatible command-line options.fixVerify that the input stream provides a valid PNG image. Check the options array passed to the `PngQuant` constructor for correctness and compatibility with the `pngquant` CLI version and the input image (e.g., valid quality ranges, color counts).
Warnings
- gotcha The `pngquant` binary is a required runtime dependency and must be installed separately and available in the system's PATH. This package does not bundle the native executable.
- gotcha Incorrectly passing options to the `PngQuant` constructor can lead to unexpected optimization results or errors from the underlying `pngquant` binary. The options array is passed directly as command-line arguments.
- gotcha Stream errors from either the input, output, or the `PngQuant` transform stream itself might not always be propagated or handled gracefully if not explicitly listened for. The `pipeline` utility from `stream/promises` is recommended for robust error handling in stream chains.
Install
-
npm install pngquant -
yarn add pngquant -
pnpm add pngquant
Imports
- PngQuant
import { PngQuant } from 'pngquant';import PngQuant from 'pngquant';
- PngQuant (CommonJS)
const PngQuant = require('pngquant'); - PngQuantOptions
import { PngQuantOptions } from 'pngquant';import type { PngQuantOptions } from 'pngquant';
Quickstart
import PngQuant from 'pngquant';
import { createReadStream, createWriteStream, promises as fsPromises } from 'fs';
import { pipeline } from 'stream/promises';
import path from 'path';
// Ensure a dummy input.png exists for this example to run.
// In a real application, 'input.png' would be provided by user upload or file system.
const inputFilePath = path.resolve(__dirname, 'input.png');
const outputFilePath = path.resolve(__dirname, 'output.png');
async function createDummyPng() {
const dummyPngContent = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=', 'base64');
await fsPromises.writeFile(inputFilePath, dummyPngContent);
console.log(`Created dummy PNG at ${inputFilePath}`);
}
async function optimizeImage() {
await createDummyPng(); // Create a dummy PNG for the example
try {
// Initialize PngQuant with specific command-line arguments for the pngquant binary.
// Here: reduce to 192 colors, target quality 60-80, disable dithering, read from stdin ('-').
const myPngQuanter = new PngQuant([192, '--quality', '60-80', '--nofs', '-']);
console.log(`Optimizing ${inputFilePath} to ${outputFilePath}...`);
await pipeline(
createReadStream(inputFilePath), // Source stream: reads the input PNG
myPngQuanter, // Transform stream: optimizes the PNG
createWriteStream(outputFilePath) // Destination stream: writes the optimized PNG
);
console.log(`Optimization complete! Optimized PNG saved to ${outputFilePath}`);
} catch (error) {
console.error('Image optimization failed:', error);
} finally {
// Clean up the dummy file
await fsPromises.unlink(inputFilePath).catch(() => {});
}
}
optimizeImage();