深掘り

PNGの誕生:特許危機をきっかけに開発者が作ったWebの可逆圧縮フォーマット

koboshiCo-founder
·4 分で読めます
PNGの誕生:特許危機をきっかけに開発者が作ったWebの可逆圧縮フォーマット
要約

PNGは1995年のGIF特許危機をきっかけに、ボランティアによって4ヶ月で構築された。フィルター前処理とDEFLATE圧縮を組み合わせてGIFを置き換えた。Unisysの訴訟からhexエディタで読めるファイル署名まで、技術的な全容を解説する。

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年のWebはGIFで回っていた。アニメーションバナー、透過ロゴ、タイル状の背景。GIFがこれらを担っていた。そしてUnisysがロイヤリティを要求した。商用ソフトウェアベンダーはライセンス料に直面した。オープンソースプロジェクトは存続の危機に瀕した。GNU Image Manipulation Program(GIMP)は直接の影響を受けた。Web開発コミュニティは激怒した。

GIFの静的画像用途を何かが置き換える必要があった。要件は明確だった。特許に絡まないこと。GIFより高い圧縮率。トゥルーカラー対応。GIFの単色透過に代わる正当なアルファチャンネル。週末に1人の開発者がデコーダーを実装できる程度の単純さも求められた。

1995年4月4日、Thomas BoutellがUsenetニュースグループcomp.graphicsに提案を投稿した。PBF(Portable Bitmap Format)と名付けた。名前は定着しなかった。その後数ヶ月でメーリングリストが形成された。貢献者にはTom Lane(Independent JPEG Groupのリーダー)、Lee Daniel CrockerAlexander Lehmann、そして数十人の開発者が含まれた。1996年10月1日までに、PNG仕様はRFC 2083として確定した。アイデアから標準化まで全体で約18ヶ月だ。比較すると、JPEGには6年かかった。

PNG以前に存在したもの

1995年の画像フォーマット選択肢は限られており、それぞれが重荷を背負っていた:

フォーマット圧縮色深度透過特許リスク一般的用途
GIFLZW256色まで1ビット、1色有り(LZW)Webグラフィック、アニメーション
JPEGDCT + Huffman24ビットトゥルーカラー無しベースライン期限切れ写真
BMP無しまたはRLE最大24ビット無し無しWindows壁紙
TIFFLZW、PackBitsなど最大48ビット有りLZWは任意印刷、スキャン
PCXRLE最大24ビット無し無しDOSゲーム、初期クリップアート

GIFはWebで使われていたが、法的に問題を抱えていた。256色パレットはアイコンや漫画には十分だったが、写真には無力だった。透過は二値的だった。ピクセルは完全に不透明か、完全に透明かのどちらかだった。ソフトな縁も、ドロップシャドウも不可能だった。

JPEGは写真をうまく扱ったが、保存のたびにデータを失っていた。JPEGを開き、編集し、再保存すれば画像は劣化した。JPEGには透過機能そのものがない。テクスチャ背景の上にロゴを浮かべたいWebデザイナーにとって、JPEGは無力だった。

BMPPCXは非圧縮、あるいはほぼ非圧縮だった。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。絶対値ではなく差分を格納すれば、結果の数値はゼロ周辺に集まる。この集まりこそが、圧縮アルゴリズムが好む性質だ。

PNGはスキャンラインごとに5種類のフィルタータイプを定義する:

フィルター名前動作
0None生バイトをそのまま格納
1Sub前のピクセルからの差分を格納
2Up上のピクセルからの差分を格納
3AverageSubとUpの平均からの差分を格納
4Paeth最良予測値(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クローンではなかった。Webデザイナーが1993年から求めていた機能が追加された。

トゥルーカラー

PNGは24ビットRGB(1670万色)と48ビットディープカラーをサポートする。パレット制限はない。PNGの写真は、人間の目が区別できるすべての色を表示できる。

アルファチャンネル

PNGは8ビットアルファをサポートする。ピクセルごとに256段階の透過が可能だ。影は不透明から透明へ滑らかにフェードできる。角丸ボタンはあらゆる背景に対してアンチエイリアスできる。GIFが提供したのは1ビット透過だった。1色が完全オンか完全オフかのどちらかだった。視覚的な差は大きい。

Adam7インターレース

PNGは7パスのインターレース順序でピクセルを格納できる。ブラウザはファイルの1/64を受信した時点で粗いプレビューを描画し、段階的に精細化していく。GIFの行ごとのインターレースとは異なり、Adam7は最初のパスから画像全体にディテールを分散する。3パス目までには画像が認識可能になる。7パス目で完全になる。

ガンマ補正

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はサイズ-品質曲線で未だに打ち破れない。

PNGは可逆データ圧縮器だ。すべてのビットを保存する。スクリーンショット、UI要素、図解、ロゴ、テキストオーバーレイ(鋭いエッジと正確な色が重要な離散階調画像)向けに設計された。その仕事において、PNGは標準だ。

2つのフォーマットは別々の領域を占めた:

用途正しいフォーマット理由
写真JPEG/AVIFロッシー圧縮が5–10倍小さい
スクリーンショットPNG/WebP可逆でテキストの鮮明さを保存
透過付きロゴPNG/WebPアルファチャンネル+可逆エッジ
UIアイコンPNG/SVG小さなサイズ、正確な色合致
科学データの可視化PNGグラデーション凡例にアーティファクトなし
印刷用画像TIFF/JPEG XLCMYK対応、高ビット深度

PNGは当初からJPEGを置き換えるつもりはなかった。ただ別の役割を見つけただけだ。

今のPNGの立ち位置

2025年Web Almanacによると、PNGはWebで配信されるすべての画像の**約22%**を占める。ピーク時からは減少している。WebPとAVIFがシェアを奪っている。ただし、PNGはあらゆるブラウザや画像エディタ、OSが迷わず開けるフォールバックフォーマットであり続けている。

WebP

WebP(Google、2010年)はロッシーとロスレスの両モードに加え、アニメーションと透過をサポートする。ロスレスWebPは同等のPNGより通常20–30%小さい。ブラウザサポートは2020年以降普遍的だ。新規プロジェクトでは、ほとんどの場合、WebPロスレスがPNGの実用的な後継だ。

AVIF

AVIF(AOM、2019年)はさらに優れた圧縮率を達成するが、ロスレスモードはPNGよりエンコードとデコードが遅い。AVIFはまた、16ビットチャンネルや埋め込みガンマ補正など、PNGの一部の高度な機能に対するブラウザサポートが不完全だ。

SVG

SVGは単純なベクターグラフィックのアイコンとロゴ領域を支配しているが、ラスタライズされた複雑なグラフィックには依然としてPNGが必要だ。

現実的には、PNGは消えない。安全なデフォルトだ。受信者がファイルを開けることを保証したいときにエクスポートするフォーマットだ。画像フォーマットのQWERTYのようなものだ。最適ではないが、普遍的に理解されている。

PNGの将来

PNGは完成した標準だ。仕様は2003年以降、実質的に変更されていない。その安定性は欠陥ではなく機能だ。1997年に作成されたPNGを現代のブラウザで開けば、同一にレンダリングされる。

しかし、PNGの周辺エコシステムは進化し続けている。

APNG

APNGが勢いを増している。Safariは2014年からサポートしている。ChromeとFirefoxも続いた。Discord、Slack、TwitterはすべてAPNGをネイティブにレンダリングする。短いUIアニメーション(ローディングスピナー、リアクション絵文字、ステータスインジケーター)において、APNGはアニメーションGIFをより小さなファイルとより良い色忠実度で置き換えている。

PNG最適化ツール

PNG最適化ツールは改善を続けている。oxipngpngcrushzopfliは、より良いフィルター組み合わせとDEFLATEパラメーターを力任せに探索することで、PNGファイルサイズをさらに10–30%削減できる。高トラフィックサイトでは、すべてのPNGをoxipngに通すことが標準的な実践だ。

PNGをコンテナとして使う

一部の現代ワークフローは、ICCカラープロファイル、EXIFメタデータ、さらにはXMPデータをPNGチャンク内に埋め込む。PNGは軽量なアーカイブフォーマットになっている。TIFFほど豊かではないが、はるかにポータブルだ。

長期的な見通し

PNGはWebP、AVIF、JPEG XLと今後も共存する。他のどのフォーマットも完全には所有していないニッチを埋めている。可逆、特許フリー、普遍的にサポートされ、仕様から1人の開発者が週単位でデコーダーを書けるほど単純だ。この組み合わせは簡単には置き換えられない。

標準になったわけ

PNGは開発者たちがうんざりした結果生まれた。特許訴訟がオープンなWebを脅かし、開発者のグループが余暇を使って代替品を構築した。三十年の標準を作り出そうとしたわけではない。1つの問題を解決しようとしていた。ライセンス料を支払うことなく、Webページに透過ロゴを置く方法だ。

想像以上に広まった。PNGはWebにトゥルーカラーグラフィックをもたらした。滑らかな透過が可能になり、破損した転送も検出できるようになった。ボランティアによって構築されたオープン標準が、大企業が支援する独自フォーマットと同等以上の価値を持ちうることを示した。

PNGは最小のフォーマットではない。デコードが最速のフォーマットでもない。アニメーションはうまくいかず、写真には向かない。しかし保存したすべてのピクセルが、取り戻すピクセルであることを確かめたいとき、PNGが依然として頼れるツールだ。

すべての画像が最初からPNGというわけではない。JPG画像を透過や可逆編集が必要な形に変えたいなら、ブラウザ上で直接変換できる(追加のソフトウェアは不要で、データが外に出ることもない)。JPG to PNGはそのままローカルで処理する。Web制作でファイルサイズが気になる場合、JPG to WebPは画質を損なわずにファイルを軽くできる。faviconアイコンが必要なときは、JPG to ICOが写真から複数サイズのICOファイルを作り出す。

その他のおすすめ記事