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

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

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

HEIC — это не просто JPEG меньшего размера. Это контейнерный формат на базе 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 перешла

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 обрабатывает весь конвейер в вашем браузере:

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

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

Ваши файлы никогда не покидают ваше устройство. В этом весь смысл.

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