Skip to content

IRodriguez13/bitgrain

Repository files navigation

Bitgrain

Image compressor (JPEG-like). Encodes to a custom .bg stream; decodes to pixels or standard image files. Grayscale, RGB, RGBA. CLI + C API (FFI-backed) with deterministic mode support.

Current focus in 2.0.0: close the size gap vs JPEG while preserving practical encode/decode speed.

Build

Requirements: Rust (stable), GCC (C11), make, libwebp (headers + lib).

./setup.sh

El script instala dependencias si faltan. Manual:

Sistema Comando
Debian/Ubuntu sudo apt install libwebp-dev
Fedora/RHEL sudo dnf install libwebp-devel
macOS brew install webp

Luego:

make bitgrain

Install: sudo make install (or PREFIX=$HOME/.local make install).

Installed artifacts:

  • bin/bitgrain
  • include/bitgrain/encoder.h
  • lib/libbitgrain.a
  • lib/libbitgrain.so (versioned symlink to libbitgrain.so.<ABI_MAJOR>)
  • lib/libbitgrain-simd.so (versioned symlink to libbitgrain-simd.so.<ABI_MAJOR>)
  • lib/pkgconfig/bitgrain.pc
  • lib/cmake/Bitgrain/BitgrainConfig.cmake

Portable build: make CFLAGS_NATIVE= RUSTFLAGS_NATIVE= bitgrain.

CLI

Preferred command style uses subcommands:

bitgrain encode <input> [-o output.bg] [--quality 1-100]
bitgrain decode <input.bg> [-o output.{png,jpg,webp,bmp,tga,pgm}]
bitgrain roundtrip <input> [-o output.jpg] [--quality 1-100] [--metrics]

Legacy flags are still supported (-i/-d/-cd/...) for backward compatibility.

Option Description
-o, --output <path> Output file or directory
-q, --quality <1-100> Encode quality (default 85)
-Q, --output-quality <1-100> Output JPG/WebP quality (default 85)
-t, --threads <n> Worker threads for codec internals
--deterministic Alias for --threads 1
-m, --metrics Round-trip: print PSNR and SSIM
-y, --overwrite Overwrite outputs
-v, --version / -h, --help Version / help

Input formats: JPEG, PNG, BMP, GIF, TGA, PGM, PSD, HDR, WebP (stb_image + libwebp).

Decode/roundtrip output formats by -o extension: .jpg/.jpeg, .png, .bmp, .tga, .pgm (grayscale), .webp.

Format .bg

Header (12 bytes): magic "BG", version, width (u32 LE), height (u32 LE), quality.

Versions:

  • v1: grayscale + RLE entropy
  • v2: RGB planar + RLE entropy (legacy)
  • v3: RGBA planar + RLE entropy (legacy)
  • v4: YCbCr 4:2:0 + Huffman (RGB output)
  • v5: YCbCr 4:2:0 + alpha + Huffman (RGBA output)
  • v6-v7: chroma AC JPEG table for Cb/Cr
  • v8-v9: perceptual quantization profile
  • v10-v11: perceptual + chroma AC + DC delta (JPEG-like DC prediction)
  • v12-v13: stronger perceptual profile
  • v14-v15: aggressive perceptual profile
  • v16-v17: very aggressive perceptual profile
  • v18-v19: ultra perceptual + AC sparsify profile (best compression in current branch)

C API

includes/encoder.h.

  • Encode: bitgrain_encode_grayscale, bitgrain_encode_rgb, bitgrain_encode_rgba
  • Decode: bitgrain_decode(buf, size, pixels, cap, &w, &h, &channels)
  • Threading: bitgrain_set_threads + env overrides in CLI (BITGRAIN_THREADS, BITGRAIN_THREADS_CAP)
  • Error state: bitgrain_last_error_code, bitgrain_last_error_message, bitgrain_clear_error

Channels are 1, 3, or 4.

Linking from external C/C++ projects

Preferred with pkg-config:

pkg-config --cflags --libs bitgrain

Manual equivalent:

-I${PREFIX}/include/bitgrain -L${PREFIX}/lib -lbitgrain -lbitgrain-simd -lpthread -ldl -lm

Important API contract notes:

  • bitgrain_last_error_message() returns a thread-local pointer; copy it if you need to keep it.
  • On decode failure, output width/height/channels must be treated as undefined.

Prioridades

  • Optimización encode/decode: Cuantización con SIMD (SSE2/NEON) en C; DCT/IDCT en referencia. Objetivo: ser más rápido que WebP/AVIF con calidad similar.
  • Transparencia y canales alfa: Hecho. PNG y WebP con alpha se cargan como RGBA; .bg versión 3 (4 canales); decode devuelve 1, 3 o 4 canales según cabecera.

Integración

  • Crate Rust: rust/Cargo.toml listo para publicar en crates.io (description, license, repository, keywords). Publicar con cargo publish desde rust/.
  • Librería C: make install instala estática + shared + metadata de consumo (pkg-config, CMake).
  • Bindings Python: bindings/python/bitgrain.py (ctypes). Carga libbitgrain-simd primero cuando aplica, luego libbitgrain.
  • Bindings Go: bindings/go/ (cgo). Usar pkg-config o CGO_LDFLAGS apuntando a -lbitgrain -lbitgrain-simd.

ABI and release policy

  • C API header: includes/encoder.h.
  • ABI major line: shared libraries soname *.so.<ABI_MAJOR>.
  • Breaking C ABI changes require major version bump.
  • See CHANGELOG.md for release notes and migration-impacting changes.

Layout

bitgrain/
├── main.c           # Orquestación CLI
├── Makefile
├── includes/encoder.h
├── c/               # Modular: cli, path_utils, encode_cli, decode_cli, roundtrip_cli,
│                    # bg_utils, config, quant (SIMD), image_loader, image_writer, metrics, webp_io, platform
├── rust/            # encoder, decoder, dct, entropy, ffi; Cargo.toml listo crates.io
├── tests/           # integration.sh (CLI end-to-end)
└── bindings/
    ├── python/      # bitgrain.py (ctypes)
    └── go/          # bitgrain.go (cgo)

Tests: ./tests/integration.sh (requiere build previo con libwebp).

Formato .bg e interoperabilidad

Especificación pública en FORMAT.md. Permite implementar lectores/escritores .bg en terceros.

Benchmark

Comparar Bitgrain vs JPEG/WebP (tamaño y tiempo, avg/p50/p95):

./scripts/benchmark.sh /ruta/imagen.jpg 85

Requiere: cjpeg/djpeg (libjpeg), cwebp/dwebp (libwebp).

Comparación directa Bitgrain vs JPEG, imagen por imagen:

./scripts/compare_bg_vs_jpeg.sh /ruta/imagenes 85 3

CSV outputs:

  • bench_out/benchmark.csv
  • bench_out/one_by_one/bg_vs_jpeg.csv

Temporary intermediate files are created under /tmp and removed automatically.

Snapshot (latest local run, quality 85)

Setup used for the numbers below:

  • Bitgrain profile: v18/v19 (ultra perceptual + AC sparsify)
  • Runs: 5
  • Codecs: Bitgrain vs JPEG (cjpeg/djpeg) vs JPEG2000 (opj_compress/opj_decompress -r 20)
  • Images: weic2517d.jpg and potm2411b.jpg
Image Codec Size (bytes) Encode avg ms Decode avg ms
weic2517d.jpg Bitgrain 638,085 131.06 179.92
weic2517d.jpg JPEG (cjpeg) 1,269,030 30.38 141.97
weic2517d.jpg JPEG2000 (opj) 1,530,779 1817.07 460.80
potm2411b.jpg Bitgrain 60,011 16.43 17.11
potm2411b.jpg JPEG (cjpeg) 173,980 3.68 13.63
potm2411b.jpg JPEG2000 (opj) 117,857 227.97 38.66

Quick ranking from this snapshot:

  • Compression (smaller is better): Bitgrain > JPEG > JPEG2000
  • Encode speed (faster is better): JPEG > Bitgrain >>> JPEG2000
  • Decode speed (faster is better): JPEG > Bitgrain >> JPEG2000

Why this still sells:

  • Bitgrain is significantly smaller than JPEG in the measured sample while remaining in practical encode/decode times.
  • Against JPEG2000, Bitgrain is both much faster and smaller in this setup.

Use these numbers as a reproducible project snapshot, not an absolute universal claim. Always validate with your own dataset and quality targets.

Roadmap

  • Formatos: AVIF (libavif), TIFF (libtiff), RAW (opcional).
  • DCT/IDCT SIMD: Implementado en c/dct.c (SSE2/NEON).
  • Streaming: decode_rle_one_block permite decodificación bloque a bloque.
  • ICC/color management: Extensión futura en FORMAT.md (v4+).
  • Progressive decode: Reordenado de bitstream (roadmap).

License: GPL-3.0-or-later. See LICENSE.