Skip to content

Instantly share code, notes, and snippets.

@zoffixznet
Created January 1, 2020 01:45
Show Gist options
  • Save zoffixznet/4a14b510ac8af02887955139cbe7a7de to your computer and use it in GitHub Desktop.
Save zoffixznet/4a14b510ac8af02887955139cbe7a7de to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
package Color::RGB::Util;
our $DATE = '2019-08-20'; # DATE
our $VERSION = '0.599'; # VERSION
use 5.010001;
use strict;
use warnings;
#use List::Util qw(min);
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
assign_rgb_color
assign_rgb_dark_color
assign_rgb_light_color
int2rgb
mix_2_rgb_colors
mix_rgb_colors
rand_rgb_color
rand_rgb_colors
reverse_rgb_color
rgb2grayscale
rgb2hsv
rgb2hsl
rgb2int
rgb2sepia
rgb_diff
rgb_distance
rgb_is_dark
rgb_is_light
rgb_luminance
tint_rgb_color
);
my $re_rgb = qr/\A#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})\z/;
sub _min {
$_[0] < $_[1] ? $_[0] : $_[1];
}
sub assign_rgb_color {
require Digest::SHA;
my ($str) = @_;
my $sha1 = Digest::SHA::sha1_hex($str);
substr($sha1, 0, 2) .
substr($sha1, 18, 2) .
substr($sha1, 38, 2);
}
sub assign_rgb_dark_color {
my $str = shift;
my $rgb = assign_rgb_color($str);
rgb_is_dark($rgb) ? $rgb : mix_2_rgb_colors($rgb, '000000');
}
sub assign_rgb_light_color {
my $str = shift;
my $rgb = assign_rgb_color($str);
rgb_is_light($rgb) ? $rgb : mix_2_rgb_colors($rgb, 'ffffff');
}
sub int2rgb {
my $int = shift;
return sprintf("%02x%02x%02x",
($int & 0xff0000) >> 16,
($int & 0x00ff00) >> 8,
($int & 0x0000ff),
);
}
sub mix_2_rgb_colors {
my ($rgb1, $rgb2, $pct) = @_;
$pct //= 0.5;
my ($r1, $g1, $b1) =
$rgb1 =~ $re_rgb or die "Invalid rgb1 color, must be in 'ffffff' form";
my ($r2, $g2, $b2) =
$rgb2 =~ $re_rgb or die "Invalid rgb2 color, must be in 'ffffff' form";
for ($r1, $g1, $b1, $r2, $g2, $b2) { $_ = hex $_ }
return sprintf("%02x%02x%02x",
$r1 + $pct*($r2-$r1),
$g1 + $pct*($g2-$g1),
$b1 + $pct*($b2-$b1),
);
}
sub mix_rgb_colors {
my (@weights, @r, @g, @b);
while (@_ >= 2) {
my ($rgb, $weight) = splice @_, 0, 2;
my ($r, $g, $b) = $rgb =~ $re_rgb
or die "Invalid rgb color '$rgb', must be in 'ffffff' form";
push @r, hex $r;
push @g, hex $g;
push @b, hex $b;
push @weights, $weight;
}
my $tot_r = 0; for (0..$#r) { $tot_r += $r[$_]*$weights[$_] }
my $tot_g = 0; for (0..$#g) { $tot_g += $g[$_]*$weights[$_] }
my $tot_b = 0; for (0..$#b) { $tot_b += $b[$_]*$weights[$_] }
my $tot_weight = 0; $tot_weight += $_ for @weights;
die "Zero/negative total weight" unless $tot_weight > 0;
return sprintf("%02x%02x%02x",
$tot_r / $tot_weight,
$tot_g / $tot_weight,
$tot_b / $tot_weight,
);
}
sub rand_rgb_color {
my ($rgb1, $rgb2) = @_;
$rgb1 //= '000000';
my ($r1, $g1, $b1) =
$rgb1 =~ $re_rgb or die "Invalid rgb1 color, must be in 'ffffff' form";
$rgb2 //= 'ffffff';
my ($r2, $g2, $b2) =
$rgb2 =~ $re_rgb or die "Invalid rgb2 color, must be in 'ffffff' form";
for ($r1, $g1, $b1, $r2, $g2, $b2) { $_ = hex $_ }
return sprintf("%02x%02x%02x",
$r1 + rand()*($r2-$r1+1),
$g1 + rand()*($g2-$g1+1),
$b1 + rand()*($b2-$b1+1),
);
}
sub rand_rgb_colors {
my $opts = ref $_[0] eq 'HASH' ? shift : {};
my $num = shift // 1;
my $light_color = exists($opts->{light_color}) ? $opts->{light_color} : 1;
my $max_attempts = $opts->{max_attempts} // 1000;
my $avoid_colors = $opts->{avoid_colors};
my @res;
while (@res < $num) {
my $num_attempts = 0;
my $rgb;
while (1) {
$rgb = rand_rgb_color();
my $reject = 0;
REJECT: {
if ($light_color) {
do { $reject++; last } if rgb_is_dark($rgb);
} elsif (defined $light_color) {
do { $reject++; last } if rgb_is_light($rgb);
}
if ($avoid_colors && ref $avoid_colors eq 'ARRAY') {
do { $reject++; last } if grep { $rgb eq $_ } @$avoid_colors;
}
if ($avoid_colors && ref $avoid_colors eq 'HASH') {
do { $reject++; last } if $avoid_colors->{$rgb}
}
} # REJECT
last if !$reject;
last if ++$num_attempts >= $max_attempts;
}
push @res, $rgb;
}
@res;
}
sub reverse_rgb_color {
my ($rgb) = @_;
my ($r, $g, $b) =
$rgb =~ $re_rgb or die "Invalid rgb color, must be in 'ffffff' form";
for ($r, $g, $b) { $_ = hex $_ }
return sprintf("%02x%02x%02x", 255-$r, 255-$g, 255-$b);
}
sub rgb2grayscale {
my ($rgb) = @_;
my ($r, $g, $b) =
$rgb =~ $re_rgb or die "Invalid rgb color, must be in 'ffffff' form";
for ($r, $g, $b) { $_ = hex $_ }
# basically we just average the R, G, B
my $avg = int(($r + $g + $b)/3);
return sprintf("%02x%02x%02x", $avg, $avg, $avg);
}
sub rgb2int {
my $rgb = shift;
# just to check
$rgb =~ $re_rgb or die "Invalid rgb color, must be in 'ffffff' form";
hex($rgb);
}
sub rgb2sepia {
my ($rgb) = @_;
my ($r, $g, $b) =
$rgb =~ $re_rgb or die "Invalid rgb color, must be in 'ffffff' form";
for ($r, $g, $b) { $_ = hex $_ }
# reference: http://www.techrepublic.com/blog/howdoi/how-do-i-convert-images-to-grayscale-and-sepia-tone-using-c/120
my $or = ($r*0.393) + ($g*0.769) + ($b*0.189);
my $og = ($r*0.349) + ($g*0.686) + ($b*0.168);
my $ob = ($r*0.272) + ($g*0.534) + ($b*0.131);
for ($or, $og, $ob) { $_ = 255 if $_ > 255 }
return sprintf("%02x%02x%02x", $or, $og, $ob);
}
sub rgb_diff {
my ($rgb1, $rgb2, $algo) = @_;
$algo //= 'euclidean';
my ($r1, $g1, $b1) =
$rgb1 =~ $re_rgb or die "Invalid rgb1 color, must be in 'ffffff' form";
my ($r2, $g2, $b2) =
$rgb2 =~ $re_rgb or die "Invalid rgb2 color, must be in 'ffffff' form";
for ($r1, $g1, $b1, $r2, $g2, $b2) { $_ = hex $_ }
my $dr2 = ($r1-$r2)**2;
my $dg2 = ($g1-$g2)**2;
my $db2 = ($b1-$b2)**2;
if ($algo eq 'approx1' || $algo eq 'approx2') {
my $rm = ($r1 + $r2)/2;
if ($algo eq 'approx1') {
return (2*$dr2 + 4*$dg2 + 3*$db2 + $rm*($dr2 - $db2)/256 )**0.5;
} else { # approx2
if ($rm < 128) {
return (3*$dr2 + 4*$dg2 + 2*$db2)**0.5;
} else {
return (2*$dr2 + 4*$dg2 + 3*$db2)**0.5;
}
}
} elsif ($algo eq 'hsv_euclidean' || $algo eq 'hsv_hue1') {
my $hsv1 = rgb2hsv($rgb1);
my ($h1, $s1, $v1) = split / /, $hsv1;
my $hsv2 = rgb2hsv($rgb2);
my ($h2, $s2, $v2) = split / /, $hsv2;
my $dh2 = ( _min(abs($h2-$h1), 360-abs($h2-$h1))/180 )**2;
my $ds2 = ( $s2-$s1 )**2;
my $dv2 = ( ($v2-$v1)/255.0 )**2;
if ($algo eq 'hsv_hue1') {
return (5*$dh2 + $ds2 + $dv2)**0.5;
} else { # hsv_euclidean
return ($dh2 + $ds2 + $dv2)**0.5;
}
} else { # euclidean
return ($dr2 + $dg2 + $db2)**0.5;
}
}
sub rgb_distance {
my ($rgb1, $rgb2) = @_;
my ($r1, $g1, $b1) =
$rgb1 =~ $re_rgb or die "Invalid rgb1 color, must be in 'ffffff' form";
my ($r2, $g2, $b2) =
$rgb2 =~ $re_rgb or die "Invalid rgb2 color, must be in 'ffffff' form";
for ($r1, $g1, $b1, $r2, $g2, $b2) { $_ = hex $_ }
(($r1-$r2)**2 + ($g1-$g2)**2 + ($b1-$b2)**2)**0.5;
}
sub rgb_is_dark {
my ($rgb) = @_;
rgb_distance($rgb, "000000") < rgb_distance($rgb, "ffffff") ? 1:0;
}
sub rgb_is_light {
my ($rgb) = @_;
rgb_distance($rgb, "000000") > rgb_distance($rgb, "ffffff") ? 1:0;
}
sub _rgb_luminance {
my ($r, $g, $b) = @_;
0.2126*$r/255 + 0.7152*$g/255 + 0.0722*$b/255;
}
sub rgb_luminance {
my ($rgb) = @_;
my ($r, $g, $b) =
$rgb =~ $re_rgb or die "Invalid rgb color, must be in 'ffffff' form";
for ($r, $g, $b) { $_ = hex $_ }
return _rgb_luminance($r, $g, $b);
}
sub tint_rgb_color {
my ($rgb1, $rgb2, $pct) = @_;
$pct //= 0.5;
my ($r1, $g1, $b1) =
$rgb1 =~ $re_rgb or die "Invalid rgb1 color, must be in 'ffffff' form";
my ($r2, $g2, $b2) =
$rgb2 =~ $re_rgb or die "Invalid rgb2 color, must be in 'ffffff' form";
for ($r1, $g1, $b1, $r2, $g2, $b2) { $_ = hex $_ }
my $lum = _rgb_luminance($r1, $g1, $b1);
return sprintf("%02x%02x%02x",
$r1 + $pct*($r2-$r1)*$lum,
$g1 + $pct*($g2-$g1)*$lum,
$b1 + $pct*($b2-$b1)*$lum,
);
}
sub rgb2hsl {
my ($rgb) = @_;
my ($r, $g, $b) =
$rgb =~ $re_rgb or die "Invalid rgb color, must be in 'ffffff' form";
for ($r, $g, $b) { $_ = hex($_)/255 }
my $max = $r;
my $maxc = 'r';
my $min = $r;
if ($g > $max) {
$max = $g;
$maxc = 'g';
}
if ($b > $max) {
$max = $b;
$maxc = 'b';
}
if ($g < $min) {
$min = $g;
}
if ($b < $min) {
$min = $b;
}
my ($h, $s, $l);
if ($max == $min) {
$h = 0;
} elsif ($maxc eq 'r') {
$h = 60 * (($g - $b) / ($max - $min)) % 360;
} elsif ($maxc eq 'g') {
$h = (60 * (($b - $r) / ($max - $min)) + 120);
} elsif ($maxc eq 'b') {
$h = (60 * (($r - $g) / ($max - $min)) + 240);
}
$l = ($max + $min) / 2;
if ($max == $min) {
$s = 0;
} elsif($l <= .5) {
$s = ($max - $min) / ($max + $min);
} else {
$s = ($max - $min) / (2 - ($max + $min));
}
return sprintf("%.3g %.3g %.3g", $h, $s, $l);
}
sub rgb2hsv {
my ($rgb) = @_;
my ($r, $g, $b) =
$rgb =~ $re_rgb or die "Invalid rgb color, must be in 'ffffff' form";
for ($r, $g, $b) { $_ = hex($_)/255 }
my $max = $r;
my $maxc = 'r';
my $min = $r;
if ($g > $max) {
$max = $g;
$maxc = 'g';
}
if($b > $max) {
$max = $b;
$maxc = 'b';
}
if($g < $min) {
$min = $g;
}
if($b < $min) {
$min = $b;
}
my ($h, $s, $v);
if ($max == $min) {
$h = 0;
} elsif ($maxc eq 'r') {
$h = 60 * (($g - $b) / ($max - $min)) % 360;
} elsif ($maxc eq 'g') {
$h = (60 * (($b - $r) / ($max - $min)) + 120);
} elsif ($maxc eq 'b') {
$h = (60 * (($r - $g) / ($max - $min)) + 240);
}
$v = $max;
if($max == 0) {
$s = 0;
} else {
$s = 1 - ($min / $max);
}
return sprintf("%.3g %.3g %.3g", $h, $s, $v);
}
1;
#!/usr/bin/env perl
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
#
# This file is part of Parse-ANSIColor-Tiny
#
# This software is copyright (c) 2011 by Randy Stauner.
#
# This is free software; you can redistribute it and/or modify it under
# the same terms as the Perl 5 programming language system itself.
#
use strict;
use warnings;
our %RGB_MAP = qw(
000000 black
FF0000 red
008000 green
FFFF00 yellow
0000FF blue
FF00FF magenta
00FFFF cyan
FFFFFF white
);
package Parse::ANSIColor::Tiny;
# git description: v0.600-2-gba6391f
our $AUTHORITY = 'cpan:RWSTAUNER';
# ABSTRACT: Determine attributes of ANSI-Colored string
$Parse::ANSIColor::Tiny::VERSION = '0.601';
our @COLORS = qw( black red green yellow blue magenta cyan white );
our %FOREGROUND = (
(map { ( $COLORS[$_] => 30 + $_ ) } 0 .. $#COLORS),
(map { ( 'bright_' . $COLORS[$_] => 90 + $_ ) } 0 .. $#COLORS),
);
our %BACKGROUND = (
(map { ( 'on_' . $COLORS[$_] => 40 + $_ ) } 0 .. $#COLORS),
(map { ('on_bright_' . $COLORS[$_] => 100 + $_ ) } 0 .. $#COLORS),
);
our %ATTRIBUTES = (
clear => 0,
reset => 0,
bold => 1,
dark => 2,
faint => 2,
underline => 4,
underscore => 4,
blink => 5,
reverse => 7,
concealed => 8,
reverse_off => 27,
reset_foreground => 39,
reset_background => 49,
%FOREGROUND,
%BACKGROUND,
);
# Generating the 256-color codes involves a lot of codes and offsets that are
# not helped by turning them into constants.
## no critic (ValuesAndExpressions::ProhibitMagicNumbers)
our @COLORS256;
# The first 16 256-color codes are duplicates of the 16 ANSI colors,
# included for completeness.
for my $code (0 .. 15) {
my $name = "ansi$code";
$ATTRIBUTES{$name} = "38;5;$code";
$ATTRIBUTES{"on_$name"} = "48;5;$code";
push @COLORS256, $name;
}
# 256-color RGB colors. Red, green, and blue can each be values 0 through 5,
# and the resulting 216 colors start with color 16.
for my $r (0 .. 5) {
for my $g (0 .. 5) {
for my $b (0 .. 5) {
my $code = 16 + (6 * 6 * $r) + (6 * $g) + $b;
my $name = "rgb$r$g$b";
$ATTRIBUTES{$name} = "38;5;$code";
$ATTRIBUTES{"on_$name"} = "48;5;$code";
push @COLORS256, $name;
}
}
}
# The last 256-color codes are 24 shades of grey.
for my $n (0 .. 23) {
my $code = $n + 232;
my $name = "grey$n";
$ATTRIBUTES{$name} = "38;5;$code";
$ATTRIBUTES{"on_$name"} = "48;5;$code";
push @COLORS256, $name;
}
# copied from Term::ANSIColor
our %ATTRIBUTES_R;
# Reverse lookup. Alphabetically first name for a sequence is preferred.
for (reverse sort keys %ATTRIBUTES) {
$ATTRIBUTES_R{$ATTRIBUTES{$_}} = $_;
}
sub new {
my $class = shift;
my $self = {
remove_escapes => 1,
@_ == 1 ? %{ $_[0] } : @_,
};
$self->{process} = 1
if $self->{auto_reverse};
# fix incorrectly specified attributes
($self->{background} ||= 'black') =~ s/^(on_)*/on_/;
($self->{foreground} ||= 'white') =~ s/^(on_)*//;
bless $self, $class;
}
sub colors {
return (@COLORS, @COLORS256);
}
sub foreground_colors {
return (
@COLORS,
(map { "bright_$_" } @COLORS),
@COLORS256,
);
}
sub background_colors {
return (
(map { "on_$_" } @COLORS),
(map { "on_bright_$_" } @COLORS),
(map { "on_$_" } @COLORS256),
);
}
sub __separate_and_normalize {
my ($codes) = @_;
# Treat empty as "clear".
defined($codes) && length($codes)
or return 0;
# Replace empty (clear) with zero to simplify parsing and return values.
$codes =~ s/^;/0;/;
$codes =~ s/;$/;0/;
# Insert a zero between two semicolons (use look-ahead to get /g to find all).
$codes =~ s/;(?=;)/;0/g;
# Remove any leading zeros from (sections of) codes.
$codes =~ s/\b0+(?=\d)//g;
# Return all matches (of extended sequences or digits).
return $codes =~ m{ ( [34]8;5;\d+ | \d+) }xg;
}
sub identify {
my ($self, @codes) = @_;
local $_;
return
grep { defined }
map { $ATTRIBUTES_R{ $_ } }
map { __separate_and_normalize($_) }
@codes;
}
sub normalize {
my $self = shift;
my @norm;
foreach my $attr ( @_ ){
if( $attr eq 'clear' ){
@norm = ();
}
elsif( $attr eq 'reverse_off' ){
# reverse_off cancels reverse
@norm = grep { $_ ne 'reverse' } @norm;
}
elsif( $attr eq 'reset_foreground' ){
@norm = grep { !exists $FOREGROUND{$_} } @norm;
}
elsif( $attr eq 'reset_background' ){
@norm = grep { !exists $BACKGROUND{$_} } @norm;
}
else {
# remove previous (duplicate) occurrences of this attribute
@norm = grep { $_ ne $attr } @norm;
# new fg color overwrites previous fg
@norm = grep { !exists $FOREGROUND{$_} } @norm if exists $FOREGROUND{$attr};
# new bg color overwrites previous bg
@norm = grep { !exists $BACKGROUND{$_} } @norm if exists $BACKGROUND{$attr};
push @norm, $attr;
}
}
return @norm;
}
sub parse {
my ($self, $orig) = @_;
my $last_pos = 0;
my $last_attr = [];
my $processed = [];
my $parsed = [];
# Strip escape sequences that we aren't going to use
$orig = $self->remove_escape_sequences($orig)
if $self->{remove_escapes};
while( $orig =~ m/(\e\[([0-9;]*)m)/mg ){
my $seq = $1;
my $attrs = $2;
my $cur_pos = pos($orig);
my $len = ($cur_pos - length($seq)) - $last_pos;
push @$parsed, [
$processed,
substr($orig, $last_pos, $len)
]
# don't bother with empty strings
if $len;
$last_pos = $cur_pos;
$last_attr = [$self->normalize(@$last_attr, $self->identify($attrs))];
$processed = $self->{process} ? [$self->process(@$last_attr)] : $last_attr;
}
push @$parsed, [
$processed,
substr($orig, $last_pos)
]
# if there's any string left
if $last_pos < length($orig);
return $parsed;
}
sub process {
my ($self, @attr) = @_;
@attr = $self->process_reverse(@attr) if $self->{auto_reverse};
return @attr;
}
sub process_reverse {
my $self = shift;
my ($rev, $fg, $bg, @attr);
my $i = 0;
foreach my $attr ( @_ ){
if( $attr eq 'reverse' ){
$rev = 1;
next;
}
elsif( $FOREGROUND{ $attr } ){
$fg = $i;
}
elsif( $BACKGROUND{ $attr } ){
$bg = $i;
}
push @attr, $attr;
$i++;
}
# maintain order for consistency with other methods
if( $rev ){
# if either color is missing then the default colors should be reversed
{
$attr[ $fg = $i++ ] = $self->{foreground} if !defined $fg;
$attr[ $bg = $i++ ] = $self->{background} if !defined $bg;
}
$attr[ $fg ] = 'on_' . $attr[ $fg ] if defined $fg;
$attr[ $bg ] = substr( $attr[ $bg ], 3 ) if defined $bg;
}
return @attr;
}
sub remove_escape_sequences {
my ($self, $string) = @_;
# This is in no way comprehensive or accurate...
# it just seems like most of the sequences match this.
# We could certainly expand this if the need arises.
$string =~ s{
\e\[
[0-9;]*
[a-ln-zA-Z]
}{}gx;
return $string;
}
our @EXPORT_OK;
BEGIN {
my @funcs = qw(identify normalize parse);
my $suffix = '_ansicolor';
local $_;
eval join '', ## no critic (StringyEval)
map { "sub ${_}$suffix { __PACKAGE__->new->$_(\@_) }" }
@funcs;
@EXPORT_OK = map { $_ . $suffix } @funcs;
}
sub import {
my $class = shift;
return unless @_;
my $caller = caller;
no strict 'refs'; ## no critic (NoStrict)
foreach my $arg ( @_ ){
die "'$arg' is not exported by $class"
unless grep { $arg eq $_ } @EXPORT_OK;
*{"${caller}::$arg"} = *{"${class}::$arg"}{CODE};
}
}
# TODO: option for blotting out 'concealed'? s/\S/ /g
1;
package IRC::FromANSI::Tiny;
# ABSTRACT: Convert ANSI color codes to IRC
our $AUTHORITY = 'cpan:ARODLAND'; # AUTHORITY
our $VERSION = '0.02'; # VERSION
use strict;
use warnings;
my %irccolors = (
black => 1,
red => 5,
green => 3,
yellow => 7,
blue => 2,
magenta => 6,
cyan => 10,
white => 14,
bright_black => 15,
bright_red => 4,
bright_green => 9,
bright_yellow => 8,
bright_blue => 12,
bright_magenta => 13,
bright_cyan => 11,
bright_white => 0,
);
sub convert {
my ($text) = @_;
my $ret = "";
my $ansi = Parse::ANSIColor::Tiny->new;
my $data = $ansi->parse($text);
my (%foregrounds, %backgrounds);
$foregrounds{$_} = 1 for $ansi->foreground_colors;
$backgrounds{$_} = 1 for $ansi->background_colors;
my ($foreground, $background, $underline, $bold) = (undef, undef, 0, 0);
for my $chunk (@$data) {
my ($attrs, $text) = @$chunk;
my ($fg) = grep $foregrounds{$_}, @$attrs;
my ($bg) = grep $backgrounds{$_}, @$attrs;
my $bb = (grep $_ eq 'bold', @$attrs) ? 1 : 0;
my $u = (grep $_ eq 'underline', @$attrs) ? 1 : 0;
my $set_color;
if ($fg) {
$foreground = ($bb ? 'bright_' : '') . $fg;
# use Acme::Dump::And::Dumper;
# warn DnD [ $foreground ];
if ($foreground =~ /^rgb/) {
# %RGB_MAP
my ($r, $g, $b) = $foreground =~ /(\d)(\d)(\d)/;
$r = 255*$r/5; $r = 255 if $r > 255; $r = 0 if $r < 0;
$g = 255*$g/5; $g = 255 if $g > 255; $g = 0 if $g < 0;
$b = 255*$b/5; $b = 255 if $b > 255; $b = 0 if $b < 0;
my $wanted = sprintf "%02x%02x%02x", $r, $g, $b;
my $smallest_distance = 999999999999999;
my $smallest = 'green';
# use Acme::Dump::And::Dumper;
for (keys %RGB_MAP) {
# warn DnD [ Color::RGB::Util::rgb_distance($wanted, $_), $wanted, $_ ];
my $d = Color::RGB::Util::rgb_distance($wanted, $_);
if ($d < $smallest_distance) {
$smallest_distance = $d;
$smallest = $RGB_MAP{$_};
}
}
# warn DnD [$foreground, $r, $g, $b, $wanted, $smallest];
$foreground = $smallest;
# $foreground = 'green'; ### FIX FOR RGB
}
$set_color = "\cC$irccolors{$foreground}";
$bb = 0;
}
if ($bg) {
$background = $bg;
$set_color = "\cC" . $irccolors{$foreground || "black"} . ",$irccolors{$background}";
}
if (!$fg && !$bg && ($foreground || $background)) {
undef $foreground;
undef $background;
if ($text =~ /^\d/) {
# Use "reset all" to clear color to avoid a following number
# being interpreted as a color code
$set_color = "\cO";
undef $underline;
undef $bold;
} else {
$set_color = "\cC";
}
}
$ret .= $set_color if length $set_color;
if ($bb ^ $bold) {
$bold = $bb;
$ret .= "\cB";
}
if ($u ^ $underline) {
$underline = $u;
$ret .= "\c_";
}
if ($ret =~ /\D\d$/ && $text =~ /^\d/) {
# Avoid a 1-digit color code (e.g. ^C1 or ^C12,3 running into a following
# digit that's supposed to be part of the literal text, by making it two-digit.
substr($ret, -1, 0, '0');
}
$ret .= $text;
}
return $ret;
}
1;
use feature 'say';
say IRC::FromANSI::Tiny::convert(do { local $/; <STDIN> });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment