Abre un archivo HEIC en un editor hexadecimal. Los primeros doce bytes:
00 00 00 18 66 74 79 70 68 65 69 63
Eso es ISOBMFF — el mismo estándar de contenedor que usa MP4. 0x18 (24 bytes) es el tamaño de la caja, ftyp es la caja de tipo de archivo, heic es la marca principal. Un archivo HEIC no es una codificación de imagen. Es un contenedor con un marcador de marca, que alberga imágenes codificadas en HEVC.
Qué es realmente HEIC
HEIC = High Efficiency Image Container. La implementación con marca de Apple de HEIF, estandarizado por MPEG como ISO/IEC 23008-12 en 2015. JPEG es tanto un algoritmo de compresión como un formato de archivo. HEIC es solo un contenedor. La compresión interna es HEVC (H.265), el mismo códec utilizado para video 4K.
Un solo archivo HEIC puede almacenar:
- Una imagen principal
- Múltiples imágenes alternativas (fotos en ráfaga)
- Secuencias de imágenes (Live Photos: imagen fija + video de 3 segundos)
- Canales alfa y mapas de profundidad
- Profundidad de color de 16 bits por canal (JPEG está limitado a 8 bits)
El contenedor usa una estructura de cajas — exactamente como MP4:
| Box | Propósito |
|---|---|
ftyp | Tipo de archivo y marcas compatibles |
meta | Metadatos y propiedades del elemento |
mdat | Datos de imagen codificados en bruto (flujo de bits HEVC) |
iloc | Ubicaciones de elementos dentro de mdat |
Esta extensibilidad permite a HEIC hacer cosas que JPEG nunca pudo hacer. Analizarlo requiere entender la jerarquía de cajas, no solo leer un flujo de bits en bruto.
Por qué Apple cambió
Apple no inventó HEIC. MPEG publicó HEIF en 2015. Apple lo adoptó como formato de cámara predeterminado del iPhone en iOS 11 (2017).
El cambio fue aritmético, no marketing. Una foto típica de iPhone de 12 MP en JPEG es ~3,5 MB. En HEIC, ~1,8 MB. Con 50 GB de nivel gratuito de almacenamiento iCloud, esa diferencia significa aproximadamente 14.000 fotos adicionales. Apple vende niveles de almacenamiento. La cuenta se hace sola.
También hubo alineación del ecosistema. Apple ya había adoptado HEVC para video (H.265 en iOS 11). Reutilizar el mismo códec para imágenes fijas significaba bloques de decodificación de hardware compartidos en los chips de la serie A, menor consumo de energía y un único camino de licenciamiento.
Los pros y los contras
HEIC es superior a JPEG en casi todas las métricas, excepto la compatibilidad.
| Aspecto | HEIC | JPEG |
|---|---|---|
| Eficiencia de compresión | ~40–50% más pequeño a igual calidad | Línea de base |
| Profundidad de color | Hasta 16 bits | 8 bits |
| Transparencia | Sí | No |
| Múltiples imágenes por archivo | Sí | No |
| Reedicionesin pérdida | Sí | No |
| Soporte nativo de Windows | Requiere extensión HEIF | Universal |
| Soporte de navegadores web | Solo Safari | Universal |
| Soporte de Android | Nativo en 9+ | Universal |
| Licenciamiento de patentes | Pool de patentes HEVC | JPEG es libre de regalías |
El HEVC está cubierto por múltiples pools de patentes (MPEG LA, Access Advance). Apple cubre las tarifas para los usuarios de iOS. Los terceros no tienen ese lujo. Esa incertidumbre es gran parte de la razón por la que la adopción fuera del ecosistema de Apple se estancó.
Detectar HEIC leyendo la firma del archivo
No confíes en la extensión .heic. Lee los primeros 32 bytes y analiza la caja ftyp.
Diseño exacto de bytes del encabezado de un archivo HEIC válido:
Bytes 0–3: Tamaño de la caja (uint32 big-endian)
Bytes 4–7: Tipo de caja: "ftyp" (0x66 0x74 0x79 0x70)
Bytes 8–11: Marca principal: "heic" o "heif" o "mif1"
Bytes 12–15: Versión menor (generalmente 0x00000000)
Bytes 16+: Lista de marcas compatibles (ej. "mif1", "heic", "MiHE")
TypeScript del lado del navegador:
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)
}
Nuestro convertidor ejecuta esta verificación antes de intentar la decodificación. Marca incorrecta = rechazo inmediato, sin ciclos de CPU desperdiciados.
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"}
Verificación de nivel superior 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"):
# contenedor válido
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+ admite HEIC si se compiló con libheif:
magick identify -verbose photo.heic | grep "Format:"
# Format: HEIC (High Efficiency Image Container)
Sin libheif: no decode delegate for this image format. En la mayoría de las distribuciones de Linux, libheif-examples proporciona heif-convert como alternativa.
La ruta de conversión
Saber que un archivo es HEIC no lo abre. Windows necesita las HEIF Image Extensions. La mayoría de los navegadores se niegan a renderizar HEIC en etiquetas <img>. Android 9+ lo maneja nativamente; los dispositivos más antiguos no.
La solución: convertir. Nuestro convertidor de HEIC a JPG maneja todo el pipeline en tu navegador:
- Soltar archivos — fotos individuales o carpetas enteras, el procesamiento por lotes es automático.
- Validación de firma — la verificación exacta de bytes de arriba se ejecuta en cada archivo. Los archivos que no son HEIC se rechazan inmediatamente con un mensaje claro.
- Decodificación del lado del cliente — una compilación WebAssembly de libheif se ejecuta localmente. Sin subidas. Sin servidores.
- Salida que preserva la calidad — JPG al 90% de calidad conserva la resolución y la precisión del color originales.
- Descarga por lotes — archivos individuales o un único archivo ZIP.
Para salida sin pérdida con transparencia: HEIC a PNG. Para tamaños optimizados para web: HEIC a WebP.
Tus archivos nunca abandonan tu dispositivo. De eso se trata.


