이미지 형식: GIF

최신 웹에서는 그다지 유용하지 않지만 GIF (그래픽 교환 형식)는 이미지 인코딩의 핵심 개념을 확실하게 소개합니다.

GIF는 이미지 데이터의 래퍼로 생각할 수 있습니다. 여기에는 일종의 '논리적 화면'이라는 표시 영역이 있으며 이 화면에 이미지 데이터의 개별 프레임이 그려집니다(Photoshop 문서의 레이어와 유사). 이러한 방식으로 GIF는 플립북 같은 애니메이션을 지원합니다. 단일 프레임이 논리 화면에 그려진 다음 다른 프레임으로 바뀌고, 그 다음 다른 프레임으로 대체됩니다. 물론, 이러한 구분은 논리 화면에 그려지는 단일 프레임으로 구성된 정적 GIF를 다룰 때는 중요하지 않습니다.

GIF는 무손실 데이터 압축 방법을 사용합니다. 무손실 데이터 압축 방법은 'Lempel–Ziv–Welch' 알고리즘의 변형입니다. 이 알고리즘의 작동 방식을 자세히 살펴보려면 여기서부터 살펴보겠지만, 개괄적으로 보면 'Uglifying' JavaScript와 약간 비슷한 방식으로 작동합니다. 이 JavaScript에서는 파일 전체에서 반복되는 문자가 일종의 내부 사전에 저장되므로 표시될 때마다 반복되지 않고 참조될 수 있습니다.

4x4 그리드를 사용한 gif 참조 시각화

사실은 알고리즘이 숫자별로 그리기처럼 간단하지 않습니다. 이 모델은 생성된 색상 코드 표를 다시 실행하여 반복되는 픽셀 색상 시퀀스를 찾고 참조 가능한 코드로 구성된 두 번째 표를 만듭니다. 그러나 이미지 데이터는 손실되지 않으며 근본적으로 변경하지 않고도 읽을 수 있는 방식으로 정렬되고 재구성됩니다.

GIF는 기술적으로 무손실 압축을 사용하지만 이미지 품질에 심각한 영향을 미치는 주요 제한사항이 있습니다. 이미지를 GIF로 저장하면 이미 256색 이하의 색상을 사용하지 않는 한 항상 화질이 저하됩니다.

GIF의 논리 화면에 그려지는 각 프레임에는 최대 256개의 색상만 포함될 수 있습니다. GIF는 '색인 투명도'도 지원합니다. 여기서는 투명한 픽셀이 색상표의 투명한 '색상' 색인을 참조합니다.

값의 범위를 더 작고 근사된 출력 값 집합으로 줄이는 방법을 양자화라고 하며, 이미지 인코딩을 배울 때 많이 접하게 되는 용어입니다. 이 팔레트 양자화의 결과는 일반적으로 다음과 같습니다.

정적 GIF 예

이 프로세스를 더 잘 이해하려면 내 설명에서 다시 만들 수 있는 래스터 이미지 그리드를 생각해 보세요.

파란색 가로 상자 3개 다음에 빨간색 상자 1개가 표시됨

이번에는 원본 이미지에 약간의 디테일을 추가합니다. 픽셀 몇 개를 더 추가합니다. 그중 하나는 약간 더 어두운 파란색 음영입니다.

2x4 구성에 파란색과 빨간색의 가로 상자가 표시되어 있고, 파란색 상자 하나가 다른 상자보다 더 어둡게 표시되어 있습니다.

압축이 없으면 이 그리드를 다음과 같이 설명할 수 있습니다.

첫 번째 행, 첫 번째 열은 #0000FF입니다. 첫 번째 행, 두 번째 열은 #0000FF입니다. 첫 번째 행, 세 번째 열은 #0000FF입니다. 1행, 4열은 #FF0000입니다. 두 번째 행, 첫 번째 열은 #0000FF입니다. 두 번째 행, 두 번째 열은 #000085입니다. 두 번째 행, 세 번째 열은 #0000FF입니다. 2행, 4열은 #FF0000입니다.

GIF의 무손실 데이터 압축 및 색상 색인과 유사한 것을 사용하면 다음과 같이 설명할 수 있습니다.

A: #0000FF, B: #FF0000, C: #000085. 1행, 1~3열은 A입니다. 1행 4열은 B입니다. 두 번째 행, 1열은 A입니다. 2행, 2열은 C입니다. 2행, 3열은 A입니다. 2행, 4열은 B입니다.

이를 통해 픽셀별 설명을 몇 군데('열 1~3은...')에 압축하고 사전에서 반복되는 색상을 미리 정의하여 몇 개의 문자를 절약할 수 있습니다. 시각적 충실도는 변경되지 않습니다. 정보가 손실 없이 압축되었습니다.

파란색과 빨간색의 가로 상자로, 2x2에 1개의 어두운 픽셀이 있습니다.

하지만 보시다시피 단일 진한 파란색 픽셀이 인코딩 크기에 상당한 영향을 미칩니다. 양자화된 색상 팔레트로 제한하면 훨씬 더 줄일 수 있습니다.

A: #0000FF, B: #FF0000입니다. 1행, 1~3열은 A입니다. 1행 4열은 B입니다. 2행, 1~3열은 A입니다. 2행, 4열은 B입니다.

이렇게 절약된 바이트로 인해 불행하게도 픽셀의 완벽한 성능을 잃게 됩니다.

파란색에서 빨간색으로 균일하게 사용된 가로 상자

물론, 렌더링 엔진인 여러분은 모르고 있습니다. 어두운 파란색 픽셀의 세밀한 부분은 제가 소스 이미지를 인코딩한 방법에서 제외되었습니다. 우리가 가진 색상에 대한 공통적인 이해를 바탕으로 내가 인코딩한 그대로 이미지를 렌더링했습니다.

이제 이 과장된 예에서 3가지 색상을 2로 줄이면 품질에 확연한 차이가 있습니다. 더 크고 자세한 이미지에서는 효과가 눈에 띄지는 않을 수 있지만 그 효과는 계속 표시됩니다.

GIF로 인코딩하면 그림자와 같은 미세한 그라데이션이 얼룩져서 개별 픽셀이 주변과 구분되어 눈에 띕니다.

녹색 배경에 분홍색 꽃입니다.

실제로 무손실 압축과 팔레트 양자화의 조합은 GIF가 최신 웹 개발에서 그다지 유용하지 않음을 의미합니다. 무손실 압축은 파일 크기를 줄이기에는 충분하지 않으며, 팔레트를 줄이면 품질이 확실히 저하됩니다.

궁극적으로 GIF는 이미 제한된 색상 팔레트, 앤티앨리어싱보다 단단한 가장자리, 그라데이션 대신 단색을 사용하는 간단한 이미지를 인코딩하는 데 효율적인 형식일 뿐입니다. 모든 사용 사례는 다른 형식에 훨씬 더 적합합니다. 래스터 이미지에 더 작고 특징적인 PNG가 더 나은 선택인 경우가 많지만, 벡터가 빛나는 아이콘이나 라인 아트와 같은 사용 사례에서는 파일 크기 및 시각적 품질 측면에서 두 가지 모두 SVG보다 훨씬 열등합니다. 가장 일반적으로 볼 수 있는 최신 GIF 사용 사례는 애니메이션이지만, 이 용도를 충족하는 보다 효율적이고 접근 가능한 최신 동영상 형식이 있습니다.