Zopfli for Python
Python bindings to the Zopfli Compression Algorithm, offering higher compression ratios than standard zlib or gzip at the cost of significantly slower compression time. It is primarily designed for pre-compressing static assets for web applications or other scenarios where file size is critical and compression is a one-off or build-time operation. Current version 0.4.1 requires Python 3.10+ and maintains an active release cadence, primarily driven by Python version compatibility and updates to the upstream C library.
Warnings
- breaking Python 3.8 and 3.9 support was dropped in v0.3.0, now requiring Python 3.10 or greater. Similarly, Python 3.7 was dropped in v0.2.3 and 2.7/3.6 in v0.2.0. Users on older Python versions must use an earlier `zopfli` release.
- breaking Starting from v0.4.0, `zopfli` utilizes CPython's `Py_LIMITED_API` to build `abi3`-tagged wheels. While this reduces the number of wheels and simplifies future Python version compatibility, it might affect users with highly specific CPython ABI requirements or custom build environments.
- gotcha Zopfli compression is significantly slower than standard `zlib` or `gzip` (often 100x slower) but yields better compression ratios. It is generally not suitable for on-the-fly compression of dynamic content in web servers.
- gotcha The `numiterations` parameter (available for `zopfli.zlib.compress` and `zopfli.gzip.compress`) controls the compression effort. Higher values (e.g., 10-15 for small files) result in better compression but drastically increase processing time. For files over several MB, values around 5 are recommended to balance compression and speed.
- gotcha The `zopfli.gzip.compress` function does not perfectly mimic the standard library's `gzip` module API for file-like objects or streaming. Decompression of `zopfli.gzip.compress` output typically requires wrapping it with `io.BytesIO` and then `gzip.GzipFile` to read.
- gotcha As of v0.4.1, the underlying C `google/zopfli` submodule was switched to the `fonttools/zopfli` fork because the Google repository was archived. This change addresses an unaligned memory access issue that caused `SIGBUS` errors on strict-alignment architectures (e.g., SPARC).
Install
-
pip install zopfli
Imports
- compress
from zopfli.zlib import compress
- compress
from zopfli.gzip import compress
- optimize
from zopfli.png import optimize
Quickstart
from zopfli.zlib import compress
from zopfli.gzip import compress as gzip_compress
import zlib
from io import BytesIO
import gzip
data = b"Hello World! This is some data to compress using Zopfli.\n" * 10
# Zlib compression
zlib_compressed_data = compress(data, numiterations=15)
print(f"Original size: {len(data)} bytes")
print(f"Zlib compressed size: {len(zlib_compressed_data)} bytes")
assert zlib.decompress(zlib_compressed_data) == data
# Gzip compression (note: does not mimic gzip module API directly)
gzip_compressed_data = gzip_compress(data, numiterations=15)
print(f"Gzip compressed size: {len(gzip_compressed_data)} bytes")
with gzip.GzipFile(fileobj=BytesIO(gzip_compressed_data)) as f:
assert f.read() == data
# PNG optimization (example, requires an actual PNG file)
# from zopfli.png import optimize
# try:
# with open('input.png', 'rb') as f_in:
# optimized_png_data = optimize(f_in.read())
# with open('output_optimized.png', 'wb') as f_out:
# f_out.write(optimized_png_data)
# print("PNG optimized successfully.")
# except FileNotFoundError:
# print("Skipping PNG optimization: 'input.png' not found.")