PNG Codec Benchmarks
A from-scratch PNG codec in Rust - blazediff-png - against spngย , image-rs (png), and zune-pngย . Decode and encode are timed (best-of, size-scaled iteration counts) over the full fixture corpus (34 PNGs, 342.7 MPx), single-threaded on Apple Silicon. Lower is better.
Encode is measured at two settings so the speed/size trade-off is explicit and zuneโs stored-only encoder is compared fairly: no compression (stored deflate blocks) and half compression (half of each codecโs own max deflate level - libdeflate 12 โ 6, zlib 9 โ 4).

Decode
blazediff decodes ~1.39ร faster than spng across the corpus.
| Benchmark | MPx | blazediff | spng | image-rs | zune | BlazeDiff vs spng |
|---|---|---|---|---|---|---|
| 4k/1a.png | 17.9 | 134.93ms | 173.28ms | 148.92ms | 200.45ms | 22.1% |
| 4k/1b.png | 17.9 | 123.27ms | 161.80ms | 139.96ms | 188.15ms | 23.8% |
| 4k/2a.png | 20.0 | 155.63ms | 211.59ms | 192.49ms | 234.31ms | 26.4% |
| 4k/2b.png | 20.0 | 160.49ms | 223.08ms | 197.56ms | 240.97ms | 28.1% |
| 4k/3a.png | 24.0 | 161.71ms | 219.93ms | 195.11ms | 266.82ms | 26.5% |
| 4k/3b.png | 24.0 | 161.93ms | 219.84ms | 192.57ms | 263.53ms | 26.3% |
| blazediff/1a.png | 0.4 | 0.60ms | 0.68ms | 0.74ms | 1.02ms | 11.5% |
| blazediff/1b.png | 0.4 | 0.61ms | 0.68ms | 0.74ms | 1.01ms | 10.3% |
| blazediff/2a.png | 0.4 | 0.60ms | 0.79ms | 0.71ms | 0.93ms | 23.7% |
| blazediff/2b.png | 0.4 | 0.65ms | 0.85ms | 0.78ms | 1.02ms | 22.9% |
| blazediff/3a.png | 1.6 | 10.78ms | 13.25ms | 12.92ms | 17.43ms | 18.7% |
| blazediff/3b.png | 1.6 | 10.77ms | 13.22ms | 12.94ms | 17.41ms | 18.5% |
| blazediff/4a.png | 3.8 | 2.77ms | 3.40ms | 3.44ms | 4.46ms | 18.4% |
| blazediff/4b.png | 3.8 | 2.83ms | 3.45ms | 3.51ms | 4.51ms | 17.7% |
| page/1a.png | 58.9 | 155.00ms | 236.10ms | 181.59ms | 243.01ms | 34.4% |
| page/1b.png | 58.9 | 155.97ms | 235.93ms | 181.84ms | 245.78ms | 33.9% |
| page/2a.png | 41.7 | 26.11ms | 36.11ms | 20.73ms | 57.29ms | 27.7% |
| page/2b.png | 41.7 | 26.19ms | 35.83ms | 20.33ms | 48.03ms | 26.9% |
| pixelmatch/1a.png | 0.1 | 0.69ms | 0.94ms | 0.72ms | 1.07ms | 26.8% |
| pixelmatch/1b.png | 0.1 | 0.54ms | 0.71ms | 0.58ms | 0.89ms | 23.3% |
| pixelmatch/2a.png | 0.1 | 0.10ms | 0.36ms | 0.12ms | 0.16ms | 71.4% |
| pixelmatch/2b.png | 0.1 | 0.11ms | 0.37ms | 0.12ms | 0.16ms | 70.7% |
| pixelmatch/3a.png | 0.1 | 0.48ms | 0.72ms | 0.51ms | 0.75ms | 33.0% |
| pixelmatch/3b.png | 0.1 | 0.49ms | 0.71ms | 0.50ms | 0.74ms | 30.7% |
| pixelmatch/4a.png | 0.2 | 1.08ms | 1.82ms | 1.35ms | 1.74ms | 40.5% |
| pixelmatch/4b.png | 0.2 | 1.29ms | 1.75ms | 1.40ms | 2.19ms | 26.5% |
| pixelmatch/5a.png | 0.1 | 0.29ms | 0.43ms | 0.28ms | 0.38ms | 32.4% |
| pixelmatch/5b.png | 0.1 | 0.29ms | 0.43ms | 0.26ms | 0.36ms | 32.9% |
| pixelmatch/6a.png | 0.1 | 0.34ms | 0.66ms | 0.38ms | 0.45ms | 47.9% |
| pixelmatch/6b.png | 0.1 | 0.57ms | 0.93ms | 0.53ms | 0.84ms | 38.9% |
| pixelmatch/7a.png | 0.3 | 0.18ms | 0.46ms | 0.19ms | 0.31ms | 61.8% |
| pixelmatch/7b.png | 0.3 | 0.17ms | 0.46ms | 0.18ms | 0.31ms | 62.1% |
| same/1a.png | 1.7 | 2.08ms | 2.52ms | 2.60ms | 9.10ms | 17.4% |
| same/1b.png | 1.7 | 2.04ms | 2.51ms | 2.62ms | 9.15ms | 18.7% |
| TOTAL | 1301.61ms | 1805.58ms | 1519.25ms | 2064.72ms | 27.9% |
Encode - No Compression
Levels: blazediff stored ยท spng stored ยท image-rs stored ยท zune stored.
blazediff encodes ~2.20ร faster than spng (stored) across the corpus.
| Benchmark | MPx | blazediff | spng | image-rs | zune | BlazeDiff vs spng |
|---|---|---|---|---|---|---|
| 4k/1a.png | 17.9 | 12.53ms | 26.57ms | 20.40ms | 54.32ms | 52.8% |
| 4k/1b.png | 17.9 | 12.40ms | 26.28ms | 22.70ms | 54.80ms | 52.8% |
| 4k/2a.png | 20.0 | 14.92ms | 33.87ms | 31.14ms | 61.48ms | 56.0% |
| 4k/2b.png | 20.0 | 13.79ms | 41.76ms | 32.74ms | 76.54ms | 67.0% |
| 4k/3a.png | 24.0 | 16.85ms | 37.14ms | 35.94ms | 73.38ms | 54.6% |
| 4k/3b.png | 24.0 | 16.96ms | 46.30ms | 33.15ms | 77.65ms | 63.4% |
| blazediff/1a.png | 0.4 | 0.30ms | 0.49ms | 0.39ms | 1.15ms | 39.6% |
| blazediff/1b.png | 0.4 | 0.30ms | 0.45ms | 0.40ms | 1.15ms | 34.0% |
| blazediff/2a.png | 0.4 | 0.23ms | 0.36ms | 0.31ms | 0.94ms | 36.1% |
| blazediff/2b.png | 0.4 | 0.23ms | 0.36ms | 0.31ms | 0.94ms | 35.7% |
| blazediff/3a.png | 1.6 | 1.10ms | 1.95ms | 2.81ms | 4.80ms | 43.6% |
| blazediff/3b.png | 1.6 | 1.10ms | 2.23ms | 2.20ms | 4.61ms | 50.6% |
| blazediff/4a.png | 3.8 | 2.55ms | 5.56ms | 7.08ms | 11.59ms | 54.2% |
| blazediff/4b.png | 3.8 | 2.50ms | 5.45ms | 4.60ms | 11.29ms | 54.1% |
| page/1a.png | 58.9 | 43.39ms | 90.77ms | 72.11ms | 184.00ms | 52.2% |
| page/1b.png | 58.9 | 42.70ms | 87.22ms | 70.88ms | 179.83ms | 51.0% |
| page/2a.png | 41.7 | 30.62ms | 66.53ms | 95.26ms | 133.57ms | 54.0% |
| page/2b.png | 41.7 | 30.99ms | 64.11ms | 53.10ms | 143.90ms | 51.7% |
| pixelmatch/1a.png | 0.1 | 0.08ms | 0.16ms | 0.10ms | 0.35ms | 46.0% |
| pixelmatch/1b.png | 0.1 | 0.09ms | 0.13ms | 0.10ms | 0.34ms | 33.7% |
| pixelmatch/2a.png | 0.1 | 0.04ms | 0.08ms | 0.05ms | 0.17ms | 46.8% |
| pixelmatch/2b.png | 0.1 | 0.04ms | 0.08ms | 0.05ms | 0.17ms | 45.7% |
| pixelmatch/3a.png | 0.1 | 0.08ms | 0.15ms | 0.10ms | 0.34ms | 45.6% |
| pixelmatch/3b.png | 0.1 | 0.09ms | 0.15ms | 0.10ms | 0.33ms | 42.2% |
| pixelmatch/4a.png | 0.2 | 0.12ms | 0.18ms | 0.15ms | 0.48ms | 33.3% |
| pixelmatch/4b.png | 0.2 | 0.12ms | 0.18ms | 0.16ms | 0.47ms | 33.8% |
| pixelmatch/5a.png | 0.1 | 0.04ms | 0.07ms | 0.05ms | 0.17ms | 35.1% |
| pixelmatch/5b.png | 0.1 | 0.04ms | 0.08ms | 0.05ms | 0.17ms | 44.5% |
| pixelmatch/6a.png | 0.1 | 0.04ms | 0.07ms | 0.05ms | 0.17ms | 38.1% |
| pixelmatch/6b.png | 0.1 | 0.04ms | 0.07ms | 0.05ms | 0.17ms | 37.6% |
| pixelmatch/7a.png | 0.3 | 0.17ms | 0.24ms | 0.22ms | 0.64ms | 29.7% |
| pixelmatch/7b.png | 0.3 | 0.17ms | 0.25ms | 0.22ms | 0.64ms | 31.5% |
| same/1a.png | 1.7 | 1.19ms | 2.03ms | 2.91ms | 5.13ms | 41.5% |
| same/1b.png | 1.7 | 1.17ms | 2.40ms | 2.90ms | 5.09ms | 51.5% |
| TOTAL | 246.98ms | 543.69ms | 492.80ms | 1090.76ms | 54.6% |
Encode Size - No Compression
Output bytes per codec; the final row is each codecโs total as a percentage of spngโs (the de-facto reference). zune-png has no compressed mode, so it always writes stored output - far larger than the rest.
| Benchmark | blazediff | spng | image-rs | zune |
|---|---|---|---|---|
| 4k/1a.png | 70008.5 KB | 70113.9 KB | 70008.5 KB | 70111.1 KB |
| 4k/1b.png | 70008.5 KB | 70113.9 KB | 70008.5 KB | 70111.1 KB |
| 4k/2a.png | 77985.6 KB | 78102.8 KB | 77985.6 KB | 78099.8 KB |
| 4k/2b.png | 77985.6 KB | 78102.8 KB | 77985.6 KB | 78099.8 KB |
| 4k/3a.png | 93761.1 KB | 93901.8 KB | 93761.1 KB | 93898.5 KB |
| 4k/3b.png | 93761.1 KB | 93901.8 KB | 93761.1 KB | 93898.5 KB |
| blazediff/1a.png | 1686.4 KB | 1689.0 KB | 1686.4 KB | 1688.8 KB |
| blazediff/1b.png | 1686.4 KB | 1689.0 KB | 1686.4 KB | 1688.8 KB |
| blazediff/2a.png | 1372.2 KB | 1374.3 KB | 1372.2 KB | 1374.2 KB |
| blazediff/2b.png | 1372.2 KB | 1374.3 KB | 1372.2 KB | 1374.2 KB |
| blazediff/3a.png | 6372.0 KB | 6381.7 KB | 6372.0 KB | 6381.3 KB |
| blazediff/3b.png | 6372.0 KB | 6381.7 KB | 6372.0 KB | 6381.3 KB |
| blazediff/4a.png | 14792.1 KB | 14814.7 KB | 14792.1 KB | 14813.8 KB |
| blazediff/4b.png | 14792.1 KB | 14814.7 KB | 14792.1 KB | 14813.8 KB |
| page/1a.png | 230305.6 KB | 230653.1 KB | 230305.6 KB | 230643.0 KB |
| page/1b.png | 230305.6 KB | 230653.1 KB | 230305.6 KB | 230643.0 KB |
| page/2a.png | 162963.6 KB | 163212.5 KB | 162963.6 KB | 163202.3 KB |
| page/2b.png | 162963.6 KB | 163212.5 KB | 162963.6 KB | 163202.3 KB |
| pixelmatch/1a.png | 512.4 KB | 513.1 KB | 512.4 KB | 513.1 KB |
| pixelmatch/1b.png | 512.4 KB | 513.1 KB | 512.4 KB | 513.1 KB |
| pixelmatch/2a.png | 256.3 KB | 256.7 KB | 256.3 KB | 256.7 KB |
| pixelmatch/2b.png | 256.3 KB | 256.7 KB | 256.3 KB | 256.7 KB |
| pixelmatch/3a.png | 512.4 KB | 513.1 KB | 512.4 KB | 513.1 KB |
| pixelmatch/3b.png | 512.4 KB | 513.1 KB | 512.4 KB | 513.1 KB |
| pixelmatch/4a.png | 705.4 KB | 706.5 KB | 705.4 KB | 706.5 KB |
| pixelmatch/4b.png | 705.4 KB | 706.5 KB | 705.4 KB | 706.5 KB |
| pixelmatch/5a.png | 256.3 KB | 256.7 KB | 256.3 KB | 256.7 KB |
| pixelmatch/5b.png | 256.3 KB | 256.7 KB | 256.3 KB | 256.7 KB |
| pixelmatch/6a.png | 256.3 KB | 256.7 KB | 256.3 KB | 256.7 KB |
| pixelmatch/6b.png | 256.3 KB | 256.7 KB | 256.3 KB | 256.7 KB |
| pixelmatch/7a.png | 977.2 KB | 978.7 KB | 977.2 KB | 978.6 KB |
| pixelmatch/7b.png | 977.2 KB | 978.7 KB | 977.2 KB | 978.6 KB |
| same/1a.png | 6789.5 KB | 6799.9 KB | 6789.5 KB | 6799.5 KB |
| same/1b.png | 6789.5 KB | 6799.9 KB | 6789.5 KB | 6799.5 KB |
| TOTAL | 1339025.9 KB | 1341050.3 KB | 1339025.9 KB | 1340987.3 KB |
| vs spng | 99.8% | 100.0% | 99.8% | 100.0% |
Encode - Half Compression
Levels: blazediff libdeflate 6 ยท spng zlib 4 ยท image-rs flate2 4 ยท zune stored.
blazediff encodes ~3.83ร faster than spng (zlib 4) across the corpus.
| Benchmark | MPx | blazediff | spng | image-rs | zune | BlazeDiff vs spng |
|---|---|---|---|---|---|---|
| 4k/1a.png | 17.9 | 1056.97ms | 2737.32ms | 1077.06ms | 63.95ms | 61.4% |
| 4k/1b.png | 17.9 | 921.76ms | 2401.56ms | 912.37ms | 60.64ms | 61.6% |
| 4k/2a.png | 20.0 | 949.57ms | 2990.64ms | 1127.18ms | 81.06ms | 68.2% |
| 4k/2b.png | 20.0 | 982.14ms | 3157.70ms | 1143.74ms | 70.00ms | 68.9% |
| 4k/3a.png | 24.0 | 1498.26ms | 4120.51ms | 1538.17ms | 75.01ms | 63.6% |
| 4k/3b.png | 24.0 | 1485.45ms | 3767.51ms | 1497.28ms | 81.17ms | 60.6% |
| blazediff/1a.png | 0.4 | 3.79ms | 33.61ms | 3.00ms | 1.14ms | 88.7% |
| blazediff/1b.png | 0.4 | 3.80ms | 33.80ms | 2.99ms | 1.16ms | 88.7% |
| blazediff/2a.png | 0.4 | 3.26ms | 27.61ms | 2.61ms | 0.94ms | 88.2% |
| blazediff/2b.png | 0.4 | 3.33ms | 27.81ms | 2.69ms | 0.94ms | 88.0% |
| blazediff/3a.png | 1.6 | 37.03ms | 156.92ms | 38.87ms | 4.84ms | 76.4% |
| blazediff/3b.png | 1.6 | 36.56ms | 155.85ms | 38.25ms | 4.71ms | 76.5% |
| blazediff/4a.png | 3.8 | 29.21ms | 290.44ms | 21.02ms | 11.51ms | 89.9% |
| blazediff/4b.png | 3.8 | 29.22ms | 290.41ms | 20.84ms | 11.36ms | 89.9% |
| page/1a.png | 58.9 | 799.06ms | 5056.84ms | 724.72ms | 176.21ms | 84.2% |
| page/1b.png | 58.9 | 797.44ms | 5039.05ms | 720.76ms | 175.49ms | 84.2% |
| page/2a.png | 41.7 | 618.68ms | 3647.39ms | 610.52ms | 142.30ms | 83.0% |
| page/2b.png | 41.7 | 617.69ms | 3644.86ms | 620.80ms | 133.95ms | 83.1% |
| pixelmatch/1a.png | 0.1 | 1.64ms | 11.06ms | 1.76ms | 0.35ms | 85.2% |
| pixelmatch/1b.png | 0.1 | 1.61ms | 11.14ms | 1.77ms | 0.34ms | 85.5% |
| pixelmatch/2a.png | 0.1 | 2.41ms | 8.75ms | 3.30ms | 0.17ms | 72.4% |
| pixelmatch/2b.png | 0.1 | 2.49ms | 9.02ms | 3.39ms | 0.17ms | 72.4% |
| pixelmatch/3a.png | 0.1 | 1.32ms | 10.43ms | 1.22ms | 0.34ms | 87.4% |
| pixelmatch/3b.png | 0.1 | 1.32ms | 10.31ms | 1.18ms | 0.33ms | 87.2% |
| pixelmatch/4a.png | 0.2 | 6.93ms | 24.16ms | 9.04ms | 0.48ms | 71.3% |
| pixelmatch/4b.png | 0.2 | 7.00ms | 24.92ms | 9.33ms | 0.47ms | 71.9% |
| pixelmatch/5a.png | 0.1 | 0.59ms | 5.02ms | 0.59ms | 0.17ms | 88.2% |
| pixelmatch/5b.png | 0.1 | 0.59ms | 4.98ms | 0.57ms | 0.17ms | 88.1% |
| pixelmatch/6a.png | 0.1 | 2.07ms | 7.19ms | 2.53ms | 0.17ms | 71.1% |
| pixelmatch/6b.png | 0.1 | 1.96ms | 6.74ms | 2.19ms | 0.17ms | 70.9% |
| pixelmatch/7a.png | 0.3 | 3.73ms | 21.97ms | 4.16ms | 0.64ms | 83.0% |
| pixelmatch/7b.png | 0.3 | 3.78ms | 22.02ms | 4.18ms | 0.64ms | 82.8% |
| same/1a.png | 1.7 | 15.44ms | 135.60ms | 12.40ms | 5.12ms | 88.6% |
| same/1b.png | 1.7 | 15.44ms | 135.81ms | 12.57ms | 5.97ms | 88.6% |
| TOTAL | 9941.57ms | 38028.96ms | 10173.07ms | 1112.08ms | 73.9% |
Encode Size - Half Compression
Output bytes per codec; the final row is each codecโs total as a percentage of spngโs (the de-facto reference). zune-png has no compressed mode, so it always writes stored output - far larger than the rest.
| Benchmark | blazediff | spng | image-rs | zune |
|---|---|---|---|---|
| 4k/1a.png | 21101.4 KB | 21854.4 KB | 22052.3 KB | 70111.1 KB |
| 4k/1b.png | 17651.2 KB | 18677.4 KB | 18347.8 KB | 70111.1 KB |
| 4k/2a.png | 26682.0 KB | 27721.7 KB | 27255.9 KB | 78099.8 KB |
| 4k/2b.png | 27245.4 KB | 28215.9 KB | 27832.4 KB | 78099.8 KB |
| 4k/3a.png | 32854.0 KB | 35811.5 KB | 33914.6 KB | 93898.5 KB |
| 4k/3b.png | 32367.2 KB | 35368.2 KB | 33383.8 KB | 93898.5 KB |
| blazediff/1a.png | 30.8 KB | 35.4 KB | 30.2 KB | 1688.8 KB |
| blazediff/1b.png | 30.9 KB | 35.4 KB | 30.3 KB | 1688.8 KB |
| blazediff/2a.png | 31.5 KB | 38.1 KB | 30.1 KB | 1374.2 KB |
| blazediff/2b.png | 32.8 KB | 39.8 KB | 31.5 KB | 1374.2 KB |
| blazediff/3a.png | 815.5 KB | 877.0 KB | 835.0 KB | 6381.3 KB |
| blazediff/3b.png | 792.2 KB | 853.3 KB | 812.1 KB | 6381.3 KB |
| blazediff/4a.png | 98.7 KB | 114.0 KB | 100.5 KB | 14813.8 KB |
| blazediff/4b.png | 98.3 KB | 114.1 KB | 100.4 KB | 14813.8 KB |
| page/1a.png | 11324.3 KB | 12237.3 KB | 11321.4 KB | 230643.0 KB |
| page/1b.png | 11315.0 KB | 12227.2 KB | 11313.6 KB | 230643.0 KB |
| page/2a.png | 10595.2 KB | 11285.2 KB | 10674.2 KB | 163202.3 KB |
| page/2b.png | 10614.5 KB | 11291.1 KB | 10702.0 KB | 163202.3 KB |
| pixelmatch/1a.png | 31.8 KB | 32.2 KB | 33.4 KB | 513.1 KB |
| pixelmatch/1b.png | 31.9 KB | 32.2 KB | 33.4 KB | 513.1 KB |
| pixelmatch/2a.png | 90.8 KB | 96.9 KB | 91.0 KB | 256.7 KB |
| pixelmatch/2b.png | 94.4 KB | 99.9 KB | 94.3 KB | 256.7 KB |
| pixelmatch/3a.png | 13.9 KB | 14.7 KB | 13.8 KB | 513.1 KB |
| pixelmatch/3b.png | 13.7 KB | 14.3 KB | 13.5 KB | 513.1 KB |
| pixelmatch/4a.png | 240.1 KB | 254.1 KB | 241.3 KB | 706.5 KB |
| pixelmatch/4b.png | 251.0 KB | 268.1 KB | 251.9 KB | 706.5 KB |
| pixelmatch/5a.png | 3.0 KB | 3.3 KB | 3.1 KB | 256.7 KB |
| pixelmatch/5b.png | 3.2 KB | 3.3 KB | 3.2 KB | 256.7 KB |
| pixelmatch/6a.png | 44.4 KB | 50.7 KB | 48.5 KB | 256.7 KB |
| pixelmatch/6b.png | 32.0 KB | 37.9 KB | 36.5 KB | 256.7 KB |
| pixelmatch/7a.png | 88.2 KB | 96.1 KB | 87.4 KB | 978.6 KB |
| pixelmatch/7b.png | 87.3 KB | 94.8 KB | 86.5 KB | 978.6 KB |
| same/1a.png | 124.9 KB | 140.3 KB | 126.7 KB | 6799.5 KB |
| same/1b.png | 124.9 KB | 140.3 KB | 126.7 KB | 6799.5 KB |
| TOTAL | 204956.5 KB | 218175.8 KB | 210059.1 KB | 1340987.3 KB |
| vs spng | 93.9% | 100.0% | 96.3% | 614.6% |