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 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 + palette extraction (drop-in for colorthief & fast-colorthief)
  • ✅ 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

All import paths work:

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

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 / BytesIO

from PIL import Image
import io

# From a Pillow Image
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

# From a BytesIO object
buf = io.BytesIO(open("photo.jpg", "rb").read())
hash_bytes = th.encode_image(buf)

# 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)

ColorThief

import colorthief as ct

# From encoded image bytes (PNG, JPEG, WebP, …)
dominant = ct.get_color(image_bytes)                    # → (r, g, b)
palette = ct.get_palette(image_bytes, color_count=5)   # → [(r, g, b), ...]

# From a file path
dominant = ct.get_color_from_file("photo.jpg")

# From a BytesIO object
import io
buf = io.BytesIO(open("photo.jpg", "rb").read())
dominant = ct.get_color(buf)                # accepts bytes, BytesIO, file path, or PIL Image
palette = ct.get_palette(buf, color_count=5)

# Class-based API (drop-in for the colorthief package)
thief = ct.ColorThief("photo.jpg")
dominant = thief.get_color()
palette = thief.get_palette(color_count=8)

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)

# ColorThief
dominant = thumbleweed.colorthief_get_color_bytes(image_bytes)
palette = thumbleweed.colorthief_get_palette_bytes(image_bytes, 5, 10)

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     # ColorThief — dominant colour & palette extraction
├── python/
│   ├── thumbleweed/      # Main package — re-exports everything
│   ├── thumbhash/        # Backward-compatible ThumbHash shim
│   ├── blurhash/         # BlurHash shim
│   └── colorthief/       # ColorThief shim
├── tests/
│   ├── test_thumbhash.py # 70 ThumbHash tests
│   ├── test_blurhash.py  # 28 BlurHash tests
│   ├── test_colorthief.py # ColorThief tests
│   └── test_imports.py   # 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, bytes, BytesIO, or file path → ThumbHash
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, bytes, BytesIO, or file path → BlurHash
decode_image(hash, w, h) → Image Decode to a Pillow Image (requires Pillow)

ColorThief (import colorthief)

Function Description
get_color(image, quality) → (r,g,b) Dominant colour from bytes, BytesIO, file path, or PIL Image
get_palette(image, color_count, quality) → list[(r,g,b)] Colour palette from bytes, BytesIO, file path, or PIL Image
get_color_from_file(path) → (r,g,b) Dominant colour from a file path
get_palette_from_file(path, color_count, quality) → list[(r,g,b)] Palette from a file path
ColorThief(image) Class-based API — accepts bytes, BytesIO, file path, or PIL Image

Building from source

git clone https://github.com/New-Elysium/thumbleweed.git
cd thumbleweed
make sync   # sync uv environment + install editable
make test   # run Python + Rust tests

Make targets

  • make sync — sync uv environment and install the extension in editable mode
  • make test — run Python tests and Rust tests
  • make dist — build wheels into dist/
  • make upload — upload dist/* with twine

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.4.tar.gz (362.1 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.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (678.7 kB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.17+ x86-64

thumbleweed-0.1.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (679.5 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (678.9 kB view details)

Uploaded CPython 3.13tmanylinux: glibc 2.17+ x86-64

thumbleweed-0.1.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (679.6 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (679.3 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (679.7 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (679.9 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl (725.7 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ i686

thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (647.2 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ARMv7l

thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (649.7 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ARM64

thumbleweed-0.1.4-cp310-cp310-macosx_11_0_arm64.whl (628.2 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

thumbleweed-0.1.4-cp310-cp310-macosx_10_12_x86_64.whl (650.8 kB view details)

Uploaded CPython 3.10macOS 10.12+ x86-64

File details

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

File metadata

  • Download URL: thumbleweed-0.1.4.tar.gz
  • Upload date:
  • Size: 362.1 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.4.tar.gz
Algorithm Hash digest
SHA256 f67f0467adac07fdb220123e20fbd52d50b0917ae101e10d69c2dc36ec569365
MD5 c39e3acf3f8a54c72c50d5a88e6b1d34
BLAKE2b-256 30956ae0d8e2c09a40dc3845bc8a4eb4442d32dd247c3d8d36c29fb214b65e69

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f8d31721bb6a753e059a67d1df3b4e5421d9f070ce60738abcd1f9a72b9e579f
MD5 f1346097c9df0fa779df77115bfa0ff5
BLAKE2b-256 f84bc1088d21f2ed151bd23c0a9d208a193ea2516cd7e77b33854a77d9472fcf

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 cb6d0d9cede10e6e674aa12771deaa831de2541355a010f5a8351df816751700
MD5 381f7ae732e031cb4dcc038d18c33a7a
BLAKE2b-256 426a4e536dea308388cc29d32c69601c7b8b684e52f82d686d9232582603a081

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 72c031c8be5f4b16b823ad460620f81754277786789668d6a94ab124026edd8c
MD5 a84fd95a4e4441b045e4bf5d9e0474c1
BLAKE2b-256 49a130cc7a897f874100d57e9f1630afb6c8d16ff33f6ba5a9972a76856661da

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 17aa85a578ea3c6df18feec776bc9a682c6f2e0c40f12c5f2017dd037a1a798f
MD5 5db0e9f799fcfb8b3f2ec5fbe7321e1e
BLAKE2b-256 90d18666875599bbaa08766d4083ee4aa2032b0e97d0e95acf2c9da67bc041f2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e6fb93583dac318df5e3aed5518e4bb1b531161372f1365cc5b0f8fb27ff0f8e
MD5 614dd0528a7b2d8fbb4e4d1672f2debb
BLAKE2b-256 3a4ba2922f822f1455168be872714baea3224bc5f0c3e2c3e33acaa0b1c5885b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 afb322467fa0fbffc670a6f0a01826f91855e3f26ec1d4d9683ebb0d1830bfd8
MD5 fcb9739d5d83daeab32865c5f391b953
BLAKE2b-256 93b6721504b1bb6ed77b7f38871b9009086167f3a2970e6d8982da1fc918a60a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a2fbde0e9fe3d25a6ab2eb305ed4113d802b45610c1500411afddcb8dd748dc5
MD5 f31400a6bfe6c59ac5ca4468d1ddfb62
BLAKE2b-256 39e1b717e33f9122ac5a7e14f77983b763172d56fc806754323ede73a0dd4446

See more details on using hashes here.

File details

Details for the file thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 cf98efca8500f2f9fae95ca4aedc2d360a88eb683226e1fb5766fff39375f2b8
MD5 9b178add8642ca4ed390bb737a7c61e2
BLAKE2b-256 c9c75d4cfcfb64b51d37c206eb1fb6566e3a61703732e1e90fdbbe79dd52331f

See more details on using hashes here.

Provenance

The following attestation bundles were made for thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl:

Publisher: build-and-publish-wheels.yml on New-Elysium/thumbleweed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 c5e53535003e84c631b91a725694d6963bf60ba06470b8dab0e54014a67c4444
MD5 fd25555a4faf2f8b33ca115cecf8b90c
BLAKE2b-256 d60333d4a31a1d6b728059fe6cf33251317608ed0be15dd5690fcd5304cace31

See more details on using hashes here.

Provenance

The following attestation bundles were made for thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl:

Publisher: build-and-publish-wheels.yml on New-Elysium/thumbleweed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 53c0a238505efb635e24a5da52bb8448f15006bcb6f71205d55779071fd8068b
MD5 9dad0bef44f2b44c3a16d28a922fe13e
BLAKE2b-256 4ec975402302f867083058b2ef7c3fa3315807e35d2fdb86eb2a86f78b099264

See more details on using hashes here.

Provenance

The following attestation bundles were made for thumbleweed-0.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: build-and-publish-wheels.yml on New-Elysium/thumbleweed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file thumbleweed-0.1.4-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 43af05479943b669f8494d2675d0394ec06e96ec9bc30ee7b3c1fa38bfa91045
MD5 99328b94439a065459860f54a1474b9f
BLAKE2b-256 4e6e741de92b0558450725aab982b52cbad83988c50ca0fd67035e8128236a6f

See more details on using hashes here.

Provenance

The following attestation bundles were made for thumbleweed-0.1.4-cp310-cp310-macosx_11_0_arm64.whl:

Publisher: build-and-publish-wheels.yml on New-Elysium/thumbleweed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file thumbleweed-0.1.4-cp310-cp310-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for thumbleweed-0.1.4-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 6f289fc90905699fe622752e6ee41a09365a3e5c032be4764dbcafcd69de281d
MD5 825ffee62025c16bb0aa8b5f2a2c4e9b
BLAKE2b-256 8458b8e21faa1cdbce31bc3ebfcf9417e344891d0119fdf5eff895a2155805db

See more details on using hashes here.

Provenance

The following attestation bundles were made for thumbleweed-0.1.4-cp310-cp310-macosx_10_12_x86_64.whl:

Publisher: build-and-publish-wheels.yml on New-Elysium/thumbleweed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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