UNPKG

merge-jpg

Version:

A privacy-first client-side image merging library powered by TLDraw Canvas

308 lines (228 loc) โ€ข 8.61 kB
# merge-jpg [![npm version](https://badge.fury.io/js/merge-jpg.svg)](https://badge.fury.io/js/merge-jpg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) A **privacy-first**, client-side image merging library powered by TLDraw Canvas. Combine multiple images into a single image or PDF document entirely within the browser - no server uploads required! ## ๐ŸŒŸ Features - **๐Ÿ”’ Complete Privacy**: All processing happens in your browser - images never leave your device - **โšก High Performance**: Powered by TLDraw Canvas with WebGL acceleration - **๐Ÿ“ฑ Zero Dependencies**: Works in any modern browser without additional setup - **๐ŸŽจ Flexible Output**: Generate JPEG, PNG, or multi-page PDF documents - **๐Ÿ›ก๏ธ TypeScript First**: Full type safety with comprehensive TypeScript definitions - **๐Ÿ“ Smart Layout**: Automatic horizontal/vertical layout with customizable spacing - **๐ŸŽฏ Easy Integration**: Simple API with both class-based and functional interfaces ## ๐Ÿš€ Quick Start ### Installation ```bash npm install merge-jpg ``` ### Basic Usage ```typescript import { mergeFiles } from 'merge-jpg'; // Simple merge with file input const fileInput = document.querySelector('#file-input') as HTMLInputElement; const files = Array.from(fileInput.files || []); const result = await mergeFiles(files, { direction: 'vertical', format: 'jpeg', quality: 90, spacing: 10, backgroundColor: '#ffffff' }); // Download the result const link = document.createElement('a'); link.href = result.url; link.download = result.filename; link.click(); // Don't forget to cleanup the blob URL URL.revokeObjectURL(result.url); ``` ### Advanced Usage with Progress Tracking ```typescript import { ImageMerger } from 'merge-jpg'; const merger = new ImageMerger(); await merger.initialize(); const result = await merger.mergeFiles(files, { direction: 'horizontal', format: 'png', spacing: 20, backgroundColor: '#f0f0f0' }, (progress) => { console.log(`Progress: ${progress}%`); // Update your progress bar here }); // Cleanup when done merger.destroy(); ``` ### PDF Generation ```typescript import { mergeFiles } from 'merge-jpg'; const pdfResult = await mergeFiles(files, { format: 'pdf', pdfPageSize: 'a4' // Each image becomes a separate page }); // Download PDF const link = document.createElement('a'); link.href = pdfResult.url; link.download = pdfResult.filename; link.click(); ``` ## ๐Ÿ“– API Reference ### Quick Functions #### `mergeFiles(files, settings?, onProgress?)` Merges File objects with automatic initialization and cleanup. **Parameters:** - `files: File[]` - Array of image files to merge - `settings?: Partial<MergeSettings>` - Optional merge settings - `onProgress?: (progress: number) => void` - Optional progress callback **Returns:** `Promise<MergeResult>` #### `mergeImages(images, settings?, onProgress?)` Merges ImageFile objects with automatic initialization and cleanup. #### `validateFiles(files)` Validates files before processing without actually merging them. ### ImageMerger Class The main class for advanced usage scenarios. ```typescript const merger = new ImageMerger(options?); await merger.initialize(); // Merge files const result = await merger.mergeFiles(files, settings, onProgress); // Or merge pre-processed images const result = await merger.mergeImages(images, settings, onProgress); // Validate files const validation = await merger.validateFiles(files); // Calculate layout without merging const layout = merger.calculateLayout(images, settings); // Get capabilities const caps = merger.getCapabilities(); // Cleanup merger.destroy(); ``` ### Types and Interfaces #### `MergeSettings` ```typescript interface MergeSettings { direction: 'horizontal' | 'vertical'; // Layout direction format: 'jpeg' | 'png' | 'pdf'; // Output format spacing: number; // Space between images (px) backgroundColor: string; // Background color (hex) quality: number; // JPEG quality (10-100) pdfPageSize?: 'a4' | 'letter' | 'a3'; // PDF page size } ``` #### `MergeResult` ```typescript interface MergeResult { url: string; // Blob URL of the result filename: string; // Generated filename size: number; // File size in bytes format?: string; // Output format } ``` #### `ImageFile` ```typescript interface ImageFile { id: string; // Unique identifier file: File; // Original File object url: string; // Blob URL for preview name: string; // Filename size: number; // File size in bytes type: string; // MIME type width?: number; // Image width in pixels height?: number; // Image height in pixels } ``` ## ๐ŸŽ›๏ธ Configuration Options ### Merge Settings | Option | Type | Default | Description | |--------|------|---------|-------------| | `direction` | `'horizontal' \| 'vertical'` | `'vertical'` | How to arrange images | | `format` | `'jpeg' \| 'png' \| 'pdf'` | `'jpeg'` | Output format | | `spacing` | `number` | `10` | Space between images in pixels | | `backgroundColor` | `string` | `'#ffffff'` | Background color (hex format) | | `quality` | `number` | `90` | JPEG quality (10-100, ignored for PNG/PDF) | | `pdfPageSize` | `'a4' \| 'letter' \| 'a3'` | `'a4'` | PDF page size (PDF format only) | ### Merger Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `debug` | `boolean` | `false` | Show TLDraw canvas for debugging | | `container` | `HTMLElement` | `undefined` | Custom container for TLDraw instance | | `maxCanvasSize` | `{width: number, height: number}` | `{width: 10000, height: 10000}` | Maximum canvas dimensions | ## ๐Ÿ—๏ธ Browser Compatibility - **Chrome/Edge**: 88+ - **Firefox**: 78+ - **Safari**: 14+ - **Mobile browsers**: iOS Safari 14+, Chrome Mobile 88+ **Required APIs:** - `URL.createObjectURL` - `FileReader` - `Canvas API` - `Blob` - Modern ES2020 features ## ๐Ÿ“Š Performance & Limits ### Default Limits | Constraint | Value | |------------|-------| | Max file size | 100MB per image | | Max file count | 50 images | | Max canvas size | 10,000 ร— 10,000 pixels | | Supported formats | JPEG, PNG | ### Performance Tips 1. **Image Size**: Smaller images process faster 2. **File Count**: Fewer images = better performance 3. **Format Choice**: - JPEG: Smaller files, faster processing - PNG: Larger files, preserves transparency - PDF: Best for document-style output 4. **Canvas Size**: Very large outputs may cause memory issues ## ๐Ÿ”ง Error Handling The library provides detailed error information: ```typescript try { const result = await mergeFiles(files); } catch (error) { if (error.type === 'file_size') { console.error('File too large:', error.fileName); } else if (error.type === 'file_type') { console.error('Unsupported format:', error.fileName); } else if (error.type === 'processing') { console.error('Processing failed:', error.message); } } ``` ### Error Types - `file_count`: Too many or too few files - `file_size`: File exceeds size limit - `file_type`: Unsupported file format - `processing`: Processing or validation error - `initialization`: Library initialization failed - `network`: Network-related error (rare) - `unknown`: Unexpected error ## ๐Ÿงช Testing ```bash # Run tests npm test # Run tests with coverage npm run test:coverage # Run tests in watch mode npm run test:watch ``` ## ๐Ÿ“ Contributing 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request ## ๐Ÿ“„ License MIT License - see the [LICENSE](LICENSE) file for details. ## ๐Ÿ™ Acknowledgments - Built on [TLDraw](https://tldraw.dev) for high-performance canvas rendering - Inspired by the privacy-first principles of client-side processing - PDF generation powered by [pdf-lib](https://pdf-lib.js.org/) ## ๐Ÿ“ž Support - ๐Ÿ“– [Documentation](https://mergejpg.me/docs) - ๐Ÿ› [Issue Tracker](https://github.com/your-username/merge-jpg/issues) - ๐Ÿ’ฌ [Discussions](https://github.com/your-username/merge-jpg/discussions) - ๐ŸŒ [Live Demo](https://mergejpg.me) --- Made with โค๏ธ for privacy-conscious developers