Complete guide to integrating compress.im compression capabilities into your applications. Learn about client-side processing, security, and implementation patterns.
compress.im provides client-side compression capabilities through JavaScript APIs. All processing happens in the user's browser, ensuring privacy and reducing server load.
Our compression system runs entirely in the browser using modern web APIs:
| Component | Purpose | Main Features | Use Cases |
|---|---|---|---|
| ImageCompressionService | Image processing | Format conversion, quality control | Photos, graphics, web images |
| PDFCompressionService | PDF optimization | Size reduction, structure optimization | Documents, reports, forms |
| BatchProcessor | Multiple files | Concurrent processing, progress tracking | Bulk operations |
| PerformanceMonitor | Analytics | Metrics collection, optimization | Performance analysis |
| FormatConverter | Format support | Advanced format handling | AVIF, TIFF, BMP conversion |
import { ImageCompressionService } from '@/lib/imageCompression'
// Simple image compression
async function compressImage(file) {
const options = {
maxSizeMB: 1, // Target file size
quality: 0.8, // Quality (0-1)
maxWidthOrHeight: 1920,
useWebWorker: true,
preserveExif: false
}
try {
const compressedFile = await ImageCompressionService.compressImage(
file,
options,
(progress) => console.log(`Progress: ${progress}%`)
)
console.log(`Original: ${file.size} bytes`)
console.log(`Compressed: ${compressedFile.size} bytes`)
console.log(`Reduction: ${((file.size - compressedFile.size) / file.size * 100).toFixed(1)}%`)
return compressedFile
} catch (error) {
console.error('Compression failed:', error.message)
throw error
}
}import { PDFCompressionService } from '@/lib/pdfCompression'
// Simple PDF compression
async function compressPDF(file) {
const options = {
mode: 'balanced', // 'size', 'quality', or 'balanced'
imageQuality: 0.8,
removeMetadata: true
}
try {
const compressedFile = await PDFCompressionService.compressPDF(
file,
options,
(progress) => console.log(`Progress: ${progress}%`)
)
return compressedFile
} catch (error) {
console.error('PDF compression failed:', error.message)
throw error
}
}Process multiple files efficiently with progress tracking:
import { ImageCompressionService } from '@/lib/imageCompression'
async function processBatch(files) {
const options = {
quality: 0.8,
maxSizeMB: 2,
useWebWorker: true
}
// Convert files to compressed image objects
const images = files.map(file => ({
id: `img_${Date.now()}_${Math.random()}`,
originalFile: file,
originalSize: file.size,
name: file.name
}))
// Process with callbacks
await ImageCompressionService.processImagesBatch(
images,
options,
// Progress callback for individual files
(imageId, progress) => {
console.log(`${imageId}: ${progress}%`)
updateProgressUI(imageId, progress)
},
// Completion callback for individual files
(imageId, result, error) => {
if (error) {
console.error(`${imageId} failed: ${error}`)
handleError(imageId, error)
} else {
console.log(`${imageId} completed`)
handleSuccess(imageId, result)
}
}
)
}Convert between different image formats:
// Convert to WebP with fallback
const options = {
format: 'webp', // Target format
quality: 0.85,
enableAdvancedFormats: true,
fallbackFormat: 'jpeg' // Fallback if WebP fails
}
// The service will automatically handle format conversion
const webpFile = await ImageCompressionService.compressImage(file, options)
// Check if conversion was successful
if (webpFile.type === 'image/webp') {
console.log('Successfully converted to WebP')
} else {
console.log('Fell back to JPEG')
}try {
const result = await ImageCompressionService.compressImage(file, options)
} catch (error) {
switch (error.name) {
case 'UnsupportedFormatError':
// File format not supported for compression
showError('Please use JPEG, PNG, or WebP files')
break
case 'FileSizeError':
// File too large to process
showError('File is too large. Please use files under 50MB')
break
case 'BrowserSupportError':
// Browser doesn't support required features
showError('Your browser doesn't support this feature')
break
case 'MemoryError':
// Not enough memory to process file
showError('Not enough memory. Try a smaller file or close other tabs')
break
default:
// Generic compression error
showError(`Compression failed: ${error.message}`)
}
}async function compressWithRetry(file, options, maxRetries = 3) {
let lastError
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
// Adjust options for retry attempts
const adjustedOptions = attempt > 1
? { ...options, quality: Math.max(0.5, options.quality - 0.1 * attempt) }
: options
return await ImageCompressionService.compressImage(file, adjustedOptions)
} catch (error) {
lastError = error
console.warn(`Attempt ${attempt} failed:`, error.message)
// Don't retry certain errors
if (error.name === 'UnsupportedFormatError' ||
error.name === 'BrowserSupportError') {
break
}
// Wait before retry
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
}
}
}
throw lastError
}import { PerformanceMonitor } from '@/lib/performanceMonitor'
// Check browser capabilities before processing
const capabilities = PerformanceMonitor.getBrowserCapabilities()
if (capabilities.estimatedMemoryGB < 2) {
console.warn('Limited memory detected')
// Reduce batch size or quality settings
}
// Get optimal settings for current batch
const optimalSettings = PerformanceMonitor.getOptimalSettings(
fileCount,
averageFileSize
)
if (optimalSettings.memoryWarning) {
showWarning(optimalSettings.memoryWarning)
}
// Use recommended settings
const batchOptions = {
concurrency: optimalSettings.recommendedConcurrency,
chunkSize: optimalSettings.recommendedChunkSize
}class CompressionProgress {
constructor() {
this.files = new Map()
this.overall = { completed: 0, total: 0, percentage: 0 }
}
updateFileProgress(fileId, progress) {
this.files.set(fileId, progress)
this.calculateOverallProgress()
this.notifyListeners()
}
calculateOverallProgress() {
const progresses = Array.from(this.files.values())
const total = progresses.reduce((sum, p) => sum + p, 0)
this.overall.percentage = progresses.length > 0
? total / progresses.length
: 0
}
notifyListeners() {
// Update UI with current progress
document.dispatchEvent(new CustomEvent('compressionProgress', {
detail: {
files: Object.fromEntries(this.files),
overall: this.overall
}
}))
}
}function validateFile(file) {
// Size limits
const MAX_SIZE = 100 * 1024 * 1024 // 100MB
if (file.size > MAX_SIZE) {
throw new Error('File too large')
}
// MIME type validation
const allowedTypes = [
'image/jpeg', 'image/png', 'image/webp', 'image/avif',
'application/pdf'
]
if (!allowedTypes.includes(file.type)) {
throw new Error('Unsupported file type')
}
// Additional security checks
return validateFileSignature(file)
}
async function validateFileSignature(file) {
const buffer = await file.slice(0, 16).arrayBuffer()
const signature = new Uint8Array(buffer)
// Check file signatures match MIME types
const signatures = {
'image/jpeg': [0xFF, 0xD8, 0xFF],
'image/png': [0x89, 0x50, 0x4E, 0x47],
'application/pdf': [0x25, 0x50, 0x44, 0x46]
}
// Validate signature matches declared type
// Implementation details...
return true
}function checkBrowserSupport() {
const support = {
webWorkers: typeof Worker !== 'undefined',
canvas: typeof HTMLCanvasElement !== 'undefined',
fileAPI: typeof File !== 'undefined' && typeof FileReader !== 'undefined',
webp: checkWebPSupport(),
avif: checkAVIFSupport(),
streams: typeof ReadableStream !== 'undefined'
}
return support
}
async function checkWebPSupport() {
return new Promise(resolve => {
const canvas = document.createElement('canvas')
canvas.width = 1
canvas.height = 1
const dataURL = canvas.toDataURL('image/webp')
resolve(dataURL.indexOf('image/webp') === 5)
})
}
// Use feature detection to adapt functionality
const browserSupport = checkBrowserSupport()
if (!browserSupport.webWorkers) {
console.warn('Web Workers not supported, falling back to main thread')
}import { useState, useCallback } from 'react'
import { ImageCompressionService } from '@/lib/imageCompression'
export function useImageCompression() {
const [isCompressing, setIsCompressing] = useState(false)
const [progress, setProgress] = useState(0)
const [error, setError] = useState(null)
const compressImage = useCallback(async (file, options) => {
setIsCompressing(true)
setProgress(0)
setError(null)
try {
const result = await ImageCompressionService.compressImage(
file,
options,
setProgress
)
return result
} catch (err) {
setError(err.message)
throw err
} finally {
setIsCompressing(false)
}
}, [])
return {
compressImage,
isCompressing,
progress,
error
}
}import { ref, computed } from 'vue'
import { ImageCompressionService } from '@/lib/imageCompression'
export function useCompression() {
const files = ref([])
const isProcessing = ref(false)
const progress = ref(new Map())
const overallProgress = computed(() => {
if (progress.value.size === 0) return 0
const total = Array.from(progress.value.values())
.reduce((sum, p) => sum + p, 0)
return total / progress.value.size
})
const addFile = (file) => {
files.value.push(file)
}
const processAll = async () => {
isProcessing.value = true
// Implementation...
}
return {
files,
isProcessing,
progress: overallProgress,
addFile,
processAll
}
}Now that you understand the basics, explore these advanced topics: