Skip to content

Instantly share code, notes, and snippets.

@kurahaupo
Created January 10, 2016 07:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kurahaupo/ee67381bc1ca58b6b2ba to your computer and use it in GitHub Desktop.
Save kurahaupo/ee67381bc1ca58b6b2ba to your computer and use it in GitHub Desktop.
Xterm Colour test pattern
#!/usr/bin/perl
use 5.008;
use strict;
use warnings;
use Getopt::Long qw(:config bundling);
use POSIX qw( floor );
use utf8;
my $as_list;
my $as_orig;
my $compact;
my $define_colours = 0;
my $gamma = 0;
my $numeric_ordering;
my $show_ansi = 1;
my $show_cube = 1;
my $show_gray = 1;
my $show_help;
my $show_hex;
my $show_sys = 1;
my $transpose;
my $use_padding;
sub N($) { my $r = \@_; if ($r->[0] && ref $r->[0] eq 'CODE') { sub { $r->[0]->( $_[0], ! $_[1] ) } } else { sub { $r->[0] = ! $_[1] } } }
sub ALL(@) { my $r = \@_; sub { $_ = $_[1] for @$r } }
GetOptions
'A|hide-ansi!' => N$show_ansi,
'a|show-ansi|ansi!' => \$show_ansi,
'f|full!' => N$compact,
'b|brief!' => \$compact,
'C|hide-cube!' => N$show_cube,
'c|show-cube|cube!' => \$show_cube,
'D!' => N$define_colours,
'd|define-colours!' => \$define_colours,
'G|hide-gray!' => N$show_gray,
'g|show-gray|gray!' => \$show_gray,
'l|as-list|list' => \$as_list,
'o|as-orig|orig' => \$as_orig,
'p|padding' => \$use_padding,
'r|t|transpose:+' => \$transpose,
'S|hide-sys!' => N$show_sys,
's|show-sys|sys!' => \$show_sys,
'V|hide-all' => N ALL($show_sys, $show_ansi, $show_cube, $show_gray),
'v|show-all|all' => ALL($show_sys, $show_ansi, $show_cube, $show_gray),
'x|show-hex|hex!' => \$show_hex,
'X|hide-hex|decimal!' => N$show_hex,
'Z|Γ|linear' => N$gamma,
'z|γ|gamma=f' => \$gamma,
'h|help' => sub { print <<EndOfHelp; exit 0; } or exit 64;
\e[0m*******************************
* XTERM 256-colour Test Chart *
*******************************
Usage: $0 [-w] [-l|-r] [-s] [-tN]
-d (-D) do (don't) send colour definitions to terminal
-z -γ gamma correction factor
-l list display
-p extra spaces padding
-rN -tN rotate (transpose) N∈{0,1,2,3,4,5}
-zGAMMA use gamma-corrected scale rather than standard offset linear
-Z use standard offset linear rather than gamme-corrected scale
Cube colour range:
16 = black
231 = white
Grayscale colour range:
232 = very dark gray
255 = very light gray
EndOfHelp
defined $transpose && $as_list and die "Can't use both --transpose and --as-list\n";
$transpose ||= 0;
my $num_fmt = $show_hex ? '%2x' : '%-3u';
sub round($) { floor(0.5+$_[0]) }
my @scale6 = map { $_*51 } 0 .. 5;
my @scale24 = map { round($_ * 255 / 25) } 1 .. 24;
if (!$gamma) {
# scales used by original xterm-colourtest
@scale6 = map { $_ && 55 + $_ * 40 } 0 .. 5; # 00 5f 87 af d7 ff
@scale24 = map { 8 + $_ * 10 } 0 .. 23; # 08 12 1c 26 30 3a 44 4e 58 62 6c 76 80 8a 94 9e a8 b2 bc c6 d0 da e4 ee
} elsif ($gamma != 1) {
$_ = round(($_ / 255) ** $gamma * 255) for @scale6, @scale24;
}
sub byte2triple($) {
use integer;
my ($v) = @_;
$v < 0 && die "Value '$v' too low";
$v < 8 && return map { $_ ? 0xcc : 0x00 } $v & 1, $v & 2, $v & 4;
$v-= 8;
$v < 8 && return map { $_ ? 0xff : 0x88 } $v & 1, $v & 2, $v & 4;
$v-= 8;
$v < 216 && return map { $scale6[$_] } $v / 36, $v / 6 % 6, $v % 6;
$v-= 216;
$v < 24 && return (($scale24[$v]) x 3);
die "Value '$v' too high";
}
sub triple2byte($$$) {
my ($R,$G,$B) = @_;
my @T = grep { $_ >= 16 && $_ <= 255 }
16,
16+int(($R-75)/40)*36+int(($G-75)/40)*6+int(($G-75)/40),
int(232+($R+$G+$B-9)/30),
231;
my @D = map {
my ($rr,$gg,$bb) = byte2triple $_;
($R-$rr)**2 + ($G-$gg)**2 + ($B-$bb)**2;
} @T;
my @O = sort { $D[$a] <=> $D[$b] } 0 .. $#D;
return $T[$O[0]];
}
sub byte2cell($) {
! $compact ? sprintf "$num_fmt:%02x/%02x/%02x\e[39;49;0m%s",
$_[0],
byte2triple $_[0],
$use_padding ? ' ' : ''
: sprintf "$num_fmt%s", $_[0], $use_padding ? ' ' : ''
}
sub is_dark($) {
my ($v) = @_;
my ($R,$G,$B) = byte2triple $v;
# weigh green more strongly when deciding on inversion
return $R + 3 * $G + $B < 255 * 5 / 2.5; # half of max brightness
}
sub printcell($) {
my ($v) = @_;
printf "\e[%u;48;5;%um%s\e[39;49;0m",
is_dark $v ? 37 : 30,
$v,
byte2cell $v;
}
if ($define_colours) {
for my $byte ( 0 .. 255 ) {
printf "\e]4;%u;rgb:%2.2x/%2.2x/%2.2x\e\\", $byte, byte2triple $byte;
}
}
my ($colour_stride_1, $colour_stride_2, $colour_stride_3) = @{[
[ 36, 6, 1 ], [ 1, 6, 36 ],
[ 1, 36, 6 ], [ 6, 36, 1 ],
[ 6, 1, 36 ], [ 36, 1, 6 ],
]->[$transpose % 6] };
my ($grayscale_stride_1, $grayscale_stride_2) = @{[
[ 6, 1 ],
[ 1, 4 ],
]->[ !$compact && $transpose / 6 % 2 ]};
if ( $as_list ) {
if ($show_ansi) {
for my $v ( 0 .. 15 ) {
printf "\e[7;%u;%u%sm%s\e[39;49;0m\n",
30+($v&7),
is_dark $v ? 47 : 40,
$v & 8 ? ';1' : '',
byte2cell $v;
}
}
my @C;
push @C, 0 .. 15 if $show_sys;
push @C, 16 .. 231 if $show_cube;
push @C, 232 .. 255 if $show_gray;
for my $v ( @C ) {
printcell $v;
print "\n";
}
} elsif ( $as_orig ) {
# This is the original colour-test layout
if ($show_ansi) {
print "ANSI colours:\n";
for my $colour ( 0 .. 7 ) { printf "\e[4%1\$um%1\$-2s", $colour } print "\e[49;0m\n";
for my $colour ( 0 .. 7 ) { printf "\e[1;7;3%1\$um%1\$-2s", $colour } print "\e[49;0m\n\n";
}
if ($show_sys) {
print "Standard colours:\n";
for my $colour ( 0 .. 15 ) { printf "\e[48;5;%um ", $colour; ($colour&7)==7 && print "\e[49;0m\n"; }
print "\n";
}
if ($show_cube) {
# now the colour cube
print "Colour cube, 6x6x6: [$colour_stride_1 $colour_stride_2 $colour_stride_3]\n";
for my $d0 ( 0 .. 5 ) {
for my $d1 ( 0 .. 5) {
for my $d2 ( 0 .. 5) {
my $colour = 16 + $d1 * $colour_stride_1 + $d0 * $colour_stride_2 + $d2 * $colour_stride_3;
print "\e[48;5;${colour}m ";
}
print "\e[49;0m ";
}
print "\n";
}
}
if ($show_gray) {
# now the grayscale ramp
print "Grayscale ramp:\n";
for my $colour ( 232 .. 255 ) {
print "\e[48;5;${colour}m ";
}
print "\e[0m\n";
}
} else {
if ($show_ansi) {
print "ANSI colours:\n";
for my $v ( 0 .. 15 ) {
printf "\e[7;%u;%u%sm%s\e[39;49;0m",
30+($v&7),
is_dark $v ? 47 : 40,
$v & 8 ? ';1' : '',
byte2cell $v;
$as_list || !($v+1 & ($compact?7:3)) and print "\n";
}
print "\n";
}
if ($show_sys) {
print "Standard colours:\n";
for my $v ( 0 .. 15 ) {
printf "\e[%u;48;5;%um%s", is_dark $v ? 37 : 30, $v, byte2cell $v;
$as_list || !($v+1 & ($compact?7:3)) and print "\e[39;49;0m\n";
}
print "\n";
}
if ($show_cube) {
print "Colour cube, 6x6x6: [$colour_stride_1 $colour_stride_2 $colour_stride_3]\n";
for my $d1 ( 0 .. 5 ) {
for my $d2 ( 0 .. 5 ) {
for my $d3 ( 0 .. 5 ) {
my $v = 16 + $d1 * $colour_stride_1 + $d2 * $colour_stride_2 + $d3 * $colour_stride_3;
printcell $v;
#my $z = is_dark $v;
#printf "\e[%u;48;5;%um%s", $z ? 37 : 30, $v, byte2cell $v;
#print "\e[39;49;0m";
$as_list and print "\n";
}
! $as_list and print $compact ? " " : "\n";
}
print "\n";
}
print "\n";
}
if ($show_gray) {
print "Gray-scale:\n";
if ( $as_list || $compact ) {
for my $v ( 232 .. 255 ) {
my $z = is_dark $v;
printf "\e[%u;48;5;%um%s\e[39;49;0m", $z ? 37 : 30, $v, byte2cell $v;
}
} else {
for my $d1 ( 0 .. 3 ) {
for my $d2 ( 0 .. 5 ) {
my $v = 232 + $d1 * $grayscale_stride_1 + $d2 * $grayscale_stride_2;
printcell $v;
#my $z = is_dark $v;
#printf "\e[%u;48;5;%um%s", $z ? 37 : 30, $v, byte2cell $v;
#print "\e[39;49;0m";
$as_list and print "\n";
}
! $as_list && ! $compact and print "\n";
}
print "\n";
}
}
}
print "\e[39;49;0m\n";
exit;
__END__
CSI codes:
0 - plain
1 - bold
2
3
4 - underline
5 - blink
6
7 - inverse
8 - hidden
22 - not bold
24 - not underline
25 - not blink
27 - not inverse
30-37 basic foreground colours
38;5;X extended foreground colour
39 default foreground colour
40-37 basic background colours
48;5;X extended background colour
49 default background colour
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment