function isImageFile(file) { return file && file.type && file.type.indexOf('image/') === 0 } function canvasToBlob(canvas, type, quality) { return new Promise(resolve => { if (!canvas.toBlob) { resolve(null) return } canvas.toBlob(blob => resolve(blob), type, quality) }) } function loadImage(file) { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = event => { const image = new Image() image.onload = () => resolve(image) image.onerror = reject image.src = event.target.result } reader.onerror = reject reader.readAsDataURL(file) }) } export async function compressImageForUpload(file, options = {}) { const maxSize = options.maxSize || 3 * 1024 * 1024 const maxWidth = options.maxWidth || 1600 const maxHeight = options.maxHeight || 1600 const outputType = options.outputType || 'image/jpeg' const minQuality = options.minQuality || 0.55 if (!isImageFile(file) || typeof FileReader === 'undefined' || typeof document === 'undefined') { return file } try { const image = await loadImage(file) let scale = Math.min(maxWidth / image.width, maxHeight / image.height, 1) let quality = options.quality || 0.82 let bestBlob = null for (let i = 0; i < 7; i++) { const width = Math.max(1, Math.round(image.width * scale)) const height = Math.max(1, Math.round(image.height * scale)) const canvas = document.createElement('canvas') canvas.width = width canvas.height = height const context = canvas.getContext('2d') context.fillStyle = '#ffffff' context.fillRect(0, 0, width, height) context.drawImage(image, 0, 0, width, height) const blob = await canvasToBlob(canvas, outputType, quality) if (!blob) { return file } bestBlob = blob if (blob.size <= maxSize) { break } scale = scale * 0.82 quality = Math.max(minQuality, quality - 0.08) } if (!bestBlob || bestBlob.size >= file.size) { return file } const fileName = file.name ? file.name.replace(/\.[^.]+$/, '.jpg') : 'upload.jpg' return new File([bestBlob], fileName, { type: outputType, lastModified: Date.now() }) } catch (error) { return file } }