Analyses Profondes

Qu'est-ce que le HEIC ? Une analyse technique approfondie des signatures, de la détection et de la conversion

koboshiCo-founder
·6 min de lecture
Qu'est-ce que le HEIC ? Une analyse technique approfondie des signatures, de la détection et de la conversion
Résumé

Le HEIC n'est pas qu'un JPEG plus petit. C'est un format conteneur basé sur l'ISO Base Media File Format avec des images encodées en HEVC à l'intérieur. Voici comment il fonctionne, comment le détecter en lisant les octets bruts, et comment le convertir quand la compatibilité échoue.

Ouvrez un fichier HEIC dans un éditeur hexadécimal. Les douze premiers octets :

00 00 00 18 66 74 79 70 68 65 69 63

C'est l'ISOBMFF — le même standard de conteneur que MP4 utilise. 0x18 (24 octets) est la taille de la boîte, ftyp est la boîte de type de fichier, heic est la marque principale. Un fichier HEIC n'est pas un encodage d'image. C'est un conteneur avec un marqueur de marque, contenant des images encodées en HEVC.

Ce qu'est réellement le HEIC

HEIC = High Efficiency Image Container. La version sous marque Apple de HEIF, standardisée par le MPEG en 2015 sous la référence ISO/IEC 23008-12. JPEG est à la fois un algorithme de compression et un format de fichier. Le HEIC n'est qu'un conteneur. La compression interne est du HEVC (H.265), le même codec utilisé pour la vidéo 4K.

Un seul fichier HEIC peut stocker :

  • Une image principale
  • Plusieurs images alternatives (photos en rafale)
  • Des séquences d'images (Live Photos : image fixe + vidéo de 3 secondes)
  • Des canaux alpha et des cartes de profondeur
  • Une profondeur de couleur de 16 bits par canal (JPEG est limité à 8 bits)

Le conteneur utilise des boîtes — même structure que MP4 :

BoxFonction
ftypType de fichier et marques compatibles
metaMétadonnées et propriétés des éléments
mdatDonnées d'image brutes encodées (flux binaire HEVC)
ilocEmplacements des éléments dans mdat

Cette extensibilité permet au HEIC de faire des choses que le JPEG n'a jamais pu faire. L'analyse nécessite de comprendre la hiérarchie des boîtes, pas seulement de lire un flux binaire brut.

Pourquoi Apple a changé

Apple n'a pas inventé le HEIC. Le MPEG a publié le HEIF en 2015. Apple l'a adopté comme format par défaut de l'iPhone dans iOS 11 (2017).

Le changement était arithmétique, pas marketing. Une photo iPhone de 12 MP en JPEG fait ~3,5 Mo. En HEIC, ~1,8 Mo. À 50 Go de stockage iCloud gratuit, cet écart représente environ 14 000 photos supplémentaires. Apple vend des paliers de stockage. Le calcul se fait tout seul.

Il y avait aussi l'alignement de l'écosystème. Apple avait déjà adopté le HEVC pour la vidéo (H.265 dans iOS 11). Réutiliser le même codec pour les images fixes signifiait des blocs de décodage matériel partagés sur les puces de série A, une consommation électrique réduite et un seul chemin de licence.

Les compromis

Le HEIC bat le JPEG sur presque toutes les métriques, sauf la compatibilité.

AspectHEICJPEG
Efficacité de compression~40–50% plus petit à qualité égaleRéférence
Profondeur de couleurJusqu'à 16 bits8 bits
TransparenceOuiNon
Images multiples par fichierOuiNon
Réédition sans perteOuiNon
Support natif WindowsNécessite l'extension HEIFUniversel
Support navigateur webSafari uniquementUniversel
Support AndroidNatif à partir de 9+Universel
Licence de brevetPool de brevets HEVCJPEG est libre de droits

Le HEVC est couvert par plusieurs pools de brevets (MPEG LA, Access Advance). Apple couvre les frais pour les utilisateurs iOS. Les tiers n'ont pas cet avantage. Cette incertitude est en grande partie la raison pour laquelle l'adoption en dehors de l'écosystème Apple a stagné.

Détecter le HEIC en lisant la signature du fichier

Ne faites pas confiance à l'extension .heic. Lisez les 32 premiers octets et analysez la boîte ftyp.

Disposition exacte des octets d'un en-tête HEIC valide :

Bytes 0–3:   Taille de la boîte (uint32 big-endian)
Bytes 4–7:   Type de boîte : "ftyp" (0x66 0x74 0x79 0x70)
Bytes 8–11:  Marque principale : "heic" ou "heif" ou "mif1"
Bytes 12–15: Version mineure (généralement 0x00000000)
Bytes 16+:   Liste des marques compatibles (ex. "mif1", "heic", "MiHE")

TypeScript côté navigateur :

async function isHeic(file: File): Promise<boolean> {
  const buffer = await file.slice(0, 32).arrayBuffer()
  const bytes = new Uint8Array(buffer)

  if (String.fromCharCode(...bytes.slice(4, 8)) !== "ftyp") return false

  const brand = String.fromCharCode(...bytes.slice(8, 12))
  return ["heic", "heif", "mif1", "msf1"].includes(brand)
}

Notre convertisseur exécute cette vérification avant de tenter le décodage. Mauvaise marque = rejet immédiat, aucun cycle CPU gaspillé.

Python

def is_heic(path: str) -> bool:
    with open(path, "rb") as f:
        header = f.read(32)

    if len(header) < 12:
        return False

    if header[4:8].decode("ascii", errors="ignore") != "ftyp":
        return False

    return header[8:12].decode("ascii", errors="ignore") in {"heic", "heif", "mif1", "msf1"}

Vérification de niveau supérieur avec filetype :

import filetype

kind = filetype.guess("photo.heic")
if kind and kind.extension in ("heic", "heif"):
    print(kind.mime)  # image/heic

Ou pillow-heif :

from pillow_heif import is_heif

if is_heif("photo.heic"):
    # conteneur valide
    pass

Go

func isHeic(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()

	buf := make([]byte, 32)
	if _, err := f.Read(buf); err != nil {
		return false
	}

	if string(buf[4:8]) != "ftyp" {
		return false
	}

	brand := string(buf[8:12])
	return brand == "heic" || brand == "heif" || brand == "mif1" || brand == "msf1"
}

PHP

function isHeic(string $path): bool {
    $header = file_get_contents($path, false, null, 0, 32);
    if (strlen($header) < 12) return false;
    if (substr($header, 4, 4) !== 'ftyp') return false;

    return in_array(substr($header, 8, 4), ['heic', 'heif', 'mif1', 'msf1'], true);
}

Avec fileinfo :

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file('photo.heic');
// image/heic ou image/heif

ImageMagick CLI

ImageMagick 7+ prend en charge le HEIC s'il est compilé avec libheif :

magick identify -verbose photo.heic | grep "Format:"
# Format: HEIC (High Efficiency Image Container)

Sans libheif : no decode delegate for this image format. Sur la plupart des distributions Linux, libheif-examples fournit heif-convert comme alternative.

Le chemin de conversion

Savoir qu'un fichier est HEIC ne l'ouvre pas. Windows a besoin des HEIF Image Extensions. La plupart des navigateurs refusent de rendre le HEIC dans les balises <img>. Android 9+ le gère nativement ; les anciens appareils non.

La solution : convertir. Notre convertisseur HEIC vers JPG gère l'intégralité du pipeline dans votre navigateur :

  1. Déposer des fichiers — photos uniques ou dossiers entiers, le traitement par lots est automatique.
  2. Validation de signature — la vérification d'octets exacte ci-dessus s'exécute sur chaque fichier. Les fichiers non-HEIC sont immédiatement rejetés avec un message clair.
  3. Décodage côté client — une build WebAssembly de libheif s'exécute localement. Aucun téléversement. Aucun serveur.
  4. Sortie préservant la qualité — JPG à 90% de qualité conserve la résolution et la précision des couleurs d'origine.
  5. Téléchargement par lots — fichiers individuels ou une archive ZIP unique.

Pour une sortie sans perte avec transparence : HEIC vers PNG. Pour des tailles optimisées pour le web : HEIC vers WebP.

Vos fichiers ne quittent jamais votre appareil. C'est tout le point.

Plus d'articles à lire