Color.XYZ (Color v0.4.0)

Copy Markdown

CIE 1931 XYZ tristimulus color space.

The struct carries the :illuminant and :observer_angle of the reference white under which the {x, y, z} values are expressed. Y is typically on the [0, 1] scale, with Y = 1.0 at the reference white.

Chromatic adaptation between illuminants is provided by adapt/3, which applies one of the transforms from Color.ChromaticAdaptation.

Summary

Functions

Chromatically adapts an XYZ color from its current reference white to a new reference white.

Applies black point compensation (BPC) to an XYZ color.

Identity conversion from Color.XYZ to Color.XYZ.

Identity conversion โ€” returns the struct wrapped in an :ok tuple.

Types

t()

@type t() :: %Color.XYZ{
  alpha: number() | nil,
  illuminant: atom() | nil,
  observer_angle: 2 | 10 | nil,
  x: number() | nil,
  y: number() | nil,
  z: number() | nil
}

Functions

adapt(xyz, dest_illuminant, options \\ [])

@spec adapt(t(), atom(), keyword()) :: {:ok, t()}

Chromatically adapts an XYZ color from its current reference white to a new reference white.

Arguments

  • xyz is a Color.XYZ struct. Its :illuminant and :observer_angle fields identify the source reference white.

  • dest_illuminant is the target illuminant atom (for example :D65).

  • options is a keyword list.

Options

  • :observer_angle is the target observer angle (2 or 10). Defaults to 2.

  • :method is the chromatic adaptation transform. One of :bradford (default), :xyz_scaling, :von_kries, :sharp, :cmccat2000, or :cat02.

Returns

  • {:ok, %Color.XYZ{}} tagged with the new illuminant and observer angle.

Examples

iex> d50 = %Color.XYZ{x: 0.96422, y: 1.0, z: 0.82521, illuminant: :D50, observer_angle: 2}
iex> {:ok, d65} = Color.XYZ.adapt(d50, :D65)
iex> {Float.round(d65.x, 5), Float.round(d65.y, 5), Float.round(d65.z, 5)}
{0.95047, 1.0, 1.08883}

apply_bpc(xyz, source_bp, dest_bp)

@spec apply_bpc(t(), number(), number()) :: t()

Applies black point compensation (BPC) to an XYZ color.

BPC rescales the XYZ such that the source's darkest reproducible black maps to the destination's darkest reproducible black, so that shadow detail is preserved across profiles with different minimum luminances. Without BPC, converting from a printer profile (whose darkest achievable black might be 3% of white) to a display profile (which can produce pure black) leaves shadows visibly lifted.

The rescale is a linear map along the achromatic axis:

Y_out = (Y_in - k_src) ยท (1 - k_dst) / (1 - k_src) + k_dst

and X / Z are rescaled by the same factor so chromaticity is preserved.

This library does not currently read ICC profiles, so in most workflows both black points default to 0.0 and apply_bpc/3 becomes an identity. It is provided for explicit use in ICC-aware pipelines and for completeness of the rendering-intent API (see Color.convert/3 with bpc: true).

Arguments

  • xyz is a Color.XYZ struct.

  • source_bp is the source black point as a relative luminance (Y) in [0.0, 1.0].

  • dest_bp is the destination black point as a relative luminance.

Returns

  • A new Color.XYZ struct with the compensation applied.

Examples

iex> xyz = %Color.XYZ{x: 0.5, y: 0.5, z: 0.5, illuminant: :D65}
iex> Color.XYZ.apply_bpc(xyz, 0.0, 0.0) == xyz
true

iex> xyz = %Color.XYZ{x: 0.1, y: 0.1, z: 0.1, illuminant: :D65}
iex> out = Color.XYZ.apply_bpc(xyz, 0.05, 0.0)
iex> Float.round(out.y, 6)
0.052632

from_xyz(xyz)

Identity conversion from Color.XYZ to Color.XYZ.

Arguments

Returns

  • {:ok, xyz}.

to_xyz(xyz)

Identity conversion โ€” returns the struct wrapped in an :ok tuple.

Arguments

Returns

  • {:ok, xyz}.