diff --git a/index.html b/index.html index 5b0c741..c5aa44b 100644 --- a/index.html +++ b/index.html @@ -249,29 +249,33 @@ this.files.push(...newFiles); - await processBatch(newFiles, async (fileObj) => { + await processBatch(newFiles, async (orig) => { + // Toujours muter via le proxy réactif d'Alpine + const f = this.files.find(x => x.id === orig.id); + if (!f) return; + // Étape 1 : HEIC → JPEG - fileObj.status = 'converting'; + f.status = 'converting'; try { - fileObj.originalBlob = await convertHeicToJpeg(fileObj.originalFile); - fileObj.originalUrl = URL.createObjectURL(fileObj.originalBlob); + f.originalBlob = await convertHeicToJpeg(orig.originalFile); + f.originalUrl = URL.createObjectURL(f.originalBlob); } catch (e) { - fileObj.status = 'error'; - fileObj.error = `Conversion échouée : ${e.message}`; + f.status = 'error'; + f.error = `Conversion échouée : ${e.message}`; return; } // Étape 2 : suppression du fond - fileObj.status = 'processing'; + f.status = 'processing'; try { - fileObj.processedBlob = await processImage( - fileObj.originalBlob, fileObj._seedColor, fileObj.tolerance + f.processedBlob = await processImage( + f.originalBlob, f._seedColor, f.tolerance ); - fileObj.processedUrl = URL.createObjectURL(fileObj.processedBlob); - fileObj.status = 'done'; + f.processedUrl = URL.createObjectURL(f.processedBlob); + f.status = 'done'; } catch (e) { - fileObj.status = 'error'; - fileObj.error = `Détourage échoué : ${e.message}`; + f.status = 'error'; + f.error = `Détourage échoué : ${e.message}`; } }, 3); }, diff --git a/js/heicConverter.js b/js/heicConverter.js index 4971c5a..3dd9b92 100644 --- a/js/heicConverter.js +++ b/js/heicConverter.js @@ -3,7 +3,7 @@ * @param {File} file * @returns {Promise} * @throws {TypeError} si l'entrée n'est pas un fichier HEIC/HEIF - * @throws {Error} si la conversion échoue + * @throws {Error} si la conversion échoue ou dépasse 30s */ export async function convertHeicToJpeg(file) { if (!(file instanceof File)) { @@ -12,18 +12,28 @@ export async function convertHeicToJpeg(file) { // Certains iPhone envoient un type MIME vide pour les HEIC — on l'autorise const type = file.type.toLowerCase(); if (type !== '' && !['image/heic', 'image/heif'].includes(type)) { - throw new TypeError(`Format attendu : HEIC/HEIF. Reçu : ${file.type}`); + throw new TypeError(`Format attendu : HEIC/HEIF. Reçu : ${file.type || '(vide)'}`); } - const result = await heic2any({ + console.log(`[heicConverter] Début conversion : ${file.name} (${file.type || 'type vide'}, ${(file.size/1024).toFixed(0)} Ko)`); + + const timeout = new Promise((_, reject) => + setTimeout(() => reject(new Error('Timeout : conversion > 30s. Vérifiez que le fichier est bien un HEIC valide.')), 30_000) + ); + + const conversion = heic2any({ blob: file, toType: 'image/jpeg', quality: 0.92, }); + const result = await Promise.race([conversion, timeout]); + const blob = Array.isArray(result) ? result[0] : result; if (!(blob instanceof Blob)) { throw new Error("heic2any n'a pas retourné un Blob"); } + + console.log(`[heicConverter] ✅ Conversion réussie : ${file.name} → ${(blob.size/1024).toFixed(0)} Ko`); return blob; }