JSPM

merge-jpg

1.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 4
  • Score
    100M100P100Q30726F
  • License MIT

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

Package Exports

  • merge-jpg

Readme

merge-jpg

npm version License: MIT TypeScript

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

npm install merge-jpg

Basic Usage

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

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

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.

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

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

interface MergeResult {
  url: string;          // Blob URL of the result
  filename: string;     // Generated filename
  size: number;         // File size in bytes
  format?: string;      // Output format
}

ImageFile

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:

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

# 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 file for details.

๐Ÿ™ Acknowledgments

  • Built on TLDraw for high-performance canvas rendering
  • Inspired by the privacy-first principles of client-side processing
  • PDF generation powered by pdf-lib

๐Ÿ“ž Support


Made with โค๏ธ for privacy-conscious developers