무심코 던진 한마디가 30년 전 숨겨진 능력을 깨웠다
7월 17일, 저명한 보안 연구자 lcamtuf(Michał Zalewski)가 Mastodon에 가벼운 생각 하나를 남겼다.
“progressive JPEG sends the low-frequency data first, then gradually fills in the detail. I bet you could do it backwards — make a ‘regressive JPEG’ that looks fine at first, then slowly turns into something awful.”
이 글이 기술계에서 큰 토론을 불러일으키지는 않았다 — 하지만 누군가는 보고, 그리고 직접 손을 댔다.
이틀 뒤, 개발자 Maurycy가 기술 커뮤니티 Lobsters에 자신의 성과를 올렸다: ‘퇴행적 이미지(regressive image)‘를 만드는 것은 물론, JPEG 파일 하나를 GIF처럼 움직이게 할 수 있다는 것. 이 글은 △95점을 받으며 그날 최고 득표 콘텐츠가 되었다.

▲ 출처: maurycyz.com. 동일한 JPEG 파일이 로딩 단계에 따라 다른 고양이를 보여준다 — 브라우저는 여전히 ‘점점 선명해지고 있다’고 믿지만, 실제로는 내용이 바꿔치기된 것이다.
JPEG 표준은 1992년에 탄생해 올해로 34년째다. 디지털 카메라에서 스마트폰 앨범, 웹 이미지에 이르기까지 전 세계는 매일 수십억 장의 JPEG을 열고, 전송하고, 저장한다. 그런데 지난달, 누군가 이 표준에 아무도 써본 적 없는 능력 하나가 숨어 있다는 것을 발견했다 — 애니메이션을 만드는 것.
흐릿하게 먼저, 선명하게 나중에 — 천재적인 설계
이 발견을 이해하려면, 필자가 먼저 1990년대의 한 설계를 설명해야 한다.
초기 인터넷을 기억하는 사람이라면 이렇게 알 것이다: 느린 망에서 큰 사진을 열면 화면이 위에서 아래로 한 줄씩 그려졌다. 이것을 ‘베이스라인 JPEG’이라 한다 — 데이터가 순서대로 배치되고, 브라우저는 받은 만큼만 보여준다.
나중에 JPEG 표준에 ‘프로그레시브 JPEG’이라는 옵션이 추가됐다. 작동 방식은 완전히 다르다: 먼저 이미지의 ‘윤곽’을 보내고, 점차 디테일을 채워 넣는다.
일상에 빗대어 설명해 보자.
친구가 신호가 아주 나쁜 산속에서 단체 사진을 하나 보내고 싶어 한다. 옛 방식대로라면 사진이 위에서 아래로 한 칸씩 그려지는 것만 볼 수 있다. 하지만 ‘프로그레시브’ 방식이라면 친구는 먼저 1/16 크기의 흐릿한 썸네일을 보낼 수 있다 — 한눈에 단체 사진임을 알아볼 수 있다. 이어서 디테일 데이터를 보내면, 인물 표정, 옷의 질감, 배경의 나뭇잎이 조금씩 선명해진다.
이 설계를 기술적으로 구현하는 방식은 이미지 데이터를 여러 ‘배치’(표준에서는 scan이라 부른다)로 쪼개는 것이다. 각 배치에는 자신이 담당하는 정밀도 범위를 알려주는 태그가 붙는다. 첫 배치는 가장 조악한 정보만 담고, 뒤따르는 배치들이 더 높은 주파수의 디테일을 보충한다.
핵심은 이것이다: 표준은 각 배치 데이터가 어느 범위를 커버하는지 선언하라고 규정했을 뿐, 뒤따르는 배치가 묘사하는 내용이 앞의 것과 반드시 같은 이미지여야 한다고는 결코 규정하지 않았다.
택배 송장에 ‘같은 사람이 받아야 한다’는 없듯이
lcamtuf의 원래 아이디어는 ‘퇴행적 JPEG’이었다: 첫 배치에 예쁜 이미지를 넣고, 뒤따르는 배치로 점차 못생긴 것으로 덮어씌운다. 예를 들어 맛있는 음식 사진이 절반쯤 로딩되다가 곰팡이 핀 음식으로 변하는 식이다.
하지만 Maurycy는 더 멀리 갈 수 있음을 발견했다.
뒤따르는 배치가 앞서 렌더링된 내용을 덮어쓸 수 있다면, 왜 여러 장의 서로 다른 이미지를 하나의 파일에 그냥 붙여 넣지 않겠는가? 구체적인 방법은 놀랍도록 단순하다.
같은 크기의 JPEG 이미지 여러 장의 ‘데이터 세그먼트’를 머리와 꼬리의 불필요한 마커를 빼고 이어 붙이면, 브라우저는 이를 같은 이미지의 여러 ‘정밀도 계층’으로 여겨 순차적으로 렌더링한다.
비유해 보자.
택배 회사에 보낼 소포 묶음이 있다. 각 소포의 송장에는 ‘배송지: 이씨네 집, 품목: 사진’이라고 적혀 있다. 택배 기사는 하나씩 배달하며 매번 이씨네 집의 ‘사진’을 갱신한다. 하지만 이씨가 받은 두 번째 사진은 첫 번째와 전혀 다르다 — 택배 시스템은 ‘사진’이라는 범주만 맞는지 확인할 뿐, 같은 사진인지는 검사하지 않는다.
브라우저도 마찬가지다. 각 배치 데이터의 태그(정밀도 범위, 색 채널)가 JPEG 표준에 맞는지 검사할 뿐, ‘이 그림이 앞의 것과 같은 내용인지’는 결코 검사하지 않는다. 그것은 충실하게 새 데이터를 낡은 화면 위에 덮어쓰고, 그래서 —
당신이 보는 화면이 바뀌는 것이다.
‘사진 바꿔치기’에서 ‘영상 재생’까지
첫 번째 버전에는 한계가 있었다: 정상적인 프로그레시브 JPEG은 약 10개의 배치(scan)를 포함한다. 대부분의 브라우저 디코더는 약 10개의 배치를 받으면 ‘이 이미지는 이제 로딩이 끝났나 보다’라고 판단해 더 받기를 거부한다. 즉, 여덟~아홉 프레임밖에 집어넣을 수 없어 애니메이션 만들기에 턱없이 부족하다.
Maurycy는 계속 다듬었다. ‘최소 배치’를 만드는 방법을 찾은 것이다: 각 프레임을 DC 스캔 한 번만 쓰도록 해, 가장 기본적인 색 정보만(디테일은 제외하고) 담는다. 이렇게 하면 이미지 한 장의 크기는 전체 버전의 1/16 선명도에 불과하지만, 애니메이션의 한 프레임으로는 충분하다.
이 방식으로, Chrome 브라우저는 포기하기 전까지 약 90프레임을 렌더링할 수 있고, Firefox의 인내심은 더 크다. 90프레임이면 짧은 동영상으로 충분하다.

▲ 출처: maurycyz.com. 정적 JPEG 파일 하나가 프로그레시브 배치의 덮어쓰기 특성을 이용해, 로딩 중에 검은 고양이가 걷는 애니메이션을 프레임별로 재생한다. 이는 JPEG 표준에 완벽히 부합하는 파일이라 어떤 브라우저에서도 열린다.
이게 대체 무슨 쓸모가 있나?
솔직히 말해 — 별로 없다.
이 해킹에는 치명적인 결함이 하나 있다: 재생 속도를 통제할 수 없다는 것. 애니메이션의 ‘프레임 레이트’가 전적으로 망 속도에 달려 있기 때문 — 다운로드가 빠르면 빨리, 느리면 천천히 재생된다. GIF나 동영상 형식에 있는 시간 제어 메커니즘이 없다.
게다가 대부분의 이미지 뷰어는 이미지가 ‘로딩 완료’되면 표시를 멈추고, 반복 재생하지 않는다. 애니메이션 효과를 보려면 망 속도가 느린 환경에서 단계적으로 로딩되게 하거나, 특별한 표시 방식을 써야 한다.
하지만 그것이 중요하지 않다.
정말 흥미로운 것은 이 발견 자체다: 30년 전에 이미 작성된 국제 표준이, 30년 동안 수많은 엔지니어에게 읽히고 구현되고 쓰였음에도, 아무도 그것이 애니메이션을 만들 수 있다는 걸 눈치채지 못했다 — 누군가 무심코 한마디 묻기 전까지는.
외면받은 표준, 그리고 기술 호기심의 승리
필자에게 이 이야기에는 특별한 매력이 있다.
JPEG 표준 — 국제표준화기구(ISO)가 발표하고, 수천 페이지의 기술 문서가 있으며, 전 세계 모든 이미지 소프트웨어가 구현한 그 표준 — 이는 그곳에, 꼼짝 않고, 34년째 있다. 그 규범의 모든 줄은 공개되어 있어 누구나 읽을 수 있다.
프로그레시브 JPEG의 ‘스캔 덮어쓰기’ 메커니즘은 처음부터 표준에 적혀 있었다. lcamtuf가 새 취약점을 발견한 것이 아니다. 그는 그저 표준이 ‘하면 안 된다’고 결코 말하지 않은 질문을 던졌을 뿐이다: 뒤의 스캔 데이터가 앞의 것과 다르면, 무슨 일이 벌어지는가?
표준은 이 질문에 답하지 못한다 — 애초에 누군가 그럴 거라고는 생각도 하지 못했으니까.
그리고 Maurycy는 복잡한 프로그램을 전혀 짜지 않았다. 그의 코드는 짧은 C 파일 하나일 뿐, 본질적으로 하는 일은 ‘여러 장의 이미지 중간 부분을 붙이고, 머리와 꼬리 마커를 지우는’ 것이다. 진짜 난이도는 이렇게 해도 된다는 생각을 해내는 데 있었다.
기술계에는 ‘모범 사례’ ‘성능 최적화’ ‘아키텍처 설계’를 둘러싼 토론이 너무 많다. 가끔 이런 이야기 하나가 — 누군가 30년 된 낡은 문서를 꺼내 한 줄을 가리키며 ‘여기엔 하지 말란 말이 없다’고 말하는 — 해커 정신의 본모습을 떠올리게 한다.
마지막으로
직접 해보고 싶다면, Maurycy가 자신의 블로그에 코드 전체와 예제 이미지를 공개했다. 수백 KB짜리 JPEG 파일을 브라우저로 열면, 로딩되는 동안 천천히 ‘깨어난다’.
물론 이건 딱히 세상을 뒤흔드는 기술 돌파구는 아니다. GIF를 대체하지도, 이미지 형식의 판도를 바꾸지도 않을 것이다. 하지만 이건 사람으로 하여금 빙그레 웃게 만드는 발견이다 — 낡은 집 바닥 밑에서 아무도 열어본 적 없는 숨은 문을 발견한 것처럼, 문 뒤에 보물은 없지만, 그것을 여는 순간 자체가 일종의 즐거움인.
참고 링크:
- Lobsters 토론: Regressive JPEGs
- lcamtuf의 원본 Mastodon 질문
- Maurycy 기술 블로그: Regressive JPEGs