
Window 운영체제에서 .jpg 확장자 이미지가 다운로드는 되지만 열리지 않는 문제를 해결한 과정을 공유합니다.
이번 문제는 안드로이드 폰에서 캡처한 이미지가 .jpg 확장자로 저장되었지만, 실제 내부 포맷은 AVIF였기 때문에 발생했습니다.
❗️ 문제 상황
Mac이나 Chrome 브라우저에서는 정상적으로 열리지만, 특정 Windows 환경에서는 이미지를 열 수 없는 문제가 발생했습니다.
🔍 문제 분석
터미널에서 문제가 된 이미지를 확인해보았습니다.

autowini2@autowiniui-MacBookPro-5 Desktop % file test.jpg
test.jpg: ISO Media, AVIF Image
autowini2@autowiniui-MacBookPro-5 Desktop % file umsungjun.jpg
umsungjun.jpg: JPEG image data, JFIF standard 1.01, resolution (DPCM), density 37x37, segment length 16, baseline, precision 8, 500x500, components 1
- test.jpg → 확장자는 .jpg이지만, 실제 내부 포맷은 AVIF
- umsungjun.jpg → 정상적인 JPEG
원인
안드로이드에서 스크린샷을 찍으면, 기기 기본 설정에 따라 AVIF(또는 HEIF) 포맷으로 저장됩니다. 하지만 일부 환경에서는 파일 확장자를 .jpg로 강제로 붙이면서, 실제 포맷과 확장자가 불일치하는 문제가 발생합니다.
- AVIF: 최신 이미지 포맷으로, 압축 효율이 높고 화질 대비 용량이 작음. 안드로이드 최신 버전에서 기본 지원.
- JPEG: 오랜 기간 표준으로 쓰인 포맷. 대부분의 OS와 앱에서 호환 가능.
- Windows 기본 사진 앱: AVIF를 지원하지 않음 → 확장자는 .jpg인데 실제로는 AVIF라서 파일 손상 에러가 발생.
포맷이란?
포맷(format)이란, 이미지 데이터를 어떻게 압축·저장할지 정한 규격(파일 형식)을 말합니다.
- JPEG → 손실 압축, 높은 호환성
- PNG → 무손실 압축, 투명 배경 지원
- AVIF → 최신 규격, 높은 압축 효율
즉, 확장자 .jpg는 껍데기일 뿐이고, 내부에 저장된 실제 데이터가 어떤 포맷이냐에 따라 열 수 있느냐 없느냐가 결정됩니다.
✅ 해결 방법
안드로이드 캡처 이미지처럼 확장자는 .jpg인데 내부 포맷이 AVIF인 경우, Windows 기본 뷰어에서는 열리지 않는 문제가 발생했습니다.
이를 해결하기 위해, 다운로드 시 blob의 MIME 타입이 image/avif라면 Canvas를 통해 JPG로 변환 후 저장하도록 처리했습니다.
/**
* @description 파일 다운로드 함수
* @param url - 파일 URL
* @param filename - 다운로드할 파일 이름
*/
export const fileDownload = async (url: string, filename: string) => {
const res = await fetch(url);
if (!res.ok) throw new Error('파일 다운로드에 실패했습니다.');
const blob = await res.blob();
// avif → jpg 변환 (내부 MIME 타입이 avif일 때만 처리)
const convertIfAvif = async (blob: Blob): Promise<Blob> => {
if (blob.type === 'image/avif') {
const img = await createImageBitmap(blob);
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
if (!ctx) throw new Error('Canvas context 생성 실패');
ctx.drawImage(img, 0, 0);
return new Promise<Blob>((resolve, reject) => {
canvas.toBlob(
(newBlob) => {
if (newBlob) resolve(newBlob);
else reject(new Error('JPG 변환 실패'));
},
'image/jpeg',
0.9
);
});
}
return blob;
};
const finalBlob = await convertIfAvif(blob);
const objectUrl = URL.createObjectURL(finalBlob);
const link = document.createElement('a');
// 내부 포맷이 avif였다면 확장자를 jpg로 강제 변경
const finalFilename =
blob.type === 'image/avif'
? filename.replace(/\.[^/.]+$/, '') + '.jpg'
: filename;
link.href = objectUrl;
link.download = finalFilename || `file-${Date.now()}`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 메모리 해제
setTimeout(() => URL.revokeObjectURL(objectUrl), 100);
};
💡 느낀 점
처음에는 단순히 “파일이 손상된 것 같다”라고만 생각했지만, 이번 경험을 통해 확장자와 실제 파일 포맷이 다를 수 있다는 점을 알게 되었습니다.
앞으로 유사한 문제가 발생하더라도, 보다 빠르게 원인을 파악하고 해결할 수 있을 것 같습니다.
'지식 정리 📝' 카테고리의 다른 글
| GitHub Copilot을 활용한 사용하지 않는 번역 키 제거 (0) | 2025.11.13 |
|---|---|
| Autowini WEB 통합 프로젝트 Vitest 테스트 시스템 도입 (1) | 2025.10.17 |
| iframe으로 인한 width 드래그 조절 문제 해결한 방법 (0) | 2025.08.22 |
| Google Spreadsheet JWT 403 PERMISSION_DENIED 오류 해결기 (0) | 2025.08.20 |
| Prettier 적용 with Import 자동 정렬 (6) | 2025.07.29 |