- Go 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .github/workflows | ||
| cmd | ||
| testdata/bench | ||
| .gitignore | ||
| .golangci.yml | ||
| .goreleaser.yaml | ||
| benchmark_test.go | ||
| blocksplitter.go | ||
| cache.go | ||
| cache_integration_test.go | ||
| deflate.go | ||
| go.mod | ||
| gzip_container.go | ||
| hash.go | ||
| katajainen.go | ||
| katajainen_test.go | ||
| lz77.go | ||
| lz77_optimization_test.go | ||
| optimization_test.go | ||
| README.md | ||
| scratch.go | ||
| squeeze.go | ||
| symbols.go | ||
| Taskfile.yml | ||
| tree.go | ||
| util.go | ||
| zlib_container.go | ||
| zopfli.go | ||
| zopfli_test.go | ||
zopfli-go
zopfli-go is a pure Go implementation of Zopfli-style compression for gzip, zlib, and raw deflate output.
Go Usage
package main
import zopfli "github.com/ralscha/zopfli-go"
func main() {
compressed := zopfli.Gzip([]byte("hello, world"))
}
For custom tuning, use DefaultOptions() and call Compress with FormatGzip, FormatZlib, or FormatDeflate.
package main
import zopfli "github.com/ralscha/zopfli-go"
func main() {
options := zopfli.DefaultOptions()
options.NumIterations = 5
options.BlockSplittingMax = 8
compressed := zopfli.CompressParallel(&options, zopfli.FormatGzip, []byte("hello, tuned world"), 4)
}
Fast profile
FastOptions() starts with DefaultOptions() and changes exactly one setting:
NumIterations is reduced from 15 to 3.
| Setting | Default | Fast |
|---|---|---|
| Optimal parsing iterations | 15 | 3 |
| Block splitting | enabled | enabled |
| Maximum split points | 15 | 15 |
Fewer parsing iterations reduce CPU time, but can produce a slightly larger
compressed file because fewer candidate parses are evaluated. The output is
still a normal, deterministic gzip, zlib, or deflate stream. Fast mode does not
enable parallelism; use CompressParallel or CLI --workers-per-file
separately when compressing a large input.
options := zopfli.FastOptions()
compressed := zopfli.Compress(&options, zopfli.FormatGzip, data)
The CLI --fast flag applies the same three-iteration profile. Explicit
--iterations, --block-splitting, and --block-splitting-max flags take
precedence over the profile.
Compress is serial. CompressParallel bounds parallel analysis inside one
file; keep its worker count at 1 when compressing many files concurrently, or
increase it for a small number of large inputs. Worker counts are capped at
MaxCompressionWorkers (currently 4). For each active 1 MiB input block, the
match cache uses about 12 MiB of metadata plus 4 bytes per cached distance run,
with a 60 MiB hard ceiling; parsing and token buffers require additional memory.
The CLI divides its default --jobs value by --workers-per-file so the two
levels of concurrency do not multiply by default; an explicit --jobs value
overrides that safeguard.
CLI Usage
The repository includes a file-oriented CLI for precompressing web assets into adjacent .gz files.
./zopfli-go --help
./zopfli-go --jobs 8 public
./zopfli-go --fast public
./zopfli-go --fast --jobs 1 --workers-per-file 4 large-asset.js
./zopfli-go --include-suffix .js --exclude-suffix .min.js public
./zopfli-go public assets/app.js
./zopfli-go --json public
Behavior:
- File and directory inputs are accepted.
- Directories are walked recursively.
- Outputs are written next to the source file as
filename.ext.gz. - Files are skipped when the
.gzoutput is larger than or equal to the original. - When a file is skipped for size, any stale adjacent
.gzoutput from an earlier run is removed. - Existing
.gzfiles are ignored as inputs unless--allow-gzip-inputsis set.
Supported CLI flags:
-j,--jobs--fast-i,--include-suffixand-x,--exclude-suffix(repeatable, matched against relative paths or base filenames)--allow-gzip-inputs-n,--iterations--workers-per-file--block-splitting--block-splitting-last=false|true|both(deprecated compatibility option)--block-splitting-max-v,--verbose-V,--verbose-more-J,--json
Benchmarks
The table below is updated by the benchmark workflow on branch pushes and workflow dispatches.
Benchmark comparisons use the original upstream Zopfli implementation from https://github.com/google/zopfli.
| Corpus | GoMs | PgoMs | CMs | PGO/Go | Go/C | PGO/C | GoBytes | CBytes | GzipBytes |
|---|---|---|---|---|---|---|---|---|---|
| mixed-256k | 2217.50 | 2193.99 | 7609.87 | 0.99 | 0.29 | 0.29 | 3162 | 3162 | 3201 |
| random-256k | 173.49 | 155.67 | 367.27 | 0.90 | 0.47 | 0.42 | 262183 | 262183 | 262204 |
| real-files-256k | 765.32 | 704.55 | 2573.09 | 0.92 | 0.30 | 0.27 | 4649 | 4649 | 5033 |
| records-logs-256k | 854.94 | 803.30 | 2233.16 | 0.94 | 0.38 | 0.36 | 2510 | 2510 | 2661 |
| tiny-text | 14.23 | 15.67 | 31.19 | 1.10 | 0.46 | 0.50 | 58 | 58 | 62 |
| web-assets-256k | 755.25 | 695.70 | 2337.14 | 0.92 | 0.32 | 0.30 | 3756 | 3756 | 4073 |
Development
Use the Go version declared in go.mod.
Run the package tests with:
go test ./...
Generate the benchmark summary locally with:
go run ./cmd/zopfli-task bench-summary
Releases
GitHub releases are produced by GoReleaser from version tags such as v1.0.0.
Release assets are archived as .tar.gz on Linux and macOS, and as .zip on Windows.
Those release assets are consumed directly by bread-compressor-cli when its --use-zopfli-go flag is enabled.