handsum

package
v0.4.0-alpha.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 23, 2026 License: Apache-2.0, MIT, Apache-2.0, + 1 more Imports: 7 Imported by: 0

Documentation

Overview

Package handsum implements the Handsum image file format.

This is a very lossy format for very small thumbnails. Very small in terms of image dimensions, up to 16×16 pixels, but also in terms of file size.

The file format has three color settings (1=Gray, 3=RGB and 4=RGBA) and four quality settings. For any given color-and-quality combination, every Handsum image file with those settings is a fixed number of bytes.

For color=1, also known as color=Gray:

  • A quality=1 file is 33 bytes long.
  • A quality=2 file is 51 bytes long.
  • A quality=3 file is 83 bytes long.
  • A quality=4 file is 99 bytes long.

For color=3, also known as color=RGB:

  • A quality=1 file is 48 bytes long.
  • A quality=2 file is 75 bytes long.
  • A quality=3 file is 123 bytes long.
  • A quality=4 file is 147 bytes long.

For color=4, also known as color=RGBA:

  • A quality=1 file is 72 bytes long.
  • A quality=2 file is 99 bytes long.
  • A quality=3 file is 147 bytes long.
  • A quality=4 file is 171 bytes long.

Every Gray/q1 image file is exactly 48 bytes (384 bits) long. For a 16×16 pixel image, this uses 1.5 bits (0.1875 bytes) per pixel.

Every RGB/q4 image file is exactly 147 bytes (1176 bits) long. This uses 4.59375 bits per pixel for a 16×16 pixel image (a 1:1 aspect ratio), or 6.125 bits per pixel for a 16×12 pixel image (a 4:3 aspect ratio).

A Handsum file's starts with a 3 byte header: a 15-bit magic signature, a 2-bit color (Gray, RGB or RGBA), a 2-bit quality and a 5-bit aspect ratio. An image's longest dimension (width or height) is 16 pixels and the aspect ratio gives the shorter dimension.

The color=RGB payload, after the header, holds a scaled 16×16 pixel YCbCr 4:2:0 JPEG MCU (Minimum Coded Unit), 4 Luma and 2 Chroma blocks. Each block is 8×8 pixels.

The color=RGB payload ends with 2 Chroma blocks in 15, 24, 40 or 48 bytes (depending on the quality setting). For a grayscale image, the encoded Chroma blocks' bytes are all 0x88, and the color=Gray payload is just the 4 Luma blocks without explicitly recording the 2 Chroma blocks.

The color=RGBA payload extends the color=RGB payload with one more 8×8 Alpha block. That seventh block is always encoded in 24 bytes (as if quality=4).

Each 8×8 block is sub-divided into 8×8 (for q1), 4×4 (for q2 and q3) or 2×2 (for q4) tiles. DCT (Discrete Cosine Transform) is applied to each tile, producing 64, 16, 16 or 4 DCT coefficients (depending on the quality). Only the 15 (out of 64), 6 (out of 16), 10 (out of 16) or 3 (out of 4) lowest frequency DCT coefficients are kept for each tile. Lowest frequency means the top-left corner in the usual visualization of JPEG's zig-zag ordering.

In percentage terms, the quality setting keeps 23%, 38%, 63% or 75% of the 64 DCT coefficients in each 8×8 block.

Each DCT coefficient is encoded as one nibble (4 bits) with fixed bias and quantization factors.

All Handsum images use the sRGB color profile and non-premultiplied alpha.

The "Handsum" name was inspired by the "Thumbhash" image file format, which is also designed for very small thumbnails (or very compact representations of image placeholders). Handsum files are bigger (but better quality) than Thumbhash. "Handsum" also sounds like "handsome", meaning "good looking".

Other techniques and image formats, similar to Thumbhash, can be found by search for "LQIP" or "Low Quality Image Placeholders".

Index

Constants

View Source
const (
	Magic0 = "\xFE\xD6"
	Magic1 = "\xFE\xD7"
)

MagicEtc is the byte string prefix of every Handsum image file. A Gray image starts with Magic0. An RGB or RGBA image starts with Magic1. The two 16-bit strings only differ in their final bit.

It's like how every JPEG image file starts with "\xFF\xD8".

View Source
const (
	ColorGray = Color(1)
	ColorRGB  = Color(3)
	ColorRGBA = Color(4)
)
View Source
const (
	QualityWorst      = Quality(1)
	QualityMediumLow  = Quality(2)
	QualityMediumHigh = Quality(3)
	QualityBest       = Quality(4)
)
View Source
const MaxDimension = 16

MaxDimension is the maximum (inclusive) width or height of every Handsum image file.

Every image is either (W × 16) or (16 × H) or both, for some positive W or H that is no greater than 16.

Variables

View Source
var (
	ErrBadArgument     = errors.New("handsum: bad argument")
	ErrNotAHandsumFile = errors.New("handsum: not a handsum file")
)

Functions

func Decode

func Decode(r io.Reader) (image.Image, error)

Decode reads a Handsum image from r.

func DecodeConfig

func DecodeConfig(r io.Reader) (image.Config, error)

DecodeConfig reads a Handsum image configuration from r.

func Encode

func Encode(w io.Writer, src image.Image, options *EncodeOptions) error

Encode writes src to w in the Handsum format.

options may be nil, which means to use the default configuration.

Types

type Color

type Color uint8

Color is a Handsum image's color setting, either 1 (Gray), 3 (RGB) or 4 (RGBA).

type EncodeOptions

type EncodeOptions struct {
	// Color is the color setting. The zero value means to use the default,
	// ColorRGB.
	Color Color

	// Quality is the quality-versus-file-size setting. The zero value means to
	// use the default, QualityBest (which is also the largest file size).
	Quality Quality
}

EncodeOptions are optional arguments to Encode. The zero value is valid and means to use the default configuration, encoding to 147 bytes.

type Quality

type Quality uint8

Quality is a Handsum image's quality setting, from 1 (worst) to 4 (best).

"Best" is relative to the other settings. In absolute terms, Handsum's image quality ranges from "potato" (best) to "extremely potato" (worst).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL