Image Optimizer is a client-side web application built with Next.js and React that allows users to compress and optimize images directly in the browser. The application focuses on simplicity, performance, and privacy: all image processing happens locally using browser APIs, and no files are uploaded to a server.
The main goal of the application is to reduce image file size while preserving acceptable visual quality, making it suitable for web delivery, documentation, and general asset optimization.
- Drag-and-drop and file picker image upload
- Support for multiple images in a single session
- Global quality control applied to all images
- Real-time image preview (original and optimized)
- Size comparison and percentage savings per image
- Bulk optimization and bulk download
- Individual image download
- Light and dark theme with system preference support
- Fully client-side processing (no backend required)
-
The user uploads one or more image files using the upload zone.
-
The application creates local object URLs to preview the images.
-
The user adjusts the compression quality using a slider.
-
When the user triggers optimization, each image is processed sequentially:
- The file is read into memory.
- The image is drawn onto a canvas element.
- The canvas is re-encoded as a JPEG blob using the selected quality.
-
Optimized images are displayed alongside original metadata.
-
The user can download individual optimized images or all images at once.
All operations occur in memory and within the browser runtime.
- Next.js (App Router)
- React (Client Components)
- TypeScript
The application uses the Next.js App Router with client components for all interactive logic. There is no server-side image processing.
State is managed locally within React components using useState and useCallback. The primary state includes:
- Uploaded image metadata and object URLs
- Global compression quality value
- Processing state (to disable actions during optimization)
The design avoids shared global state and keeps logic scoped to the components that own it.
Image optimization is implemented using standard browser APIs:
FileReaderto read image dataHTMLImageElementfor decodingHTMLCanvasElementfor renderingcanvas.toBlob()for JPEG re-encoding with adjustable quality
This approach ensures:
- No external dependencies for image compression
- Predictable behavior across modern browsers
- No network usage for processing
The core component responsible for:
- Managing the list of uploaded images
- Storing quality settings
- Coordinating optimization and download actions
- Rendering the main layout (settings + previews)
This component also contains the optimizeImage function, which encapsulates the canvas-based compression logic.
Handles user input for images:
- Drag-and-drop support
- File input fallback
- File type filtering to images only
Emits selected files upward without performing any processing.
Displays per-image information:
- Preview image (original or optimized)
- Original and optimized file sizes
- Percentage savings
- Download and remove actions
Each preview is fully independent and driven by props.
Reusable UI primitives such as buttons, cards, labels, and sliders are implemented using:
- Radix UI primitives
- Tailwind CSS
- Class Variance Authority for styling variants
These components are generic and not coupled to image-specific logic.
- Tailwind CSS for utility-first styling
- CSS variables for color tokens
- Shared design tokens for light and dark themes
- Light and dark themes are supported
- System preference is respected on first load
- User preference is persisted in
localStorage
The theme is applied by toggling a dark class on the root HTML element.
- Object URLs are revoked when images are removed or cleared to avoid memory leaks
- Optimization runs asynchronously to keep the UI responsive
- Processing state disables actions during active compression
Because processing is client-side, performance depends on device capabilities and image resolution.
- Images are re-encoded as JPEG regardless of original format
- Metadata such as EXIF is not preserved
- Very large images may impact performance on low-end devices
- No server-side or batch background processing
These constraints are deliberate to keep the application simple and dependency-free.
app/
layout.tsx # Application layout and metadata
page.tsx # Main entry page
globals.css # Global styles and design tokens
components/
image-optimizer.tsx
image-upload-zone.tsx
image-preview.tsx
theme-provider.tsx
theme-toggle.tsx
ui/ # Reusable UI primitives
lib/
utils.ts # Shared utility functions
styles/
globals.css # Theme and base styles
npm install
npm run dev
npm run build
npm run start
- Compressing images before uploading to websites
- Reducing asset size for documentation or presentations
- Quick local optimization without external tools
- Demonstrating client-side image processing techniques
Image Optimizer is a lightweight, fully client-side image compression tool built with modern React and Next.js. Its design prioritizes clarity, performance, and privacy, while remaining easy to extend or adapt for more advanced image workflows in the future.