# PNGer - Modern PNG Editor & Resizer A sleek, modern PNG editor and resizer with **live preview**, **dark/light mode theming**, and direct upload/download features. Built with TypeScript and deployed as a single Docker container on Unraid. ## ✨ Features ### 🎨 Modern UI with Dark/Light Mode - **Dark Mode**: Black background (#0a0a0a) with light gold (#daa520) accents - **Light Mode**: White background with dark gold (#b8860b) accents - Perfect for inspecting PNG transparency on different backgrounds - Persistent theme preference - Smooth color transitions ### ⚡ Live Preview - **Real-time preview** of transformations before download - **Side-by-side comparison** (original vs transformed) - **File size analysis** showing savings or increase - **Instant feedback** using client-side Canvas API (< 500ms) - No server round-trip needed for preview ### 🖼️ Image Operations - **Resize Operations**: Width, height, and aspect ratio controls - **Crop to Fit**: Smart cropping with position control (9 positions) - **Format Conversion**: PNG, WebP, and JPEG output - **Quality Control**: Adjustable compression settings (10-100%) - **Fit Modes**: Inside (resize only) or Cover (crop to fill) ### 🚀 Performance & Usability - **Direct Download**: No server-side storage, immediate download - **Modern UI**: Sleek, responsive TypeScript/Svelte design - **File Analysis**: Original size, transformed size, savings percentage - **Debounced Updates**: Smooth preview generation (300ms delay) - **Visual Feedback**: Loading states, error messages, success indicators ## Tech Stack - **Frontend**: Svelte 4 + Vite + TypeScript - **Backend**: Node.js + Express + TypeScript - **Image Processing**: Sharp (high-performance image library) - **Preview**: Canvas API (client-side) - **Container**: Docker (Alpine-based, multi-stage build) - **Deployment**: Unraid via Docker Compose ## Quick Start ### Unraid Deployment (Recommended) 1. **Clone or pull this repository to your Unraid server:** ```bash cd /mnt/user/appdata git clone https://git.alwisp.com/jason/pnger.git cd pnger ``` 2. **Build the Docker image:** ```bash docker build -t pnger:latest . ``` 3. **Run via docker-compose:** ```bash docker compose up -d ``` 4. **Access the application:** - Navigate to `http://[unraid-ip]:8080` ### Unraid Environment Variables (Configurable via UI) When setting up in Unraid Docker UI, you can configure: | Variable | Default | Description | |----------|---------|-------------| | `HOST_PORT` | `8080` | External port to access the app | | `MAX_FILE_SIZE` | `10485760` | Max upload size in bytes (10MB default) | | `MEM_LIMIT` | `512m` | Memory limit for container | | `CPU_LIMIT` | `1.0` | CPU limit (1.0 = 1 full core) | | `NODE_ENV` | `production` | Node environment | ### Unraid Docker Template Example ```xml pnger pnger:latest bridge false http://[IP]:[PORT:8080] 8080 10485760 512m ``` ## Local Development ### Prerequisites - Node.js 20+ - npm or yarn ### Setup 1. **Install backend dependencies:** ```bash cd backend npm install ``` 2. **Install frontend dependencies:** ```bash cd frontend npm install ``` 3. **Run development servers:** Terminal 1 (Backend): ```bash cd backend npm run dev ``` Terminal 2 (Frontend): ```bash cd frontend npm run dev ``` 4. **Access dev server:** - Frontend: `http://localhost:5173` - Backend API: `http://localhost:3000/api` ### Building for Production ```bash # Backend TypeScript compilation cd backend npm run build # Frontend build cd frontend npm run build ``` ## Docker Deployment (Manual) ```bash # Build the image (all dependencies and builds are handled internally) docker build -t pnger:latest . # Run the container docker run -d \ --name pnger \ -p 8080:3000 \ -e MAX_FILE_SIZE=10485760 \ --restart unless-stopped \ pnger:latest ``` ## Project Structure ``` pnger/ ├── frontend/ # Svelte + TypeScript application │ ├── src/ │ │ ├── App.svelte # Main UI component (with live preview) │ │ ├── main.ts # Entry point │ │ ├── app.css # Design system (dark/light modes) │ │ └── lib/ │ │ ├── api.ts # API client │ │ ├── preview.ts # Live preview logic │ │ └── theme.ts # Theme management store │ ├── package.json │ ├── tsconfig.json │ └── vite.config.ts ├── backend/ # Express + TypeScript API server │ ├── src/ │ │ ├── index.ts # Express server │ │ ├── routes/ │ │ │ └── image.ts # Image transform endpoint │ │ └── types/ │ │ └── image.ts # TypeScript types │ ├── package.json │ └── tsconfig.json ├── Dockerfile # Multi-stage build (frontend + backend) ├── docker-compose.yml # Unraid deployment config ├── ROADMAP.md # Feature roadmap └── UI_UPGRADE_NOTES.md # UI upgrade documentation ``` ## How It Works 1. User uploads an image via the web interface 2. **Live preview** generates instantly using Canvas API 3. User adjusts parameters (width, height, quality, format, etc.) 4. Preview updates in real-time (debounced 300ms) 5. User sees file size comparison and savings 6. When satisfied, user clicks "Transform & Download" 7. Frontend sends image + parameters to backend API 8. Backend processes using Sharp (resize, crop, compress, convert) 9. Processed image returned directly to browser 10. Browser triggers automatic download 11. No files stored on server (stateless operation) ## API Endpoints ### POST /api/transform Transform an image with resize, crop, and format conversion. **Request:** - Method: `POST` - Content-Type: `multipart/form-data` - Body: - `file`: Image file (PNG/JPEG/WebP) - `width`: Target width (optional) - `height`: Target height (optional) - `quality`: Quality 10-100 (optional, default: 80) - `format`: Output format `png|webp|jpeg` (optional, default: `png`) - `fit`: Resize mode `inside|cover` (optional, default: `inside`) - `position`: Crop position when `fit=cover` (optional, default: `center`) **Response:** - Content-Type: `image/[format]` - Body: Transformed image binary ## Configuration All configuration is handled via environment variables passed through Docker/Unraid: - `PORT`: Server port (default: `3000`, internal) - `MAX_FILE_SIZE`: Maximum upload size in bytes (default: `10485760` = 10MB) - `TEMP_DIR`: Temporary directory for uploads (default: `/app/temp`) - `NODE_ENV`: Node environment (default: `production`) ## UI Features in Detail ### Dark/Light Mode - **Toggle Button**: Sun (☀️) / Moon (🌙) icon in header - **Persistent**: Saved to localStorage - **System Detection**: Uses OS preference on first visit - **Smooth Transitions**: Colors fade smoothly (250ms) - **Use Case**: Compare PNG transparency on black vs white backgrounds ### Live Preview - **Side-by-Side**: Original image on left, preview on right - **File Size**: Shows before and after sizes - **Savings Indicator**: Green for reduction, yellow for increase - **Instant Updates**: Debounced at 300ms for smooth performance - **Canvas-Based**: No server load, runs in browser ### Image Analysis - Original file size displayed - Preview size estimation - Savings/increase percentage - Visual feedback with color coding ## Roadmap See [ROADMAP.md](./ROADMAP.md) for planned features including: - Drag & drop upload - Batch processing - Smart presets - Watermarking - Advanced crop tool - And more! ## License MIT License - See LICENSE file for details ## Repository https://git.alwisp.com/jason/pnger ## Screenshots ### Light Mode Clean white interface with dark gold accents, perfect for inspecting dark images ### Dark Mode Sleek black interface with light gold accents, ideal for viewing light/transparent PNGs ### Live Preview Side-by-side comparison showing original and transformed image with file size analysis