Skip to content

Commit

Permalink
Improve RGB→256-colour palette interpolation by trying cueb for greys
Browse files Browse the repository at this point in the history
The 6×6×6 colour cube includes gray colours.  Black and white are
already used but the cube also includes other greys such as #5f5f5f
or #d7d7d7.  For those colours it’s better to use colour from the
cube rather than from the grayscale ramp.

Change rgb2ansi_grey to try approximation using coulours in either
section in the pallette and choose the best one.

This only affects 20 colours in total.
  • Loading branch information
mina86 committed Aug 19, 2018
1 parent 1994647 commit 9cd3d80
Showing 1 changed file with 34 additions and 8 deletions.
42 changes: 34 additions & 8 deletions src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,38 @@ fn rgb2ansi(r: u8, g: u8, b: u8) -> u8 {
/// ANSI palette.
#[inline]
fn rgb2ansi_grey(y: u8) -> u8 {
// In the 256-colour ANSI palette grey colours are included in the greyscale
// ramp as well as in the colour cube. Because of this we’re trying to
// approximate grey in both and choose whichever gives better result.

const BLACK: u8 = 16;
const WHITE: u8 = 231;

// The greyscale ramp starts at rgb(8, 8, 8) and steps every rgb(10, 10, 10)
// until rgb(238, 238, 238). We’re adding 6 so that division rounds to
// nearest rather than truncating. Due to asymmetry at the edges those need
// to be handled specially.
// until rgb(238, 238, 238). Due to the asymmetry, edges need to be handled
// separately.
if y < 4 {
BLACK
return BLACK;
} else if y >= 247 {
WHITE
} else {
231 + if y >= 234 { 24 } else { ((y + 6) / 10) as u8 }
return WHITE;
} else if y >= 234 {
return 255;
}

// We’re adding 6 so that division rounds to nearest rather than truncating.
let gi = (y + 6) / 10;

// There’s only a few values in which using colour cube for grey colours is
// better.
if y >= 92 && y <= 216 {
let grey = (gi * 10 - 2) as i32;
let yi = cube_index(y);
if (cube_value(yi) as i32 - y as i32).abs() < (grey - y as i32).abs() {
return 16 + (36 + 6 + 1) * yi;
}
}

gi + 231
}

/// Approximate a 24-bit colour as an index in 6×6×6 colour cube of the
Expand Down Expand Up @@ -58,7 +76,6 @@ fn cube_index(v: u8) -> u8 {

/// Converts index on one dimension of the 6×6×6 ANSI colour cube into value in
/// sRGB space.
#[cfg(test)]
fn cube_value(i: u8) -> u8 {
if i == 0 {
0
Expand Down Expand Up @@ -118,6 +135,15 @@ fn test_rgb2ansi_color() {
assert_eq!(193, rgb2ansi(0xd7, 0xff, 0xaf));
}

#[test]
fn test_rgb2ansi_grey_using_cube() {
// Even though those are grey colours they have a perfect match in the
// colour cube so use that rather than greyscale ramp.
assert_eq!(59, rgb2ansi(0x5f, 0x5f, 0x5f));
assert_eq!(102, rgb2ansi(0x87, 0x87, 0x87));
assert_eq!(145, rgb2ansi(0xaf, 0xaf, 0xaf));
}

#[test]
fn test_rgb2ansi_approx() {
assert_eq!(231, rgb2ansi(0xfe, 0xfe, 0xfe));
Expand Down

0 comments on commit 9cd3d80

Please sign in to comment.