JPEG 압축은 실제로 어떻게 동작할까
DCT 변환, 양자화 테이블, 이미지마다 압축률이 다른 이유까지 시각적으로 살펴보는 JPEG 압축 원리 가이드입니다.

JPEG은 파일 포맷계의 바퀴벌레입니다. 1992년에 표준화되었고, 웹 브라우저보다도 먼저 나왔으며, 이를 대체하려던 모든 시도를 버텨냈죠. WebP, AVIF, HEIC 같은 포맷은 모두 더 나은 압축률을 보여주지만, JPEG은 여전히 인터넷에서 가장 널리 쓰이는 이미지 포맷입니다. 관성도 한몫하지만, 더 큰 이유는 JPEG의 압축 파이프라인이 정말 훌륭하기 때문입니다. 인코더를 직접 짤 일이 없더라도 한 번쯤 이해해볼 가치가 있는, 응용 신호 처리의 교과서 같은 설계예요.
대부분의 개발자는 JPEG을 블랙박스처럼 다룹니다. 이미지를 넣으면 용량이 줄어든 파일이 나오고, 품질 슬라이더를 적당히 맞추면 끝이죠. 하지만 그 상자 안에서 무슨 일이 벌어지는지 알면, 이미지와 압축, 그리고 파일 크기와 화질 사이의 트레이드오프를 보는 시각이 달라집니다.
한눈에 보는 파이프라인
JPEG 압축은 저마다 영리한 일을 하는 다섯 단계의 파이프라인입니다. 핵심은 이 단계들이 서로 맞물린다는 점이에요. 각 단계가 다음 단계가 더 효과적으로 작동하도록 준비해 줍니다.
- 색 공간 변환 — RGB를 YCbCr로 변환 (밝기와 색상을 분리)
- 크로마 서브샘플링 — 색상 채널의 해상도 줄이기
- 이산 코사인 변환(DCT) — 공간 데이터를 주파수 데이터로 변환
- 양자화 — 고주파 디테일 버리기 (손실이 발생하는 단계)
- 엔트로피 부호화 — 양자화된 데이터를 무손실로 압축
1단계와 2단계는 인간의 시각 특성을 활용합니다. 3단계와 4단계는 자연 이미지의 성질을 활용하죠. 5단계는 일반적인 데이터 압축 기법입니다. 각 단계는 개별로 보면 단순해요. 핵심은 그 순서에 있습니다.
1단계: 색 공간 변환
카메라는 이미지를 RGB, 즉 빨강·초록·파랑 채널로 캡처하며, 픽셀당 채널마다 8비트를 씁니다. JPEG의 첫 단계는 이를 밝기(휘도) 채널 하나와 색상(색차) 채널 두 개로 이루어진 YCbCr로 바꾸는 것입니다. 아직 압축이 아니에요. 데이터는 전혀 잃지 않습니다. 좌표축을 회전하는 것과 같은 좌표 변환일 뿐이죠.
왜 굳이 이렇게 할까요? 사람의 눈은 색보다 밝기에 훨씬 민감하기 때문입니다. 흑백 사진에서는 아주 미세한 디테일까지 볼 수 있지만, 색의 해상도는 그보다 훨씬 거칠게 인지하죠. 밝기와 색을 분리하면 JPEG은 둘을 다르게 다룰 수 있습니다. 밝기 디테일은 보존하고, 색 디테일은 과감하게 줄이는 거죠.
RGB to YCbCr conversion (simplified):
Y = 0.299R + 0.587G + 0.114B (luminance — brightness)
Cb = -0.169R - 0.331G + 0.500B (blue chrominance)
Cr = 0.500R - 0.419G - 0.081B (red chrominance)
Note: green dominates the luminance calculation because
human eyes have far more green-sensitive cone cells.
This isn't arbitrary — it matches the physiology.
2단계: 크로마 서브샘플링
데이터 축소가 처음으로 일어나는 지점입니다. 사람은 색을 전체 공간 해상도로 인지하지 못하기 때문에, JPEG은 Cb와 Cr 채널의 해상도를 보통 가로세로 각각 절반으로 줄입니다. 이를 4:2:0 서브샘플링이라고 부릅니다. 휘도 픽셀 네 개당 색차 샘플은 하나만 남는 셈이죠.
결과적으로 원본 데이터를 절반 가까이 줄이게 됩니다(풀 해상도 채널 3개에서 풀 해상도 1개와 4분의 1 해상도 2개로). 그런데도 이미지는 원본과 거의 똑같아 보입니다. 직접 확인해 보세요. 아무 사진이나 가져다가 색상 채널 해상도를 4배로 줄여보면, 차이를 찾기 어려울 겁니다. 뇌가 휘도 정보를 바탕으로 색 디테일을 채워 넣기 때문이에요.
이 방식이 모든 이미지에 똑같이 잘 먹히지는 않습니다. 사진은 자연 장면이 부드러운 색 그라데이션을 가지고 있어서 아주 잘 압축됩니다. 하지만 색이 뚜렷하게 나뉘는 이미지, 예를 들어 색 배경 위의 텍스트, 흰 바탕의 빨간 원, 픽셀 아트 같은 것은 서브샘플링 후 색 번짐(컬러 프린지)이 눈에 띕니다. 색의 경계가 날카로운 탓에 번져 버리는 것이죠. JPEG이 텍스트에 약한 이유가 바로 이것입니다.
3단계: 이산 코사인 변환
여기서부터 JPEG이 정말 흥미로워집니다. 이미지를 8×8 픽셀 블록으로 나누고, 각 블록을 공간 영역(픽셀 밝기 값)에서 주파수 영역(각 공간 주파수가 얼마나 들어 있는지)으로 변환합니다.
이렇게 생각해 보세요. 8×8 픽셀 블록은 64개의 기저 패턴을 가중합한 것으로 표현할 수 있습니다. 첫 번째 패턴은 평평한 블록(평균값)입니다. 다음 패턴들은 수평과 수직 방향의 그라데이션을 더해 줍니다. 번호가 높은 패턴일수록 밝기가 빠르게 진동하는 더 세밀한 디테일을 더하죠.
An 8x8 DCT block conceptually:
DC ──► Low frequency ──────────────► High frequency
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ AVG │ → │ → │ → │ → │ → │ → │ → │ Low freq
│ │ │ │ │ │ │ │ │ ↓
│ ↓ │ ↘ │ │ │ │ │ │ │
│ │ │ ↘ │ │ │ │ │ │
│ │ │ │ ↘ │ │ │ │ │
│ │ │ │ │ ↘ │ │ │ │
│ │ │ │ │ │ ↘ │ │ │
│ │ │ │ │ │ │ ↘ │ │
│ │ │ │ │ │ │ │ FINE │ High freq
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
Top-left = low frequency (smooth gradients)
Bottom-right = high frequency (sharp edges, fine detail)
Natural images: most energy concentrated in top-left
Text/line art: significant energy in bottom-right
DCT 자체는 무손실입니다. 64개의 DCT 계수만 있으면 원래의 8×8 블록을 완벽하게 복원할 수 있어요. 하지만 여기서 핵심 성질이 있습니다. 자연 이미지(사진, 그라데이션, 유기적인 질감)의 경우 대부분의 에너지가 저주파 계수에 몰려 있다는 것입니다. 세밀한 디테일을 나타내는 고주파 계수는 대체로 값이 작습니다. 이 점이 바로 다음 단계가 효과를 내는 이유입니다.
왜 하필 8×8일까요? 절충의 결과입니다. 16×16이나 32×32처럼 블록을 키우면 에너지를 더 잘 모을 수 있지만, 계산 비용이 늘고 낮은 품질 설정에서 눈에 띄는 '블로킹' 아티팩트가 생깁니다. 4×4처럼 작게 잡으면 블로킹은 줄지만 에너지를 잘 모으지 못하죠. 8×8은 30년 넘게 살아남은 적당한 균형점으로 판명되었습니다.
4단계: 양자화 — 데이터가 사라지는 지점
손실이 발생하는 단계입니다. 모든 DCT 계수는 양자화 테이블의 대응 값으로 나눈 뒤 가장 가까운 정수로 반올림됩니다. 고주파 계수에 대해서는 큰 나눗셈 값을 쓰기 때문에 작은 값들이 0으로 반올림되어 버립니다. 이 0들은 영원히 사라지고, 정보가 돌이킬 수 없이 버려지는 곳이 바로 여기입니다.
Example quantization (quality ~50):
DCT coefficient: 42.7 Quantization divisor: 16 Result: round(42.7/16) = 3
DCT coefficient: 8.3 Quantization divisor: 40 Result: round(8.3/40) = 0
DCT coefficient: -2.1 Quantization divisor: 99 Result: round(-2.1/99) = 0
The quality slider in your image editor controls the quantization table.
Quality 100: divisors close to 1 (almost no rounding, huge file)
Quality 75: moderate divisors (good balance, typical web use)
Quality 50: large divisors (noticeable artifacts, small file)
Quality 10: very large divisors (blocky mess, tiny file)
양자화 테이블은 JPEG 품질을 좌우하는 가장 중요한 요소입니다. JPEG 표준은 기본 테이블을 정의하고 있지만, 인코더는 원하는 어떤 테이블이든 쓸 수 있습니다. MozJPEG 같은 최신 인코더는 최적화된 테이블을 사용합니다. 사람의 지각 민감도에 맞춰 나눗셈 값을 조정해서, 사람이 덜 민감하게 느끼는 주파수에 대해서는 더 과감하게 압축하고, 같은 용량에서 더 나은 화질을 얻어냅니다.
양자화 후 중간 정도 품질의 전형적인 8×8 블록은 64개 중 0이 아닌 계수가 6~10개 정도만 남습니다. 나머지는 모두 0이에요. 이렇게 0이 아닌 값이 크게 줄어드는 덕분에 마지막 압축 단계가 효과를 발휘합니다.
5단계: 엔트로피 부호화
마지막 단계는 양자화된 계수에 대한 무손실 압축입니다. JPEG은 런 렝스 인코딩(RLE)과 허프만 부호화를 조합해서 사용합니다. 계수는 8×8 블록에서 지그재그 패턴으로 읽힙니다. DC(왼쪽 위) 계수에서 시작해 점점 높은 주파수로 지그재그 이동하는 방식이죠. 이렇게 하면 뒤쪽의 0들이 한데 모이고, RLE가 이를 효율적으로 처리합니다. '0, 0, 0, ..., 0'을 저장하는 대신 '0이 47개'라고 저장하는 식입니다.
허프만 부호화는 자주 나오는 값에는 짧은 비트열을, 드물게 나오는 값에는 긴 비트열을 할당합니다. 0이 아닌 계수 대부분은 1, -1, 2, -2 같은 작은 정수이므로 아주 짧은 코드를 얻게 됩니다. 결과적으로 64개 값으로 시작했던 양자화된 8×8 블록은 이미지 내용과 품질 설정에 따라 보통 20~40바이트로 줄어듭니다.
왜 어떤 이미지는 다른 이미지보다 더 잘 압축될까
파이프라인을 이해하면, 그렇지 않으면 신비롭게만 보이는 압축 동작이 설명됩니다.
- 사진은 잘 압축됩니다. 부드러운 색 그라데이션이 있어서 크로마 서브샘플링이 잘 먹히고, 에너지의 대부분이 저주파 DCT 계수에 있어서 양자화가 화질에 눈에 띄는 영향 없이 많은 계수를 0으로 만들 수 있기 때문입니다.
- 텍스트와 선화는 잘 압축되지 않습니다. 날카로운 가장자리가 큰 고주파 DCT 계수를 만들어내고, 이를 눈에 띄는 아티팩트 없이 0으로 만들 수 없기 때문입니다. 8×8 블록 경계가 텍스트 가장자리 주변의 링잉(번짐 무늬)으로 드러나게 됩니다.
- 노이즈는 압축을 망칩니다. 센서 노이즈는 고주파의 무작위 데이터이기 때문입니다. 노이즈가 있는 픽셀마다 0이 아닌 고주파 계수가 추가되고, 이런 계수들은 양자화에 잘 저항합니다. 같은 장면을 찍었을 때, 품질 80에서 노이즈가 많은 사진이 깨끗한 사진보다 3~5배 큰 용량이 나올 수 있습니다.
- 그라데이션은 거의 공짜입니다. 8×8 블록에 걸친 부드러운 그라데이션은 2~3개의 DCT 계수만으로 표현되기 때문입니다. 양자화를 하지 않아도 나머지는 모두 0이에요.
- 다시 저장하면 화질이 떨어집니다. 저장할 때마다 양자화가 다시 적용되고, 반올림 오차가 쌓이기 때문입니다. 품질 75로 JPEG을 10번 저장하면, 품질 75로 한 번 저장한 것보다 눈에 띄게 나빠집니다. 그래서 편집은 항상 원본 소스 파일에서 시작해야 합니다.
JPEG 품질 슬라이더는 선형이 아니다
많은 개발자가 JPEG 품질 슬라이더를 선형적인 트레이드오프처럼 생각합니다. 품질 50은 품질 100의 절반 화질이고 파일 크기도 절반일 것이라고 믿는 거죠. 둘 다 사실이 아닙니다.
품질 100은 '무손실'이 아닙니다. 여전히 양자화를 적용하며, 다만 나눗셈 값이 작을 뿐이에요. 파일은 매우 크고(종종 PNG보다 큽니다), 품질 95와 시각적으로 구별되지 않습니다. 사진의 경우 품질 95와 90도 시각적으로 구별하기 어렵습니다. 품질 85와 75 사이의 지각적 차이는 100과 85 사이보다 큽니다. 품질 50 아래에서는 아티팩트가 심해지고, 파일 크기 감소도 둔화됩니다.
웹 이미지에 가장 적당한 지점은 보통 품질 75~85입니다. 75 아래에서는 일반적인 보기 크기에서도 아티팩트가 보입니다. 85를 넘으면 파일 크기는 크게 늘어나는데 체감 화질은 거의 나아지지 않아요. MozJPEG의 기본 품질 75는 대부분의 사진에서 화질 대 용량 곡선의 꺾이는 지점을 잘 짚은 값입니다.
최신 JPEG 인코더는 생각보다 똑똑하다
JPEG 표준은 인코더가 아니라 디코딩 포맷을 정의합니다. 그래서 인코더 구현에 따라 압축 효율이 크게 달라질 수 있지만, 모두 표준을 따르는 파일을 만들어냅니다. Mozilla가 개발한 MozJPEG은 여러 기법을 통해 같은 시각 품질에서 libjpeg보다 5~15% 작은 파일을 만들어냅니다.
- 트렐리스 양자화 — 각 DCT 계수를 독립적으로 반올림하는 대신, 반올림 결정이 엔트로피 부호화 단계에 어떤 영향을 주는지 고려해서 전체적으로 더 나은 선택을 합니다.
- 최적화된 허프만 테이블 — 기본 JPEG 허프만 테이블은 범용적입니다. MozJPEG은 각 이미지의 실제 계수 분포에 맞춘 테이블을 새로 만듭니다.
- 프로그레시브 인코딩 — 프로그레시브 JPEG은 계수를 여러 번에 나눠 저장합니다(거친 정보를 먼저, 그다음 세부 보정). 거친 단계의 계수 분포가 더 예측 가능하기 때문에, 순차 인코딩보다 압축이 더 잘되는 경우가 많습니다.
- 적응형 양자화 테이블 — 이미지 전체에 하나의 양자화 테이블을 쓰는 대신, 적응형 인코더는 영역별로 양자화를 조정합니다. 복잡한 영역(아티팩트가 덜 눈에 띄는 곳)에서는 더 과감하게, 부드러운 영역에서는 더 보수적으로 압축하죠.
웹에서 이미지를 서빙하고 있다면, 기본 libjpeg 인코더에서 MozJPEG으로 바꾸는 것이 가장 손쉬운 성능 개선 방법 중 하나입니다. 대부분의 이미지 CDN과 처리 라이브러리가 지원합니다. 인코딩은 느려지지만(미리 처리해 두는 정적 이미지라면 상관없습니다), 같은 품질에서 결과물은 더 작아집니다.
JPEG과 새로운 포맷 비교
WebP, AVIF, HEIC은 모두 더 현대적인 압축 기법을 사용합니다. 더 큰 변환 블록, 루프 내 디블로킹 필터, 인트라 예측(주변 블록을 이용해 현재 블록을 예측하는 방식) 등이죠. 같은 시각 품질에서 JPEG보다 20~50% 더 잘 압축합니다. 특히 AV1 비디오 코덱을 기반으로 한 AVIF는 인상적일 만큼 효율적입니다.
그런데 왜 JPEG은 여전히 어디에나 있을까요? 보편적인 지원 덕분입니다. 모든 브라우저, 모든 이미지 뷰어, 모든 운영체제, 모든 카메라, 모든 휴대폰, 이미지를 다루는 모든 소프트웨어가 JPEG을 지원합니다. WebP는 브라우저에서는 거의 보편적이지만 OS 기본 지원이 부족합니다. AVIF 지원은 아직 들쭉날쭉하고, HEIC은 주로 Apple 생태계의 포맷입니다. 어디서나 동작해야 하는 포맷이라면, JPEG이 여전히 유일하게 안전한 선택입니다.
실용적인 조언은 이렇습니다. 서빙 인프라가 지원한다면(대부분의 CDN이 콘텐츠 협상으로 지원합니다) JPEG 폴백과 함께 AVIF나 WebP를 쓰세요. 한 가지 포맷만 쓸 수 있다면, 사진에는 품질 80의 MozJPEG 인코딩 JPEG을 이기기 어렵습니다. 스크린샷, 다이어그램, 텍스트가 많은 이미지에는 PNG가 여전히 더 나은 선택입니다. 이미지 표현에 대한 더 창의적인 접근법도 살펴보세요.
세상을 정복한 8×8 블록
JPEG의 압축 파이프라인은 인간의 지각과 맞서지 않고 함께 작동하도록 설계된 공학의 교과서적 사례입니다. 각 단계는 색에 둔감한 인간의 특성, 자연 이미지의 주파수 분포, 양자화 노이즈의 지각적 마스킹 같은 특정 성질을 활용하고, 이들이 맞물려 최소한의 눈에 띄는 손실로 파일을 10~20배까지 줄이는 시스템을 만들어냅니다. 34년이 지난 지금도, 1992년 하드웨어에서 돌던 그 8×8 DCT 블록이 인터넷 이미지의 대부분을 여전히 실어 나르고 있습니다. 기본기를 제대로 잡은 설계가 가진 힘이죠.


