diff --git a/src/utils/image-resize.js b/src/utils/image-resize.js new file mode 100644 index 0000000..8cf6a11 --- /dev/null +++ b/src/utils/image-resize.js @@ -0,0 +1,94 @@ +export function readFileAsDataURL(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsDataURL(file); + }); +} + +function getBase64Size(base64) { + const str = base64.split(',')[1] || base64; + return Math.ceil((str.length * 3) / 4); +} + +function createResizedImage(dataUrl, options) { + return new Promise((resolve, reject) => { + const img = new Image(); + img.onload = () => { + const scale = Math.min( + options.width / img.width, + options.height / img.height, + 1 + ); + const w = Math.round(img.width * scale); + const h = Math.round(img.height * scale); + + const canvas = document.createElement('canvas'); + canvas.width = w; + canvas.height = h; + const ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, w, h); + ctx.imageSmoothingEnabled = true; + ctx.imageSmoothingQuality = 'high'; + ctx.drawImage(img, 0, 0, w, h); + + resolve({ + dataUrl: canvas.toDataURL('image/jpeg', options.quality), + width: w, + height: h + }); + }; + img.onerror = reject; + img.src = dataUrl; + }); +} + +export async function resizeImage(dataUrl, opts) { + let bestResult = null; + let minQuality = 0; + let maxQuality = 100; + + while (maxQuality - minQuality > 1) { + const quality = Math.round((minQuality + maxQuality) / 2); + const result = await createResizedImage(dataUrl, { + width: opts.width, + height: opts.height, + quality: quality / 100 + }); + + const size = getBase64Size(result.dataUrl); + if (size <= opts.maxSize) { + bestResult = result; + minQuality = quality; + } else { + maxQuality = quality; + } + } + + if (!bestResult) { + throw new Error('Failed to compress image within size limit'); + } + + return bestResult; +} + +export async function processPhotos(files) { + const processed = []; + for (const file of files) { + const dataUrl = await readFileAsDataURL(file); + const resized = await resizeImage(dataUrl, { + width: 2000, + height: 2000, + maxSize: 900000 + }); + processed.push({ + dataUrl: resized.dataUrl, + width: resized.width, + height: resized.height + }); + } + return processed; +}