Guides

Comment compresser une image Base64 (pourquoi Gzip échoue souvent)

Réduisez Base64 en optimisant l’image décodée, comprenez pourquoi Gzip ne remplace pas une Data URL et visez 100 Ko en JavaScript.

Pourquoi Base64 grossit d’environ 33,3%

Base64 code trois octets avec quatre caractères. La longueur exacte est 4 × ceil(n / 3), avant le préfixe Data URL.

Trois chaînes possibles

Octets→Base64 est standard mais plus gros. Base64→Gzip→Base64 impose deux inversions. Décoder image→optimiser→Base64 garde une image normale pour img src.

Pourquoi le gain Gzip disparaît en revenant au texte

Le Gzip intermédiaire peut sembler plus petit, mais un nouveau Base64 et les en-têtes coûtent de l’espace. Le résultat est du Gzip, pas du JPEG, PNG ou WebP directement affichable.

Les formats sont déjà compressés

JPEG, PNG et WebP ont leur propre compression. Les gains viennent surtout de moins de pixels, d’une qualité avec perte, de métadonnées retirées ou d’un meilleur format.

JavaScript correct dans le navigateur

Validez Base64 et magic bytes, décodez avec ImageBitmap, dessinez sur une Canvas limitée et utilisez toBlob. En production, ajoutez limites, refus d’animation, détection WebP et protection contre les tâches anciennes.

Exemple concis avec les API natives

async function compressBase64Image(dataUrl, maxWidth = 1600, quality = 0.82) {
  const [header, payload] = dataUrl.split(',', 2);
  const mime = header.match(/^data:([^;]+);base64$/)?.[1];
  if (!mime || !/^image\/(png|jpeg|webp)$/.test(mime)) throw new Error('Unsupported image');

  const binary = atob(payload.replace(/\s+/g, ''));
  const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
  const bitmap = await createImageBitmap(new Blob([bytes], { type: mime }));
  try {
    const scale = Math.min(1, maxWidth / bitmap.width);
    const canvas = document.createElement('canvas');
    canvas.width = Math.max(1, Math.round(bitmap.width * scale));
    canvas.height = Math.max(1, Math.round(bitmap.height * scale));
    const context = canvas.getContext('2d');
    if (!context) throw new Error('Canvas 2D unavailable');
    context.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
    const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/webp', quality));
    if (!blob) throw new Error('Encoding failed');
    const output = new Uint8Array(await blob.arrayBuffer());
    let outputBinary = '';
    for (let offset = 0; offset < output.length; offset += 0x8000) {
      outputBinary += String.fromCharCode(...output.subarray(offset, offset + 0x8000));
    }
    return `data:${blob.type};base64,${btoa(outputBinary)}`;
  } finally {
    bitmap.close();
  }
}

Viser 100 Ko

Considérez 102 400 octets d’image. Cherchez la qualité JPEG/WebP avec une limite, puis réduisez proportionnellement avec sqrt(cible/actuel) pendant peu de tours.

Qualité, dimensions et format

La qualité modifie le codec ; le redimensionnement retire des pixels. Photo : JPEG/WebP ; transparence : PNG/WebP. Comparez les sorties.

Transparence PNG et fond JPEG

JPEG n’a pas d’alpha. Gardez PNG/WebP ou imposez un fond confirmé avant l’aplatissement.

GIF, WebP animé et SVG

Canvas capture souvent une image. Refusez GIF, WebP animé et ICO ; SVG exige un optimiseur texte spécifique.

Local améliore la confidentialité, pas la sûreté

Cela évite envoi et conservation serveur, sans remplacer une analyse de sécurité. Appareil, extensions et codecs restent concernés.

Quand abandonner Base64

Pour les grandes images, utilisez Blob URL, fichier cacheable séparé ou transfert binaire avec Blob, FormData ou ArrayBuffer.

Questions fréquentes

Peut-on compresser Base64 ?

Oui, mais une compression générale ne donne pas du Base64 d’image directement utilisable.

Fonctionne-t-il dans img src ?

Seulement si le contenu décodé reste une image ; Gzip doit être décompressé.

Comment viser 100 Ko ?

Cherchez la qualité avec une limite, puis réduisez proportionnellement les dimensions.

La qualité baisse-t-elle ?

Le redimensionnement et la qualité avec perte peuvent la réduire.

Pourquoi 33% de plus ?

Trois octets sont représentés par quatre caractères.

Est-ce envoyé ?

Le compresseur travaille uniquement dans le navigateur.

Gzip avant ou après ?

Utilisez la compression HTTP autour du document, pas dans la Data URL.

Standards et références navigateur