Release Image Tools 0.1.0
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# Accessibility
|
||||
|
||||
Image Tools uses semantic landmarks, labelled controls, fieldsets, status regions and native buttons/inputs. The file drop target is also a keyboard-operable file input. Queue state is conveyed by text as well as colour, and before/after images have source-specific alternative text.
|
||||
|
||||
The layout collapses to one column on narrow screens. Focus indicators use the Toolbox focus colour, controls remain at least 2.45 rem high, and reduced-motion preferences disable the processing pulse and transitions. Light, dark and system modes inherit the shared Toolbox shell tokens.
|
||||
|
||||
Image comparison is inherently visual. Export dimensions, source/output size, metadata policy, colour policy, errors and operation progress are also exposed as text. The application does not infer meaningful alternative text from private image pixels.
|
||||
@@ -0,0 +1,37 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Privacy and security
|
||||
|
||||
## Local processing
|
||||
|
||||
Selected images stay in the browser. Image Tools has no analytics, telemetry, account, upload endpoint or CDN dependency. Tests fail external requests, and the release CSP restricts scripts, workers, images and connections to packaged/local resources and generated blob URLs.
|
||||
|
||||
## Untrusted input controls
|
||||
|
||||
- Supported signatures are JPEG, PNG and WebP only; a filename or browser-provided MIME type is not trusted.
|
||||
- Metadata inspection reads at most a 1 MiB window; PNG and WebP animation
|
||||
detection additionally read only bounded eight-byte chunk headers and skip
|
||||
payloads by checked offset.
|
||||
- Checked arithmetic protects marker/chunk offsets and declared dimensions.
|
||||
- Sources are limited to 256 MiB each, 512 MiB per queue, 32,768 pixels per edge and 40 megapixels.
|
||||
- Estimated processing memory is limited to 512 MiB.
|
||||
- Recognized APNG, animated WebP and JPEG MPF/multi-picture files are refused before decode.
|
||||
- Each material operation has an abort signal, disposable worker and 120-second deadline.
|
||||
- A batch is sequential and retains at most 256 MiB of completed output.
|
||||
- Imported strings are rendered as React text, never active markup.
|
||||
- Unsafe path characters and leading/trailing dots are removed from generated download names.
|
||||
|
||||
Header inspection is deliberately not full format validation. The browser decoder remains authoritative and may reject a file after the bounded header has passed. The UI reports this as failure, never as an empty successful result.
|
||||
|
||||
## Metadata and colour claims
|
||||
|
||||
The editor decodes to pixels and creates a new encoded file. It does not intentionally copy source EXIF, XMP, ICC, text/comments, embedded thumbnails or trailing bytes. However, it does not independently parse every possible proprietary block or re-scan exported bytes, so it must not be advertised as a verified metadata scrubber or anonymity tool.
|
||||
|
||||
Visible pixels can contain faces, text, locations, watermarks or steganographic data. Copies and sidecars outside the selected file are unaffected. Use a dedicated Privacy Tools audit when available.
|
||||
|
||||
Canvas operates on a browser-managed 8-bit representation. Arbitrary ICC profiles, HDR/wide-gamut precision, original gamma/chroma decisions and original compression are not preserved. JPEG export is lossy, and browser encoder bytes may differ across engines and versions. These limitations appear in the interface and every JSON operation report.
|
||||
|
||||
## Reporting vulnerabilities
|
||||
|
||||
Do not attach a private image to a public issue. Follow [SECURITY.md](../SECURITY.md) and provide a synthetic reproducer where possible.
|
||||
Reference in New Issue
Block a user