Skip to content

Zlib & Deflate

Zlib and Deflate are closely related formats based on the DEFLATE algorithm. They’re used extensively in PNG images, ZIP files, HTTP, and many other contexts.

FormatDescriptionChecksumAuto-detect
DeflateRaw DEFLATE streamNoneNo
ZlibDEFLATE + zlib header/trailerAdler-32Yes
GzipDEFLATE + gzip header/trailerCRC32Yes

All three use the same compression algorithm but different wrappers.

FormatCompressDecompressRatio
Deflate2.4 GB/s2.4 GB/s99.2%
Zlib2.4 GB/s2.4 GB/s99.2%
Use CaseFormat
PNG imagesZlib
ZIP filesDeflate (raw)
HTTP Content-EncodingGzip
Custom protocolDeflate (minimal overhead)
Data integrity neededZlib (Adler-32)
General file compressionGzip

Zlib wraps DEFLATE with a small header and Adler-32 checksum.

const cz = @import("compressionz");
// Compress
const compressed = try cz.zlib.compress(data, allocator, .{});
defer allocator.free(compressed);
// Decompress
const decompressed = try cz.zlib.decompress(compressed, allocator, .{});
defer allocator.free(decompressed);
// Compression level
const best = try cz.zlib.compress(data, allocator, .{
.level = .best,
});
const dictionary = "common patterns in your data...";
// Compress with dictionary
const compressed = try cz.zlib.compressWithDict(data, dictionary, allocator, .{});
defer allocator.free(compressed);
// Decompress with same dictionary
const decompressed = try cz.zlib.decompressWithDict(compressed, dictionary, allocator, .{});
defer allocator.free(decompressed);
+-----------------------------------------------------+
| Zlib Header (2 bytes) |
| - CMF: compression method and flags |
| - FLG: flags (check bits, preset dict, level) |
| - [Dictionary ID] (4 bytes, if FDICT set) |
+-----------------------------------------------------+
| Compressed Data (DEFLATE) |
+-----------------------------------------------------+
| Adler-32 Checksum (4 bytes) |
+-----------------------------------------------------+
// Zlib detection (CMF * 256 + FLG must be divisible by 31)
fn isZlib(data: []const u8) bool {
if (data.len < 2) return false;
const cmf = data[0];
const flg = data[1];
return (cmf & 0x0F) == 8 and // DEFLATE method
(@as(u16, cmf) * 256 + flg) % 31 == 0;
}

Raw DEFLATE stream without any wrapper.

const cz = @import("compressionz");
// Compress
const compressed = try cz.zlib.compressDeflate(data, allocator, .{});
defer allocator.free(compressed);
// Decompress
const decompressed = try cz.zlib.decompressDeflate(compressed, allocator, .{});
defer allocator.free(decompressed);
+-----------------------------------------------------+
| DEFLATE Blocks |
| |
| Block Header (3 bits) |
| - BFINAL: 1 if last block |
| - BTYPE: block type (00=stored, 01=fixed, 10=dyn) |
| |
| Block Data |
| - Huffman-coded literals and length/distance pairs |
| |
| ... more blocks ... |
| |
| Final block (BFINAL=1) |
+-----------------------------------------------------+

Zlib and Deflate support dictionary compression for small data with known patterns.

The dictionary provides a “seed” of common patterns that the compressor can reference:

// Without dictionary: compressor builds patterns from scratch
// With dictionary: compressor starts with known patterns
const json_dict =
\\{"id":,"name":,"email":,"created_at":,"updated_at":
\\,"status":"active","status":"inactive","status":"pending"
\\,"type":"user","type":"admin","type":"guest"
;
// Small JSON objects compress much better with dictionary
const compressed = try cz.zlib.compressWithDict(json_data, json_dict, allocator, .{});
Data SizeWithout DictWith DictImprovement
100 bytes95 bytes45 bytes53% smaller
500 bytes380 bytes210 bytes45% smaller
1 KB720 bytes520 bytes28% smaller
10 KB6.5 KB5.8 KB11% smaller

Dictionary compression is most effective for small data with predictable patterns.

Both formats support streaming:

const cz = @import("compressionz");
const std = @import("std");
// Streaming compression (Zlib)
pub fn compressStream(allocator: std.mem.Allocator, input: anytype, output: anytype) !void {
var comp = try cz.zlib.Compressor(@TypeOf(output)).init(allocator, output, .{});
defer comp.deinit();
var buf: [65536]u8 = undefined;
while (true) {
const n = try input.read(&buf);
if (n == 0) break;
try comp.writer().writeAll(buf[0..n]);
}
try comp.finish();
}
// Streaming decompression (Zlib)
pub fn decompressStream(allocator: std.mem.Allocator, input: anytype) ![]u8 {
var decomp = try cz.zlib.Decompressor(@TypeOf(input)).init(allocator, input);
defer decomp.deinit();
return decomp.reader().readAllAlloc(allocator, 1024 * 1024 * 1024);
}
// Raw Deflate streaming
pub fn compressDeflateStream(allocator: std.mem.Allocator, output: anytype) !cz.zlib.DeflateCompressor(@TypeOf(output)) {
return cz.zlib.DeflateCompressor(@TypeOf(output)).init(allocator, output, .{});
}

DEFLATE combines two compression techniques:

  1. LZ77 — Replace repeated sequences with (length, distance) pairs
  2. Huffman Coding — Use shorter codes for more frequent symbols
Input: "ABRACADABRA"
LZ77 output:
A B R A C A D [match: length=4, distance=7] A
(The "ABRA" at the end matches "ABRA" from 7 positions back)
Huffman coding:
Assign short bit sequences to common symbols
A=0, B=10, R=110, C=1110, D=11110, etc.
TypeNameUse Case
00StoredIncompressible data (passed through)
01FixedPre-defined Huffman codes
10DynamicCustom Huffman codes per block

PNG uses Zlib internally:

// PNG file structure (simplified)
// IHDR chunk (image header)
// IDAT chunk (zlib-compressed image data) <-- Zlib here
// IEND chunk (end marker)

ZIP uses raw Deflate:

// ZIP local file header
// Deflate-compressed file data <-- Raw Deflate here
// Data descriptor (optional)

For minimal overhead, use raw Deflate:

fn sendCompressed(socket: *Socket, data: []const u8, allocator: Allocator) !void {
// 4-byte size prefix + deflate data (no zlib overhead)
const compressed = try cz.zlib.compressDeflate(data, allocator, .{});
defer allocator.free(compressed);
var header: [4]u8 = undefined;
std.mem.writeInt(u32, &header, @intCast(compressed.len), .little);
try socket.writeAll(&header);
try socket.writeAll(compressed);
}
AspectDeflateZlibGzip
Overhead0 bytes6 bytes18+ bytes
ChecksumNoneAdler-32CRC32
DictionaryYesYesNo
Auto-detectNoYesYes
Use caseEmbeddingLibrariesFiles