HEIC 파일 포맷 지원을 통한 사용자 경험 향상 시키기

jpapa
원티드랩 기술 블로그
8 min readApr 1, 2024
Photo by Jo Barnard on Unsplash

HEIC/HEIF 란?

HEIC(High Efficiency Image Container) 파일 포맷은 Apple이 모바일 디바이스에서 전통적으로 사용하던 HEIF(Efficiency Image Format)의 업데이트 버전입니다.

출처: HEIC 파일의 역사 / 장,단점

HEIC 형식은 우리 주변에서 쉽게 볼 수 있습니다. 예를 들어, iPhone에서 사진을 찍고 AirDrop으로 데스크탑으로 전송하면 HEIC 파일로 나타납니다. Android 에서도 카메라 설정에서 HEIF 타입을 켜거나 끌 수 있습니다.

iPhone에서 사진 촬영한 파일을 airdrop으로 보낸 파일.

문제 상황

원티드 소셜에서 글 작성 및 사진 첨부 시 에러가 발생하는 상황을 접했습니다. 유저가 업로드하려는 파일은 .jpg 확장자였으나,

유저에게 받은 이미지 파일

실제 파일 타입은 image/heic으로 확인되었습니다.
원티드 소셜에서 지원하는 이미지 포맷은 image/jpeg과 image/png 두 가지뿐이었습니다.

실제 파일 타입 체크

실제 파일 타입 확인시 이용해 보세요.
CheckFileType.com — Free Online File Type Checker

파일 타입 감지 필요성

대부분 바이너리 파일은 파일의 시작 부분에 파일 유형을 포함한 다양한 정보를 담고 있습니다. 이 정보를 참고하여 파일의 형식을 감지할 수 있습니다. 파일 시그니처(매직 넘버)는 파일의 맨 앞부분에 삽입되는 고유한 값으로, 파일의 형식을 구분하는 데 사용됩니다.

https://namu.wiki/w/파일 시그니처

파일 시그니처 검색용 사이트 입니다. (ctrl + f 눌러서 검색이 가능)

쉽게 파일 시그니처 확인

terminal에서 od 명렁어를 이용하여 쉽게 byte와 string을 확인 할 수 있습니다. (mac, linux 가능)

$ od -xc IMG_2987.HEIC | head -n 2
0000000 0000 2400 7466 7079 6568 6369 0000 0000
\0 \0 \0 $ f t y p h e i c \0 \0 \0 \0sh

HEIC파일을 해더 정보에 파일 시그니처가 존재 합니다. ftypheic 이값이 파일 형식을 나타내는 데이터 입니다.

이부분을 읽어, heic/heif 파일인지 감지 할 수 있습니다.

JavaScript로 HEIC 파일 시그니처 감지

웹 환경에서도 파일 시그니처를 통해 HEIC 파일을 감지할 수 있습니다. 아래의 코드는 파일 객체를 받아서 HEIC 형식인지 아닌지를 판별하는 함수입니다.

// HEIC 파일 시그니처 값
const HEIC_SIGNATURE = ['ftypmif1', 'ftypmsf1', 'ftypheic', 'ftypheix', 'ftyphevc', 'ftyphevx'];

export async function isHeicFormat(file: File): Promise<boolean> {
// 1. File 객체를 Bytes로 변환
const byteArray: Uint8Array = await convertFileToUint8Array(file);
const heicRange = byteArray.slice(4, 12);

// 2. byte를 string으로 변환
const heicRangeHeader = heicRange.reduce(
(heicRangeHeader, uint8) => (heicRangeHeader += String.fromCharCode(uint8)),
'',
);

// 3. HEIC_SIGNATURE가 있으면 true 리턴
return HEIC_SIGNATURE.includes(heicRangeHeader);
}

function convertFileToUint8Array(file: File): Promise<Uint8Array> {
return new Promise<Uint8Array>((resolve, reject) => {
const fileReader = new FileReader();

fileReader.onload = (event: ProgressEvent<FileReader>) => {
const readResult = event.target?.result;
if (readResult instanceof ArrayBuffer) {
const byteArray = new Uint8Array(readResult);
resolve(byteArray);
} else {
reject(new Error('ArrayBuffer로 파일 읽기 실패'));
}
};

fileReader.onerror = () => {
reject(new Error('파일 읽기 실패'));
};

fileReader.readAsArrayBuffer(file);
});
}

HEIC/HEIF → JPEG/PNG 컨버팅

대부분의 브라우저가 HEIC/HEIF 파일 타입을 지원하지 않아, 이를 JPEG나 PNG로 변환해야 합니다. 이 과정은 복잡하고 컴퓨터 자원을 많이 사용하기 때문에, 잘 만들어진 라이브러리를 사용하는 것이 좋습니다.

https://caniuse.com/?search=HEIC

heic2Any 라이브러리 사용

alexcorvi/heic2any

heic2Any는 HEIC 포맷을 jpg, png로 컨버팅 해주는 라이브러리 중 하나입니다. 아래 코드는 heic2Any를 사용하여 HEIC 파일을 JPEG로 변환하는 예시입니다.

/**
* HEIC 형식의 파일을 받아 JPEG로 변환합니다.
* @return {Promise<File>} 변환된 JPEG 이미지 파일로 반환합니다.
*/
async function convertHeicToJpeg(heicFile: File): Promise<File> {
const { default: convertHeicToAnyFormat } = await import('heic2any');
const jpegBlob = await convertHeicToAnyFormat({
blob: heicFile,
toType: 'image/jpeg',
quality: 0.8,
});
return new File([jpegBlob as Blob], 'converted_image.jpeg', {
type: 'image/jpeg',
});
}
export default convertHeicToJpeg;

다른 플랫폼들이 어떻게 HEIC 포맷을 지원하는지?

Jira, Confluence, Slack은 모두 HEIC 포맷을 지원합니다.
Slack에서는 HEIC 파일을 업로드하면, 화면에 표시되는 이미지는 PNG 형식으로 나타나지만, 실제로 다운로드 링크를 클릭하면 HEIC 파일이 다운로드됩니다.
(당연하게도, HEIC 파일을 올렸으니 HEIC 형식으로 다운받게 되는 것이죠!)

마무리

중요한 교훈을 얻었습니다. 바로 사용자가 업로드한 파일의 확장자명만 보고 그 파일의 타입을 판단해서는 안 된다는 것입니다. 파일의 실제 타입을 확인하려면 파일 시그니처를 검사해야 합니다. 이를 통해 이미지 업로드 기능을 개선하여 HEIC 타입을 지원하도록 만들면, 사용자 경험을 한층 더 향상시킬 수 있습니다. HEIC 파일 포맷 지원은 생각보다 어렵지 않으니, 이 방향으로 개발을 고려해보는 것은 어떨까요?

--

--