Skip to main content

Strings, hex and named colors

There are two parsers with different reach. Hex (plt_from_hex, plt_to_hex) is palette's own reader and writer: compact, strict, no color names. CSS (plt_css_parse, plt_css_serialize) goes through csscolorparser and understands the full CSS Color Level 4 grammar, including lab(), oklch() and color(display-p3 …).

Both parsers produce sRGB colors, because both formats encode sRGB. Nothing ever returns an oklch value from a string: parse first, then plt_convert if you want another space.

Hex​

plt_from_hex(text)​

Signature: plt_from_hex(text VARCHAR) -> plt_color

Parses #rgb, #rgba, #rrggbb or #rrggbbaa; the leading # is optional. Short forms expand each digit by duplication (#f80 is #ff8800), and a 4- or 8-digit value carries alpha. Text that is not a hex color returns NULL, not an error — so it composes with WHERE and COALESCE:

SELECT plt_to_hex(plt_from_hex('#f80')) AS short,
plt_to_hex(plt_from_hex('#ff800080')) AS with_alpha,
plt_to_hex(plt_from_hex('ff8000')) AS without_hash,
plt_from_hex('orange') IS NULL AS unknown_is_null;

plt_to_hex(color)​

Signature: plt_to_hex(color plt_color) -> VARCHAR

Converts to sRGB, quantizes to 8 bits per channel and writes #rrggbb; when alpha is not exactly 1 it writes #rrggbbaa instead. Out-of-gamut components are clamped, so this is always a valid hex string:

SELECT plt_to_hex(plt_srgb(1, 0.5, 0)) AS orange,
plt_to_hex(plt_color('srgb', 1, 0.5, 0, 0.5)) AS translucent,
plt_to_hex(plt_oklch(0.7, 0.1, 120)) AS from_oklch;

plt_to_hex6(color) and plt_to_hex8(color)​

Signature: plt_to_hex6(color plt_color) -> VARCHAR Signature: plt_to_hex8(color plt_color) -> VARCHAR

Fixed-width variants of plt_to_hex: plt_to_hex6 always writes six digits and drops alpha, and plt_to_hex8 always writes eight and includes it. Use these when the consumer requires one width, instead of switching on whether the color happens to be opaque:

SELECT plt_to_hex6(plt_color('srgb', 1, 0, 0, 0.5)) AS six,
plt_to_hex8(plt_srgb(1, 0, 0)) AS eight;

CSS syntax​

plt_css_parse(text)​

Signature: plt_css_parse(text VARCHAR) -> plt_color

Parses any CSS Color Level 4 color into an sRGB color with alpha. That covers named colors, all hex forms, rgb(), rgba(), hsl(), hsla(), hwb(), lab(), lch(), oklab(), oklch() and color(...) with the usual color spaces. Separators may be commas or spaces, and the alpha may be a number or a percentage.

Unparsable text returns NULL:

SELECT plt_to_hex(plt_css_parse('hsl(120 100% 50% / 0.5)')) AS hsl,
plt_to_hex(plt_css_parse('rgb(255, 128, 0)')) AS rgb,
plt_to_hex(plt_css_parse('oklch(0.7 0.15 250)')) AS oklch,
plt_css_parse('not a color') IS NULL AS invalid_is_null;

plt_css_is_valid(text)​

Signature: plt_css_is_valid(text VARCHAR) -> BOOLEAN

Whether plt_css_parse would succeed. Use it to validate a column before parsing, or to keep the invalid rows visible in a report:

SELECT plt_css_is_valid('#ff0000') AS hex_ok,
plt_css_is_valid('rgb(300 0 0)') AS clampable,
plt_css_is_valid('rgb(nope)') AS broken;

plt_css_serialize(color, format)​

Signature: plt_css_serialize(color plt_color, format VARCHAR) -> VARCHAR

Writes a color as CSS text, converting to sRGB first. The eight formats are the eight functions csscolorparser offers: hex, rgb, hsl, hwb, lab, lch, oklab, oklch.

SELECT plt_css_formats() AS formats;
SELECT plt_css_serialize(plt_srgb(1, 0.5, 0), 'hex') AS hex,
plt_css_serialize(plt_srgb(1, 0.5, 0), 'rgb') AS rgb,
plt_css_serialize(plt_srgb(1, 0.5, 0), 'oklch') AS oklch,
plt_css_serialize(plt_srgb(1, 0.5, 0), 'lab') AS lab;

A full round trip through CSS text stays in sRGB and keeps alpha:

SELECT plt_css_parse(plt_css_serialize(c, 'oklch')) AS reparsed,
plt_to_hex(plt_css_parse(plt_css_serialize(c, 'oklch'))) AS hex
FROM (SELECT plt_color('srgb', 0.2, 0.4, 0.6, 0.5) AS c);

An unknown format fails the statement:

SELECT plt_css_serialize(plt_srgb(1, 0, 0), 'hsv');

plt_css_name(color)​

Signature: plt_css_name(color plt_color) -> VARCHAR

The CSS keyword whose sRGB bytes exactly match the color, or NULL when no keyword matches. It is an exact-match lookup, not a nearest-name search — most colors have no name:

SELECT plt_css_name(plt_srgb(1, 0, 0)) AS red,
plt_css_name(plt_named('rebeccapurple')) AS purple,
plt_css_name(plt_srgb(0.2, 0.4, 0.6)) IS NULL AS unnamed;

plt_css_formats()​

Signature: plt_css_formats() -> VARCHAR[]

The eight format names accepted by plt_css_serialize.

More output formats​

plt_to_percentage_rgb and plt_to_hsv_string are tinycolor's two extra writers. Both convert to sRGB, round channel percentages and hues to whole numbers and alpha to two decimals, and switch to the alpha form when alpha is not exactly 1 — so the text is stable enough for display and logging.

plt_to_percentage_rgb(color)​

Signature: plt_to_percentage_rgb(color plt_color) -> VARCHAR

rgb(100%, 50%, 0%), or rgba(…, 0.5) when translucent.

SELECT plt_to_percentage_rgb(plt_srgb(1, 0.5, 0)) AS opaque,
plt_to_percentage_rgb(plt_with_alpha(plt_srgb(1, 0.5, 0), 0.5)) AS translucent;

plt_to_hsv_string(color)​

Signature: plt_to_hsv_string(color plt_color) -> VARCHAR

hsv(0, 100%, 100%), or hsva(…) when translucent. CSS itself has no HSV notation; this is the tinycolor spelling, useful when the text is consumed by a design tool rather than a browser.

SELECT plt_to_hsv_string(plt_srgb(1, 0, 0)) AS opaque,
plt_to_hsv_string(plt_with_alpha(plt_srgb(0, 0.5, 1), 0.25)) AS translucent;

Named colors​

plt_named(name)​

Signature: plt_named(name VARCHAR) -> plt_color

One of palette's 148 SVG/CSS3 keyword colors, as an opaque sRGB color. Matching is case-insensitive. An unknown name returns NULL:

SELECT plt_to_hex(plt_named('rebeccapurple')) AS purple,
plt_to_hex(plt_named('Gold')) AS gold,
plt_named('notacolor') IS NULL AS unknown_is_null;

plt_nearest_named(color)​

Signature: plt_nearest_named(color plt_color) -> VARCHAR

The closest of the 148 keyword colors, measured with CIEDE2000 — the opposite of the exact-match plt_css_name. It always returns a name, so it is the one to use for human-readable labels or for "snap this palette to named colors". Ties break alphabetically.

SELECT plt_nearest_named(plt_srgb(1, 0, 0)) AS red,
plt_nearest_named(plt_srgb(0.99, 0.01, 0.02)) AS almost_red,
plt_nearest_named(plt_oklch(0.7, 0.1, 150)) AS from_oklch,
plt_css_name(plt_srgb(0.99, 0.01, 0.02)) IS NULL AS no_exact_name;

plt_named_names()​

Signature: plt_named_names() -> VARCHAR[]

Every keyword name, sorted alphabetically. Use it to build a reference table without copying the list into your SQL:

SELECT list_count(plt_named_names()) AS count,
plt_named_names() AS names;
SELECT name, plt_to_hex(plt_named(name)) AS hex
FROM unnest(plt_named_names()) t(name)
WHERE name IN ('red', 'green', 'blue', 'rebeccapurple');

Which function do I want?​

Input or outputFunction
A hex string from a database columnplt_from_hex
A CSS color from a stylesheet or APIplt_css_parse
A short hex string for displayplt_to_hex
A hex string that is always 6 or always 8 digitsplt_to_hex6 / plt_to_hex8
A specific CSS function, e.g. oklch(...)plt_css_serialize
Percentage rgb() or hsv() textplt_to_percentage_rgb / plt_to_hsv_string
One of the 148 keyword colorsplt_named / plt_named_names
The keyword name of a color, exactly matchingplt_css_name
The closest keyword nameplt_nearest_named
Whether text is a valid CSS colorplt_css_is_valid