# Capability Spec: compress-image **Package**: `@suaveplan/compress-image` **Version**: 0.0.0 (genesis) **Status**: ADDED --- ## ADDED Requirements ### CI-01 — Format coverage `VALID_FORMATS` MUST include `'jpeg' | 'png' | 'webp' | 'avif'`. Each format MUST have a working adapter invoked by the dispatcher. ### CI-02 — Compression API `ImageCompressor.compress(input, options?)` MUST accept `Uint8Array | ArrayBuffer | Blob`, resolve options to a `ResolvedCompressionOptions`, build a `CompressionPlan`, and execute it to produce `CompressionResult { format, bytes, width, height, durationMs, steps: CompressionStep[], inputBytes, outputBytes, savedBytes }`. ### CI-03 — Quality presets `QUALITY_PRESETS` MUST define `'maximum' | 'high' | 'balanced' | 'fast' | 'aggressive'` with deterministic per-format quality values obeying `FORMAT_QUALITY_RANGES`. Custom `options.quality` numeric values outside the format range MUST throw `COMPRESS_IMAGE.INVALID_QUALITY`. ### CI-04 — Max dimension `options.maxDimension` MUST resize the longest side to at most the given pixel count. A resize step MUST appear in `CompressionPlan.steps`. Inputs exceeding `MAX_DIMENSION` (default 20 000) MUST throw `COMPRESS_IMAGE.DIMENSION_TOO_LARGE`. ### CI-05 — Degenerate output If `outputBytes > inputBytes` and `options.preserveSmaller` is `true` (default), the compressor MUST return the original input with a `CompressionStep { action: 'skip', reason: 'output-larger-than-input' }`. Otherwise the larger compressed output is returned. ### CI-06 — Format selection When `options.format` is omitted, the compressor MUST keep the input format. `options.format: 'auto'` MUST choose based on input type (`jpeg` → `webp` at lower size if supported; `png` with alpha → `webp`/`avif`; etc.). ### CI-07 — Observability Every compress call MUST record `compress_image.compress.duration_ms{format, preset}`, `compress_image.compress.total{format, outcome}`, and `compress_image.bytes.saved{format}` gauge.