# Local Image Editor A fast, privacy-friendly browser image overlay editor. Upload a PNG, JPEG, or WebP image, add one or more predefined or custom overlays, position them precisely, and download the result at the source image's original resolution. All user image processing happens locally in the browser. The project has no backend, database, image upload endpoint, account system, or credentials. The interface supports English and Portuguese (Portugal). It uses the browser language by default and remembers the selected language locally. ## Highlights - Multiple independent overlays - Runtime-configured overlay library - Custom local overlay uploads - Mouse, touch, and numeric X/Y/width controls - Accessible overlay selector for keyboard users - Four quick corner positions with bounds enforcement - Original-image pixels remain the canonical coordinate system - Low-resolution interactive Fabric.js backing canvas for better mobile memory usage - Full-resolution PNG/JPEG export only when needed - JPEG export explicitly flattens transparency onto white - No server-side image processing ## Run locally Requirements: Node.js 22 or newer and npm. ```sh npm ci npm run dev ``` Open the URL printed by Vite. Useful checks: ```sh npm run type-check npm test npm run lint npm run security-check npm run build ``` Or run all non-build checks together: ```sh npm run check ``` The application uses Fabric only in the browser. CI and Docker use `npm ci` so installs are reproducible from the committed lockfile. ## Docker Create an optional local `.env` from the public example and set a host port or overlay directory if needed: ```sh cp .env.example .env docker compose up --build ``` The application is served at `http://localhost:8080` unless `APP_PORT` is changed. Compose mounts `OVERLAYS_DIR` read-only at `/usr/share/nginx/html/overlays` in the container. It defaults to `./public/overlays`: ```env OVERLAYS_DIR=/srv/local-image-editor/overlays ``` Images and `overlays.json` in that directory are served with revalidation rather than week-long caching, so a replaced logo is picked up on reload without rebuilding the container. The included nginx configuration adds a restrictive Content Security Policy and basic browser security headers. ## Overlay library Predefined overlays are loaded at runtime from `public/overlays/overlays.json`. In Docker deployments, this is the directory configured by `OVERLAYS_DIR`. Example entry: ```json { "id": "example-badge", "name": "Example badge", "file": "example-badge.png" } ``` Overlay configuration is intentionally restricted to simple local PNG/JPEG/WebP filenames. Empty fields, duplicate IDs/files, nested paths, remote URLs, path traversal, and unsupported extensions are rejected. To add an overlay: 1. Copy the image into the overlay directory. 2. Add its entry to `overlays.json`. 3. Reload the application. No Vue source change or image rebuild is required. ## Coordinate and rendering model The source image's original dimensions are always the logical coordinate system. For example, a `4032 x 3024` image remains a `4032 x 3024` logical scene even when the editor is displayed at `900 x 675`. Fabric.js uses a viewport transform to render that scene into a smaller interactive backing store. This keeps X/Y/width values pixel-accurate while avoiding multiple full-resolution canvas surfaces during normal editing. During export, the canvas is temporarily rendered at the exact source dimensions. The normal low-resolution editor state and selection are restored in a `finally` block even if export fails. ## Public repository and configuration security The repository is designed to be safe to publish. - `.env` and `.env.*` are ignored by Git and Docker, except `.env.example`. - `.env.example` contains only non-sensitive Docker Compose values. - There are no `VITE_*` deployment settings because Vite values are compiled into browser JavaScript and therefore cannot hold secrets. - If a future feature requires a real secret, it must be handled by a server-side component or deployment secret store and must never be bundled into this frontend. - CI runs a small repository security check and a production dependency audit. Do not commit credentials, tokens, passwords, private keys, private certificates, or private deployment configuration. ## Runtime/deployment path The Docker/nginx setup expects the application to be exposed at the root of a hostname, for example: ```text https://editor.example.com/ ``` The Vite bundle itself uses relative asset URLs, but if a reverse proxy publishes it under a path prefix, the proxy must strip that prefix before forwarding requests to the included nginx container so `/overlays/` continues to resolve correctly. ## Quality checks A Gitea Actions workflow is provided in `.gitea/workflows/quality.yml`. It runs: ```text npm ci npm run check npm run build npm audit --omit=dev --omit=optional --audit-level=high ``` Unit tests cover coordinate/display scaling, transformed overlay bounds, corner positioning, and overlay-library validation. The repository check also detects common formatting/configuration mistakes and basic accidental secret material. ## Replacing the background If overlays already exist, the app asks for confirmation before replacing the background because the current composition will be cleared. The header branding is intentionally not a link so it cannot accidentally reload and discard a composition. ## Licensing This repository may be publicly readable, but public visibility alone does not grant reuse or redistribution rights. Choose and add a `LICENSE` file explicitly if the project is intended to be open source.