Skip to main content

Unified image hashing — ThumbHash, BlurHash, and more — Rust-powered Python bindings

Project description

thumbleweed

Unified image hashing for Python — ThumbHash, BlurHash, and (soon) ColorThief.
Rust-powered via PyO3 + maturin. Zero mandatory dependencies.

  • ThumbHash — compact image placeholder hashes (drop-in for thumbhash & fast-thumbhash)
  • BlurHash — smooth gradient placeholders (drop-in for blurhash-python)
  • 🔜 ColorThief — dominant colour extraction (placeholder, not yet implemented)
  • ✅ Python 3.10 – 3.14 (including free-threaded 3.13t / 3.14t)
  • ✅ Pillow > 11 integration (optional)
  • ✅ Typed (py.typed + .pyi stubs)
  • ✅ Pure-Rust core — no C extensions, no NumPy required

Installation

pip install thumbleweed
# with Pillow helpers:
pip install "thumbleweed[pillow]"

Development with uv

curl -LsSf https://astral.sh/uv/install.sh | sh
make sync
make test
make prepare
make dist

All import paths work:

import thumbleweed   # the unified package
import thumbhash     # ThumbHash only (backward-compatible)
import blurhash      # BlurHash only
import colorthief    # ColorThief (placeholder)

Quick-start

ThumbHash

import thumbhash as th

# Encode — rgba_bytes must be bytes/bytearray of length w*h*4 (R G B A, non-premultiplied)
hash_bytes: bytes = th.encode(w, h, rgba_bytes)

# Decode
w_out, h_out, rgba_out = th.decode(hash_bytes)

# Helpers
r, g, b, a = th.average_rgba(hash_bytes)           # dominant colour [0, 1]
ratio = th.approximate_aspect_ratio(hash_bytes)     # width / height

BlurHash

import blurhash as bh

# Encode
hash_str: str = bh.encode(rgba_bytes, cx=4, cy=3, width=w, height=h)

# Decode
rgba: bytes = bh.decode(hash_str, width=64, height=64)

Pillow images

from PIL import Image

# ThumbHash
import thumbhash as th
img = Image.open("photo.jpg")
hash_bytes = th.encode_image(img)           # any mode, any size
placeholder = th.decode_image(hash_bytes)   # → RGBA Image, ≈32 px

# BlurHash
import blurhash as bh
hash_str = bh.encode_image(img, cx=4, cy=3)
placeholder = bh.decode_image(hash_str, width=64, height=64)

thumbleweed (unified)

import thumbleweed

# ThumbHash
hash_bytes = thumbleweed.thumbhash_encode(w, h, rgba)
w, h, rgba = thumbleweed.thumbhash_decode(hash)

# BlurHash
hash_str = thumbleweed.blurhash_encode(rgba, 4, 3, w, h)
rgba = thumbleweed.blurhash_decode(hash_str, 64, 64)

Project structure

thumbleweed/
├── src/
│   ├── lib.rs            # PyO3 module — Python bindings
│   ├── thumbhash.rs      # Pure Rust ThumbHash encode/decode
│   ├── blurhash.rs       # Pure Rust BlurHash encode/decode
│   └── colorthief.rs     # Placeholder for future color extraction
├── python/
│   ├── thumbleweed/      # Main package — re-exports everything
│   ├── thumbhash/        # Backward-compatible ThumbHash shim
│   ├── blurhash/         # BlurHash shim
│   └── colorthief/       # Placeholder shim
├── tests/
│   ├── test_thumbhash.py # 70 ThumbHash tests
│   ├── test_blurhash.py  # 28 BlurHash tests
│   └── test_imports.py   # 13 import / version-consistency tests
└── Cargo.toml

API reference

ThumbHash (import thumbhash)

Function Description
encode(w, h, rgba) → bytes Encode raw RGBA bytes → ThumbHash
decode(hash) → (w, h, rgba) Decode ThumbHash → raw RGBA bytes
average_rgba(hash) → (r,g,b,a) Dominant colour in [0, 1]
approximate_aspect_ratio(hash) → float Width / height of the original image
encode_image(img) → bytes Encode a Pillow Image (requires Pillow)
decode_image(hash) → Image Decode to a Pillow Image (requires Pillow)

BlurHash (import blurhash)

Function Description
encode(pixels, cx, cy, w, h) → str Encode raw RGBA bytes → BlurHash string
decode(hash, w, h) → bytes Decode BlurHash → raw RGBA bytes
encode_image(img, cx, cy) → str Encode a Pillow Image (requires Pillow)
decode_image(hash, w, h) → Image Decode to a Pillow Image (requires Pillow)

thumbleweed (import thumbleweed)

All of the above, prefixed with thumbhash_ or blurhash_.


Building from source

git clone https://github.com/New-Elysium/thumbleweed.git
cd thumbleweed
make sync
make test
make prepare

Make targets

  • make sync — sync uv environment (dev + bench) and install the extension in editable mode
  • make test — run Python tests and Rust tests
  • make prepare — run the real-image performance benchmark and inject the table into CLAUDE.md
  • make dist — build wheels / distributions into dist/
  • make upload — upload dist/* with twine
  • make upload-testpypi — upload dist/* to TestPyPI with twine

The repository is uv-managed and includes a checked-in uv.lock.


Licence

MIT — see LICENCE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

thumbleweed-0.1.3.tar.gz (362.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

thumbleweed-0.1.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (673.2 kB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.17+ x86-64

thumbleweed-0.1.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (673.9 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (673.3 kB view details)

Uploaded CPython 3.13tmanylinux: glibc 2.17+ x86-64

thumbleweed-0.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (674.1 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (673.7 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (674.2 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (674.4 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

File details

Details for the file thumbleweed-0.1.3.tar.gz.

File metadata

  • Download URL: thumbleweed-0.1.3.tar.gz
  • Upload date:
  • Size: 362.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for thumbleweed-0.1.3.tar.gz
Algorithm Hash digest
SHA256 038d07a734217af41789a9ce29c6e96571b697b2bd1c2387a792306e3726f71e
MD5 f045fca586ae5ed0dfa2d0a9d5c1f8c9
BLAKE2b-256 a6888d3f7a2658ff6c5d99ff5a3f047103af76f594ecde7cc15d9f79efbce5bf

See more details on using hashes here.

File details

Details for the file thumbleweed-0.1.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 46a3bae380c751cfee90b9ba40e79958e7cb8f4dd609bd38c631c0308c25310f
MD5 03721973c6d9e03bff77bd4373f716bb
BLAKE2b-256 038789066310f2e0c75765584180dd1a8cf63aa16ab8ded76c3cfb50dd7173de

See more details on using hashes here.

File details

Details for the file thumbleweed-0.1.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 60d1b27d7510d54e3833c5f05fc7441d050154820d34bff052fb01a01795cdc2
MD5 48f1074e1cf46c4ee20b0bdafd679692
BLAKE2b-256 8fa0e061e4f203f7ca98cba022f6d403f61d30330eb3be97efb4ffebaedab267

See more details on using hashes here.

File details

Details for the file thumbleweed-0.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 32709498316a9e27eeb311d1ea829dc537dc221025ba0dc2f648e18972834353
MD5 d09f755049a981e477097436ddd5d839
BLAKE2b-256 1a9844c2bf9e4da79503012f849bb08fc92a95275feac38be3beca50a7633bd5

See more details on using hashes here.

File details

Details for the file thumbleweed-0.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c510ba4cfb85005df1f6d52fcfe313527373dd46fefbc763630bc44ad3d538cb
MD5 371ed5c8e5aa2f942ac379b60da0550d
BLAKE2b-256 e26d48dfad0ff217c18c8449c0a07eed9fdb38ebd2fe6b568caeec6e7efa865c

See more details on using hashes here.

File details

Details for the file thumbleweed-0.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 eefa9ed811c0b1a412156ee5aebba4f7661e740ed7e6ce0509d5c3401f97b671
MD5 d0697b825350756ff1a1bdaea9a3fe47
BLAKE2b-256 ecd834c7605c1e7b1e591c471253804158459980d747fdb6924835813812b285

See more details on using hashes here.

File details

Details for the file thumbleweed-0.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 77a5cbcc86576bfb0aa08cc29d35199713d18165be45e14f428ce9f45f06bf8d
MD5 4b7be00f010baf5c080eb804e8c0f2bd
BLAKE2b-256 4eaf63e04ee47b64aae046074c299baf1b5dd029c15264f19f572af1a86a4b26

See more details on using hashes here.

File details

Details for the file thumbleweed-0.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c36a49ad1356dbc528fd13a070a8b9b730fadb63adccfce6cbf94749f0f25f78
MD5 c5af68521f0ff744bd0f6014e57b277e
BLAKE2b-256 82afa7c660b90486221a11878702e22b063c44f5c891aff245758cf6129ac217

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page