zlib で圧縮して Base64 にエンコードする方法
- テキストを入力するか貼り付けるか、ファイルをドロップします。
- 形式 は最初 zlib (deflate) になっています。受け取る側がむき出しのストリームを求めるなら raw deflate に、または gzip に切り替えます。
- 必要に応じて URLセーフ(- _) や 76 文字で折り返し にチェックを入れます。
- 出力をコピー するか、Base64 の
.txt、またはバイナリの.zz/.deflateファイルをダウンロードします。
入れ替え を押すと出力が 展開 側に送られ、往復変換を確認できます。
同じテキストを 3 種類のラッパーで
Hello, world!(13 バイト)をデフォルトのレベルで圧縮した結果です。
| 形式 | バイト数 | Base64 |
|---|---|---|
| raw deflate | 15 | 80jNycnXUSjPL8pJUQQA |
| zlib | 21 | eJzzSM3JyddRKM8vyklRBAAgXgSK |
| gzip | 33 | H4sIAAAAAAAAA/NIzcnJ11Eozy/KSVEEAObG5usNAAAA |
deflate のストリームは 3 つとも同じ 15 バイトですが、Base64 が違って見えるのは、2 バイトや 10 バイトのヘッダーによって、各バイトが 3 バイトのグループのどこに入るかがずれるからです。zlib のヘッダーはデフォルトのレベルでは 78 9C で、zlib の Base64 が eJ で始まるのはこのためです。レベル 9 では 78 DA で、Base64 では eN になります。
どの呼び出しがどの形式を出力するか
「deflate」のバグのほとんどは、双方が同じ言葉で違うラッパーを指していることから生まれます。
| 言語 | zlib(RFC 1950) | raw deflate(RFC 1951) | gzip |
|---|---|---|---|
| Python | zlib.compress() | zlib.compressobj(wbits=-15) | gzip.compress() |
| Node.js | zlib.deflateSync() | zlib.deflateRawSync() | zlib.gzipSync() |
| ブラウザ | CompressionStream("deflate") | CompressionStream("deflate-raw") | CompressionStream("gzip") |
| PHP | gzcompress() | gzdeflate() | gzencode() |
| Java | new Deflater() | new Deflater(level, true) | GZIPOutputStream |
| .NET | ZLibStream(.NET 6 以降) | DeflateStream | GZipStream |
| Go | compress/zlib | compress/flate | compress/gzip |
落とし穴に注意してください。.NET の DeflateStream と Go の compress/flate は raw ですが、Node とブラウザの「deflate」は zlib です。どちらも「deflate を使う」C# のサービスと Node のクライアントは、どちらか一方を変えない限り互いを理解できません。
各ラッパーが使われる場面
- zlib:PDF の
FlateDecodeストリーム、PNG の画像データ、Git のオブジェクト、多くのバイナリプロトコルやゲームのセーブ形式。 - raw deflate:SAML の HTTP-Redirect バインディング(SAML デコーダー が対応しています)、ZIP ファイル内のエントリ、WebSocket の
permessage-deflate。 - gzip:ファイル、HTTP、ログ。gzip のページ で扱っています。
コードでの zlib + Base64
import base64, zlib
packed = base64.b64encode(zlib.compress(b"Hello, world!")).decode()
# 'eJzzSM3JyddRKM8vyklRBAAgXgSK'
text = zlib.decompress(base64.b64decode(packed))
// Node.js: raw deflate for a SAML-style payload
const zlib = require("zlib");
const packed = zlib.deflateRawSync(Buffer.from("Hello, world!")).toString("base64");
// '80jNycnXUSjPL8pJUQQA'
こうした文字列を読み戻すには、3 種類のラッパーをすべて判別する Base64 gzip・zlib デコーダー を使ってください。詳しくは Python と Node.js を参照してください。
よくある問題
incorrect header check:zlib のデコーダーに raw deflate か gzip のデータを渡しています。ラッパーを合わせてください。invalid stored block lengthsまたはinvalid block type:raw deflate のデコーダーに zlib のデータを渡しています。先頭の 2 バイトのヘッダーが deflate のブロックとして読まれています。- 結果が入力より長くなる:短い文字列は圧縮できません。およそ 50~100 バイト未満なら、普通の Base64 のほうが短くなります。
- ほかのツールの出力とバイト単位で一致しない:圧縮レベルとライブラリの両方がバイト列を変えますが、正しい展開処理ならどちらからでも同じ元データが返ります。
よくある質問
zlib と deflate の違いは何ですか?
deflate は圧縮アルゴリズムです。raw deflate はむき出しの圧縮ストリームで、zlib はその前後に 2 バイトのヘッダーと 4 バイトの Adler-32 チェックサムを付け、gzip は 10 バイトのヘッダーと CRC-32 を含む 8 バイトのトレーラーを付けます。中央の圧縮データはまったく同じです。
「incorrect header check」の原因は何ですか?
展開処理が zlib のヘッダーを想定していたのに、別のもの、たいていは raw deflate か gzip を受け取ったことです。対応する呼び出し(Python で raw deflate なら zlib.decompress(data, -15))を使うか、受け取る側が想定する形式でエンコードし直してください。
HTTP の Content-Encoding: deflate は raw deflate と zlib のどちらですか?
HTTP の仕様では zlib です。古いサーバーの中にはその名前で raw deflate を送るものがあったため、HTTP では gzip のほうが安全です。