Web Application

Image Converter Web App

A browser-native local-first image converter built with React, TypeScript, Web Workers, and a Rust/WebAssembly npm engine.

Web Application TypeScript React WebAssembly

Web App: https://image-converter-web-app-project.leonardwalujan.eu.org/

GitHub: https://github.com/walujanle/image-converter-web-app

GitLab: https://gitlab.com/walujanle/image-converter-web-app

Build File: https://links.leonardwalujan.eu.org/lw/image-converter-web-app-latest-build-file

Build File Checksum (SHA-256): https://links.leonardwalujan.eu.org/lw/image-converter-web-app-latest-build-file-checksum

Source Code: https://links.leonardwalujan.eu.org/lw/image-converter-web-app-latest-source-code

Screenshots

  1. Image Converter Web App Screenshot 1
    Image Converter Web App Screenshot 1
  2. Image Converter Web App Screenshot 2
    Image Converter Web App Screenshot 2
  3. Image Converter Web App Screenshot 3
    Image Converter Web App Screenshot 3
  4. Image Converter Web App Screenshot 4
    Image Converter Web App Screenshot 4

Short Explanation

Image Converter Web App is a browser-native image converter for batch image processing. The application lets users select image files, choose conversion options, run conversion in the browser, and download the converted results without sending the images to an upload API.

The image processing itself is handled by the published npm package @walujanle/image-converter-wasm. This web app is the frontend host around that package: it provides the React interface, simple and advanced modes, queue management, worker orchestration, settings persistence, presets, downloads, ZIP packaging, and production asset caching.

The current app accepts JPEG, PNG, WebP, AVIF, and HEIC/HEIF input files. It can output JPEG, PNG, WebP, and AVIF. HEIC/HEIF is input-only because the current Rust/WASM engine does not expose HEIC output encoding.

Why I Built This Project

I built this project to apply a web-based image conversion workflow where the actual image processing stays local on the user’s own device. The important part was not only making a form with a conversion button, but proving that a frontend app can call my own Rust/WebAssembly npm package and still keep file handling, queueing, settings, and downloads inside the browser.

This project also became the practical consumer of my WASM package. The package provides the conversion engine, while the web app shows how that engine behaves in a real frontend: files are selected through the browser, work is sent to Web Workers, conversion options are mapped into the package API, and the output is returned as downloadable browser blobs.

I wanted the converter to be customizable enough for real use. Users can choose output format, quality, WebP lossless mode, PNG optimization, resize, crop, metadata preservation, filename rules, auto suffixes, batch size, concurrency, presets, and dataset list generation. The goal is not to create a server-side online converter service. The goal is to make a local-first web app that gives the user control over the conversion result.

Tech Stack Used

  • React 19 for the user interface.
  • TypeScript 5.8 for the application code.
  • Vite 8 for development and production builds.
  • Bun for scripts and package management.
  • Zustand for mode-specific application state.
  • Tailwind CSS 4 for styling.
  • Web Workers for conversion execution outside the main UI thread.
  • @walujanle/image-converter-wasm for decode, crop, resize, encode, metadata handling, and output dimensions.
  • JSZip for ZIP download packaging.
  • A generated service worker for production asset caching.
  • Biome for linting.
  • Vitest for tests.

This web app repository is licensed as AGPL-3.0-only, matching the WASM package that is shipped to the browser runtime.

Features

Local-first batch conversion

Users can add images to a queue and convert them in batches. The source repository does not implement an upload API, and the conversion flow is designed around local browser files and browser downloads.

Supported formats

Input support covers JPEG, PNG, WebP, AVIF, HEIC, and HEIF. Output support covers JPEG, PNG, WebP, and AVIF. GIF, BMP, TIFF, and RAW formats are not part of the current web app contract.

Simple and Advanced modes

Simple mode focuses on common conversion controls: output format, quality presets for lossy formats, PNG optimization, queue management, conversion, cancellation, and downloads.

Advanced mode exposes the full conversion panel, image queue, batch actions, and preset manager. It includes resize, crop, filename transforms, auto suffixes, dataset list generation, batch size, and more detailed output controls.

Independent mode state

Simple mode and Advanced mode have separate queues and separate persisted settings. Switching modes does not reuse the same queue by accident.

Worker-based conversion

The app uses a worker pool. Conversion jobs are sent to dedicated Web Workers, and those workers call @walujanle/image-converter-wasm. This keeps expensive conversion work away from the main UI thread.

Background engine warmup

After the page loads, the app warms the converter worker so the WASM engine can be ready before the first conversion. The UI shows a small toast for the warmup/cache state, and conversion can still initialize on demand if background warmup fails.

Production asset cache

Production builds generate a service worker. It precaches hashed JavaScript, CSS, worker, and WASM assets, then removes older app caches when emitted filenames change. This is used to make repeat visits faster without hardcoding a manual cache version.

Memory guards

Before conversion, the app estimates browser memory usage. Files that look unsafe for browser memory are rejected before worker conversion. The current hard file size limit is 256 MB, and resize inputs are limited to 7680 px.

Filename and dataset output

The app can sanitize output names, replace file extensions, add prefixes, apply find/replace, avoid filename collisions, and add optional automatic suffixes based on output dimensions and quality. Dataset list generation creates dataset_log.txt; when it is enabled, non-individual downloads are packaged as ZIP files so the log can be delivered with the images.

Presets

Users can save, apply, import, and export conversion presets. Preset import is validated before settings are accepted.

Metadata preservation

Metadata preservation is opt-in through the app settings. When enabled, the request is passed to the WASM package. Coverage depends on the output format, and AVIF metadata preservation is more limited than JPEG, PNG, and WebP.

How It Works

The app starts by creating a WorkerPool. A background warmup request initializes one converter worker and calls the WASM package init() function. In production, the app also registers the generated service worker for the app cache.

When users select files, the app validates file size, declared MIME type, binary signatures, and ISO BMFF brands for AVIF and HEIC/HEIF. The app does not trust filename extension or browser-provided File.type alone.

When conversion starts, useConverter() snapshots the active mode, active queue, and active settings. It builds output filenames, checks memory estimates, and sends jobs into a concurrency queue. The worker pool dynamically creates conversion workers up to the configured limit.

Each worker receives the file bytes and conversion settings. The worker maps the web app settings into the public options shape used by @walujanle/image-converter-wasm, then calls convertImageWithInfo(...). The WASM package handles image decoding, optional crop, optional resize, encoding, metadata handling, and final output dimensions.

When a conversion finishes, the worker returns a Blob, dimensions, output format, and duration. The UI stores that as a converted artifact. Users can download individual files directly from the queue, download completed files, or download a ZIP when there are multiple outputs or when dataset list generation is enabled.

Cancellation is handled defensively. Queued tasks can be aborted before they start, active worker work is guarded against stale UI updates, and workers can be restarted after cancellation or warmup timeout.

Privacy and Security Notes

The app is designed as a local-first frontend. The repository has no upload API, cookies, or first-party analytics code. Files are selected from the user’s browser session, processed through browser workers, and downloaded back through Blob URLs.

Validation is still important because local processing can still be abused by malformed or oversized files. The app checks accepted MIME types, content signatures, ISO BMFF brands, file size, crop settings, resize settings, batch size, preset import size, and other settings before accepting work.

Metadata is treated carefully because EXIF, XMP, IPTC, and ICC data can include GPS location, camera information, author names, timestamps, and editing history. Metadata preservation is disabled by default and must be explicitly enabled by the user.

The production headers file includes security and caching headers for hosts that support static _headers files, including HSTS, Referrer-Policy, Permissions-Policy, nosniff, frame denial, COOP, COEP, CORP, immutable asset caching, and no-store behavior for the service worker file.

Build and Development Notes

The repository is a web application, not an npm package. It consumes the published npm package @walujanle/image-converter-wasm as a runtime dependency.

Common development commands:

bun install
bun run dev
bun run lint
bun run typecheck
bun run test
bun run test:coverage
bun run audit
bun run build

The source project documents the latest stable state as 1.0.3 - Stable Version. The latest validation baseline recorded in the repository is 21 test files and 276 tests passing, with lint, typecheck, coverage, audit, and production build also passing.

Limit Problems

  • Conversion is browser memory-bound, so large files can be rejected before conversion.
  • Separate chunked streaming conversion is disabled; conversion uses the worker pipeline after memory checks.
  • HEIC/HEIF is input-only. HEIC output is not available.
  • GIF, BMP, TIFF, and RAW files are not part of the current web app input contract.
  • AVIF output has limited metadata preservation compared with JPEG, PNG, and WebP.
  • Resize controls are available in Advanced mode and the maximum resize input is 7680 px.
  • Dataset numbering only applies to the generated dataset list file, not to individual output filenames.
  • Full WCAG conformance still requires manual assistive technology testing and external accessibility checks beyond the current test suite.
  • Legal compliance and production security certification depend on the actual deployment and operational controls, not only on the source code.

License

Image Converter Web App is released under AGPL-3.0-only.

The application distributes and runs @walujanle/image-converter-wasm in the browser, and that engine package is also licensed as AGPL-3.0-only. The matching license keeps the web app and the browser-delivered WASM runtime aligned.

Latest Projects