HEIF형식 이미지 업로드 대응
2023-10-10어느 날, 사용자로부터 HEIC(HEIF) 이미지 파일이 업로드되지 않는다는 문의가 들어왔습니다.
1. HEIF란?
HEIF는 고효율 이미지 파일 포맷(High Efficiency Image Format)의 약자입니다.
주요 특징:
- 동일한 크기의 JPEG보다 2배나 더 많은 정보를 저장할 수 있습니다
- 화질이 더 우수합니다
- 파일 크기는 더 작습니다
문제점:
- 2023년 현재에도 웹 브라우저 호환성이 떨어집니다
- 대부분의 브라우저에서 기본적으로 지원하지 않습니다
플랫폼별 차이점
| 플랫폼 | HEIF 처리 방식 |
|---|---|
| iOS | 업로드 시 자동으로 JPG로 변환 |
| Android | 직접 변환 로직 필요 |
| 웹 브라우저 | 직접 변환 로직 필요 |
따라서 Android와 브라우저에서 HEIF 이미지를 지원하려면, JPG로 변환하는 로직을 직접 구현해야 합니다.
2. heic2any 라이브러리 도입
첫 번째 시도: 단순 타입 변경
처음에는 단순하게 Blob의 타입만 image/jpeg로 지정하면 되지 않을까 생각했습니다.
const blob = new Blob([innerFile[1]], {
type: "image/jpeg",
});
const heifToPngFile = new File(
[blob],
innerFile[1].name
.replaceAll(".heif", ".jpg")
.replaceAll(".heic", ".jpg")
.replaceAll(".HEIC", ".jpg")
.replaceAll(".HEIF", ".jpg"),
{
type: "image/jpeg",
}
);
결과: 실패했습니다. 확장자만 변경되고 실제 문서 유형은 변경되지 않았습니다.
해결책: heic2any 라이브러리
CTO님이 추천해주신 heic2any 라이브러리를 사용하기로 결정했습니다. 구글링 결과, 이 라이브러리로 HEIF 파일을 성공적으로 변환한 사례들이 많았습니다.
const blob = new Blob([files[0]]);
const transBlob = await heic2any({
blob,
quality: 0.1,
toType: "image/jpeg",
});
const trnasFile = new File(
[transBlob],
files[0].name
.replaceAll(".heif", ".jpg")
.replaceAll(".heic", ".jpg")
.replaceAll(".HEIC", ".jpg")
.replaceAll(".HEIF", ".jpg"),
{
type: "image/jpeg",
lastModified: new Date().getTime(),
}
);
위 로직을 테스트해보니 잘 작동했습니다! 하지만... 뜻밖의 문제가 하나 더 발생했습니다.
3. Android 버전별 호환성 문제
회사에서 안드로이드폰으로 테스트하던 중, Android 8 버전에서는 이미지가 업로드되지 않는 문제를 발견했습니다.
원인 분석
디버깅을 진행한 결과, 다음과 같은 원인을 찾았습니다:
- 특정 Android 버전에서는 HEIF 형식을 지원하지 않습니다
- 지원하지 않는 버전에서 HEIF 파일을 업로드하면 파일 타입이 비어있는 상태로 전송됩니다
- 서버에서 타입이 없는 파일은 거부되므로 업로드가 실패합니다
Android 공식 문서에 따르면, Android 10 버전부터 HEIF 형식을 공식 지원한다고 합니다.
해결 방법
Android 10 미만 버전에서는 Blob으로 변환 후 타입을 강제로 지정하는 방식으로 해결했습니다.
const userAgent = navigator.userAgent.toLowerCase();
const androidIndex = userAgent.indexOf("android");
const androidVer = Number(
userAgent
.substring(androidIndex + 8)
.split(";")[0]
.split(".")[0]
);
if (androidVer < 10) {
const blob = new Blob([innerFile[1]], {
type: "image/jpeg",
});
const heifToPngFile = new File(
[blob],
innerFile[1].name
.replaceAll(".heif", ".jpg")
.replaceAll(".heic", ".jpg")
.replaceAll(".HEIC", ".jpg")
.replaceAll(".HEIF", ".jpg"),
{
type: "image/jpeg",
}
);
}
이렇게 Android 버전을 감지해서 10 미만에서는 단순 타입 변경으로 처리하니 문제가 해결되었습니다.
4. 개선이 필요한 부분
heic2any 라이브러리로 문제를 해결할 수 있었지만, 한 가지 큰 문제가 있습니다.
번들 사이즈 문제

라이브러리의 번들 사이즈가 상당히 큽니다.
이 문제는 GitHub 이슈에도 이미 등록되어 있었는데요. 개발자의 답변에 따르면:
HEIF 변환 시 사용하는 libheif 라이브러리 용량 자체가 크기 때문에 해결 방법이 없다
고 합니다.
향후 개선 방향
- 다른 경량 라이브러리 탐색
- 서버 사이드에서 변환 처리하는 방안 검토
- 필요한 경우에만 동적으로 라이브러리를 로드하는 방식 고려
정리
HEIF 이미지 업로드를 지원하려면:
- iOS: 자동으로 JPG 변환 (별도 처리 불필요)
- Android 10 이상: heic2any 라이브러리로 변환
- Android 10 미만: Blob 타입 강제 지정
- 웹 브라우저: heic2any 라이브러리로 변환
다만 번들 사이즈 문제를 고려하여, 프로젝트 규모에 따라 적절한 방식을 선택해야 합니다!