
무슨 일이 있었나요
Rust 그래픽스 생태계에서 잘 알려진 Raph Levien이 GitHub에 Nibnib이라는 이미지 압축 프로젝트를 공개했어요. 한 줄 소개는 “극단적인 압축 해제 속도를 가진 이미지 압축”이에요.
Raph Levien이 낯선 분들을 위해 소개하면, 구글 시절 텍스트 에디터 프로젝트 xi-editor를 시작했던 사람이에요. 지금은 Rust 그래픽스·GUI 커뮤니티인 Linebender를 이끌면서, GPU로 2D 벡터 그래픽을 그리는 렌더러 Vello와 Rust GUI 프레임워크 Xilem 같은 프로젝트를 하고 있어요. 폰트 렌더링, 곡선 수학, GPU 컴퓨트 분야에서는 손꼽히는 전문가죠. 그래서 이 사람이 이미지 포맷을 만들었다는 건, UI를 빠르게 그리려다 보니 기존 포맷으로는 부족한 지점이 보였다는 신호로 읽을 수 있어요.
> 아직 초기 단계 프로젝트로 보여요. 정확한 포맷 스펙, 손실/무손실 여부, 벤치마크 수치는 저장소 README에서 직접 확인해 보세요. 이 글은 이런 포맷이 왜 필요하고 어떤 위치에 있는지를 중심으로 풀어볼게요.
압축 해제 속도가 왜 그렇게 중요할까
이미지 포맷을 평가할 땐 보통 세 가지를 봐요. 압축률(파일이 얼마나 작아지나), 인코딩 속도(압축하는 데 얼마나 걸리나), 디코딩 속도(다시 풀어서 화면에 쓸 수 있게 만드는 데 얼마나 걸리나). 셋을 다 잡기는 어려워서 포맷마다 우선순위가 달라요.
웹 이미지는 압축률이 1순위예요. 네트워크로 받아야 하니까 몇 KB라도 줄이는 게 중요하죠. 그런데 앱, 게임, 데스크톱 UI처럼 이미 로컬 디스크나 메모리에 있는 이미지를 빠르게 띄워야 하는 상황은 달라요. 아이콘 수백 개, 썸네일 수천 장을 스크롤하며 보여줘야 하는데, 디코딩이 느리면 그대로 버벅임이 되거든요. NVMe SSD 덕분에 디스크 읽기는 초당 몇 GB까지 빨라졌어요. 하지만 PNG 디코더는 그 속도를 못 따라가요. 병목이 I/O에서 CPU의 압축 해제로 옮겨온 거예요.
PNG가 느린 이유는 내부에서 DEFLATE(zip과 같은 압축 방식)를 쓰기 때문이에요. 여기 들어가는 허프만 코딩은 “자주 나오는 값은 짧게, 드문 값은 길게” 적는 방식이에요. 압축률엔 좋지만, 풀 때는 비트를 하나씩 읽으며 분기해야 해서 CPU가 병렬로 처리하기 어려워요.
이런 포맷은 보통 어떻게 빨라질까
Nibnib의 구현은 저장소를 봐야 정확히 알 수 있어요. 다만 디코딩 속도를 극대화하려는 포맷들이 흔히 쓰는 전략은 꽤 정해져 있어요.
- 고정 폭 비트 패킹: 길이가 들쭉날쭉한 코드 대신 정해진 비트 수로 값을 적으면, 다음 값이 어디서 시작하는지 미리 알 수 있어요. 그러면 여러 값을 동시에 풀 수 있죠. 이름의 “nib”이 4비트 단위를 뜻하는 니블(nibble)에서 왔다면 이쪽 방향일 가능성이 커요.
- SIMD 친화적 레이아웃: SIMD는 명령어 하나로 데이터 여러 개를 한꺼번에 처리하는 CPU 기능이에요. 계산대에서 물건을 하나씩 찍는 대신 16개를 한 번에 찍는다고 생각하면 돼요. 데이터 배치를 SIMD 레지스터에 맞춰 설계하면 속도가 몇 배로 뛰어요.
- 분기 없는(branchless) 디코딩: if문이 많으면 CPU가 다음 경로를 잘못 예측할 때마다 손해를 봐요. 분기를 줄이면 파이프라인이 쉬지 않고 돌아가요.
- 게임·데스크톱 앱 개발자: 앱 번들에 넣는 에셋은 포맷을 자유롭게 고를 수 있어요. 로딩 시간이 중요하다면 내부용 포맷으로 검토해 볼 만해요.
- 이미지 파이프라인 백엔드 개발자: 썸네일 생성이나 이미지 캐시처럼 디코딩을 대량으로 하는 서비스라면, 진짜 병목이 어디인지 다시 재볼 계기가 될 거예요.
- 성능 최적화를 공부하는 분: 작은 코덱 코드는 SIMD, 비트 연산, 캐시 친화적 설계를 배우기에 좋은 교재예요. QOI 디코더를 직접 짜보는 게 유명한 연습 과제인 것처럼요.
업계 맥락: 비슷한 시도들과 비교
이 방향의 대표 선배는 2021년에 나온 QOI(Quite OK Image Format)예요. 스펙이 한 페이지 남짓할 만큼 단순한데, PNG와 비슷한 압축률을 내면서 인코딩은 수십 배, 디코딩은 몇 배 빨라서 큰 반향을 일으켰어요. 다만 픽셀을 순서대로 하나씩 처리하는 구조라 SIMD나 멀티코어로 확장하기엔 한계가 있어요.
PNG 진영에서는 fpng, fpnge처럼 PNG 호환을 유지하면서 아주 빠르게 인코딩하는 도구들이 나왔어요. 반대편 끝에는 JPEG XL, WebP lossless처럼 압축률을 끝까지 밀어붙이는 포맷이 있고요.
또 하나 중요한 비교 대상은 GPU 텍스처 압축(BC7, ASTC, ETC2)이에요. GPU 하드웨어가 직접 풀도록 만든 고정 비율 포맷이라 디코딩 비용이 사실상 없어요. 대신 압축률이 낮고 화질 손실이 있어요. 게임 업계에서는 Basis Universal처럼 작게 저장해 뒀다가 로딩할 때 GPU 포맷으로 빠르게 변환하는 방식도 써요.
Nibnib은 이 스펙트럼에서 압축률을 어느 정도 양보하더라도 압축 해제 속도를 끝까지 끌어올리는 자리를 노리는 것으로 보여요. Vello처럼 GPU로 화면을 그리는 렌더러와 짝을 이룬다면 활용 범위가 꽤 넓어질 수 있어요.
한국 개발자에게 주는 시사점
당장 프로덕션에 넣을 포맷은 아니에요. 브라우저가 지원하지 않아서 웹에선 못 쓰고, 뷰어나 변환 도구 같은 생태계도 아직 없으니까요. 그래도 이런 분들께는 들여다볼 가치가 충분해요.
마무리
한 줄 정리: 디스크가 빨라진 지금, 이미지의 병목은 ‘크기’에서 ‘푸는 속도’로 옮겨가고 있어요.
여러분 서비스에서 이미지 디코딩이 병목이었던 적이 있나요? 압축률과 디코딩 속도 중 하나만 골라야 한다면, 어떤 상황에서 어느 쪽을 고르시겠어요?
🔗 출처: Hacker News