Skip to content

geo-mena/squish

Repository files navigation

Squish Icon

Squish β€” Modern Image Compression Tool

Browser-based image compression powered by WebAssembly, with zero server uploads.

Introduction

Squish is a browser-based image compression tool engineered to deliver high-performance optimization entirely on the client side, without transmitting files to any external server. The application leverages WebAssembly codecs through the jSquash library, enabling native-speed encoding and decoding directly within the browser runtime.

The tool supports five industry-standard image formats β€” AVIF, JPEG via MozJPEG, JPEG XL, PNG via OxiPNG and WebP β€” and exposes granular quality controls per format, batch processing capabilities and real-time compression statistics through an intuitive drag-and-drop interface.

A live instance is available at squish.tofi.pro.

Features

  • Multi-Format Compression: full encoding and decoding support for AVIF, JPEG, JPEG XL, PNG and WebP, each powered by dedicated WebAssembly modules.
  • Client-Side Processing: all compression operations execute in the browser, ensuring that no image data leaves the user's device at any point.
  • Smart Queue System: a parallel processing queue with a concurrency limit of three simultaneous operations prevents browser resource exhaustion during large batch workloads.
  • Batch Processing: multiple images can be uploaded, compressed and downloaded in a single workflow.
  • Format Conversion: images can be transcoded from any supported source format to any supported target format.
  • Per-Format Quality Control: adjustable quality settings for lossy formats, with PNG operating in lossless mode exclusively.
  • Real-Time Preview: compressed image previews and size reduction statistics are rendered as each file completes processing.
  • Drag and Drop Interface: native HTML5 drag-and-drop with file type validation for seamless image ingestion.
  • Dark Mode: theme switching support via system preference detection and manual toggle.

Architecture

Squish follows a component-based architecture built on React 18 with TypeScript in strict mode, organized into four clearly delineated layers.

flowchart LR
    A[DropZone\nCompressionOptions\nImageList\nDownloadAll] -->|state & events| B[useImageQueue]
    B -->|encode / decode| C[imageProcessing.ts\nwasm.ts\ncanvas.ts\nresize.ts]
    C -->|WASM calls| D[avif Β· jpeg Β· jxl\npng Β· webp]
Loading

The UI Layer comprises React components responsible for presentation: DropZone handles file ingestion, CompressionOptions manages format selection and quality adjustment, ImageList renders processing status per image, and DownloadAll enables batch downloads.

The State Management Layer centralizes orchestration through the useImageQueue hook, which implements a queue-based parallel processing strategy. This hook tracks processing state via refs rather than React state to avoid unnecessary re-renders during high-throughput operations.

The Business Logic Layer encapsulates encoding, decoding, WASM module initialization, canvas manipulation and image resizing as pure utility functions, decoupled from any UI concern.

The Codec Layer consists of five jSquash WebAssembly packages, each wrapping a production-grade compression library: libavif for AVIF, MozJPEG for JPEG, libjxl for JPEG XL, OxiPNG for PNG and libwebp for WebP.

Compression Pipeline

The following diagram illustrates the complete lifecycle of an image from ingestion to download.

flowchart LR
    A[File Drop / Select] --> B[Validate MIME Type]
    B --> C[Create ImageFile Object]
    C --> D[Add to Processing Queue]
    D --> E{Concurrency < 3?}
    E -- Yes --> F[Read as ArrayBuffer]
    E -- No --> G[Wait in Queue]
    G --> E
    F --> H[Detect Source Format]
    H --> I[Decode via jSquash Codec]
    I --> J[Encode to Target Format]
    J --> K[Generate Blob + Preview URL]
    K --> L[Update Status: Complete]
    L --> M[User Downloads]
Loading

Upon file ingestion, the DropZone component validates MIME types and, for JPEG XL files, performs an additional extension-based check given the limited browser MIME support for this format. Each validated file is wrapped in an ImageFile object with a unique identifier, original size metadata and a pending status.

The useImageQueue hook then orchestrates processing. A requestAnimationFrame call ensures the UI renders the pending state before compression begins, preventing visual freezing during large uploads. The queue enforces a maximum of three concurrent operations, processing additional files as slots become available.

Each image traverses a decode-then-encode pipeline: the source file is read as an ArrayBuffer, decoded to raw ImageData using the appropriate jSquash codec, then re-encoded to the target format with the user-specified quality settings. The resulting compressed Blob and its corresponding Object URL are stored in state, and the image status transitions to complete.

Default Quality Settings

Format Default Quality Compression Mode
AVIF 50% Lossy, effort level 4
JPEG 75% Lossy via MozJPEG
JPEG XL 75% Lossy
PNG β€” Lossless via OxiPNG
WebP 75% Lossy

Technology Stack

Squish is built on a carefully selected set of modern web technologies.

  • React 18 with TypeScript 5 in strict mode for the application foundation.
  • Vite 5 as the build tool, with jSquash packages excluded from dependency optimization to preserve proper dynamic WASM imports.
  • Tailwind CSS 3 for utility-first styling, complemented by shadcn/ui components built on Radix UI primitives.
  • Lucide React for the icon system.
  • next-themes for dark mode support with class-based toggling and system preference detection.
  • clsx and tailwind-merge for conditional class name composition.

Project Structure

squish/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ CompressionOptions.tsx
β”‚   β”‚   β”œβ”€β”€ DropZone.tsx
β”‚   β”‚   β”œβ”€β”€ ImageList.tsx
β”‚   β”‚   β”œβ”€β”€ DownloadAll.tsx
β”‚   β”‚   └── providers/
β”‚   β”‚       └── theme-provider.tsx
β”‚   β”œβ”€β”€ hooks/
β”‚   β”‚   └── useImageQueue.ts
β”‚   β”œβ”€β”€ ui/
β”‚   β”‚   β”œβ”€β”€ button.tsx
β”‚   β”‚   β”œβ”€β”€ card.tsx
β”‚   β”‚   └── slider.tsx
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”œβ”€β”€ imageProcessing.ts
β”‚   β”‚   β”œβ”€β”€ wasm.ts
β”‚   β”‚   β”œβ”€β”€ formatDefaults.ts
β”‚   β”‚   β”œβ”€β”€ download.ts
β”‚   β”‚   β”œβ”€β”€ canvas.ts
β”‚   β”‚   └── resize.ts
β”‚   β”œβ”€β”€ types/
β”‚   β”‚   β”œβ”€β”€ encoders.ts
β”‚   β”‚   └── types.ts
β”‚   β”œβ”€β”€ App.tsx
β”‚   β”œβ”€β”€ main.tsx
β”‚   └── index.css
β”œβ”€β”€ public/
β”œβ”€β”€ vite.config.ts
β”œβ”€β”€ tsconfig.json
β”œβ”€β”€ tailwind.config.js
└── package.json

Getting Started

Prerequisites

  • Node.js 18 or later
  • npm 7 or later

Installation

  1. Clone the repository:
git clone https://github.com/geo-mena/squish.git
cd squish
  1. Install dependencies:
npm install
  1. Start the development server:
npm run dev
  1. Build for production:
npm run build

Usage

  1. Drop or Select Images: drag and drop images onto the upload area or click to select files from the file system.
  2. Choose Output Format: select the desired target format among AVIF, JPEG, JPEG XL, PNG or WebP.
  3. Adjust Quality: use the quality slider to calibrate the balance between file size and visual fidelity. This control is disabled for PNG, which operates in lossless mode.
  4. Download: retrieve individual compressed images or use the batch download function to export all completed files.

Contributing

Contributions are welcome. Please open an issue first to discuss proposed changes before submitting a Pull Request.

  1. Fork the repository
  2. Create your feature branch: git checkout -b feature/AmazingFeature
  3. Commit your changes: git commit -m 'Add some AmazingFeature'
  4. Push to the branch: git push origin feature/AmazingFeature
  5. Open a Pull Request

License

This project is licensed under the MIT License. See the LICENSE file for details.

Acknowledgments

  • jSquash for the WebAssembly image codec implementations
  • MozJPEG for JPEG compression
  • libavif for AVIF support
  • libjxl for JPEG XL support
  • OxiPNG for PNG optimization

About

🎴 Compress and convert your images to AVIF, JPEG, JPEG XL, PNG, or WebP.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors