# PortalFit - Technical Specification & Failure-Mode Map

## 1. Overview
PortalFit is a client-side web tool for resizing and target-KB compressing photos to exact passport, visa, and portal specifications without uploading data to any external server.

## 2. Input Contract
- **File Types Accepted:** JPEG (`image/jpeg`), PNG (`image/png`), WebP (`image/webp`). Output is always normalized to JPEG (`image/jpeg`).
- **Dimensions:** Target width and target height in pixels (positive integers).
- **Target KB Range:** `minKB` and `maxKB` (integers, `maxKB >= minKB > 0`).
- **EXIF Orientation:** Must be extracted from JPEG binary header (tags 1..8) and physically transformed onto the canvas before resizing. CSS orientation properties (`image-orientation`) are not relied upon.

## 3. Processing State Machine
The core binary search / compressor must return exactly one of the following state status codes:

1. `ALREADY_IN_RANGE`:
   - Source image already matches target width & height (or falls within aspect ratio) AND byte size is between `minKB` and `maxKB`.

2. `SUCCESS_EXACT`:
   - Binary search successfully found a JPEG quality factor `q ∈ [0.1, 1.0]` yielding file size `S` where `minKB <= S <= maxKB` (or within ±1 KB tolerance).

3. `CLOSEST_POSSIBLE`:
   - Target range is unreachable (e.g. image contains high frequency noise that cannot reach `< minKB` or `< maxKB` even at quality 0.1, or quality 1.0 is still smaller than `minKB`). The engine produces the closest achievable compression ratio and returns actionable advice.

4. `FILE_TOO_SMALL`:
   - Source image dimensions are smaller than the requested target width/height, and upscaling is disabled to prevent pixelation/rejection by visa portals.

5. `UNSUPPORTED_FORMAT`:
   - The input file is corrupt, unreadable by HTML5 Image element, or an unsupported file type.

## 4. Edge Cases & Guardrails
- **EXIF Orientation != 1:** Physical canvas rotation must take place prior to downscaling.
- **Large Image Protection:** If source image dimension exceeds 4096px, downscale to a maximum bounding canvas of 4096×4096 first to avoid mobile browser canvas memory crashes.
- **Memory Management:** All Object URLs created via `URL.createObjectURL()` must be explicitly revoked (`URL.revokeObjectURL()`) when a new image is loaded or after download completes.
- **Animated Images (GIF / APNG):** HTML5 Image element decoding extracts frame 0. User is advised that static frame 0 will be processed.
- **Quality Floor:** Minimum allowed quality factor during binary search is `0.1`.
- **Iteration Limit:** Maximum 15 binary search iterations.

## 5. Security & Privacy Guarantees
- Zero outbound network requests (`fetch`, `XMLHttpRequest`, `sendBeacon`, `WebSocket`).
- All scripts are inline or local.
- No external CDNs, tracking scripts, or remote web fonts.
- Favicon embedded as Data URI.
