Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
59
plugins/document-navigator/docs/media/image/image/README.md
Normal file
59
plugins/document-navigator/docs/media/image/image/README.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# @suaveplan/image - Universal image metadata extraction, format detection, resize math, crop validation, and transform pipeline planning
|
||||
|
||||
Universal image metadata extraction, format detection, resize math, crop validation, and transform pipeline planning. Zero browser or Node dependencies — runs in Bun, Node, and browsers alike. Provides `ImageProcessor` for planning image transforms, `PipelineBuilder` for fluent composition, and header-based dimension parsers for JPEG, PNG, WebP, GIF, and AVIF.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [error-codes](./src/error-codes/error-codes.md) — `error-codes.ts` declares the canonical error-code registry for `@suaveplan/image`. Every failure mode that the image p…
|
||||
- [error-codes](./src/error-codes/error-codes.md) — `error-codes.ts` declares the canonical error-code registry for `@suaveplan/image`. Every failure mode that the image p…
|
||||
- [errors](./src/errors/errors.md) — `errors.ts` provides the typed error hierarchy for `@suaveplan/image`. `ImageError` extends `SuaveplanError` so that ca…
|
||||
- [errors](./src/errors/errors.md) — `errors.ts` provides the typed error hierarchy for `@suaveplan/image`. `ImageError` extends `SuaveplanError` so that ca…
|
||||
- [dimensions](./src/processor/dimensions/dimensions.md) — `dimensions.ts` extracts width and height from raw image headers for the four supported raster formats: PNG, JPEG, GIF,…
|
||||
- [dimensions](./src/processor/dimensions/dimensions.md) — `dimensions.ts` extracts width and height from raw image headers for the four supported raster formats: PNG, JPEG, GIF,…
|
||||
- [instruments](./src/processor/instruments/instruments.md) — `instruments.ts` lazily initialises the OpenTelemetry counters and histograms used by `ImageProcessor`. Each instrument…
|
||||
- [instruments](./src/processor/instruments/instruments.md) — `instruments.ts` lazily initialises the OpenTelemetry counters and histograms used by `ImageProcessor`. Each instrument…
|
||||
- [pipeline-builder](./src/processor/pipeline-builder/pipeline-builder.md) — `pipeline-builder.ts` implements a fluent, chainable API for constructing image transform pipelines. Each method append…
|
||||
- [pipeline-builder](./src/processor/pipeline-builder/pipeline-builder.md) — `pipeline-builder.ts` implements a fluent, chainable API for constructing image transform pipelines. Each method append…
|
||||
- [processor](./src/processor/processor/processor.md) — `processor.ts` is the orchestration layer of `@suaveplan/image`. `ImageProcessor` accepts a `Uint8Array` of image bytes…
|
||||
- [processor](./src/processor/processor/processor.md) — `processor.ts` is the orchestration layer of `@suaveplan/image`. `ImageProcessor` accepts a `Uint8Array` of image bytes…
|
||||
- [image-detect](./src/types/image-detect/image-detect.md) — `image-detect.ts` provides fast, deterministic format detection from raw binary headers. It inspects the first bytes of…
|
||||
- [image-detect](./src/types/image-detect/image-detect.md) — `image-detect.ts` provides fast, deterministic format detection from raw binary headers. It inspects the first bytes of…
|
||||
- [image-types](./src/types/image-types/image-types.md) — `image-types.ts` is the universal type system and pure-function toolkit for image metadata. It defines Zod schemas…
|
||||
- [image-types](./src/types/image-types/image-types.md) — `image-types.ts` is the universal type system and pure-function toolkit for image metadata. It defines Zod schemas…
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/image
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```ts
|
||||
import { ImageProcessor } from "@suaveplan/image";
|
||||
|
||||
const proc = new ImageProcessor({ maxPixels: 50_000_000 });
|
||||
const meta = proc.extractMetadata(imageBytes);
|
||||
console.log(`${meta.format} ${meta.width}x${meta.height}`);
|
||||
|
||||
const result = proc.planTransform(meta, {
|
||||
operations: [
|
||||
{ type: "resize", options: { width: 400 } },
|
||||
{ type: "format", format: "webp" },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
- [`src/processor/processor/processor.md`](./src/processor/processor/processor.md) — `ImageProcessor` and `PipelineBuilder`
|
||||
- [`src/processor/instruments/instruments.md`](./src/processor/instruments/instruments.md) — OpenTelemetry instrumentation helpers
|
||||
- [`src/processor/dimensions/dimensions.md`](./src/processor/dimensions/dimensions.md) — Header dimension parsers for JPEG, PNG, WebP, GIF, AVIF
|
||||
- [`src/processor/pipeline-builder/pipeline-builder.md`](./src/processor/pipeline-builder/pipeline-builder.md) — Fluent transform pipeline builder
|
||||
- [`src/types/image-types/image-types.md`](./src/types/image-types/image-types.md) — TypeScript interfaces and Zod schemas
|
||||
- [`src/types/image-detect/image-detect.md`](./src/types/image-detect/image-detect.md) — Format detection types and constants
|
||||
- [`src/errors/errors.md`](./src/errors/errors.md) — `ImageError` hierarchy and typed factories
|
||||
- [`src/error-codes/error-codes.md`](./src/error-codes/error-codes.md) — Stable `IMAGE.*` error code registry
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# error-codes
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`error-codes.ts` declares the canonical error-code registry for `@suaveplan/image`. Every failure mode that the image package can surface — from unsupported formats to dimension violations — is assigned a stable, namespaced string via `defineCodes` from `@suaveplan/error`. This gives downstream log analysers, retry policies, and problem+json renderers a deterministic contract they can match against without parsing human-readable messages.
|
||||
|
||||
## Features
|
||||
|
||||
- Seven stable codes under the `IMAGE.*` namespace
|
||||
- Type-safe `ImageCode` union derived from the registry object
|
||||
- Zero runtime side effects — the registry is a plain constant
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { IMAGE_CODES } from "@suaveplan/image/error-codes";
|
||||
|
||||
function handleImageError(err: { code: string }) {
|
||||
if (err.code === IMAGE_CODES.FORMAT_UNSUPPORTED) {
|
||||
return { status: 415, message: "Format not supported" };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { IMAGE_CODES, type ImageCode } from "@suaveplan/image/error-codes";
|
||||
|
||||
const retryableCodes: ImageCode[] = [
|
||||
IMAGE_CODES.DECODE_FAILED,
|
||||
IMAGE_CODES.ENCODE_FAILED,
|
||||
];
|
||||
|
||||
function shouldRetry(code: ImageCode): boolean {
|
||||
return retryableCodes.includes(code);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `IMAGE_CODES`
|
||||
|
||||
A frozen object mapping human-readable keys to namespaced string values:
|
||||
|
||||
- `NOT_FOUND` → `"IMAGE.NOT_FOUND"`
|
||||
- `DECODE_FAILED` → `"IMAGE.DECODE_FAILED"`
|
||||
- `ENCODE_FAILED` → `"IMAGE.ENCODE_FAILED"`
|
||||
- `FORMAT_UNSUPPORTED` → `"IMAGE.FORMAT_UNSUPPORTED"`
|
||||
- `TOO_LARGE` → `"IMAGE.TOO_LARGE"`
|
||||
- `PROCESSING_FAILED` → `"IMAGE.PROCESSING_FAILED"`
|
||||
- `DIMENSIONS_INVALID` → `"IMAGE.DIMENSIONS_INVALID"`
|
||||
|
||||
### `ImageCode`
|
||||
|
||||
A TypeScript union of all seven code string literals. Useful for function parameters and discriminated unions.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The registry is produced by `defineCodes("IMAGE", [...])`. If the namespace or code list ever changes, every test that asserts against `IMAGE_CODES.*` will fail, which is the desired behaviour — it prevents silent drift in the error contract.
|
||||
|
||||
Namespaces matter in a package ecosystem. Without the `IMAGE.` prefix, a generic name like `NOT_FOUND` could collide with `DRIVE.NOT_FOUND` or `CONTACTS.NOT_FOUND`. The `defineCodes` utility enforces a namespace at compile time and produces a frozen object, so consumers cannot accidentally mutate the registry at runtime. When adding a new failure mode, the code must be added to the `defineCodes` array first; only then can it be used in `src/` or tests. This two-step discipline ensures the error surface remains intentional and auditable.
|
||||
@@ -0,0 +1,75 @@
|
||||
# errors
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`errors.ts` provides the typed error hierarchy for `@suaveplan/image`. `ImageError` extends `SuaveplanError` so that callers receive structured failures with a stable code, a message key, an optional context object, and an optional cause chain. Typed factory functions make it easy to construct correctly-coded errors without hand-typing string literals.
|
||||
|
||||
## Features
|
||||
|
||||
- `ImageError` class with `code`, `message`, `context`, and `cause`
|
||||
- Factory functions for every failure mode
|
||||
- Backwards-compatibility aliases for upstream consumers
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { imageFormatUnsupported } from "@suaveplan/image/errors";
|
||||
|
||||
function processImage(data: Uint8Array) {
|
||||
if (data.length === 0) {
|
||||
throw imageFormatUnsupported("empty buffer");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { ImageError, IMAGE_CODES } from "@suaveplan/image/errors";
|
||||
|
||||
function enrichError(err: unknown): ImageError {
|
||||
if (err instanceof ImageError) return err;
|
||||
return new ImageError(
|
||||
IMAGE_CODES.PROCESSING_FAILED,
|
||||
"Unexpected failure",
|
||||
{ cause: err instanceof Error ? err : undefined }
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `ImageError`
|
||||
|
||||
Extends `SuaveplanError<ImageCode>`.
|
||||
|
||||
- `constructor(code, messageKey, options?)` — `options` may include `cause` and `context`.
|
||||
- `context?: ImageErrorContext` — carries `format`, `width`, `height`, `pixels`, `maxPixels`, `path`.
|
||||
|
||||
### Factory Functions
|
||||
|
||||
- `imageNotFound(path?)`
|
||||
- `imageDecodeFailed(format?, cause?)`
|
||||
- `imageEncodeFailed(format?, cause?)`
|
||||
- `imageFormatUnsupported(format?)`
|
||||
- `imageTooLarge(pixels, maxPixels)`
|
||||
- `imageProcessingFailed(message, cause?)`
|
||||
- `imageDimensionsInvalid(width, height)`
|
||||
|
||||
### Backwards-Compatibility Aliases
|
||||
|
||||
- `unknownFormat()` → alias for `imageFormatUnsupported()`
|
||||
- `invalidDimensions(w, h)` → alias for `imageDimensionsInvalid(w, h)`
|
||||
- `invalidCrop(msg)` → alias for `imageProcessingFailed("Invalid crop region: " + msg)`
|
||||
- `metadataParseFailed(cause?)` → alias for `imageDecodeFailed(undefined, cause)`
|
||||
- `invalidTransform(msg)` → alias for `imageProcessingFailed("Invalid transform: " + msg)`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All aliases are thin wrappers — they do not duplicate logic. The `ImageErrorContext` interface extends `Record<string, unknown>` so callers can safely add custom fields without losing type safety.
|
||||
|
||||
Because `ImageError` extends `SuaveplanError`, it inherits cause-chain traversal and OTel span-event adaptation for free. When surfacing an image failure inside an HTTP handler, the error can be passed directly to the logger or telemetry layer without manual unpacking. Canonical factories should be preferred for new code; backwards-compatibility aliases exist only to ease migration from upstream packages that used the old naming convention. Each factory constructs the error with a consistent message key derived from the code name, so telemetry dashboards can aggregate by message key while retry policies discriminate by code.
|
||||
@@ -0,0 +1,48 @@
|
||||
# dimensions
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`dimensions.ts` extracts width and height from raw image headers for the four supported raster formats: PNG, JPEG, GIF, and BMP. It is a pure, side-effect-free module consumed by `ImageProcessor`. Short or malformed buffers return `{ width: 0, height: 0 }` rather than throwing, so callers can decide whether zero dimensions are fatal.
|
||||
|
||||
## Features
|
||||
|
||||
- PNG IHDR dimension parsing
|
||||
- JPEG SOF0 marker scanning (skips APP segments)
|
||||
- GIF logical screen dimension parsing
|
||||
- BMP DIB header dimension parsing (handles negative height for top-down bitmaps)
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { parseDimensions } from "@suaveplan/image/processor";
|
||||
|
||||
const dims = parseDimensions(pngBytes, "png");
|
||||
console.log(`${dims.width}x${dims.height}`);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { parseDimensions } from "@suaveplan/image/processor";
|
||||
import { detectFormat } from "@suaveplan/image/types";
|
||||
|
||||
function getDimensions(data: Uint8Array) {
|
||||
const format = detectFormat(data);
|
||||
if (!format) return null;
|
||||
return parseDimensions(data, format);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `parseDimensions(data, format): { width: number; height: number }`
|
||||
|
||||
Dispatches to the appropriate parser based on `format`. Returns `{ width: 0, height: 0 }` for unsupported formats or buffers that are too short.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
JPEG parsing walks the segment chain starting at offset 2 (after the SOI marker). It stops on the first SOF0-SOF15 marker (excluding DHT, DAC, and DHP) and reads the 16-bit width and height fields. BMP parsing uses `Math.abs` on the height field because Windows bitmaps can encode top-down images with a negative height value. TIFF is detected at the format level but dimension parsing is intentionally not implemented yet; callers receive `{ width: 0, height: 0 }` for TIFF rather than an exception, which lets `ImageProcessor` decide whether to treat the format as supported for metadata extraction while deferring dimension work. All four parsers validate buffer length before reading every multi-byte field, so truncated or corrupt headers never throw — they simply return zero dimensions. This design keeps `extractMetadata` robust against partial reads from network streams or damaged files.
|
||||
@@ -0,0 +1,54 @@
|
||||
# instruments
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`instruments.ts` lazily initialises the OpenTelemetry counters and histograms used by `ImageProcessor`. Each instrument is created on first access to avoid registering metrics at module-load time, keeping the package `sideEffects: false`. A matching tracer helper provides span creation for `extractMetadata` and `planTransform`.
|
||||
|
||||
## Features
|
||||
|
||||
- Lazy OTel counter and histogram creation
|
||||
- Four instruments: two counters + two histograms
|
||||
- Tracer helper for span creation
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
This module is internal — consumers do not interact with it directly. `ImageProcessor` calls the helpers automatically.
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
If you need to override the global meter provider in tests, install a custom provider via `@opentelemetry/api` before constructing `ImageProcessor`:
|
||||
|
||||
```ts
|
||||
import { metrics } from "@opentelemetry/api";
|
||||
metrics.setGlobalMeterProvider(myTestProvider);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `getExtractCounter(): Counter`
|
||||
|
||||
Returns the `image.metadata.extracted_total` counter, creating it on first call.
|
||||
|
||||
### `getExtractDuration(): Histogram`
|
||||
|
||||
Returns the `image.metadata.extract_duration_ms` histogram.
|
||||
|
||||
### `getPlanCounter(): Counter`
|
||||
|
||||
Returns the `image.transform.planned_total` counter.
|
||||
|
||||
### `getPlanDuration(): Histogram`
|
||||
|
||||
Returns the `image.transform.plan_duration_ms` histogram.
|
||||
|
||||
### `getTracer(): Tracer`
|
||||
|
||||
Returns the `@suaveplan/image` tracer from the global tracer provider.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The module-level caches mean that switching meter providers after the first instrument has been created has no effect. In practice this is fine because the global provider is set once at application startup. Tests that need deterministic instrumentation should set the provider before the first `ImageProcessor` call.
|
||||
@@ -0,0 +1,63 @@
|
||||
# pipeline-builder
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`pipeline-builder.ts` implements a fluent, chainable API for constructing image transform pipelines. Each method appends an operation to an internal list and returns `this`, so callers can compose resize, crop, rotate, flip, quality, and format changes in a single expression. The builder validates dimensions at call time via Zod-derived guards, surfacing structured `ImageError`s immediately rather than deferring failures to execution.
|
||||
|
||||
## Features
|
||||
|
||||
- Fluent chaining API
|
||||
- Runtime validation of resize and crop dimensions
|
||||
- Quality clamping to `[1, 100]`
|
||||
- Immutable pipeline output via spread copy
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { ImageProcessor } from "@suaveplan/image/processor";
|
||||
|
||||
const proc = new ImageProcessor();
|
||||
const pipeline = proc
|
||||
.createPipeline()
|
||||
.resize({ width: 400 })
|
||||
.toFormat("webp")
|
||||
.quality(75)
|
||||
.build();
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { ImageProcessor } from "@suaveplan/image/processor";
|
||||
|
||||
const proc = new ImageProcessor();
|
||||
const result = proc
|
||||
.createPipeline()
|
||||
.resize({ width: 800, height: 600, fit: "cover" })
|
||||
.crop({ x: 0, y: 0, width: 400, height: 300 })
|
||||
.rotate(90)
|
||||
.apply(metadata, proc);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `PipelineBuilder`
|
||||
|
||||
- `resize(options: ResizeOptions): this` — validates width/height are positive.
|
||||
- `crop(region: CropRegion): this` — validates width/height are positive.
|
||||
- `rotate(degrees: number): this`
|
||||
- `flip(direction: "horizontal" | "vertical"): this`
|
||||
- `quality(value: number): this` — clamps to `[1, 100]`.
|
||||
- `toFormat(format: ImageFormat): this`
|
||||
- `build(): TransformPipeline` — returns a frozen snapshot of operations.
|
||||
- `apply(metadata, processor): TransformResult` — delegates to `processor.planTransform`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Negative or zero dimensions in `resize` and `crop` throw `IMAGE_CODES.DIMENSIONS_INVALID` synchronously. The `quality` clamping is a defensive convenience — passing `150` silently becomes `100`, while passing `0` becomes `1`. This avoids silent truncation bugs in downstream pipelines.
|
||||
|
||||
The internal `ops` array is a plain JavaScript array of discriminated objects. Each fluent method pushes a new object and returns `this`, so multiple calls on the same builder accumulate operations in call order. `build()` spreads the array into a new object, so the returned `TransformPipeline` is immutable — further mutations to the builder do not affect previously built pipelines. The `apply` method is sugar for calling `build()` followed by `processor.planTransform(metadata, pipeline)`, making it easy to use the builder in one-shot expressions without storing the intermediate pipeline object.
|
||||
@@ -0,0 +1,70 @@
|
||||
# processor
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`processor.ts` is the orchestration layer of `@suaveplan/image`. `ImageProcessor` accepts a `Uint8Array` of image bytes, detects the format, parses dimensions, enforces configurable pixel-count limits, and emits structured metadata. It also plans transform pipelines — computing the final dimensions, format, and quality after applying a sequence of resize, crop, rotate, flip, quality, and format operations. All public entrypoints are instrumented with OpenTelemetry counters, histograms, and spans, and they accept an optional `AbortSignal` for cancellation.
|
||||
|
||||
## Features
|
||||
|
||||
- Metadata extraction with format auto-detection
|
||||
- Configurable `maxPixels`, `defaultQuality`, and `defaultFormat`
|
||||
- Transform pipeline planning with dimension tracking
|
||||
- Typed event bus for `metadata.extracted` and `transform.planned`
|
||||
- Zod validation on config and pipeline boundaries
|
||||
- OTel metrics and spans on every operation
|
||||
- `AbortSignal` pre-abort short-circuit
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { ImageProcessor } from "@suaveplan/image/processor";
|
||||
|
||||
const proc = new ImageProcessor({ maxPixels: 50_000_000 });
|
||||
const meta = proc.extractMetadata(imageBytes);
|
||||
console.log(`${meta.format} ${meta.width}x${meta.height}`);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { ImageProcessor } from "@suaveplan/image/processor";
|
||||
|
||||
const proc = new ImageProcessor();
|
||||
proc.on("metadata.extracted", (meta) => {
|
||||
console.log("Extracted", meta.format);
|
||||
});
|
||||
|
||||
const meta = proc.extractMetadata(imageBytes);
|
||||
const result = proc.planTransform(meta, {
|
||||
operations: [
|
||||
{ type: "resize", options: { width: 400 } },
|
||||
{ type: "format", format: "webp" },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `ImageProcessor`
|
||||
|
||||
- `constructor(config?: ImageProcessorConfig)` — validates config via Zod.
|
||||
- `extractMetadata(data, signal?): ImageMetadata` — detects format, parses dimensions, enforces `maxPixels`, emits event.
|
||||
- `planTransform(metadata, pipeline, signal?): TransformResult` — applies operations in order, emits event.
|
||||
- `createPipeline(): PipelineBuilder` — returns a fresh builder instance.
|
||||
- `on(type, listener): unsubscribe` — subscribe to events.
|
||||
- `once(type, listener): unsubscribe` — subscribe once.
|
||||
- `off(type, listener): void` — remove listener.
|
||||
|
||||
### `ImageProcessorConfig`
|
||||
|
||||
- `maxPixels?: number` — default `100_000_000`
|
||||
- `defaultQuality?: number` — default `80`
|
||||
- `defaultFormat?: ImageFormat` — default `"jpeg"`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`extractMetadata` catches non-`ImageError` exceptions and wraps them in `imageDecodeFailed` so callers always receive a typed error. The `finally` blocks guarantee that OTel metrics are emitted even when an error is thrown. Because the event bus is an internal `EventBus` instance, listeners are scoped to the processor — there is no global singleton.
|
||||
@@ -0,0 +1,63 @@
|
||||
# image-detect
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`image-detect.ts` provides fast, deterministic format detection from raw binary headers. It inspects the first bytes of a `Uint8Array` against known magic-byte signatures and falls back to UTF-8 text sniffing for SVG documents. The module is pure and side-effect-free, making it safe to run in any JavaScript runtime including browsers, Node.js, and Bun.
|
||||
|
||||
## Features
|
||||
|
||||
- Magic-byte matching for PNG, JPEG, GIF, BMP, TIFF (little- and big-endian), ICO, and WebP
|
||||
- RIFF/WebP validation: verifies the `WEBP` tag at bytes 8-11 after the `RIFF` header
|
||||
- SVG textual sniffing via UTF-8 decoding of the first 100 bytes
|
||||
- Early return for buffers shorter than 4 bytes
|
||||
- Structured signature table (`FORMAT_SIGNATURES`) for extensibility
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { detectFormat } from "@suaveplan/image/types";
|
||||
|
||||
const header = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);
|
||||
const format = detectFormat(header);
|
||||
console.log(format); // "png"
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { detectFormat, FORMAT_SIGNATURES } from "@suaveplan/image/types";
|
||||
|
||||
function isSupported(header: Uint8Array): boolean {
|
||||
const fmt = detectFormat(header);
|
||||
return fmt !== null;
|
||||
}
|
||||
|
||||
function listSignatures() {
|
||||
return FORMAT_SIGNATURES.map((s) => ({
|
||||
format: s.format,
|
||||
prefix: s.bytes.map((b) => b.toString(16)).join(" "),
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `detectFormat(header: Uint8Array): ImageFormat | null`
|
||||
|
||||
Returns the detected image format or `null` if the header does not match any known signature.
|
||||
|
||||
### `FORMAT_SIGNATURES`
|
||||
|
||||
Readonly array of signature objects:
|
||||
|
||||
- `format: ImageFormat` — the format name
|
||||
- `bytes: readonly number[]` — the magic bytes to match
|
||||
- `offset?: number` — optional byte offset (defaults to `0`)
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
WebP detection is special-cased because the `RIFF` container is shared with other formats (e.g., WAV). After matching the `RIFF` prefix, the function verifies that bytes 8-11 spell `WEBP` (0x57 0x45 0x42 0x50). SVG sniffing uses `TextDecoder` to decode up to 100 bytes and searches for `<svg` or `<?xml` substrings. TIFF has two signatures to cover both little-endian (`II*`) and big-endian (`MM*`) byte orders.
|
||||
@@ -0,0 +1,75 @@
|
||||
# image-types
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`image-types.ts` is the universal type system and pure-function toolkit for image metadata. It defines Zod schemas for every public boundary, a discriminated union for transform operations, magic-byte format detection, resize math with multiple fit modes, crop validation, and MIME-type mapping. Everything in this module is deterministic and side-effect free.
|
||||
|
||||
## Features
|
||||
|
||||
- Magic-byte detection for PNG, JPEG, GIF, BMP, TIFF, ICO, WebP, SVG
|
||||
- Dimension-parsing helpers for the four raster formats
|
||||
- Resize calculator with `cover`, `contain`, `fill`, `inside`, `outside`
|
||||
- Crop validator with bounds checking
|
||||
- Zod schemas for runtime validation
|
||||
- MIME-type and file-extension lookup tables
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { detectFormat, calculateResize, validateCrop } from "@suaveplan/image/types";
|
||||
|
||||
const format = detectFormat(headerBytes);
|
||||
const newSize = calculateResize({ width: 1920, height: 1080 }, { width: 400 });
|
||||
const ok = validateCrop({ width: 800, height: 600 }, { x: 0, y: 0, width: 200, height: 200 });
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { ImageMetadataSchema, MIME_TYPES, formatToExtension } from "@suaveplan/image/types";
|
||||
|
||||
const meta = ImageMetadataSchema.parse({
|
||||
format: "png",
|
||||
width: 100,
|
||||
height: 100,
|
||||
hasAlpha: true,
|
||||
isAnimated: false,
|
||||
});
|
||||
|
||||
const mime = MIME_TYPES[meta.format];
|
||||
const ext = formatToExtension(meta.format);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Zod Schemas
|
||||
|
||||
- `ImageFormatSchema` — enum of supported formats
|
||||
- `ImageMetadataSchema` — full metadata shape
|
||||
- `CropRegionSchema` — x, y, width, height
|
||||
- `ResizeOptionsSchema` — width, height, fit, withoutEnlargement
|
||||
- `TransformOpSchema` — discriminated union of six op types
|
||||
- `TransformPipelineSchema` — operations + outputFormat + quality
|
||||
- `TransformResultSchema` — planned result shape
|
||||
- `ImageProcessorConfigSchema` — maxPixels, defaultQuality, defaultFormat
|
||||
|
||||
### Pure Functions
|
||||
|
||||
- `detectFormat(header: Uint8Array): ImageFormat | null`
|
||||
- `aspectRatio(w, h): string`
|
||||
- `calculateResize(original, options): Dimensions`
|
||||
- `validateCrop(dims, crop): boolean`
|
||||
- `formatToExtension(format): string`
|
||||
|
||||
### Constants
|
||||
|
||||
- `FORMAT_SIGNATURES` — array of magic-byte patterns
|
||||
- `MIME_TYPES` — format → MIME string map
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`detectFormat` decodes up to 100 bytes as UTF-8 to sniff SVG textual headers. For WebP, it validates the `WEBP` tag at bytes 8-11 after the RIFF header. TIFF is detected but dimension parsing is not yet implemented — callers receive `{ width: 0, height: 0 }` for TIFF rather than an exception.
|
||||
Reference in New Issue
Block a user