Files
skills/plugins/library-navigator/skills/sp-compress-image/SKILL.md
2026-05-29 08:20:56 +01:00

5.6 KiB
Raw Blame History

id, name, library, description
id name library description
sp-compress-image Compress Image @suaveplan/compress-image Runtime-agnostic image compression utilities with pluggable adapters. Supports resize, quality reduction, format conversion (JPEG, PNG, WebP, AVIF), and metadata stripping. Core is pure TypeScript; Sharp adapter requires the native `sharp` library.

@suaveplan/compress-image

Architecture

Module Role Key exports
Compressor Orchestrator + validation + OTel ImageCompressor, createCompressor(adapter?)
Sharp Adapter Production Node.js adapter SharpAdapter — wraps sharp library
Memory Adapter Test / no-op adapter MemoryAdapter — passthrough with format detection
Schemas Zod validation CompressOptionsSchema
Types TypeScript contracts ImageAdapter, CompressOptions, CompressResult, ImageInfo
Utils Pure helpers detectFormat, parseJpegDimensions, parsePngDimensions, validateDimensions
Errors Typed errors CompressImageError, COMPRESS_IMAGE_CODES

File Structure

src/
├── index.ts                    # Public barrel
├── core/
│   └── compressor/
│       └── compressor.ts       # ImageCompressor, createCompressor()
├── adapters/
│   ├── sharp/
│   │   └── sharp.ts            # SharpAdapter (production)
│   └── memory/
│       └── memory.ts           # MemoryAdapter (testing)
├── schemas/
│   └── compress-options.schema.ts # Zod schema for options
├── types/
│   └── compress-image.types.ts # TypeScript interfaces
├── utils/
│   └── image-utils.ts          # detectFormat, validateDimensions
└── errors/
    └── compress-image-error.ts # CompressImageError, COMPRESS_IMAGE_CODES

Patterns

Basic — Compress with Sharp adapter

import { createCompressor } from "@suaveplan/compress-image/compressor";
import { SharpAdapter } from "@suaveplan/compress-image/adapters/sharp";
import sharp from "sharp";

const compressor = createCompressor(new SharpAdapter(sharp));

const result = await compressor.compress(imageBuffer, {
  format: "webp",
  quality: 75,
  width: 1280,
  height: 720,
  resizeMode: "cover",
  stripMetadata: true,
});

console.log(result.compressionRatio, result.compressedSize);

Basic — Compress only if larger than threshold

const result = await compressor.compressIfLarger(imageBuffer, 500_000, {
  format: "jpeg",
  quality: 80,
});
// If input ≤ 500KB: returns original with ratio = 1
// If input > 500KB: compresses and returns compressed data

Basic — Extract metadata

const info = await compressor.getInfo(imageBuffer);
console.log(info.format, info.width, info.height, info.size);

Basic — Resize

const resized = await compressor.resize(imageBuffer, 400, 300, "contain");
// Returns Uint8Array of resized image

Advanced — Swap adapter at runtime

const compressor = createCompressor(new MemoryAdapter());

// Later, swap to Sharp for production
compressor.setAdapter(new SharpAdapter(sharp));

Advanced — Write a custom adapter

import type { ImageAdapter, CompressOptions, CompressResult } from "@suaveplan/compress-image";

class MyAdapter implements ImageAdapter {
  async compress(input: Uint8Array, options: CompressOptions): Promise<CompressResult> {
    // … implementation …
  }
  async getInfo(input: Uint8Array): Promise<ImageInfo> {
    // … implementation …
  }
  async resize(input: Uint8Array, w: number, h: number, mode?: ResizeMode): Promise<Uint8Array> {
    // … implementation …
  }
}

Constraints

  • Adapter pattern: core is pure TypeScript; actual image processing delegated to pluggable ImageAdapter.
  • Sharp is optional: only required when using SharpAdapter. Package has zero direct dependency on sharp.
  • Zod validation: all options validated before adapter call; invalid options throw CompressImageError(INVALID_OPTIONS).
  • Dimension limits: width/height must be 1–32767 inclusive.
  • Quality range: 1–100 inclusive, integer only.
  • Effort range: 0–6 inclusive (Sharp-specific encoding effort).
  • Supported formats: jpeg, png, webp, avif.
  • Resize modes: cover, contain, fill, inside, outside.
  • OTel: compress_image.compress.total (counter), compress_image.compress.duration_ms (histogram).
  • Error codes: COMPRESS_IMAGE.UNSUPPORTED_FORMAT, COMPRESS_IMAGE.COMPRESS_FAILED, COMPRESS_IMAGE.INVALID_OPTIONS, COMPRESS_IMAGE.ADAPTER_NOT_SET.
  • MemoryAdapter: safe for tests; detects format and returns passthrough data with synthetic metadata.

Subpath Exports

Export Path
Main @suaveplan/compress-image
Compressor @suaveplan/compress-image/compressor
Sharp Adapter @suaveplan/compress-image/adapters/sharp
Memory Adapter @suaveplan/compress-image/adapters/memory
Errors @suaveplan/compress-image/errors

Checklist

  • Need to compress images → compressor.compress(input, options)
  • Need conditional compression → compressor.compressIfLarger(input, maxBytes, options)
  • Need to resize → compressor.resize(input, width, height, mode)
  • Need metadata extraction → compressor.getInfo(input)
  • Need Sharp integration → new SharpAdapter(sharp)
  • Need test adapter → new MemoryAdapter()
  • Need custom adapter → implement ImageAdapter interface
  • Need Zod option validation → CompressOptionsSchema
  • Need typed errors → CompressImageError, COMPRESS_IMAGE_CODES