Approfondimenti

Cos'è HEIC? Un approfondimento tecnico su firme dei file, rilevamento e conversione

koboshiCo-founder
·6 min di lettura
Cos'è HEIC? Un approfondimento tecnico su firme dei file, rilevamento e conversione
Riepilogo

HEIC non è solo un JPEG più piccolo. È un formato contenitore basato su ISO Base Media File Format con immagini codificate in HEVC al suo interno. Ecco come funziona, come rilevarlo leggendo byte raw, e come convertirlo quando la compatibilità fallisce.

Apri un file HEIC in un editor esadecimale. I primi dodici byte:

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

Questo è ISOBMFF, lo stesso standard di contenitore usato da MP4. 0x18 (24 byte) è la dimensione della box, ftyp è la box del tipo di file, heic è il brand principale. Un file HEIC non è una codifica di immagine. È un contenitore con un marker di brand che ospita immagini codificate in HEVC.

Cos'è realmente HEIC

HEIC = High Efficiency Image Container. È l'implementazione con marchio Apple di HEIF, standardizzato dal MPEG come ISO/IEC 23008-12 nel 2015. JPEG è sia un algoritmo di compressione che un formato di file. HEIC, invece, è principalmente un contenitore. La compressione interna è HEVC (H.265), lo stesso codec utilizzato per il video 4K.

Un singolo file HEIC può memorizzare:

  • Un'immagine primaria
  • Più immagini alternative (scatti in sequenza)
  • Sequenze di immagini (Live Photos: immagine fissa + video di 3 secondi)
  • Canali alpha e mappe di profondità
  • Profondità di colore a 16 bit per canale (JPEG è limitato a 8 bit)

Il contenitore usa una struttura di box, esattamente come MP4:

BoxScopo
ftypTipo di file e brand compatibili
metaMetadati e proprietà dell'elemento
mdatDati immagine codificati grezzi (flusso di bit HEVC)
ilocPosizioni degli elementi all'interno di mdat

Questa struttura consente funzionalità che JPEG non supporta. Per fare il parsing devi conoscere la gerarchia dei box, non bastano i byte grezzi.

Perché Apple ha cambiato

Apple non ha inventato HEIC. MPEG ha pubblicato HEIF nel 2015. Apple lo ha adottato come formato fotocamera predefinito dell'iPhone in iOS 11 (2017).

Il cambiamento era aritmetico, non marketing. Una tipica foto iPhone da 12 MP in JPEG pesa circa 3,5 MB. In HEIC, circa 1,8 MB. Con 50 GB di piano iCloud gratuito, questa differenza significa circa 14.000 foto aggiuntive. Apple vende piani di archiviazione. Il conto si fa da sé.

C'era anche l'allineamento dell'ecosistema. Apple aveva già adottato HEVC per il video (H.265 in iOS 11). Riutilizzare lo stesso codec per le immagini fisse significava blocchi di decodifica hardware condivisi sui chip della serie A, minore consumo di energia e un unico percorso di licenza.

I compromessi

Dal punto di vista tecnico, HEIC supera JPEG su quasi ogni fronte. Il problema è la compatibilità.

AspettoHEICJPEG
Efficienza di compressione~40–50% più piccolo alla stessa qualitàBaseline
Profondità di coloreFino a 16 bit8 bit
TrasparenzaNo
Immagini multiple per fileNo
Riediting senza perditaNo
Supporto Windows nativoRichiede estensione HEIFUniversale
Supporto browser webSolo SafariUniversale
Supporto AndroidNativo su 9+Universale
Licenza brevettualePool di brevetti HEVCJPEG è royalty-free

L'HEVC è coperto da più pool di brevetti (MPEG LA, Access Advance). Apple copre le tariffe per gli utenti iOS. Le terze parti non hanno quel vantaggio. Questa incertezza è in gran parte il motivo per cui l'adozione al di fuori dell'ecosistema Apple è stagnata.

Rilevare HEIC leggendo la firma del file

Non fidarti dell'estensione .heic. Leggi i primi 32 byte e analizza la box ftyp.

Layout esatto dei byte di un'intestazione di file HEIC valida:

Bytes 0–3:   Dimensione della box (uint32 big-endian)
Bytes 4–7:   Tipo di box: "ftyp" (0x66 0x74 0x79 0x70)
Bytes 8–11:  Brand principale: "heic" o "heif" o "mif1"
Bytes 12–15: Versione minore (generalmente 0x00000000)
Bytes 16+:   Elenco di brand compatibili (es. "mif1", "heic", "MiHE")

TypeScript lato browser:

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)
}

Il nostro convertitore esegue questo controllo prima di tentare la decodifica. Se il brand è sbagliato, il file viene rifiutato immediatamente senza sprecare cicli CPU.

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"}

Controllo di livello superiore con filetype:

import filetype

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

O con pillow-heif:

from pillow_heif import is_heif

if is_heif("photo.heic"):
    # contenitore valido
    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);
}

Con fileinfo:

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

ImageMagick CLI

ImageMagick 7+ supporta HEIC se compilato con libheif:

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

Senza libheif: no decode delegate for this image format. Nella maggior parte delle distribuzioni Linux, libheif-examples fornisce heif-convert come alternativa.

Il percorso di conversione

Sapere che un file è HEIC non significa che puoi aprirlo. Windows richiede le HEIF Image Extensions. La maggior parte dei browser rifiuta ancora di renderizzare HEIC nei tag <img>. Android 9+ lo gestisce nativamente; i dispositivi più vecchi no.

La soluzione è convertire. Il nostro convertitore da HEIC a JPG gestisce l'intero pipeline nel tuo browser. Puoi trascinare foto singole o intere cartelle, e l'elaborazione batch parte automaticamente. Ogni file viene validato con il controllo byte per byte descritto sopra; i file non HEIC vengono rifiutati subito con un messaggio chiaro. La decodifica avviene lato client tramite una build WebAssembly di libheif, quindi non c'è caricamento verso server esterni. L'output è JPG al 90% di qualità, che conserva risoluzione e accuratezza del colore originali. Puoi scaricare i file singoli o un unico archivio ZIP.

Per output senza perdita con trasparenza: HEIC a PNG. Per dimensioni ottimizzate per il web: HEIC a WebP.

I file restano sempre sul tuo dispositivo, senza mai raggiungere un server.

Altri post del blog da leggere