moonrgbacolour for MoonBit

Reference

Everything that is public.

One package, one import: moonbitstack/moonrgba. Each entry below is a signature and the reason it is that shape. The signatures are the ones in the interface file; the words are the ones beside the code.

82 entries1 packageApache-2.0

Types

10

The values a colour is made of, and the other types the functions return.

structColor

pub(all) struct Color

A colour: three components in a named space, and an alpha.

Alpha is kept apart from the components because it is not a colour: it says how much of what is behind shows through, and it survives a change of space untouched.

A component may be none, which CSS writes as the none keyword and which this library carries as a NaN — "this space did not say", which interpolation then fills in from the other side. Ordinary arithmetic on such a component gives NaN back, which is the honest answer.

  • space : Space
  • x : Double
  • y : Double
  • z : Double
  • alpha : Double

enumSpace

pub(all) enum Space

The space a colour's three components are read in.

spacexyz
Srgb, SrgbLinear, DisplayP3, Rec2020, A98Rgb, ProPhotoredgreenblue
Hslhue, degreessaturationlightness
Hsvhue, degreessaturationvalue
Hwbhue, degreeswhitenessblackness
Lablightness, 0–100ab
Lchlightness, 0–100chromahue, degrees
Oklablightness, 0–1ab
Oklchlightness, 0–1chromahue, degrees
XyzD50, XyzD65XYZ
YCbCrlumablue differencered difference
Current———

Component ranges are the ones the format itself uses, not a common scale: Lab lightness is 0–100 because that is what lab() writes, while Oklab lightness is 0–1 because that is what oklab() writes. A colour out of its space's range is still a valid value — CSS Color 4 lets a colour be outside its gamut and leaves clipping to the moment it is painted.

  • SrgbGamma-encoded sRGB, components 0–1. The one space every screen has.
  • SrgbLinearLinear-light sRGB, components 0–1: sRGB without the transfer curve.
  • HslHue in degrees, saturation and lightness 0–1.
  • HsvHue in degrees, saturation and value 0–1. No CSS syntax of its own.
  • HwbHue in degrees, whiteness and blackness 0–1.
  • LabCIE Lab, D50. Lightness 0–100, a and b roughly ±125.
  • LchCIE LCh, D50: Lab in polar form, hue in degrees.
  • OklabOklab. Lightness 0–1, a and b roughly ±0.4.
  • OklchOkLCh: Oklab in polar form, hue in degrees.
  • XyzD50CIE XYZ relative to D50, Y = 1 for white.
  • XyzD65CIE XYZ relative to D65, Y = 1 for white. What color(xyz ...) writes.
  • DisplayP3Display P3, components 0–1, sRGB's transfer curve with wider primaries.
  • DisplayP3LinearLinear-light Display P3: P3 without the transfer curve.
  • Rec2020Rec. 2020, components 0–1.
  • A98RgbAdobe RGB (1998), components 0–1.
  • ProPhotoProPhoto RGB, components 0–1, D50 white.
  • YCbCr(Luma)A luma/chroma pair as BT.601, BT.709 or BT.2020 define it. Luma 0–1, chroma −0.5–0.5. No CSS syntax.
  • CurrentNot a space: the currentcolor keyword, which stands for whatever colour the element it is painted on already has. Carried in a Color so that a declaration can be read and written back unchanged; resolve it before converting, with Color::resolve.

Space::code

pub fn Space::code(self : Space) -> String

The identifier this space is written with in CSS, or the one this library uses where CSS has no syntax for it.

Space::has_gamut

pub fn Space::has_gamut(self : Space) -> Bool

Whether a space has a bounded gamut at all. XYZ and the polar spaces do not: every triple is a colour, and only the RGB spaces say which ones a display can show.

Space::is_polar

pub fn Space::is_polar(self : Space) -> Bool

Whether the space writes a hue in its third component (Hsl, Hsv, Hwb) or in its third of a polar pair (Lch, Oklch).

Space::is_predefined

pub fn Space::is_predefined(self : Space) -> Bool

Whether this space can be written inside CSS's color().

Space::of

pub fn Space::of(code : StringView) -> Space?

The space an identifier names, if any.

enumFormat

pub(all) enum Format

How to write a colour out.

  • ShortestThe shortest spelling the colour's own space allows, falling back to sRGB for the spaces CSS has no syntax for.
  • Hex#rgb, #rgba, #rrggbb or #rrggbbaa, whichever is shortest and exact. Always sRGB, so a colour in another space is converted and may be clipped.
  • Rgbrgb(0 0 0) or rgb(0 0 0 / 0.5), always sRGB.
  • Hslhsl(0 0% 0%).
  • Hwbhwb(0 0% 0%).
  • Lablab(0 0 0).
  • Lchlch(0 0 0).
  • Oklaboklab(0 0 0).
  • Oklchoklch(0 0 0).
  • Colorcolor(srgb 0 0 0) and the rest of the spaces color() takes. A space it cannot name is written in its own syntax instead.
  • NamedThe name the colour has, or the same string Hex would give.

enumDelta

pub(all) enum Delta

Which colour difference to measure. The name is the question, not the space: three of these are computed in Lab and one in Oklab.

  • E76CIE76: the Euclidean distance in Lab, which is 1976's answer.
  • E94CIE94, with the graphic-arts weights: 1 for lightness, 1 for chroma, 1 for hue. The textile weights (2, 1, 1) are a different question.
  • E2000CIEDE2000, the current CIE recommendation, with all three weights at 1.
  • OkThe Euclidean distance in Oklab, which needs no weights to be even.

enumHue

pub(all) enum Hue

Which way round the hue circle an interpolation travels.

  • ShorterThe way that is at most half a turn: 350° to 10° goes through 0°.
  • LongerThe way that is at least half a turn.
  • IncreasingAlways increasing, so 350° to 10° goes through 360°.
  • DecreasingAlways decreasing.

enumLuma

pub(all) enum Luma

Which luma coefficients a YCbCr colour uses.

The three differ only in how much of each primary counts as brightness, and a value converted with the wrong one is visibly off, so the choice is part of the value rather than a global setting.

  • Bt601BT.601: the coefficients of SD television.
  • Bt709BT.709: the coefficients of HD television, and of sRGB in practice.
  • Bt2020BT.2020: the coefficients of UHD television, on wider primaries.

structCmyk

pub(all) struct Cmyk

CMYK for print, as four inks in 0–1.

The conversion is the arithmetic one — full black is all key, and the other three inks spread what is left — not the one an ICC profile for a particular press and paper would give.

Four inks do not fit in three channels, so the arithmetic has to choose: for one colour there are many ink combinations, and to_cmyk returns the one with as much key as possible, which is the usual choice because key ink is cheap and the three colour inks are not. That means a colour survives the round trip but its inks may not: cmyk(0.2 0.4 0.6 0.1) prints the same colour as cmyk(0 0.25 0.5 0.28), and only the second comes back.

  • c : Double
  • m : Double
  • y : Double
  • k : Double

Cmyk::of

pub fn Cmyk::of(c : Double, m : Double, y : Double, k : Double) -> Cmyk

Four inks. Nothing is clamped here: an ink of 1.2 is a number no press can lay down, and deciding that is the printer's business rather than the type's. to_color clamps on the way back out, so the arithmetic stays total.

Cmyk::to_color

pub fn Cmyk::to_color(self : Cmyk, alpha? : Double) -> Color

A colour from CMYK inks, in sRGB.

enumAnsi16

pub(all) enum Ansi16

The sixteen colours a terminal names, in the order their escape sequences number them.

  • Black
  • Red
  • Green
  • Yellow
  • Blue
  • Magenta
  • Cyan
  • White
  • BrightBlack
  • BrightRed
  • BrightGreen
  • BrightYellow
  • BrightBlue
  • BrightMagenta
  • BrightCyan
  • BrightWhite

Ansi16::code

pub fn Ansi16::code(self : Ansi16) -> Int32

Where a named colour sits in the palette, which is also the low nibble of the escape sequence that selects it.

Ansi16::color

pub fn Ansi16::color(self : Ansi16) -> Color

The sRGB colour of a named slot: xterm's defaults.

Ansi16::of

pub fn Ansi16::of(code : Int32) -> Ansi16?

The colour a palette slot stands for, if the number names one.

structAnsi256

pub(all) struct Ansi256

A slot in the 256-colour palette: 0–15 are the named colours, 16–231 a 6×6×6 cube, and 232–255 a grey ramp.

  • code : Int320–255. Kept in range by Ansi256::of; written by hand it is a number a terminal would mask, so nothing here trusts it to be inside.

Ansi256::code

pub fn Ansi256::code(self : Ansi256) -> Int32

The number to put in an escape sequence.

Ansi256::color

pub fn Ansi256::color(self : Ansi256) -> Color

The colour a slot stands for.

Ansi256::of

pub fn Ansi256::of(code : Int32) -> Ansi256

The palette slot with this number. Numbers outside 0–255 are clamped rather than wrapped, so that an out-of-range number lands on the nearest end rather than on a colour that is nothing like it.

suberrorRefused

pub(all) suberror Refused

Why a string is not a CSS colour.

  • Unexpected(at~ : Int32, got~ : String, want~ : String)The text did not continue the way the syntax required, at this offset.
  • Unknown(at~ : Int32, got~ : String)A function or keyword that is valid CSS but not a colour this library knows, at this offset.

Making a colour

22

One constructor per space, each taking that space's own units. The colour stays in the space it was made in, so it is written back in that space.

methodColor::black

pub fn Color::black() -> Color

Black in sRGB.

methodColor::white

pub fn Color::white() -> Color

White in sRGB.

methodColor::transparent

pub fn Color::transparent() -> Color

transparent: black with no alpha at all. Not a space of its own, because what shows through is decided by the backdrop, not by the colour.

methodColor::current

pub fn Color::current() -> Color

The currentcolor keyword.

methodColor::rgb

pub fn Color::rgb( red : Int32, green : Int32, blue : Int32, alpha? : Double, ) -> Color

sRGB from bytes, 0–255, which is how a colour usually arrives from a file, a theme or a terminal.

methodColor::srgb

pub fn Color::srgb( r : Double, g : Double, b : Double, alpha? : Double, ) -> Color

sRGB from components in 0–1.

methodColor::srgb_linear

pub fn Color::srgb_linear( r : Double, g : Double, b : Double, alpha? : Double, ) -> Color

Linear-light sRGB from components in 0–1.

methodColor::hsl

pub fn Color::hsl(h : Double, s : Double, l : Double, alpha? : Double) -> Color

HSL: hue in degrees, saturation and lightness in 0–1.

methodColor::hsv

pub fn Color::hsv(h : Double, s : Double, v : Double, alpha? : Double) -> Color

HSV: hue in degrees, saturation and value in 0–1.

methodColor::hwb

pub fn Color::hwb(h : Double, w : Double, b : Double, alpha? : Double) -> Color

HWB: hue in degrees, whiteness and blackness in 0–1.

methodColor::lab

pub fn Color::lab(l : Double, a : Double, b : Double, alpha? : Double) -> Color

CIE Lab with a D50 white: lightness 0–100.

methodColor::lch

pub fn Color::lch(l : Double, c : Double, h : Double, alpha? : Double) -> Color

CIE LCh with a D50 white: lightness 0–100, hue in degrees.

methodColor::oklab

pub fn Color::oklab( l : Double, a : Double, b : Double, alpha? : Double, ) -> Color

Oklab: lightness 0–1.

methodColor::oklch

pub fn Color::oklch( l : Double, c : Double, h : Double, alpha? : Double, ) -> Color

OkLCh: lightness 0–1, hue in degrees.

methodColor::display_p3

pub fn Color::display_p3( r : Double, g : Double, b : Double, alpha? : Double, ) -> Color

Display P3, components in 0–1.

methodColor::rec2020

pub fn Color::rec2020( r : Double, g : Double, b : Double, alpha? : Double, ) -> Color

Rec. 2020, components in 0–1.

methodColor::a98_rgb

pub fn Color::a98_rgb( r : Double, g : Double, b : Double, alpha? : Double, ) -> Color

Adobe RGB (1998), components in 0–1.

methodColor::prophoto

pub fn Color::prophoto( r : Double, g : Double, b : Double, alpha? : Double, ) -> Color

ProPhoto RGB, components in 0–1, D50 white.

methodColor::xyz_d50

pub fn Color::xyz_d50( x : Double, y : Double, z : Double, alpha? : Double, ) -> Color

CIE XYZ relative to D50, Y = 1 for white.

methodColor::xyz_d65

pub fn Color::xyz_d65( x : Double, y : Double, z : Double, alpha? : Double, ) -> Color

CIE XYZ relative to D65, Y = 1 for white.

methodColor::ycbcr

pub fn Color::ycbcr( y : Double, cb : Double, cr : Double, luma? : Luma, alpha? : Double, ) -> Color

YCbCr: luma in 0–1, chroma in −0.5–0.5.

methodColor::of

pub fn Color::of( space : Space, x : Double, y : Double, z : Double, alpha? : Double, ) -> Color

A colour in any space, from components already in that space's own units.

The named constructors below cover the common spaces; this one is for the rest, and for code that picks a space at run time.

Reading and writing

5

CSS in, CSS out, and the name table in both directions.

methodColor::decode

pub fn Color::decode(text : StringView) -> Color raise Refused

A <color>: everything from the first non-blank to the closing bracket.

methodColor::decode_opt

pub fn Color::decode_opt(text : StringView) -> Color?

Read a colour, or None where the text is not one.

methodColor::encode

pub fn Color::encode(self : Color, format? : Format) -> String

A colour as CSS, in the shortest spelling that reads back as the same colour.

Without a format the colour stays in the space it is in, which matters: an OkLCh colour written through sRGB would be clipped to a gamut it never asked for. The spaces CSS cannot spell — HSV, YCbCr — go out as sRGB, and the unresolved currentcolor goes out as itself.

methodColor::of_name

pub fn Color::of_name(name : StringView) -> Color?

The colour a CSS keyword names, or None if it names nothing.

transparent and currentcolor are not here: one is a colour with no alpha and the other is not a colour yet, and both are handled where a declaration is read rather than in the table of names.

methodColor::name

pub fn Color::name(self : Color) -> String?

The name this colour has, if it has one, and the shortest such name where several do: aqua and cyan are the same colour, and four letters beat four letters only by coming first in the table.

A colour that is not one of the 148 opaque names has no name, however close it looks: a name is a spelling, not an approximation.

Converting

18

One method per destination space, and to_space for a space known only at run time. A conversion is exact in both directions.

methodColor::to_srgb

pub fn Color::to_srgb(self : Color) -> Color

sRGB, components 0–1.

methodColor::to_srgb_linear

pub fn Color::to_srgb_linear(self : Color) -> Color

Linear-light sRGB, components 0–1.

methodColor::to_hsl

pub fn Color::to_hsl(self : Color) -> Color

HSL: hue in degrees, saturation and lightness 0–1.

methodColor::to_hsv

pub fn Color::to_hsv(self : Color) -> Color

HSV: hue in degrees, saturation and value 0–1.

methodColor::to_hwb

pub fn Color::to_hwb(self : Color) -> Color

HWB: hue in degrees, whiteness and blackness 0–1.

methodColor::to_oklab

pub fn Color::to_oklab(self : Color) -> Color

Oklab, lightness 0–1.

methodColor::to_oklch

pub fn Color::to_oklch(self : Color) -> Color

OkLCh, lightness 0–1.

methodColor::to_lab

pub fn Color::to_lab(self : Color) -> Color

CIE Lab relative to D50, lightness 0–100.

methodColor::to_lch

pub fn Color::to_lch(self : Color) -> Color

CIE LCh relative to D50, lightness 0–100.

methodColor::to_xyz_d65

pub fn Color::to_xyz_d65(self : Color) -> Color

CIE XYZ relative to D65, Y = 1 for white.

methodColor::to_xyz_d50

pub fn Color::to_xyz_d50(self : Color) -> Color

CIE XYZ relative to D50, Y = 1 for white.

methodColor::to_display_p3

pub fn Color::to_display_p3(self : Color) -> Color

Display P3, components 0–1.

methodColor::to_rec2020

pub fn Color::to_rec2020(self : Color) -> Color

Rec. 2020, components 0–1.

methodColor::to_a98_rgb

pub fn Color::to_a98_rgb(self : Color) -> Color

Adobe RGB (1998), components 0–1.

methodColor::to_prophoto

pub fn Color::to_prophoto(self : Color) -> Color

ProPhoto RGB, components 0–1.

methodColor::to_cmyk

pub fn Color::to_cmyk(self : Color) -> Cmyk

The colour as four inks: the arithmetic conversion, through sRGB, taking as much key as the colour allows. Black is all key, and a white has none.

This is the inverse of Cmyk::to_color for the colour but not for the inks — the note on Cmyk says why, and the platform test that reads it back says it in numbers.

methodColor::to_ycbcr

pub fn Color::to_ycbcr(self : Color, luma~ : Luma) -> Color

YCbCr with the given luma coefficients: luma 0–1, chroma −0.5–0.5.

methodColor::to_space

pub fn Color::to_space(self : Color, space : Space) -> Color

The same colour in another space.

This is the one conversion every to_* goes through, so that a pair of spaces is only ever defined once. Converting to the space a colour is already in returns it unchanged rather than round-tripping it through a hub, which would otherwise cost a matrix inversion for nothing.

Components

9

The three numbers, read and replaced. A colour keeps its space, so reading a component gives the number that space uses.

methodColor::components

pub fn Color::components(self : Color) -> (Double, Double, Double)

The three components, in the order the space writes them.

methodColor::with_components

pub fn Color::with_components( self : Color, x : Double, y : Double, z : Double, ) -> Color

The same colour with different components, in the same space.

methodColor::with_alpha

pub fn Color::with_alpha(self : Color, alpha : Double) -> Color

The same colour at a different alpha.

methodColor::hue

pub fn Color::hue(self : Color) -> Double

The hue in degrees, or NaN where the space has none.

methodColor::lightness

pub fn Color::lightness(self : Color) -> Double

The lightness, or NaN where the space has none.

methodColor::saturation

pub fn Color::saturation(self : Color) -> Double

The saturation, or NaN where the space has none.

methodColor::chroma

pub fn Color::chroma(self : Color) -> Double

The chroma, or NaN where the space has none.

methodColor::is_current

pub fn Color::is_current(self : Color) -> Bool

Whether this is the unresolved currentcolor keyword.

methodColor::resolve

pub fn Color::resolve(self : Color, current : Color) -> Color

Substitute the colour that currentcolor stands for. Anything else is returned unchanged, so this is safe to call on every colour.

Gamut

3

Whether a colour fits, and what to do about it when it does not.

methodColor::in_gamut

pub fn Color::in_gamut(self : Color, space? : Space) -> Bool

Whether the colour is inside the gamut of its space, or of space if one is given.

A space with no gamut answers true: there is nothing for a colour to be outside of.

methodColor::to_gamut

pub fn Color::to_gamut(self : Color, space? : Space) -> Color

The colour brought into the gamut of its space, or of space if one is given, by CSS Color 4's chroma reduction.

A colour already inside comes back unchanged, in the space asked for. One outside loses chroma at constant lightness and hue until it fits, and only in the cases where that cannot work — a colour too light or too dark to exist at all — falls back to clipping.

methodColor::clip

pub fn Color::clip(self : Color, space? : Space) -> Color

The colour with every component clamped into 0–1 of its space, which is what a display does with a colour it cannot show.

Clipping is a blunt instrument: it moves a colour along whichever axis overflows and leaves hue and lightness to follow. to_gamut is the answer that keeps them; this is the answer that costs nothing, and the one to use when the colour is already close to the edge.

Mixing and adjusting

6

color-mix() and the four verbs that move one quantity.

methodColor::mix

pub fn Color::mix( self : Color, other : Color, space? : Space, hue? : Hue, weight? : Double, ) -> Color

A mix of two colours, as color-mix() defines one.

weight is how much of this colour the result has: 0.3 means three parts of this and seven of other, which is what color-mix(in oklab, this 30%, other) writes. It defaults to half.

The result is in the interpolation space, not in the space either colour came from: mixing in Oklab and then converting back to sRGB would lose the out-of-gamut values the mix produced, and to_gamut is the caller's decision to make.

A missing component — none — takes the other colour's value before the mix, so that oklch(none 0.1 200) mixed with a colour that has a lightness interpolates that lightness rather than treating the gap as zero.

currentcolor is not mixed: it stands for a colour nobody has resolved yet, and the result would be a colour that pretends to know.

methodColor::lighten

pub fn Color::lighten(self : Color, amount : Double) -> Color

Move the colour towards white by amount, a fraction of its space's lightness scale: 0.1 in HSL is a tenth of the way to white, 10 in Lab is ten units of lightness.

Hue and chroma are kept, so this is not the same as mixing with white: a mix with white washes the chroma out as well.

methodColor::darken

pub fn Color::darken(self : Color, amount : Double) -> Color

Move the colour towards black by amount, a fraction of its space's lightness scale.

methodColor::saturate

pub fn Color::saturate(self : Color, amount : Double) -> Color

Add chroma, by amount of the space's chroma scale: 0.1 is a tenth of the chroma a colour can have before it leaves what people can see.

A colour already at the edge of its gamut gains nothing visible from this; to_gamut afterwards is what says so.

methodColor::desaturate

pub fn Color::desaturate(self : Color, amount : Double) -> Color

Take chroma away, by amount of the space's chroma scale. At 1 the colour is grey.

methodColor::fade

pub fn Color::fade(self : Color, amount : Double) -> Color

The same colour with less alpha, by amount of what it has: 0.25 leaves three quarters.

Measuring

4

Two contrast measures and four colour differences, each on its own scale.

methodColor::contrast

pub fn Color::contrast(self : Color, other : Color) -> Double

The WCAG 2 contrast ratio between two colours: 1 for the same colour, 21 for black on white.

The order does not matter — this is the measure that is symmetric, and that is one of the reasons APCA exists.

methodColor::apca

pub fn Color::apca(self : Color, background : Color) -> Double

The APCA lightness contrast Lc of this colour as text on background: positive for dark text on a light background, negative the other way round, and zero when the pair is too close to read at all.

The constants are APCA 0.98G-4g, the version the SAPC project publishes for web use. A sign-flipped result is not a mistake: it says which way round the pair is, and the thresholds for readable text are different in each direction, so a caller that wants "is this readable" has to ask about a specific way round.

methodColor::luminance

pub fn Color::luminance(self : Color) -> Double

Relative luminance per WCAG 2: sRGB made linear, weighted by the eye's sensitivity to each primary, with the components clamped to what a screen can show.

methodColor::delta_e

pub fn Color::delta_e(self : Color, other : Color, delta? : Delta) -> Double

The distance between two colours, by the chosen measure.

Colours in any space are converted to the one the measure is defined on, so delta_e answers about the colours, not about where they are written. Opaque alpha plays no part: this is a distance between colours, and a colour at 10% opacity is the same colour as one at 100%.

A terminal

3

The nearest named colour, the nearest slot of the 256, and the three bytes of true colour.

methodColor::to_ansi16

pub fn Color::to_ansi16(self : Color) -> Ansi16

The named slot closest to this colour by ΔE OK.

methodColor::to_ansi256

pub fn Color::to_ansi256(self : Color) -> Ansi256

The slot of the 256-colour palette closest to this colour by ΔE OK.

methodColor::rgb8

pub fn Color::rgb8(self : Color) -> (Int32, Int32, Int32)

The colour as the three bytes a true-colour escape sequence carries, 0–255 each, clipped the way a terminal clips.

The name table

2

The 148 names CSS defines, in the order the table keeps them.

fnnames_all

pub fn names_all() -> Array[StringView]

All the names, in the order the table keeps them.

fnnames_count

pub fn names_count() -> Int32

The number of names, which CSS Color 4 fixes at 148.