Глубокие погружения

Что такое HEIC? Техническое погружение в сигнатуры файлов, детектирование и конвертацию

koboshiCo-founder
·5 мин чтения
Что такое HEIC? Техническое погружение в сигнатуры файлов, детектирование и конвертацию
Кратко

HEIC, по сути, контейнерный формат на базе ISO Base Media File Format с HEVC-кодированными изображениями внутри. В статье разбираем его устройство, детектирование чтением сырых байтов и способы конвертации, когда совместимость даёт сбой.

Откройте файл HEIC в шестнадцатеричном редакторе. Первые двенадцать байтов:

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

Это ISOBMFF, тот же контейнерный стандарт, что и у MP4. 0x18 (24 байта) обозначает размер бокса, ftyp — бокс типа файла, heic — основной бренд. HEIC сам по себе не кодирует изображение; это контейнер с маркером бренда, внутри которого лежат HEVC-кодированные изображения.

Внутреннее устройство HEIC

HEIC расшифровывается как High Efficiency Image Container. Это брендированная Apple реализация формата HEIF, стандартизированного MPEG как ISO/IEC 23008-12 в 2015 году. JPEG одновременно задаёт и алгоритм сжатия, и формат файла. HEIC же отвечает только за контейнер. Само сжатие выполняет HEVC (H.265), тот же кодек, что применяется для 4K-видео.

Один файл HEIC может хранить:

  • Одно основное изображение
  • Несколько альтернативных изображений (серийная съёмка)
  • Последовательности изображений (Live Photos: статичное фото + 3-секундное видео)
  • Альфа-каналы и карты глубины
  • 16-битную глубину цвета на канал (JPEG ограничен 8 битами)

Контейнер использует структуру боксов, как и MP4:

BoxНазначение
ftypТип файла и совместимые бренды
metaМетаданные и свойства элементов
mdatСырые закодированные данные изображения (HEVC-битстрим)
ilocРасположение элементов внутри mdat

Такая расширяемость даёт HEIC гибкость, которой у JPEG нет. Парсинг требует понимания иерархии боксов, а не простого чтения сырого битстрима.

Почему Apple выбрала HEIC

Apple не изобрела HEIC. MPEG опубликовал HEIF в 2015 году. Apple приняла его как формат камеры iPhone по умолчанию в iOS 11 (2017).

Переход легко объяснить цифрами. Фото iPhone 12 МП в JPEG занимает ~3,5 МБ, а в HEIC — ~1,8 МБ. При 50 ГБ бесплатного тарифа iCloud такая разница даёт примерно 14 000 дополнительных фотографий. Apple продаёт тарифы хранилища, так что выгода понятна.

К этому добавилась экосистемная логика. Apple уже внедрила HEVC для видео (H.265 в iOS 11). Повторное использование того же кодека для статичных изображений означало совместные аппаратные блоки декодирования на чипах серии A, меньшее энергопотребление и единый путь лицензирования.

Компромиссы

HEIC обычно превосходит JPEG по техническим параметрам, но уступает в совместимости.

АспектHEICJPEG
Эффективность сжатия~40–50% меньше при том же качествеБазовый уровень
Глубина цветаДо 16 бит8 бит
ПрозрачностьДаНет
Несколько изображений в файлеДаНет
Неразрушающее редактированиеДаНет
Нативная поддержка WindowsТребуется расширение HEIFУниверсальная
Поддержка веб-браузеровТолько SafariУниверсальная
Поддержка AndroidНативная с 9+Универсальная
Патентное лицензированиеПул патентов HEVCJPEG без лицензионных отчислений

HEVC покрывается несколькими патентными пулами (MPEG LA, Access Advance). Apple оплачивает сборы за пользователей iOS, тогда как сторонние производители такого преимущества не имеют. Из-за этой неопределённости внедрение за пределами экосистемы Apple идёт медленно.

Детектирование HEIC по сигнатуре файла

Расширению .heic доверять не стоит. Надёжнее прочитать первые 32 байта и распарсить бокс ftyp.

Точная байтовая раскладка заголовка валидного файла HEIC:

Bytes 0–3:   Размер бокса (big-endian uint32)
Bytes 4–7:   Тип бокса: "ftyp" (0x66 0x74 0x79 0x70)
Bytes 8–11:  Основной бренд: "heic" или "heif" или "mif1"
Bytes 12–15: Минорная версия (обычно 0x00000000)
Bytes 16+:   Список совместимых брендов (напр. "mif1", "heic", "MiHE")

TypeScript в браузере:

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

Наш конвертер выполняет эту проверку перед декодированием. При неправильном бренде файл отклоняется сразу, без лишней нагрузки на 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"}

Проверка более высокого уровня с filetype:

import filetype

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

Или с pillow-heif:

from pillow_heif import is_heif

if is_heif("photo.heic"):
    # действительный контейнер
    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);
}

С fileinfo:

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

ImageMagick CLI

ImageMagick 7+ поддерживает HEIC при компиляции с libheif:

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

Без libheif: no decode delegate for this image format. В большинстве дистрибутивов Linux установка libheif-examples предоставляет утилиту heif-convert в качестве альтернативы.

Конвертация HEIC

Знание формата файла ещё не означает, что его можно открыть. Windows требует HEIF Image Extensions. Большинство браузеров до сих пор не рендерят HEIC в тегах <img>. Android 9+ обрабатывает его нативно, старые устройства — нет.

Решение — конвертировать. Наш конвертер HEIC в JPG обрабатывает весь конвейер в браузере. Перетаскивайте отдельные фото или целые папки, пакетная обработка работает автоматически. Каждый файл проходит байтовую валидацию сигнатуры; не-HEIC файлы отклоняются с чётким сообщением. Декодирование выполняется локально сборкой WebAssembly libheif, без загрузок на сервер и без сетевых запросов. Результат сохраняется в JPG качеством 90%, с исходным разрешением и точностью цвета. Готовые файлы можно скачать по отдельности или одним ZIP-архивом.

Для вывода без потерь с прозрачностью подходит HEIC в PNG, а для компактных веб-размеров — HEIC в WebP.

Файлы остаются на вашем устройстве: никаких облачных загрузок и посторонних серверов.

Ещё посты в блоге