back

Posts

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 라이브러리로 문제를 해결할 수 있었지만, 한 가지 큰 문제가 있습니다.

번들 사이즈 문제

heic2any library size

라이브러리의 번들 사이즈가 상당히 큽니다.

이 문제는 GitHub 이슈에도 이미 등록되어 있었는데요. 개발자의 답변에 따르면:

HEIF 변환 시 사용하는 libheif 라이브러리 용량 자체가 크기 때문에 해결 방법이 없다

고 합니다.

향후 개선 방향

  • 다른 경량 라이브러리 탐색
  • 서버 사이드에서 변환 처리하는 방안 검토
  • 필요한 경우에만 동적으로 라이브러리를 로드하는 방식 고려

정리

HEIF 이미지 업로드를 지원하려면:

  1. iOS: 자동으로 JPG 변환 (별도 처리 불필요)
  2. Android 10 이상: heic2any 라이브러리로 변환
  3. Android 10 미만: Blob 타입 강제 지정
  4. 웹 브라우저: heic2any 라이브러리로 변환

다만 번들 사이즈 문제를 고려하여, 프로젝트 규모에 따라 적절한 방식을 선택해야 합니다!