4.4 KiB
sharp-adapter
(no submodules)
Purpose
Provides a production-grade ImageAdapter implementation backed by the Sharp image processing library. Sharp delivers native-speed JPEG, PNG, WebP, and AVIF encoding through libvips, making it the recommended adapter for server-side workloads where pixel-accurate compression and real resizing are required.
Sharp is deliberately not a direct dependency of this package. The caller supplies a Sharp factory function at construction time, which eliminates the native-addon from the @suaveplan/compress-image dependency tree and allows the package to be used in environments where Sharp cannot be installed (e.g., edge runtimes, bundled frontends, or CI test runs).
Features
- Full
ImageAdapterimplementation using the real Sharp pipeline - JPEG progressive encoding, PNG compression levels, WebP lossless, AVIF effort tuning
- Metadata stripping by default; opt-in preservation via
stripMetadata: false ResizeModemapped to Sharp'sfitoption (cover / contain / fill / inside / outside)- Caller-supplied Sharp factory for dependency injection
- Wraps all Sharp errors in
CompressImageErrorwith cause-chain forwarding
Usage: Basic Example
import sharp from 'sharp';
import { SharpAdapter } from '@suaveplan/compress-image/adapters/sharp';
import { createCompressor } from '@suaveplan/compress-image/compressor';
const compressor = createCompressor(new SharpAdapter(sharp));
const result = await compressor.compress(imageBuffer, {
format: 'webp',
quality: 75,
width: 800,
height: 600,
});
Usage: Advanced Example
import sharp from 'sharp';
import { SharpAdapter } from '@suaveplan/compress-image/adapters/sharp';
const adapter = new SharpAdapter(sharp);
// Get metadata
const info = await adapter.getInfo(jpegBuffer);
console.log(info.width, info.height, info.format, info.hasAlpha);
// Convert JPEG to AVIF with high compression effort
const result = await adapter.compress(jpegBuffer, {
format: 'avif',
quality: 60,
effort: 6,
stripMetadata: true,
});
// Resize to thumbnail keeping aspect ratio (contain mode)
const thumb = await adapter.resize(jpegBuffer, 128, 128, 'contain');
API Reference
interface SharpLike
A minimal factory interface matching the Sharp module export signature. Implement this to inject a mock in tests.
interface SharpLike {
(input: Buffer | Uint8Array): SharpInstance;
}
interface SharpInstance
The fluent pipeline instance returned by SharpLike. Covers the methods used by SharpAdapter.
class SharpAdapter implements ImageAdapter
constructor(sharp: SharpLike)
Stores the provided Sharp factory. No I/O occurs at construction time.
compress(input: Uint8Array, options: CompressOptions): Promise<CompressResult>
Runs the Sharp pipeline with format conversion, quality settings, and optional resize. Returns a CompressResult with real output bytes and actual dimensions. Throws CompressImageError(UNSUPPORTED_FORMAT) for undetectable inputs; throws CompressImageError(COMPRESS_FAILED) for all other Sharp errors.
getInfo(input: Uint8Array): Promise<ImageInfo>
Calls sharp(input).metadata() to extract width, height, format, and alpha channel information. Throws CompressImageError(UNSUPPORTED_FORMAT) if Sharp returns a format not in the known set.
resize(input: Uint8Array, width: number, height: number, mode?: ResizeMode): Promise<Uint8Array>
Resizes using sharp.resize() with the mapped fit option. Returns a Uint8Array wrapping the Sharp output Buffer. Default mode is 'cover'.
Implementation Notes
Format encoding options are mapped per-format: JPEG receives quality and progressive; WebP receives quality, lossless, and effort; AVIF receives quality and effort; PNG receives compressionLevel (mapped from effort) but no quality parameter since PNG is lossless.
A second .metadata() pass on the output buffer is used to derive the final width and height in CompressResult. This adds a small overhead but guarantees accuracy after resize operations where the actual output dimensions may differ from the requested values (e.g., when using inside or outside fit modes).
Sharp's Buffer is wrapped in new Uint8Array(buffer) to satisfy the Uint8Array contract in CompressResult.data, ensuring interoperability with environments that do not use Node.js Buffer.