38 lines
3.4 KiB
Markdown
38 lines
3.4 KiB
Markdown
# Architecture
|
||
|
||
Image Tools is a relocatable Vite/React application using the shared Toolbox shell. It has no server component, account, database, telemetry or remote processing API.
|
||
|
||
## Trust boundary and lifecycle
|
||
|
||
Every selected `File` is untrusted. `src/image/headers.ts` reads a metadata window of at most the first 1 MiB with `Blob.slice()` and performs checked-offset parsing for JPEG markers, PNG chunks and WebP RIFF chunks. PNG and WebP receive an additional structural pass that reads only eight-byte chunk headers, skips payloads by checked offset, stops at image data, and refuses more than 4,096 pre-image chunks. This prevents APNG or animated-WebP control chunks hidden behind a large ancillary payload from bypassing static-only enforcement. Inspection establishes dimensions, recognized animation/multi-picture state, EXIF orientation and a bounded metadata inventory. The image is not given to a browser decoder until source, dimension, pixel and estimated-memory policies pass.
|
||
|
||
Each preview or export gets its own generation-bound module worker. The caller terminates the worker on replacement, cancellation, unmount or the 120-second deadline, so a stale result cannot replace current state. Files are structured-cloned to the worker; results return as `Blob` objects. Browsers without worker `OffscreenCanvas` use the same pure pipeline on the main thread and report missing capabilities instead of substituting a remote service.
|
||
|
||
Object URLs are scoped to React lifecycles and revoked on replacement/unmount. Source files are never mutated. Downloads happen only after an explicit user action.
|
||
|
||
## Operation order
|
||
|
||
The canvas pipeline has one documented order:
|
||
|
||
1. Decode with `createImageBitmap(..., { imageOrientation: "none" })`.
|
||
2. Normalize EXIF orientation 1–8 into visible pixel coordinates.
|
||
3. Apply the normalized crop rectangle.
|
||
4. Apply the selected quarter-turn and flips around the image centre.
|
||
5. Apply fit, centre-cropped fill, exact resize, or keep the transformed size.
|
||
6. Composite transparency over the selected background for JPEG only.
|
||
7. Encode with the browser's PNG, JPEG or WebP canvas encoder.
|
||
|
||
The returned MIME type must exactly equal the requested type. A browser that substitutes PNG for an unsupported encoder produces an error and no misleading filename.
|
||
|
||
Intermediate canvases are released as soon as their next stage is drawn. The conservative preflight estimate allows twelve live bytes per source pixel, covers three RGBA-sized surfaces, and rejects sources above 40 megapixels or 512 MiB estimated working memory. Preview output is capped to a 1,600-pixel edge, while reports retain intended export dimensions. Batch execution is sequential and keeps at most 256 MiB of completed output blobs.
|
||
|
||
## Domain boundaries
|
||
|
||
Format inspection, checked limits, geometry, filenames, reports, downloads and processor RPC are separate modules under `src/image/`. These are deliberately shaped for later replacement with `@add-ideas/toolbox-helpers` primitives. The Helpers 0.1 package was not yet published while this slice was implemented, so Image Tools does not carry an unresolved dependency.
|
||
|
||
No third-party codec or helper runtime dependency is added in v0.1. Native
|
||
codecs avoid a large WASM/source-identity release burden, at the cost of
|
||
explicitly documented browser-dependent encoding and colour-management
|
||
behaviour. A future controlled codec adapter can implement the same processing
|
||
request/result contract without changing the UI model.
|