PNG 파일을 hex 에디터로 열어보자. 처음 8바이트:
89 50 4E 47 0D 0A 1A 0A
이것이 PNG 파일 시그니처다. 모든 PNG 디코더는 이것을 확인한다. 첫 번째 바이트 0x89은 의도적으로 높은 값으로 선택되었다——단순한 텍스트 에디터가 이 파일을 ASCII로 처리하는 것을 막기 위해서다. 50 4E 47은 ASCII로 "PNG"를 스펠링한다. 0D 0A는 DOS 줄바꿈, 1A는 DOS EOF 마커, 0A는 Unix 라인 피드다. 설계자들은 이 줄바꿈 문자들을 의도적으로 삽입했다——텍스트 모드 FTP 전송이 파일을 즉시 손상시켜 바이너리 모드 전송을 강제하기 위해서다. 특허 받은 포맷이 법적 무기로 변하는 것을 방금 목격한 개발자들의 작은 의심이었다.
PNG는 오늘날 어디에나 있다. 스크린샷, UI 에셋, 다이어그램, 로고, 반복적으로 저장할 때도 픽셀이 정확히 동일하게 유지되어야 하는 모든 이미지를 뒷받침한다. Google보다 오래되었고, iPod보다 오래되었다. 무손실 압축이 중요할 때 여전히 기본 선택지다. 하지만 원래 PNG는 포맷으로 만들어진 것이 아니었다. 임시 방편으로 시작했고, 표준이 된 것이다.
새로운 포맷을 강요한 소송
1995년 1월, Unisys는 LZW 압축 특허——미국 특허 4,558,302호——을 GIF 포맷을 사용하는 개발자들에게 집행할 것이라고 발표했다. 이 특허는 Lempel-Ziv-Welch 알고리즘을 커버했고, 모든 GIF 인코더와 디코더의 핵심이었다.
1995년의 웹은 GIF로 돌아갔다. 애니메이션 배너, 투명 로고, 타일 배경——GIF가 모든 것을 담당했다. 그러자 Unisys가 로열티를 요구했다. 상용 소프트웨어 벤더는 라이선스 비용에 직면했다. 오픈소스 프로젝트는 존립의 위기에 처했다. GNU Image Manipulation Program(GIMP)은 직접적인 영향을 받았다. 웹 개발 커뮤니티는 분노했다.
GIF의 정적 이미지 용도를 무언가가 대체해야 했다. 요구사항은 명확했다: 특허 없음, GIF보다 나은 압축률, 트루컬러 지원, 그리고 GIF의 조잡한 단색 투명도를 대체할 제대로 된 알파 채널. 또한 단 한 명의 개발자가 주말에 디코더를 구현할 수 있을 정도로 단순해야 했다.
1995년 4월 4일, Thomas Boutell이 Usenet 뉴스그룹 comp.graphics에 제안을 게시했다. PBF——Portable Bitmap Format——이라고 불렀다. 이름은 정착하지 않았다. 다음 몇 달 동안 메일링 리스트가 형성되었다. 기여자에는 Tom Lane(Independent JPEG Group의 리더), Lee Daniel Crocker, Alexander Lehmann, 그리고 수십 명의 다른 개발자들이 포함되었다. 1996년 10월 1일까지 PNG 사양은 RFC 2083으로 확정되었다. 아이디어에서 표준화까지 전 과정이 대략 18개월이 걸렸다. 비교를 하자면, JPEG에는 6년이 걸렸다.
PNG 이전에 존재했던 것들
1995년, 이미지 포맷 선택지는 제한적이었고 각각이 짐을 안고 있었다:
| 포맷 | 압축 | 색 깊이 | 투명도 | 특허 리스크 | 일반적인 용도 |
|---|---|---|---|---|---|
| GIF | LZW | 최대 256색 | 1비트, 1색 | 예 (LZW) | 웹 그래픽, 애니메이션 |
| JPEG | DCT + Huffman | 24비트 트루컬러 | 없음 | 베이스라인 만료 | 사진 |
| BMP | 없음 또는 RLE | 최대 24비트 | 없음 | 없음 | Windows 배경화면 |
| TIFF | LZW, PackBits 등 | 최대 48비트 | 예 | LZW 선택적 | 인쇄, 스캔 |
| PCX | RLE | 최대 24비트 | 없음 | 없음 | DOS 게임, 초기 클립아트 |
GIF는 웹을 지배했지만 법적으로 유독했다. 256색 팔레트는 아이콘과 만화에는 충분했지만 사진에는 쓸모없었다. 투명도는 이진적이었다: 픽셀은 완전히 불투명하거나 완전히 투명했다. 부드러운 경계도, 드롭 섀도우도 없었다.
JPEG는 사진을 훌륭하게 처리했지만 데이터를 되돌릴 수 없게 파괴했다. JPEG을 열고, 편집하고, 다시 저장하면 이미지가 저하되었다. JPEG에는 투명도 자체가 없었다. 텍스처 배경 위에 로고를 띄우고 싶은 웹 디자이너에게 JPEG은 쓸모없었다.
BMP와 PCX는 비압축이거나 거의 비압축이었다. 1995년의 640 × 480 BMP는 900 KB를 차지했다. 28.8 kbps 모뎀에서는 다운로드에 4분 이상 걸렸다.
TIFF는 강력하고 유연했지만, 그 유연성이 저주가 되었다. TIFF 파일은 수십 가지의 다른 압축 방식, 색 공간, 비트 깊이를 사용할 수 있었다. 범용 TIFF 디코더를 작성하는 것은 주말 해킹이 아니라 논문 수준의 프로젝트였다.
PNG는 좁은 목표를 겨냥해 설계되었다: GIF의 정적 이미지 용도를 대체하고, 압축을 능가하며, 트루컬러와 진정한 투명도를 추가하고, 영원히 물질적으로 자유롭게 유지하는 것.
PNG가 실제로 압축하는 방식
PNG 압축은 2단계 파이프라인이다. 어느 단계도 그 자체로 똑똑한 건 아니다. 하지만 함께 작동하면 놀랍도록 효과적이다.
단계 1: 필터링
압축이 일어나기 전에, PNG는 원시 픽셀 데이터를 필터에 통과시킨다. 필터는 아무것도 압축하지 않는다. 데이터를 재배열하여 다음 단계가 더 잘 압축할 수 있게 할 뿐이다.
이미지는 바이트의 그리드다. 맑은 하늘 사진에서 인접 픽셀은 거의 동일한 값을 가진다. 하지만 원시 바이트 스트림은 여전히 각 채널에 대해 120, 121, 120, 122, 119를 저장한다. 차이는 미미하다: +1, -1, +2, -3. 절대값 대신 차이를 저장하면, 결과 값은 0 주변에 모인다. 이 모임이 압축 알고리즘이 좋아하는 특성이다.
PNG는 스캔라인당 5가지 필터 타입을 정의한다:
| 필터 | 이름 | 동작 |
|---|---|---|
| 0 | None | 원시 바이트를 저장 |
| 1 | Sub | 이전 픽셀과의 차분을 저장 |
| 2 | Up | 위 픽셀과의 차분을 저장 |
| 3 | Average | Sub와 Up의 평균과의 차분을 저장 |
| 4 | Paeth | 최적 예측값(Sub/Up/대각선)과의 차분을 저장 |
인코더는 스캔라인당 5개의 필터를 모두 시도하고, 단계 2 이후 가장 작은 출력을 만드는 것을 선택한다. 이것이 PNG 인코더가 느려지는 이유다: 필터 조합에 대한 무차별 대입 탐색을 수행하고 있다. 하지만 디코딩은 빠르다——필터 타입은 파일에 저장되므로, 디코더는 역연산만 적용하면 된다.
단계 2: DEFLATE
필터링 후, 데이터는 DEFLATE로 압축된다. 이는 gzip과 ZIP 파일이 사용하는 것과 동일한 알고리즘이다. DEFLATE는 LZ77(슬라이딩 윈도우 중복 문자열 제거)과 허프만 코딩(빈번한 기호에 대한 가변 길이 프리픽스 코드)의 조합이다.
결과: 일반적인 스크린샷이나 UI 그래픽은 비압축 BMP보다 3–5배 작아진다. PNG로 압축된 사진은 보통 JPEG보다 5–10배 크지만, 모든 픽셀이 복구 가능하다. 압축은 구조적으로 무손실이다: 어떤 데이터도 버려지지 않고, 중복성만 제거된다.
맥락을 보자면, 1920 × 1080 스크린샷을 원시 RGB로 저장하면 6.2 MB다. 동일한 스크린샷을 PNG로 하면 보통 800 KB – 1.5 MB로 줄어든다. 동일 이미지를 JPEG 품질 90으로 저장하면 300–500 KB지만, 10번 다시 저장하면 가시적인 아티팩트가 생긴다.
중요했던 기능들
PNG는 단순한 특허 프리 GIF 클론이 아니었다. 1993년부터 웹 디자이너들이 애원하던 기능이 추가되었다.
트루컬러: PNG는 24비트 RGB(1670만 색)과 48비트 딥컬러를 지원한다. 팔레트 제한이 없다. PNG 사진은 인간의 눈이 구분할 수 있는 모든 색을 표시할 수 있다.
알파 채널: PNG는 8비트 알파——픽셀당 256단계의 투명도——를 지원한다. 그림자는 불투명에서 투명으로 부드럽게 페이드할 수 있다. 둥근 버튼은 어떤 배경에 대해서도 안티앨리어싱할 수 있다. GIF가 제공한 것은 1비트 투명도였다: 한 색이 완전히 켜지거나 완전히 꺼지거나. 시각적 차이는 하늘과 땅 차이다.
Adam7 인터레이싱: PNG는 7패스 인터레이스 순서로 픽셀을 저장할 수 있다. 브라우저는 파일의 1/64를 수신한 후에도 거친 프리뷰를 렌더링하고, 점진적으로 세밀화한다. GIF의 줄 단위 인터레이싱과 달리, Adam7은 첫 번째 패스부터 이미지 전체에 디테일을 분산시킨다. 세 번째 패스까지면 이미지가 알아볼 수 있다. 일곱 번째에서 완벽해진다.
감마 보정: PNG는 메타데이터에 감마 값을 저장한다. Mac(감마 1.8)에서 생성된 이미지가 Windows PC(감마 2.2)에서 수동 색 보정 없이도 올바르게 표시된다. 이것은 1990년대, 크로스플랫폼 일관성이 드물었을 때의 진짜 문제였다.
CRC 체크섬: 모든 PNG 청크는 CRC-32 체크섬을 가진다. 손상된 다운로드는 반쯤 렌더링된 이미지를 생성하는 대신 즉시 감지된다.
파일 시그니처를 읽어 PNG 감지하기
.png 확장자를 믿지 마라. 처음 8바이트를 읽어 시그니처를 확인하라.
정확한 바이트 레이아웃:
Bytes 0–7: Signature 89 50 4E 47 0D 0A 1A 0A
Bytes 8–11: Chunk length (big-endian uint32)
Bytes 12–15: Chunk type: "IHDR" (image header)
Bytes 16–19: Image width (big-endian uint32)
Bytes 20–23: Image height (big-endian uint32)
Byte 24: Bit depth
Byte 25: Color type
Byte 26: Compression method (always 0)
Byte 27: Filter method (always 0)
Byte 28: Interlace method (0 or 1)
브라우저에서 TypeScript:
async function isPng(file: File): Promise<boolean> {
const buffer = await file.slice(0, 8).arrayBuffer()
const bytes = new Uint8Array(buffer)
const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]
return bytes.length === 8 && bytes.every((b, i) => b === signature[i])
}
Python
def is_png(path: str) -> bool:
with open(path, "rb") as f:
header = f.read(8)
return header == b"\x89PNG\r\n\x1a\n"
표준 라이브러리를 사용한 고수준 옵션:
import imghdr
if imghdr.what("image.png") == "png":
pass
Pillow를 사용한 경우:
from PIL import Image
try:
with Image.open("image.png") as img:
is_png = img.format == "PNG"
except Exception:
is_png = False
Go
func isPng(path string) bool {
f, err := os.Open(path)
if err != nil {
return false
}
defer f.Close()
buf := make([]byte, 8)
if _, err := f.Read(buf); err != nil {
return false
}
return bytes.Equal(buf, []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a})
}
PHP
function isPng(string $path): bool {
$header = file_get_contents($path, false, null, 0, 8);
return $header === "\x89PNG\r\n\x1a\n";
}
fileinfo를 사용한 경우:
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file('image.png');
// image/png
ImageMagick CLI
magick identify -verbose image.png | grep "Format:"
# Format: PNG (Portable Network Graphics)
또는 단순하게:
file image.png
# image.png: PNG image data, 1200 x 675, 8-bit/color RGBA, non-interlaced
PNG의 한계
PNG는 완벽하지 않다. 설계상의 선택은 트레이드오프였고, 그중 일부는 오늘날에도 여전히 비용을 치른다.
내장 애니메이션 없음: PNG 워킹 그룹은 명시적으로 애니메이션을 거부했다. 복잡성을 추가하기 전에 정적 이미지 문제를 완전히 해결하고 싶어했다. 결과: 애니메이션 GIF는 그 후 20년간 생존했다. APNG(Animated PNG)는 2004년에 최종적으로 표준화되었지만, 브라우저 지원은 2010년대 후반까지 불규칙한 상태였다. 오늘날에도 애니메이션 GIF는 APNG를 수량적으로 압도한다.
사진의 큰 파일 크기: 12 MP 사진을 PNG로 저장하면 보통 15–25 MB다. JPEG 품질 90으로는 3–5 MB다. PNG의 무손실 압축은 JPEG의 DCT 기반 심시각적 버리기와 경쟁할 수 없다. 사진에는 PNG는 잘못된 도구다.
CMYK 미지원: PNG는 RGB 전용이다. CMYK 분리가 필요한 인쇄 워크플로우에서는 PNG를 TIFF나 JPEG로 변환해야 한다. 이것은 의도적인 선택이었다——설계자들은 인쇄가 아닌 화면 표시에 초점을 맞췄다——지만 전문 출판에서 PNG의 유용성을 제한한다.
JPEG보다 느린 디코딩: PNG 디코딩은 스캔라인당 역필터링과 DEFLATE 압축 해제를 필요로 한다. JPEG 디코딩은 고도로 병렬화 가능하고 하드웨어에서 대폭 최적화되어 있다. 모바일 기기에서 큰 PNG는 동일 해상도의 JPEG보다 2–3배 더 오래 걸려 렌더링될 수 있어 Largest Contentful Paint를 지연시킨다.
프로그레시브 품질 없음: JPEG 2000이나 JPEG XL과 달리, PNG는 잘린 파일에서 낮은 품질의 프리뷰를 생성할 수 없다. 파일 전체를 가지거나, 아무것도 가지지 않거나다. Adam7 인터레이싱은 거친 프리뷰에 도움이 되지만, 총 파일 크기를 줄이지는 않는다.
PNG가 JPEG을 대체하지 못한 이유
이것은 이미지 포맷에 관한 가장 흔한 오해다. PNG와 JPEG은 결코 같은 일을 놓고 경쟁한 적이 없다.
JPEG은 손실 심시각적 압축기다. 눈이 거의 알아차리지 못할 데이터를 버린다. 연속 톤 사진——부드러운 그라데이션, 섬세한 질감, 자연광——을 위해 설계되었다. 그 일에 대해 JPEG은 33년이 지난 지금도 크기-품질 곡선에서 여전히 능가할 수 없다.
PNG은 무손실 데이터 압축기다. 모든 비트를 보존한다. 스크린샷, UI 요소, 다이어그램, 로고, 텍스트 오버레이——선명한 에지와 정확한 색이 중요한 이산 톤 이미지——를 위해 설계되었다. 그 일에 대해, PNG는 표준이다.
두 포맷은 각자 별도의 영역을 구축했다:
| 사용 사례 | 올바른 포맷 | 이유 |
|---|---|---|
| 사진 | JPEG/AVIF | 손실 압축이 5–10배 작다 |
| 스크린샷 | PNG/WebP | 무손실이 텍스트 선명도를 보존 |
| 투명도 있는 로고 | PNG/WebP | 알파 채널 + 무손실 에지 |
| UI 아이콘 | PNG/SVG | 작은 크기, 정확한 색 일치 |
| 과학 데이터 시각화 | PNG | 그라데이션 범례에 아티팩트 없음 |
| 인쇄용 이미지 | TIFF/JPEG XL | CMYK 지원, 높은 비트 깊이 |
PNG은 JPEG을 대체하려 한 적이 없다. 그저 다른 역할을 찾았을 뿐이다.
오늘날 PNG의 위치
2025년 Web Almanac에 따르면, PNG은 웹에서 제공되는 모든 이미지의 **약 22%**를 차지한다. 정점에서는 점유율이 줄었——WebP와 AVIF가 지분을 먹고 있지만——PNG은 여전히 모든 브라우저, 모든 이미지 에디터, 모든 운영체제가 별문제 없이 열 수 있는 폴백 포맷이다.
WebP(Google, 2010년)은 손실과 무손실 모두를 지원하며, 애니메이션과 투명도까지 더한다. 무손실 WebP는 동등한 PNG보다 보통 20–30% 작다. 브라우저 지원은 2020년부터 보편적이다. 새 프로젝트에서는 대부분의 경우 WebP 무손실이 PNG의 실용적인 대체재다.
AVIF(AOM, 2019년)은 더 나은 압축률을 달성하지만, 무손실 모드는 PNG보다 인코딩과 디코딩이 느리다. AVIF는 또한 16비트 채널이나 내장 감마 보정과 같은 PNG의 일부 고급 기능에 대한 브라우저 지원이 부족하다.
SVG는 단순한 벡터 그래픽의 아이콘과 로고 영역을 장악하고 있지만, 래스터화된 복잡한 그래픽에는 여전히 PNG가 필요하다.
실제적인 현실: PNG는 사라지지 않는다. 안전한 기본값이다. 수신자가 파일을 열 수 있음을 보장하고 싶을 때 선택할 수 있는 포맷이다. 이미지 포맷의 QWERTY다——최적은 아니지만, 보편적으로 이해된다.
PNG의 미래
PNG은 완성된 표준이다. 사양은 2003년 이후 실질적으로 변경되지 않았다. 그 안정성은 버그가 아니라 기능이다. 1997년에 생성된 PNG를 현대 브라우저에서 열어도 동일하게 렌더링될 것이다.
하지만 PNG 주변의 생태계는 계속 진화하고 있다:
APNG가 탄력을 받고 있다. Safari는 2014년부터 지원하고 있다. Chrome과 Firefox가 뒤따랐다. Discord, Slack, Twitter는 모두 APNG를 네이티브로 렌더링한다. 짧은 UI 애니메이션——로딩 스피너, 리액션 이모지, 상태 표시기——에 있어, APNG은 애니메이션 GIF를 더 작은 파일과 더 나은 색 재현율로 대체하고 있다.
PNG 최적화 도구는 계속 개선되고 있다. oxipng, pngcrush, zopfli는 더 나은 필터 조합과 DEFLATE 파라미터를 무차별 대입으로 탐색하여 PNG 파일 크기를 또 10–30% 줄일 수 있다. 고트래픽 사이트에서는 모든 PNG을 oxipng에 통과시키는 것이 표준적인 실천이다.
PNG as a container: 일부 현대 워크플로우는 ICC 색 프로파일, EXIF 메타데이터, 심지어 XMP 데이터를 PNG 청크 안에 포함시킨다. PNG은 가벼운 아카이브 포맷이 되었다——TIFF만큼 풍부하지는 않지만, 훨씬 더 포터블하다.
장기적인 전망: PNG은 WebP, AVIF, JPEG XL과 수년간 공존할 것이다. 다른 어떤 포맷도 완전히 소유하지 못한 틈새를 메운다: 무손실, 특허 프리, 보편적으로 지원되며, 한 명의 개발자가 사양에서 일주일 안에 디코더를 작성할 수 있을 만큼 단순하다. 이 조합은 쉽게 대체되지 않는다.
결론
PNG은 개발자들이 참지 못하고 만들어낸 것이다. 특허 소송이 오픈 웹을 위협했고, 개발자 무리가 여가 시간을 이용해 대안을 구축했다. 그들은 30년 표준을 만들려 한 것이 아니다. 한 가지 문제를 해결하려 했다: 라이선스 비용을 지불하지 않고 웹 페이지에 투명한 로고를 올리는 방법.
결과는 누구의 예상보다 훨씬 좋았다. PNG은 웹에 트루컬러 그래픽, 부드러운 투명도, 손상에 강한 파일 무결성을 제공했다. 자원봉사자들에 의해 구축된 오픈 표준이, 대기업이 뒷받침하는 독점 포맷을 능가할 수 있음을 증명했다.
가장 작은 포맷은 아니다. 디코딩이 가장 빠른 포맷도 아니다. 애니메이션은 잘하지 못하고, 사진에는 무용지물이다. 하지만 저장한 모든 픽셀이, 되찾을 픽셀임을 확신하고 싶을 때——PNG이 여전히 손이 가는 도구다.
모든 이미지가 처음부터 PNG인 건 아니다. JPG 이미지를 투명도나 무손실 편집이 필요한 형태로 바꾸고 싶다면, 브라우저에서 바로 변환할 수 있다——별도 프로그램을 깔 필요도 없고, 내 기기 밖으로 데이터가 나가지도 않는다. JPG to PNG는 로컬에서 그대로 처리한다. 웹 작업에서 파일 크기가 부담일 땐, JPG to WebP가 화질을 건드리지 않고 파일을 가볍게 만들어준다. 파비콘 아이콘이 필요할 땐 JPG to ICO가 사진에서 여러 크기의 ICO 파일을 만들어낸다.


