김솔비 블로그
기술 블로그

[Part 5] 이미지가 깨져 보였던 이유 3가지

4분 읽기시리즈 6/10

TL;DR

  • 결과 이미지가 깨져 보인 원인은 세 가지였다. 이중 압축, 칸에 맞춰 잘라서 늘리기, 캔버스 기본(저품질) 축소.
  • 업로드는 긴 변 2048px·JPEG 92%로 올리고, 상세에서는 원래 비율 그대로 보여 준다.
  • 표시 품질은 WebP 80 한 종류, 크기 단계는 15개에서 8개로 줄였다. 상세 이미지(1440px)는 약 98KB다.

문제

프롬피드 상세 페이지의 핵심은 결과 예시 이미지다. 이걸 보고 "해 볼 만한지" 판단한다. 그런데 이 이미지가 흐릿하고 깨져 보였다. AI 결과물의 매력이 사진 품질에서 반쯤 사라졌다.

원인 세 가지

① 두 번 압축했다

관리자가 이미지를 올릴 때 브라우저에서 한 번 줄이면서 JPEG 86%로 압축했다. 화면에 보여 줄 때 Next.js 이미지 최적화가 다시 품질 75%로 압축했다. 손실 압축을 두 번 거치면 뭉개짐이 겹친다.

② 칸에 맞춰 잘라서 늘렸다

결과 이미지를 4:3 칸에 맞춰 잘라서 늘려 보여 줬다. 원래 비율과 다른 이미지는 잘리고, 잘린 만큼 늘어나서 확대된 것처럼 보였다.

③ 캔버스 기본 축소가 저품질이었다

업로드 전에 캔버스로 크기를 줄일 때, 캔버스의 기본 보간 품질은 low다. 크게 줄이면 계단 현상과 뭉개짐이 생긴다.

선택지

  • 원본을 그대로 올리고 그대로 보여 준다. 화질은 가장 좋지만 용량이 크다. 휴대폰에서 느려진다.
  • 화면마다 최적의 품질을 따로 준다. Vercel 무료 플랜은 이미지 변환 횟수 한도(월 약 5,000회)가 있다. 품질과 크기 조합이 늘어날수록 변환 횟수가 늘어난다.
  • 업로드는 고화질로 한 번, 표시는 한 종류로. 이걸 골랐다.

내 선택

업로드: 고화질로 한 번만

ts
const MAX_SIDE = 2048; /** 긴 변 2048px 이하 JPEG 로 줄인다 (고화질 92%). */ export async function resizeImage(file: File, quality = 0.92): Promise<Blob> { // 이미 작은 JPEG 는 다시 압축하지 않는다 if (file.type === "image/jpeg" && long <= MAX_SIDE && file.size <= KEEP_ORIGINAL_BYTES) return file; // ... ctx.imageSmoothingQuality = "high"; // 기본(low)은 줄일 때 계단·뭉개짐이 생긴다 // ... }
  • 긴 변 2048px, JPEG 92%로 올린다.
  • 이미 충분히 작은 JPEG는 다시 압축하지 않는다. 압축을 한 번이라도 줄이려고 그렇게 했다.
  • 캔버스 축소는 imageSmoothingQuality = "high"로 한다.

표시: 자르지 않는다

상세 페이지에서는 칸에 맞춰 자르지 않고 원래 비율 그대로 보여 준다.

비용: 변환 횟수를 줄인다

Next.js 이미지 최적화 설정을 무료 한도에 맞췄다.

  • 품질은 WebP 80 한 종류. 화면마다 품질이 다르면 같은 이미지라도 변환이 따로 일어난다.
  • 크기 단계를 15개에서 8개로 줄였다.
  • 캐시는 31일. 한 번 변환한 이미지는 오래 쓴다.
  • 크게 보기에서도 원본 대신 캐시된 사본을 쓴다.
ts
// next.config.ts images: { formats: ["image/webp"], deviceSizes: [640, 828, 1080, 1440, 2048], imageSizes: [128, 256, 384], minimumCacheTTL: 2_678_400, // 31일 },

결과

항목값
원본 JPEG220~330KB
상세 이미지 (1440px, WebP 80)약 98KB
크기 단계15개 → 8개

화질은 원본에 가깝게 유지하면서, 용량은 원본의 절반 아래로 줄었다.

배운 점

  • 화질 문제는 한 군데가 아니라 흐름 전체에서 생긴다. 올리기, 줄이기, 보여 주기를 한 번에 봐야 원인이 보인다.
  • 손실 압축은 한 번만. 파이프라인에 압축이 두 번 있으면 둘 중 하나는 빼는 게 맞다.
  • 무료 플랜에서는 조합의 수가 곧 비용이다. 품질과 크기 종류를 줄이는 게 가장 확실한 절약이었다.

프롬피드 개발기

프롬피드: promfeed.solfany.com