HEIC 파일을 16진수 편집기로 열어라. 처음 12바이트:
00 00 00 18 66 74 79 70 68 65 69 63
이것은 ISOBMFF —— MP4가 사용하는 것과 동일한 컨테이너 표준이다. 0x18(24바이트)는 box 크기, ftyp는 파일 유형 box, heic는 주 브랜드다. HEIC 파일은 이미지 인코딩이 아니다. 브랜드 마커가 있는 컨테이너로, 내부에 HEVC 인코딩 이미지를 캡슐화하고 있다.
HEIC은 실제로 무엇인가
HEIC = High Efficiency Image Container. Apple이 브랜딩한 HEIF의 구현체로, MPEG에 의해 2015년 ISO/IEC 23008-12로 표준화되었다. JPEG은 압축 알고리즘이자 파일 형식이지만, HEIC은 컨테이너에 불과하다. 내부 압축은 HEVC(H.265), 4K 비디오에 사용되는 것과 동일한 코덱이다.
단일 HEIC 파일은 다음을 저장할 수 있다:
- 하나의 기본 이미지
- 여러 대체 이미지(연사 촬영)
- 이미지 시퀀스(Live Photos: 정지 이미지 + 3초 비디오)
- 알파 채널 및 깊이 맵
- 채널당 16비트 색 심도(JPEG은 8비트로 제한됨)
컨테이너는 box 구조를 사용한다 —— MP4와 정확히 동일하다:
| Box | 용도 |
|---|---|
ftyp | 파일 유형 및 호환 브랜드 |
meta | 항목 메타데이터 및 속성 |
mdat | 원시 인코딩 이미지 데이터(HEVC 비트스트림) |
iloc | mdat 내 항목 위치 |
이러한 확장성이 HEIC이 JPEG이 결코 할 수 없는 것을 가능하게 한다. 파싱하려면 box 계층 구조를 이해해야 하며, 단순히 원시 비트스트림을 읽는 것으로는 부족하다.
Apple이 전환한 이유
Apple은 HEIC을 발명하지 않았다. MPEG은 2015년에 HEIF를 발표했고, Apple은 2017년 iOS 11에서 iPhone의 기본 카메라 형식으로 채택했다.
동기는 마케팅이 아니라 산술이었다. iPhone의 1200만 화소 사진은 JPEG에서 약 3.5MB, HEIC에서는 약 1.8MB다. 50GB 무료 iCloud 스토리지 티어에서 이 차이는 대략 14,000장의 추가 사진을 의미한다. 스토리지 티어를 판매하는 Apple에게 이 계산은 자명하다.
또 다른 요인은 생태계 정렬이었다. Apple은 이미 비디오에서 HEVC를 채택하고 있었다(iOS 11의 H.265). 정지 이미지에 동일한 코덱을 재사용한다는 것은 A 시리즈 칩에서 하드웨어 디코딩 블록을 공유하고, 전력 소비를 낮추며, 단일 라이선스 경로를 유지함을 의미했다.
장단점
호환성이라는 한 가지를 제외하고 HEIC은 거의 모든 면에서 JPEG을 능가한다.
| 측면 | HEIC | JPEG |
|---|---|---|
| 압축 효율 | 동일 화질에서 약 40–50% 더 작음 | 기준선 |
| 색 심도 | 최대 16비트 | 8비트 |
| 투명도 | 있음 | 없음 |
| 단일 파일 다중 이미지 | 있음 | 없음 |
| 무손실 재편집 | 있음 | 없음 |
| Windows 기본 지원 | HEIF 확장 필요 | 보편적 |
| 웹 브라우저 지원 | Safari만 | 보편적 |
| Android 지원 | 9 이상 기본 지원 | 보편적 |
| 특허 라이선스 | HEVC 특허 풀 | JPEG은 로열티 무료 |
HEVC는 여러 특허 풀(MPEG LA, Access Advance)에 의해 커버된다. Apple은 iOS 사용자를 대신해 라이선스 비용을 지불하지만, 서드파티 벤더에게는 그 특권이 없다. 이러한 불확실성이 Apple 생태계 외부에서의 채택이 정체된 주된 이유다.
파일 서명을 읽어 HEIC 감지하기
.heic 확장자를 믿지 마라. 처음 32바이트를 읽고 ftyp box를 파싱하라.
유효한 HEIC 파일 헤더의 정확한 바이트 레이아웃:
Bytes 0–3: Box 크기(빅엔디안 uint32)
Bytes 4–7: Box 유형: "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+는 libheif로 컴파일된 경우 HEIC을 지원한다:
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에는 Microsoft Store의 HEIF Image Extensions가 필요하다. 대부분의 브라우저는 <img> 태그에서 HEIC 렌더링을 거부한다. Android 9+는 기본적으로 처리하지만, 오래된 장치는 그렇지 않다.
해결책: 변환하라. 우리의 HEIC to JPG 컨버터는 브라우저 내에서 전체 파이프라인을 처리한다:
- 파일 드롭 — 단일 사진 또는 전체 폴더, 일괄 처리는 자동이다.
- 서명 검증 — 위의 바이트 체크가 각 파일에 대해 실행된다. HEIC이 아닌 파일은 명확한 불일치 메시지와 함께 즉시 거부된다.
- 클라이언트 사이드 디코딩 — libheif의 WebAssembly 빌드가 로컬에서 실행된다. 업로드 없음. 서버에 접근하지 않음.
- 품질 보존 출력 — 90% 품질의 JPG는 원본 해상도와 색 정확도를 유지한다.
- 일괄 다운로드 — 개별 파일 또는 단일 ZIP 아카이브.
투명도가 있는 무손실 출력이 필요한 경우: HEIC to PNG. Web 최적화 크기가 필요한 경우: HEIC to WebP.
당신의 파일은 장치를 떠나지 않는다. 그것이 핵심이다.


