BlurHash

repository·master·Indexed 12 days ago

https://github.com/woltapp/blurhash

An encoder and decoder for the Wolt BlurHash algorithm, which converts images into compact, colorful blur strings to serve as placeholders. It provides implementations in JavaScript/TypeScript (v2.0.5), C, Swift, and Kotlin, allowing developers to store small strings in databases and decode them into low-resolution blurry images on the client side to save bandwidth.

Tokens
4K
Snippets
14
Records
23
Agent score
94%

What's inside BlurHash

  1. Overview of BlurHashKit

    master

    BlurHashKit is an advanced, experimental library currently in development. It is designed for more complex BlurHash operations beyond simple encoding and decoding, such as:

    • Testing if specific parts of an image are dark or light.
    • Generating BlurHashes as gradients from corner colors.

    Note: This library is not yet finalized or fully documented. Users should refer to the source files or the BlurHashTest.app implementation to understand its current capabilities.

  2. What is BlurHash and how does it work?

    master

    BlurHash is a compact representation of an image placeholder. It converts an image into a short string (typically 20-30 characters) that can be easily stored in databases or sent via JSON.

    Workflow:

    1. Backend: Encode an image into a BlurHash string and store it alongside the image URL.
    2. Client: Receive the BlurHash string and the image URL.
    3. Client: Decode the string into a small, blurry image to serve as a placeholder while the high-resolution image loads over the network.

    This approach avoids the need to store or transmit actual thumbnail images, saving bandwidth and database space.

  3. Understand the BlurHash string structure

    master

    A BlurHash string is a compact representation of an image's average color and its DCT (Discrete Cosine Transform) components. The string is composed of several parts encoded in a custom Base 83 character set: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~.

    String Layout

    An example string: LlMF%n00%#MwS|WCWEM{R*bbWBbH

    1. Number of components (1 digit): Represents the complexity of the hash. For a hash with nx components along the X axis and ny components along the Y axis, this value is (nx - 1) + (ny - 1) * 9.
    2. Maximum AC component value (1 digit): A scaling factor for AC components. The floating-point value is (max + 1) / 166.
    3. Average colour (4 digits): The average image color in sRGB space, encoded as a 24-bit RGB value (R in the most significant position). This can be used directly to get the average color without full decoding.
    4. AC components (2 digits each): There are nx * ny - 1 components in total. They are ordered by increasing X first, then Y. Each component encodes R, G, and B values (each 0-18) combined as R * 19^2 + G * 19 + B (range 0-6859).
  4. How the BlurHash encoding and decoding works

    master

    BlurHash uses a Discrete Cosine Transform (DCT) to compress image data.

    Encoding Logic

    • The DC component (average color) is stored exactly as an sRGB value.
    • The AC components are encoded lossily.
    • Values are encoded using a custom Base 83 encoding (JSON, HTML, and shell-safe). Multiple-digit values are stored in big-endian order.

    Decoding Logic

    To decode a pixel at normalized position (x, y) (where coordinates range from 0 to 1), calculate the weighted sum of cosine functions for R, G, and B:

    foreach j in 0 ... ny - 1
        foreach i in 0 ... nx - 1
            value = value + Cij * cos(x * i * pi) * cos(y * j * pi)

    Important Color Space Steps:

    1. The DC component (C00) must be converted from sRGB to linear RGB space.
    2. AC components are already in linear space.
    3. After calculating the final R, G, and B values in linear space, convert them back to your output colorspace (usually sRGB).
  5. Configure BlurHash components and the punch parameter

    master

    When working with BlurHash, you can tune the visual output using components and the punch parameter:

    • X and Y Components: These determine how much information is retained. More components result in a more accurate placeholder but a longer string. A common balance is 4x3 components. Adjust the ratio based on the image aspect ratio (e.g., use more X components for very wide images).
    • The punch parameter: This adjusts the contrast of the decoded image.
      • 1: Normal contrast.
      • < 1: More subtle effect.
      • > 1: Stronger, higher contrast effect.
      • Technical note: It works by scaling the AC components up or down.
  6. Integrate BlurHash as a C library

    master

    To use the BlurHash encoder in your C project, include encode.c and encode.h directly. The implementation has no external dependencies, making it suitable for FFI (Foreign Function Interface) integration with other languages.

    #include "encode.h"
    // Include encode.c in your build process
  7. Install standalone BlurHash decoder and encoder in Swift

    master

    To use BlurHash in your iOS project, you can copy the standalone implementation files directly into your project. No external dependency manager is required.

    • For decoding (BlurHash string to UIImage): Copy BlurHashDecode.swift.
    • For encoding (UIImage to BlurHash string): Copy BlurHashEncode.swift.
  8. Optimize BlurHash performance for encoding and decoding

    master

    BlurHash implementations are not highly optimized for large data. To ensure smooth performance, follow these best practices:

    • For Encoding (Backend): Do not run the encoder on full-sized images. Scale the image down to a small size (e.g., a thumbnail) before encoding. The fine detail is discarded anyway, so encoding a smaller image is much faster and produces the same result.
    • For Decoding (Client): Decode the placeholder into a very small image (e.g., 32x32 or even 20x20 pixels) and let the UI layer (CSS, Android/iOS scaling) scale it up to the required size. This is computationally efficient and visually indistinguishable from decoding at full size.
  9. Decode a BlurHash string into a UIImage

    master

    The BlurHashDecode.swift file provides a convenience initializer on UIImage to create a placeholder image from a BlurHash string.

    Initializer Signature: public convenience init?(blurHash: String, size: CGSize, punch: Float = 1)

    Parameters:

    • blurHash: The BlurHash string.
    • size: The requested output size. It is recommended to keep this small (e.g., 32 pixels wide) and allow UIKit to scale it up to avoid performance issues.
    • punch: A Float used to adjust the contrast of the output image. Tweak this value to change the look of your placeholders.

    Returns nil if decoding fails.

    if let image = UIImage(blurHash: "L6PZfSaD00%~00%M00%M00%M00%M", size: CGSize(width: 32, height: 32)) {
        // Use the decoded image
    }