fix: conversion HEIC native d'abord (Safari/macOS), heic2any fallback 30s
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
/**
|
||||
* Convertit un Blob HEIC/HEIF en Blob JPEG via heic2any.
|
||||
* Convertit un Blob HEIC/HEIF en Blob JPEG.
|
||||
* Tente d'abord la conversion native du navigateur (instantané sur Safari/macOS),
|
||||
* puis repasse sur heic2any si le natif échoue (Chrome, Firefox).
|
||||
* À utiliser uniquement côté client (navigateur).
|
||||
*/
|
||||
export async function convertHeicToJpeg(blob: Blob): Promise<Blob> {
|
||||
if (!(blob instanceof Blob)) {
|
||||
throw new TypeError('L\'entrée doit être un Blob')
|
||||
throw new TypeError("L'entrée doit être un Blob")
|
||||
}
|
||||
|
||||
const type = blob.type.toLowerCase()
|
||||
@@ -12,14 +14,26 @@ export async function convertHeicToJpeg(blob: Blob): Promise<Blob> {
|
||||
throw new TypeError(`Format attendu : HEIC/HEIF. Reçu : ${blob.type || '(vide)'}`)
|
||||
}
|
||||
|
||||
// Méthode 1 : conversion native (Safari 14+, macOS Chrome 105+)
|
||||
try {
|
||||
const result = await convertNative(blob)
|
||||
console.log('[heicConverter] ✅ Conversion native réussie')
|
||||
return result
|
||||
} catch (e) {
|
||||
console.warn(`[heicConverter] Conversion native échouée (${(e as Error).message}), repasse sur heic2any…`)
|
||||
}
|
||||
|
||||
// Méthode 2 : heic2any fallback (plus lent, ~10-30s)
|
||||
const heic2any = (await import('heic2any')).default
|
||||
|
||||
const timeout = new Promise<never>((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Timeout conversion HEIC (120s)')), 120_000),
|
||||
setTimeout(
|
||||
() => reject(new Error('Timeout conversion HEIC (30s). Essayez de convertir le fichier en JPG avant de le déposer.')),
|
||||
30_000,
|
||||
),
|
||||
)
|
||||
|
||||
const conversion = heic2any({ blob, toType: 'image/jpeg', quality: 0.92 })
|
||||
|
||||
const result = await Promise.race([conversion, timeout])
|
||||
const output = Array.isArray(result) ? result[0] : result
|
||||
|
||||
@@ -27,5 +41,24 @@ export async function convertHeicToJpeg(blob: Blob): Promise<Blob> {
|
||||
throw new Error("heic2any n'a pas retourné un Blob")
|
||||
}
|
||||
|
||||
console.log('[heicConverter] ✅ Conversion heic2any réussie')
|
||||
return output
|
||||
}
|
||||
|
||||
async function convertNative(blob: Blob): Promise<Blob> {
|
||||
// Force le type MIME pour que le navigateur reconnaisse le format
|
||||
const typed = blob.type ? blob : new Blob([blob], { type: 'image/heic' })
|
||||
const bitmap = await createImageBitmap(typed)
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = bitmap.width
|
||||
canvas.height = bitmap.height
|
||||
canvas.getContext('2d')!.drawImage(bitmap, 0, 0)
|
||||
bitmap.close()
|
||||
return new Promise<Blob>((resolve, reject) => {
|
||||
canvas.toBlob(
|
||||
b => (b ? resolve(b) : reject(new Error('canvas.toBlob a retourné null'))),
|
||||
'image/jpeg',
|
||||
0.92,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user