# `Color.SRGB`

sRGB color space, using the Lindbloom sRGB working space
(primaries from IEC 61966-2-1, D65 reference white) and the sRGB
companding function.

Channels `r`, `g` and `b` are unit floats in the nominal range `[0, 1]`.
The legacy 0..255 convention is not used — convert with
`scale255/1` / `unscale255/1` if you need 8-bit values.

# `t`

```elixir
@type t() :: %Color.SRGB{
  alpha: number() | nil,
  b: number() | nil,
  g: number() | nil,
  r: number() | nil
}
```

# `from_xyz`

```elixir
@spec from_xyz(Color.XYZ.t()) :: {:ok, t()}
```

Converts a CIE `XYZ` color to sRGB.

This assumes the `xyz` is already in the sRGB working space's reference
white (D65/2°). If your `XYZ` is under a different illuminant, adapt it
with `Color.ChromaticAdaptation` first.

### Arguments

* `xyz` is a `Color.XYZ` struct on the `Y ∈ [0, 1]` scale.

### Returns

* A `Color.SRGB` struct.

### Examples

    iex> xyz = %Color.XYZ{x: 0.95047, y: 1.0, z: 1.08883, illuminant: :D65, observer_angle: 2}
    iex> {:ok, srgb} = Color.SRGB.from_xyz(xyz)
    iex> {Float.round(srgb.r, 4), Float.round(srgb.g, 4), Float.round(srgb.b, 4)}
    {1.0, 1.0, 1.0}

# `parse`

Parses a CSS hex color or CSS named color into an sRGB struct.

Accepts any of the CSS Color Module Level 4 hex forms:

* `#RGB` — 4-bit-per-channel shorthand (e.g. `#f80`).

* `#RGBA` — shorthand with alpha.

* `#RRGGBB` — 8-bit per channel.

* `#RRGGBBAA` — 8-bit per channel with alpha.

The leading `#` is optional. Parsing is case-insensitive. Any other
string is looked up in `Color.CSS.Names`, so named colors like
`"rebeccapurple"` also work.

### Arguments

* `input` is a string.

### Returns

* `{:ok, %Color.SRGB{}}` with unit-range channels.

* `{:error, reason}` if the input can't be parsed.

### Examples

    iex> {:ok, red} = Color.SRGB.parse("#ff0000")
    iex> {red.r, red.g, red.b}
    {1.0, 0.0, 0.0}

    iex> {:ok, c} = Color.SRGB.parse("#f80")
    iex> {c.r, c.g, c.b}
    {1.0, 0.5333333333333333, 0.0}

    iex> {:ok, c} = Color.SRGB.parse("rebeccapurple")
    iex> {c.r, c.g, c.b}
    {0.4, 0.2, 0.6}

    iex> {:ok, c} = Color.SRGB.parse("#ff000080")
    iex> {c.r, c.g, c.b, Float.round(c.alpha, 4)}
    {1.0, 0.0, 0.0, 0.502}

# `scale255`

Scales unit-range sRGB channels to the conventional 0..255 byte range.

### Arguments

* `srgb` is a `Color.SRGB` struct with unit-range channels.

### Returns

* A `{r, g, b}` tuple of floats in `[0, 255]`.

### Examples

    iex> Color.SRGB.scale255(%Color.SRGB{r: 1.0, g: 0.5, b: 0.0})
    {255.0, 127.5, 0.0}

# `to_hex`

Formats an sRGB color as a CSS hex string.

Channels are clamped to `[0, 1]` and rounded to 8 bits. If the alpha
channel is `nil` or `1.0`, a six-digit `#RRGGBB` is produced.
Otherwise an eight-digit `#RRGGBBAA` is produced.

### Arguments

* `srgb` is a `Color.SRGB` struct.

### Returns

* A lowercase hex string starting with `#`.

### Examples

    iex> Color.SRGB.to_hex(%Color.SRGB{r: 1.0, g: 0.0, b: 0.0})
    "#ff0000"

    iex> Color.SRGB.to_hex(%Color.SRGB{r: 1.0, g: 0.5333333, b: 0.0})
    "#ff8800"

    iex> Color.SRGB.to_hex(%Color.SRGB{r: 1.0, g: 0.0, b: 0.0, alpha: 0.5})
    "#ff000080"

# `to_xyz`

```elixir
@spec to_xyz(t()) :: {:ok, Color.XYZ.t()}
```

Converts an sRGB color to a CIE `XYZ` color.

### Arguments

* `srgb` is a `Color.SRGB` struct with unit-range channels.

### Returns

* A `Color.XYZ` struct tagged with the sRGB working space illuminant
  (`:D65`, 2° observer). `Y ∈ [0, 1]`.

### Examples

    iex> {:ok, xyz} = Color.SRGB.to_xyz(%Color.SRGB{r: 1.0, g: 1.0, b: 1.0})
    iex> {Float.round(xyz.x, 4), Float.round(xyz.y, 4), Float.round(xyz.z, 4)}
    {0.9505, 1.0, 1.0888}

# `unscale255`

Builds an sRGB struct from 0..255 byte channels.

### Arguments

* `rgb` is an `{r, g, b}` tuple of numbers in `[0, 255]`.

* `alpha` is an optional alpha value, defaults to `nil`.

### Returns

* A `Color.SRGB` struct with unit-range channels.

### Examples

    iex> Color.SRGB.unscale255({255, 0, 0})
    %Color.SRGB{r: 1.0, g: 0.0, b: 0.0, alpha: nil}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
