Image.Lqip.Css (image v0.71.0)

Copy Markdown View Source

Encodes an image as an LQIP CSS (Low Quality Image Placeholder) value.

LQIP CSS represents a placeholder as a single 32-bit value packed into an RGBA hex code such as #a1b2c3d4. A static CSS rule then unpacks that value into three colors and paints two radial gradients over a background color, producing a blurred gradient placeholder using only the browser's CSS engine.

This module is the encoder only: it extracts the three colors and returns the packed hex string. The CSS is static and identical for every image.

See the LQIP CSS guide for the copy-and-paste stylesheet.

How it works

The image is resized to a 3x3 thumbnail and three pixels are sampled:

  • the top-left pixel becomes the background color (--lqip-c0)
  • the center pixel becomes the first radial gradient (--lqip-c1)
  • the bottom-right pixel becomes the second radial gradient (--lqip-c2)

Each color is quantized (adjusted for chroma) and bit-packed: the first two into 11 bits (RRRR GGGG BBB) and the third into 10 bits (RRR GGGG BBB). They are then combined into a single 32-bit value rendered as an 8-digit #RRGGBBAA hex string.

Usage

Compute the value once and store it. Then set a CSS variable using inline styles or use a data attribute, and include the LQIP CSS stylesheet:

hex = Image.Lqip.Css.encode!(image)
# => "#a1b2c3d4"

# In your template:
# <img src="photo.jpg" style="--lqip: #a1b2c3d4" />
# or
# <img src="photo.jpg" data-lqip="#a1b2c3d4" />

See the LQIP CSS guide for more usage information.

Chroma-aware packing

Because each channel is packed into only 3 or 4 bits, independent per-channel rounding can give near-grey colors a visible tint. To reduce that, the encoder chooses each color's packed value to be the one closest to the source in the CIELAB space, measured with CIEDE2000 (via Color.Distance.delta_e_2000/3).

This keeps near-greys closer to neutral while still preserving chroma for saturated colors.

Example

iex> image = Image.open!("./test/support/images/Kip_small.jpg")
iex> Image.Lqip.Css.encode(image)
{:ok, "#22333091"}

Summary

Operations

Encodes an image as a packed LQIP hex value.

Encodes an image as a packed LQIP hex value, or raises on error.

Operations

encode(image)

@spec encode(image :: Vix.Vips.Image.t()) ::
  {:ok, String.t()} | {:error, Image.error()}

Encodes an image as a packed LQIP hex value.

Arguments

  • image is any Vix.Vips.Image.t/0. It is converted to the :srgb colorspace before sampling, and any alpha channel is ignored.

Returns

  • {:ok, hex} where hex is an 8-digit #RRGGBBAA string, or

  • {:error, reason}

Example

iex> image = Image.open!("./test/support/images/Kip_small.jpg")
iex> Image.Lqip.Css.encode(image)
{:ok, "#22333091"}

encode!(image)

@spec encode!(image :: Vix.Vips.Image.t()) :: String.t() | no_return()

Encodes an image as a packed LQIP hex value, or raises on error.

See encode/1.

Example

iex> image = Image.new!(32, 32, color: :white)
iex> Image.Lqip.Css.encode!(image)
"#ffffffff"