웹 브라우저인 Chrome에서 작은 JPEG 이미지가 어째서인지 다른 브라우저와 다르게 표시되는 현상을 발견한 적이 있을지도 모릅니다. 이는 단순한 버그가 아니라, Chrome이 고도의 JPEG 디코딩 최적화 처리를 채택하고 있기 때문입니다. 아이콘과 같이 작고 선명한 이미지에서 눈에 띄는 표시 차이가 관찰되는 경우가 있습니다. Guillaume Técherhttps://guillaumetech.github.io/posts/jpg-scaling-chrome/ 소프트웨어 개발자인 Guillaume Técher 씨는 동료와 채팅을 하다가 자신의 PC에 표시되는 로고와 동료의 PC에 표시되는 로고가 미묘하게 다르다는 것을 알게 되었습니다. 동료의 PC에서 본 로고는 더 옅게 표시되어 원본 이미지에 가까운 느낌이었습니다. 이미지는 불과 15픽셀의 매우 작은 크기로 표시되고 있었으며, Firefox와 Chrome을 비교해보면 Chrome 쪽이 더 굵게 보였습니다. SVG 형식으로 전환함으로써 문제는 해결되었지만, Técher 씨는 왜 표시 차이가 발생했는지 흥미를 가졌습니다. 아래의 그림은 실제 이미지와는 다르지만 두 브라우저의 표시 차이를 알기 쉽게 만든 이미지로, 왼쪽이 Firefox, 오른쪽이 Chrome에서의 표시를 나타냅니다. 눈을 가늘게 뜨거나 한 걸음 물러서서 보면 Chrome 쪽이 더 굵게 보입니다. 기묘하게도 이미지를 SVG로 교체하자 표시는 동일해졌습니다.
일반적으로 JPEG 이미지를 작게 표시할 때, 이미지를 메모리상에서 완전히 전개한 후 목적하는 크기로 축소하는 절차를 생각해 볼 수 있습니다. 하지만 예를 들어 2000x2000 픽셀(약 12MB)의 이미지를 20x20 픽셀(약 1.2KB)로 축소하는 경우를 생각해 보면, 대량의 메모리가 소비되는 것에 비해 최종적으로 사용되는 정보는 극히 일부분이므로 비효율적이라고 할 수 있습니다. 축소 프로세스에서 손실되는 것은 랜덤한 정보가 아니라 주로 고주파 정보의 디테일, 즉 세밀한 문양이나 급격한 색상 변화입니다. 한 예로 많은 잎과 거친 나무껍질을 가진 나무 이미지를 생각해 보면, 잎이나 나무껍질 같은 세밀한 부분은 픽셀에서 픽셀로 급격하게 변화하기 때문에 고주파 정보로 파악할 수 있습니다. 다음으로 나무 이미지를 20×10 픽셀과 같은 작은 크기로 스케일 다운하면, 잎 상단에 있는 녹색 덩어리나 줄기 하단에 있는 갈색 막대만이 정보로 남습니다. 즉, 축소된 버전에서는 세부적인 고주파 정보가 버려진다는 뜻이 됩니다.
JPEG 압축 메커니즘에 대해 약간의 기술적인 이야기를 하자면, JPEG 압축에서는 이미지를 8x8 픽셀의 블록으로 분할하고 이산 코사인 변환(DCT)을 통해 주파수 영역으로 변환합니다. 8×8 픽셀 블록에서 가장 낮은 주파수는 단색입니다. 엄밀히 말하면 단색은 아무런 변화도 없기 때문에 주파수조차 아니며 상수 성분이라고 할 수 있습니다. 그 정반대에 있는 가장 높은 주파수는 체커보드처럼 보이는 것으로, 값이 최대한으로 변화합니다. 그 사이의 모든 것이 나머지 주파수 영역을 나타내며, 기저 함수라고 불립니다. 즉, 8×8 블록을 주파수 영역으로 변환한다는 것은 기본적으로 "이 블록에는 각 패턴이 어느 정도 포함되어 있는가"를 묻는 것과 동의어이며, "어느 정도 포함되어 있는가"의 비율을 계수라고 부릅니다.
다음으로 이미지를 8분의 1 크기로 축소하는 경우를 생각해보면, 원래의 8x8 픽셀 블록은 축소된 이미지에서 1픽셀에 해당합니다. 그리고 고주파 디테일은 축소로 인해 손실되기 때문에, 이미지에는 저주파 성분 정보만 필요하게 됩니다. Chrome은 이러한 특성을 활용하여 이미지 전체를 완전히 압축 해제하는 대신 고주파 성분의 계수를 건너뛰고, 거친 버전의 이미지에 필요한 저주파 성분의 계수만을 사용하여 디코딩을 수행합니다. 따라서 원래 이미지를 완전히 전개하지 않고도 축소된 결과를 얻을 수 있어, 디코딩에 필요한 메모리 양과 시간을 대폭 줄일 수 있습니다. 이 기술은 '부분 IDCT 스케일링(partial IDCT scaling)'이라고 불리며, 특히 타겟 크기가 원래 이미지의 8분의 1, 4분의 1, 8분의 3과 같이 분모가 8인 분수배인 경우에 효과적입니다. Chrome은 그래픽 라이브러리 Skia를 통해 libjpeg-turbo를 이용하고 있으며, libjpeg-turbo가 부분 IDCT 스케일링을 구현하고 있습니다. Chrome은 먼저 부분 IDCT 스케일링을 사용하여 이미지를 분모가 8인 가장 가까운 분수로 산출하여 디코딩하고, 다음으로 일반적인 스케일링 알고리즘으로 최종 크기까지 축소합니다. 이 두 단계의 프로세스, 즉 부분 IDCT 스케일링으로 저주파 성분만 남겨진 이미지에 대해 추가로 스케일링 알고리즘이 적용됨으로써 엣지의 소프트화나 그라데이션 같은 처리는 일절 적용되지 않고, 이미지가 두껍게 보이거나 디테일이 손실되는 표시 상의 차이가 발생하는 것입니다. 결론적으로 부분 IDCT 스케일링은 사진과 같은 이미지에 대해서는 효과적인 최적화이지만, 아이콘과 같이 샤프한 디테일이 요구되는 이미지에는 적합하지 않습니다. JPEG 포맷은 인간의 시각이 사진의 디테일을 어떻게 인식하는지에 기반하여 설계되었기 때문에 아이콘과 같은 용도에서는 의도치 않은 표시 열화를 유발할 가능성이 있습니다. 따라서 아이콘 등의 용도에는 JPEG가 아닌 SVG 등의 다른 이미지 포맷을 사용해야 합니다.
원문 보기 | 출처: Gigazine