#!/usr/local/bin/perl -w
## Make a gif "transparent"
##
## Jeffrey Friedl
## jfriedl@omrongw.wg.omron.co.jp
## 15 July 1994


#$version = "960330.8";
## 960330.8 -- made $&-clean.
##
## 950918.7 -- replaced all instances 'sysread' with 'read' -- for some
## 	       reason, sysread() is broken on all Linuxi I've checked.
##
## 950905.6 -- another binmode fix (Michael Spencer)
##             Added -in to edit in place, and cleaned up documentation.
##
## 950328.5 -- added binmode to the filehandles for DOS
##	       (thanks to Michael Spencer and Eric Mumpower).
##
## 941219.4 -- Colormap and typo fixes due to Jon Reeves
##	       Put the RGB table into <DATA> -- should load faster now.
##	       Put color names into output -- made more readable (hopefully).
##	       Added -help
##
## 940825.3 -- modified to work with possible future versions of the
##             GIF standard... just in case.
##
## 2 Aug 1994 - added ability to select transparent color by RGB values.
##
##
## BLURB:
## Transforms a "normal" gif into a "transparent background" gif.
## This can be very useful for gifs that are inlined in a Web page.

##  Other references:
##   http://www.galcit.caltech.edu/~ta/tgif/transgifnotes.html
##   http://www.bae.ncsu.edu/bae/people/faculty/walker/hotlist/transpar.html
##   http://www.vrl.com/Imaging/transparent.html

##
##>
##
## Usage:
##      transgif -in pic1.gif [pic2.gif ....]
##   or
##      .... | transgif [options] | ....
##   or
##      transgif [options] regular.gif > transparent.gif
##
## Normally used as
##	transgif -in pic.gif
## the "-in" means to update the gif in place. You can list as many files
## as you like.
##
## If there are no files given, transgif filters STDIN to STDOUT.
## In this case, STDIN should be one gif.
##
## If there is exactly one file, a modified version is spit to STDOUT.
## This is rather odd (it'd be nice if it was done in-place, with a special
## option to have it spit to stdout), but is a throwback from the first
## version I whipped up for the old comp.infosystems.www (back when it
## existed)
## 
## For each picture, the default is that whatever color happens to fall
## into the first colormap slot (often black) will be made transparent. 
## This can be changed via the the options.
##
## The options are from:
##   -p              print the colormap (to STDERR).
##		     The new gif still goes to STDOUT.
##
##   -###            make colormap index-### transparent (default is -0)
##
##   -rgb ## ## ##   Take the three numbers as R G B values (in the range
##		     of 0..255 (or 0x00..0xff). The first colormap entry
##		     with those RGB values is made transparent.
##
##   -rgb name       Use the R G B values of the color 'name' if known
##		     by this program (data from X11's rgb.txt)
##
##   -help           show a short help message and exit.
##
##   -in             [not an regular option, but listed here because it
##                   looks like one]. Says to transform each gif in
##                   place. Happens automatically if more than one gif
##		     is given.
##
## I wrote this because people ask for something like this all the time.
## I just learned the format of GIFs a week ago, so this will likely be
## lacking in many respects. Still, from what I hear people find it useful.
##
##<

$0 =~ s#.*/##;
sub usage {
   die "@_\nUsage: $0 [-help] [-p] [-## | -rgb name | -rgb ## ## ##] [file ...]\n";
}

$trans_index = 0;
$print_color_map = 0;
$select_via_rgb = 0;
$in_place = 0;

while (@ARGV && $ARGV[0] =~ m/^-/)
{
    $arg = shift;
    $print_color_map = 1, next if $arg eq '-p'; ## print color map
    $trans_index = $1,    next if $arg =~ m/^-(\d+)$/; ## set color map index
    $in_place = 1,        next if $arg eq '-in';

    if ($arg eq '-rgb')	     ## set what color to make transparent
    {
        $select_via_rgb = 1;

	## if next three args look numerical (## or 0x##), use as R B G.
	if (@ARGV >= 3 &&
	    $ARGV[0] =~ m/^(0x[\da-f]+|0[0-7]+|\d+)$/i &&
	    $ARGV[1] =~ m/^(0x[\da-f]+|0[0-7]+|\d+)$/i &&
	    $ARGV[2] =~ m/^(0x[\da-f]+|0[0-7]+|\d+)$/i)
	{
	    ($R, $G, $B) = splice(@ARGV, 0, 3);

	    $R = eval($R); ## eval these to process any hex or octal values.
	    $G = eval($G); ## eval these to process any hex or octal values.
	    $B = eval($B); ## eval these to process any hex or octal values.

	    ## If all of RGB are exactly 0 or 1 each, then we'll translate
	    ## 1s to 255s.
	    if (($R || $G || $B) &&      ($R == 0 || $R == 1) &&
		($G == 0 || $G == 1) && ($B == 0 || $B == 1))
	    {
		$R = 255 if $R == 1;
		$G = 255 if $G == 1;
		$B = 255 if $B == 1;
	    }
	    $rgb = qq/"-rgb $R $G $B"/;

	## if next arg looks like a color name, use those R G B values.
	} elsif (@ARGV && (@RGB = &name2rgb($ARGV[0]), @RGB == 3)) {
	    ($R, $G, $B) = @RGB;
	    $rgb = qq/"-rgb $ARGV[0]" ($R $G $B)/;
	    shift; ## eat name;

	} else {
	   warn(qq/(don't understand "$ARGV[0]" as a color name)\n/) if @ARGV;
	   die qq/$0: expected color name or a numerical triplet for $arg.\n/;
	}
	next;
    }

    if ($arg eq '-help')
    {
	print STDERR <<"END OF HELP"; exit(0);
usage: $0 [options] [file.gif] > new.gif
 The named gif (or STDIN) is sent to STDOUT, converted to a transparent gif
 along the way.  Normally, the first color in the colormap (with index 0,
 often black) is the one turned "transparent".

Options are from:
  -help    Print this help message and immediately exit.
  -p       Print the image's colormap (to STDERR) while doing the conversion.
  -###     Use color map index ### (given in decimal) instead of 0.

  -rgb colorname
    Use the color map index corresponding to the named color given. The names
    and values were taken from X11's "rgb.txt". For example, use
    "-rgb red" to set the image's red to be the transparent color.

  -rgb ## ## ##
    Use the color with the R-G-B components given. Values may be given in
    decimal (123), octal (0173), or hex (0x7b).  Values for each number
    normally range 0 - 255 (0x00-0xff).  However, as a convenience, if each
    number is either 0 or 1, then the "1" means 255 (i.e. "-rgb 255 0 0"
    and "-rgb 1 0 0" both mean "red";  "-rgb 1 1 1" means "white").
END OF HELP
    }

    &usage(qq/unknown arg "$arg".\n/);
}

&usage('too many args.') if @ARGV > 1;

##
## If no args, filter STDIN -> STDOUT.
## If one arg and no -i given, filter file -> STDOUT
## If 1+ args, or one arg and -i given, edit file in place.
##
if (@ARGV == 0) {
    &giftrans(*STDIN, *STDOUT, $trans_index);
} else {
    ## quick check to see if each file exists
    foreach $file (@ARGV) {
	die("$0: can't find [$file].\n") if !-f $file;
    }

    if (@ARGV == 1 && !$in_place)
    {
	$file = shift;	
	open(INPUT, $file) || die "$0: couldn't open [$file] for input.\n";
	&giftrans(*INPUT, *STDOUT, $trans_index);
	close(INPUT);
    }
    else
    {
	($tmpfile = time) =~ s/.*(\d{1,7})(\d{1,3})$/X$1.$2/;

	foreach $file (@ARGV) {
	    open(INPUT, $file) || die "$0: couldn't open [$file] for input.\n";
	    open(OUTPUT, '>'.$tmpfile) || die "$0: couldn't open [$tmpfile] for output.\n";
	    &giftrans(*INPUT, *OUTPUT, $trans_index);
	    close(INPUT);
	    close(OUTPUT);
	    unlink($file) && rename($tmpfile, $file);
	}
    }
}
exit(0);


##
## Given indirect references to two filehandles, pass the file from
## one to the other, changing nothing unless it's a GIF that we know
## how to deal with, and if so do so.
##
## This is written rather verbosely for the sake of clarity... speed not
## much of an issue for something like this, and the difference is minimal
## anyway.
##
sub giftrans
{
  local(*IN, *OUT, $trans_index) = @_;
  binmode(IN);
  binmode(OUT);
  $trans_index = 0 if !defined $trans_index;
  local($header, $color_table, $nextblock, $buffer) = ('') x 4;

  ## The header looks like:
  ##   byte 0 - 5:  "GIF89a" or "GIF87a"
  ##   byte 6, 7:   width  (low order first)
  ##   byte 8, 9:   height (low order first)
  ##   byte 10:     various flags
  ##   byte 11:     background color index
  ##   byte 12:     aspect ratio
  sysread(IN, $header, 13) || die "sysread header: $!";
  substr($header, 0, 6) = 'GIF89a' if substr($header,0,6) eq 'GIF87a';
  print OUT $header;

  if (substr($header, 0, 3) ne 'GIF') {
      print STDERR "don't know input filetype, passing unchanged\n";
  } else {
    ##
    ## Look at flags (8 bits): hi[MCCCSPPP]low
    ##   M   = global colormap present?
    ##   CCC = bits/color/colormapentry - 1 (this field not important here)
    ##   S   = color map sorted by importance?
    ##   PPP = bits/pixel - 1
    ## therefore
    ##   Bits/pixel = PPP+1
    ##   Number of possible colors (entries in colormap): 2 ** (PPP+1)
    ##                                                  : 1 << (PPP+1)
    ##   Size (bytes) of colormap: 3 * Number of possible colors
    ##                           : 3 * (1 << (PPP+1))
    ##
    local($flags) = ord(substr($header, 10, 1));
    local($has_global_colormap) = $flags & 0x80;

    ## Copy over the colormap if need be.
    if (!$has_global_colormap)
    {
       die "$0: picture has no colormap, so -rgb arg invalid.\n"
	    if $select_via_rgb;
       die "$0: no colormap, so any index except 0 or 1 makes no sense.\n"
	    if $trans_index > 1;
    } else {
	local($bits_per_pixel) = 1 + ($flags & 0x07);
	local($colormap_entries) = 1 << $bits_per_pixel;
	local($color_tbl_size) = 3 * $colormap_entries;

	sysread(IN, $color_table, $color_tbl_size) || die "sysread color";
	print OUT $color_table;

	if ($print_color_map || $select_via_rgb)
	{
	    local($r,$g,$b);
	    local($best_delta) = 1000; ## any big number ok
	    local(@delta, @r, @b, @g);
	    ## local($bits_color_byte) = 1 + (($flags >> 4) & 0x07);
	    ## local($rgb_byte_mask) = (1 << $bits_color_byte) - 1;

	    for ($i = 0; $i < $colormap_entries; $i++)
	    {
	       ($r, $g, $b) = unpack("CCC", substr($color_table, $i*3, 3));

	       if ($select_via_rgb) {
		  if ($r == $R && $g == $G && $b == $B) {
		    $select_via_rgb = 0;
		    $trans_index = $i;
		    $colorname = 
		    print STDERR "Found exact match for $rgb at index #$i".
				 &rgb2name($r, $g, $b) . ".\n";
		  } else {
		    $delta = ($r < $R ? $R - $r : $r - $R) +
			     ($g < $G ? $G - $g : $g - $G) +
			     ($b < $B ? $B - $b : $b - $B);
		    if ($delta < $best_delta) {
			@delta = ($i);
			@r = $r; @g = $g; @b = $b;
			$best_delta = $delta;
		    } elsif ($delta == $best_delta) {
			push(@delta, $i);
			push(@r, $r); push(@g, $g); push(@b, $b);
		    }
		  }
	       }

	       if ($print_color_map) {
		printf(STDERR "%03d: %3d %3d %3d [x%02x x%02x x%02x]%s\n", $i,
		      $r, $g, $b, $r, $g, $b, &rgb2name($r, $g, $b));
	       }
	    }

	    if ($select_via_rgb) {
		## Mmm, didn't find it. Use one of the close ones.
		$trans_index = shift(@delta);
		$r = shift(@r);
		$g = shift(@g);
		$b = shift(@b);

		printf(STDERR "warning: can't find a match for $rgb;\n".
			      "Instead, using index ".
			      "#%d: %d %d %d [x%02x x%02x x%02x]%s.\n",
			       $trans_index,
			       $r, $g, $b, $r, $g, $b, &rgb2name($r,$g,$b));

		if (@delta)
		{
		    $count = @delta;
		    printf(STDERR
			"note: %d other entr%s equally close:\n",
			    $count, $count == 1 ? "y seems" : "ies seem");
		    while (@delta) {
			$index = shift(@delta);
			$r = shift(@r);
			$g = shift(@g);
			$b = shift(@b);
			printf(STDERR "  index %d: %3d %3d %3d ".
				      "[x%02x x%02x x%02x]%s\n",
				      $index, $r, $g, $b, $r, $g, $b,
				      &rgb2name($r,$g,$b));
		    }
		}
	    }
	}
    }

    ##
    ## The next 8 bytes will either be an already-there graphic-extension
    ## block, or something else that we'll not care about. In the latter
    ## case, we'll add a graphic-extension block saying "color such-and-
    ## such is transparent". If there's already one there, we'll just
    ## ensure that it says that.
    ##
    sysread(IN, $nextblock, 8) || die "sysread nextblock";
    local($extension, $label) = unpack('CC', $nextblock);
    ## If extension is 0x21 and label is 0xf9, that's the magic that means
    ## there's already a graphic extension there.
    if ($extension == 0x21 && $label == 0xf9) {
	substr($nextblock, 3, 1) = pack('C', 1|unpack('C',substr($nextblock, 3, 1)));
	substr($nextblock, 6, 1) = pack('C', $trans_index);
    } else {
	print OUT pack('CCC CCCC C',
	    0x21,  ## magic: "Extension Introducer"
	    0xf9,  ## magic: "Graphic Control Label"
	       4,  ## bytes in block (between here and terminator)
	    0x01,  ## indicates that 'transparent index' is given
	    0, 0,  ## delay time.
	    $trans_index, ## index number of colormap entry
	    0x00); ## terminator.
    }
    print OUT $nextblock;
  }

  ## Now just pass the rest of the file over unchanged.

  print OUT $buffer while sysread(IN, $buffer, 4096);
  close(IN);
  close(OUT);
  print STDERR "done.\n";
}

##
## Given a color name (such as "Light Spring Green"), return
## the R G B triplet.
##
## As a byproduct, %rgb2name will be loaded (calling with a dummy
## color, such as "dummy color" will serve to load %rgb2name).
##
sub name2rgb
{
    local($name) = @_;  ## name;
    local(@retval);
    local($val, @val, $regex, $color);
    while (<DATA>) {
	last if m/__END__/;
	next unless ($val, $regex) = m/^([^-]*)\s*->\s*(.*\S)/;
	@val = split(',', $val);
	$val[0]+=0; $val[1]+=0;	$val[2]+=0; ## turn into numbers

	$color = $regex;
	$color =~ s/\[(.)[^]]*]/$1/g;  ## take first character in a class
	$color =~ s/(\(([^()]*)\))/ $2=~ m!^[^|]+!; $1/e; ##first alt in parens
	$color =~ s/\|.*//;                               ##first alt
	$color =~ s/\d?\?//g; ## leave optional things, except digits

	## The +0 below turn the values from strings to numbers, removing
	## possible whitespace.
	$rgb2name{$val[0], $val[1], $val[2]} = $color;

	##
	## If the desired color, save for the return value
	##
	if (@retval == 0 && $name =~ m/^$regex$/i) {
	    ## found a match
	    @retval = @val;
	}
    }
    return @retval;
}

##
## Given an rgb value, return its color name as " (name)" if found,
## return "" otherwise.
##
sub rgb2name
{
    local($r,$g,$b) = @_;  ## +0 to ensure numerical values.
    &name2rgb("dummy value") if !defined %rgb2name;
    local($colorname) = $rgb2name{$r+0, $g+0, $b+0};
    return "" if !defined $colorname;
    " ($colorname)";
}
__END__
  0,  0,  0 -> black|gr[ae]y0
  0,  0,128 -> navy([ \-]?blue)?
  0,  0,139 -> blue4
  0,  0,205 -> medium[ \-]?blue|blue3
  0,  0,238 -> blue2
  0,  0,255 -> blue1?
  0,100,  0 -> dark[ \-]?green
  0,104,139 -> deepskyblue4
  0,134,139 -> turquoise4
  0,139,  0 -> green4
  0,139, 69 -> springgreen4
  0,139,139 -> cyan4
  0,154,205 -> deepskyblue3
  0,178,238 -> deepskyblue2
  0,191,255 -> deep[ \-]?sky[ \-]?blue1?
  0,197,205 -> turquoise3
  0,205,  0 -> green3
  0,205,102 -> springgreen3
  0,205,205 -> cyan3
  0,206,209 -> dark[ \-]?turquoise
  0,229,238 -> turquoise2
  0,238,  0 -> green2
  0,238,118 -> springgreen2
  0,238,238 -> cyan2
  0,245,255 -> turquoise1
  0,250,154 -> medium[ \-]?spring[ \-]?green
  0,255,  0 -> green1?
  0,255,127 -> spring[ \-]?green1?
  0,255,255 -> cyan1?
  3,  3,  3 -> gr[ae]y1
  5,  5,  5 -> gr[ae]y2
  8,  8,  8 -> gr[ae]y3
 10, 10, 10 -> gr[ae]y4
 13, 13, 13 -> gr[ae]y5
 15, 15, 15 -> gr[ae]y6
 16, 78,139 -> dodgerblue4
 18, 18, 18 -> gr[ae]y7
 20, 20, 20 -> gr[ae]y8
 23, 23, 23 -> gr[ae]y9
 24,116,205 -> dodgerblue3
 25, 25,112 -> midnight[ \-]?blue
 26, 26, 26 -> gr[ae]y10
 28, 28, 28 -> gr[ae]y11
 28,134,238 -> dodgerblue2
 30,144,255 -> dodger[ \-]?blue1?
 31, 31, 31 -> gr[ae]y12
 32,178,170 -> light[ \-]?sea[ \-]?green
 33, 33, 33 -> gr[ae]y13
 34,139, 34 -> forest[ \-]?green
 36, 36, 36 -> gr[ae]y14
 38, 38, 38 -> gr[ae]y15
 39, 64,139 -> royalblue4
 41, 41, 41 -> gr[ae]y16
 43, 43, 43 -> gr[ae]y17
 46, 46, 46 -> gr[ae]y18
 46,139, 87 -> sea[ \-]?green4?
 47, 79, 79 -> dark[ \-]?slate[ \-]?gr[ae]y
 48, 48, 48 -> gr[ae]y19
 50,205, 50 -> lime[ \-]?green
 51, 51, 51 -> gr[ae]y20
 54, 54, 54 -> gr[ae]y21
 54,100,139 -> steelblue4
 56, 56, 56 -> gr[ae]y22
 58, 95,205 -> royalblue3
 59, 59, 59 -> gr[ae]y23
 60,179,113 -> medium[ \-]?sea[ \-]?green
 61, 61, 61 -> gr[ae]y24
 64, 64, 64 -> gr[ae]y25
 64,224,208 -> turquoise
 65,105,225 -> royal[ \-]?blue
 66, 66, 66 -> gr[ae]y26
 67,110,238 -> royalblue2
 67,205,128 -> seagreen3
 69, 69, 69 -> gr[ae]y27
 69,139,  0 -> chartreuse4
 69,139,116 -> aquamarine4
 70,130,180 -> steel[ \-]?blue
 71, 60,139 -> slateblue4
 71, 71, 71 -> gr[ae]y28
 72, 61,139 -> dark[ \-]?slate[ \-]?blue
 72,118,255 -> royalblue1
 72,209,204 -> medium[ \-]?turquoise
 74, 74, 74 -> gr[ae]y29
 74,112,139 -> skyblue4
 77, 77, 77 -> gr[ae]y30
 78,238,148 -> seagreen2
 79, 79, 79 -> gr[ae]y31
 79,148,205 -> steelblue3
 82, 82, 82 -> gr[ae]y32
 82,139,139 -> darkslategray4
 83,134,139 -> cadetblue4
 84, 84, 84 -> gr[ae]y33
 84,139, 84 -> palegreen4
 84,255,159 -> seagreen1
 85, 26,139 -> purple4
 85,107, 47 -> dark[ \-]?olive[ \-]?green
 87, 87, 87 -> gr[ae]y34
 89, 89, 89 -> gr[ae]y35
 92, 92, 92 -> gr[ae]y36
 92,172,238 -> steelblue2
 93, 71,139 -> mediumpurple4
 94, 94, 94 -> gr[ae]y37
 95,158,160 -> cadet[ \-]?blue
 96,123,139 -> lightskyblue4
 97, 97, 97 -> gr[ae]y38
 99, 99, 99 -> gr[ae]y39
 99,184,255 -> steelblue1
100,149,237 -> cornflower[ \-]?blue
102,102,102 -> gr[ae]y40
102,139,139 -> paleturquoise4
102,205,  0 -> chartreuse3
102,205,170 -> aquamarine3|medium[ \-]?aquamarine
104, 34,139 -> darkorchid4
104,131,139 -> lightblue4
105, 89,205 -> slateblue3
105,105,105 -> dim[ \-]?gr[ae](y|y41)
105,139, 34 -> olivedrab4
105,139,105 -> darkseagreen4
106, 90,205 -> slate[ \-]?blue
107,107,107 -> gr[ae]y42
107,142, 35 -> olive[ \-]?drab
108,123,139 -> slategray4
108,166,205 -> skyblue3
110,110,110 -> gr[ae]y43
110,123,139 -> lightsteelblue4
110,139, 61 -> darkolivegreen4
112,112,112 -> gr[ae]y44
112,128,144 -> slate[ \-]?gr[ae]y
115,115,115 -> gr[ae]y45
117,117,117 -> gr[ae]y46
118,238,  0 -> chartreuse2
118,238,198 -> aquamarine2
119,136,153 -> light[ \-]?slate[ \-]?gr[ae]y
120,120,120 -> gr[ae]y47
121,205,205 -> darkslategray3
122, 55,139 -> mediumorchid4
122,103,238 -> slateblue2
122,122,122 -> gr[ae]y48
122,139,139 -> lightcyan4
122,197,205 -> cadetblue3
123,104,238 -> medium[ \-]?slate[ \-]?blue
124,205,124 -> palegreen3
124,252,  0 -> lawn[ \-]?green
125, 38,205 -> purple3
125,125,125 -> gr[ae]y49
126,192,238 -> skyblue2
127,127,127 -> gr[ae]y50
127,255,  0 -> chartreuse1?
127,255,212 -> aquamarine1?
130,130,130 -> gr[ae]y51
131,111,255 -> slateblue1
131,139,131 -> honeydew4
131,139,139 -> azure4
132,112,255 -> light[ \-]?slate[ \-]?blue
133,133,133 -> gr[ae]y52
135,135,135 -> gr[ae]y53
135,206,235 -> sky[ \-]?blue
135,206,250 -> light[ \-]?sky[ \-]?blue
135,206,255 -> skyblue1
137,104,205 -> mediumpurple3
138, 43,226 -> blue[ \-]?violet
138,138,138 -> gr[ae]y54
139,  0,  0 -> red4
139,  0,139 -> magenta4
139, 10, 80 -> deeppink4
139, 26, 26 -> firebrick4
139, 28, 98 -> maroon4
139, 34, 82 -> violetred4
139, 35, 35 -> brown4
139, 37,  0 -> orangered4
139, 54, 38 -> tomato4
139, 58, 58 -> indianred4
139, 58, 98 -> hotpink4
139, 62, 47 -> coral4
139, 69,  0 -> darkorange4
139, 69, 19 -> saddle[ \-]?brown|chocolate4
139, 71, 38 -> sienna4
139, 71, 93 -> palevioletred4
139, 71,137 -> orchid4
139, 76, 57 -> salmon4
139, 87, 66 -> lightsalmon4
139, 90,  0 -> orange4
139, 90, 43 -> tan4
139, 95,101 -> lightpink4
139, 99,108 -> pink4
139,101,  8 -> darkgoldenrod4
139,102,139 -> plum4
139,105, 20 -> goldenrod4
139,105,105 -> rosybrown4
139,115, 85 -> burlywood4
139,117,  0 -> gold4
139,119,101 -> peachpuff4
139,121, 94 -> navajowhite4
139,123,139 -> thistle4
139,125,107 -> bisque4
139,125,123 -> mistyrose4
139,126,102 -> wheat4
139,129, 76 -> lightgoldenrod4
139,131,120 -> antiquewhite4
139,131,134 -> lavenderblush4
139,134, 78 -> khaki4
139,134,130 -> seashell4
139,136,120 -> cornsilk4
139,137,112 -> lemonchiffon4
139,137,137 -> snow4
139,139,  0 -> yellow4
139,139,122 -> lightyellow4
139,139,131 -> ivory4
140,140,140 -> gr[ae]y55
141,182,205 -> lightskyblue3
141,238,238 -> darkslategray2
142,229,238 -> cadetblue2
143,143,143 -> gr[ae]y56
143,188,143 -> dark[ \-]?sea[ \-]?green
144,238,144 -> palegreen2
145, 44,238 -> purple2
145,145,145 -> gr[ae]y57
147,112,219 -> medium[ \-]?purple
148,  0,211 -> dark[ \-]?violet
148,148,148 -> gr[ae]y58
150,150,150 -> gr[ae]y59
150,205,205 -> paleturquoise3
151,255,255 -> darkslategray1
152,245,255 -> cadetblue1
152,251,152 -> pale[ \-]?green
153, 50,204 -> dark[ \-]?orchid
153,153,153 -> gr[ae]y60
154, 50,205 -> darkorchid3
154,192,205 -> lightblue3
154,205, 50 -> yellow[ \-]?green|olivedrab3
154,255,154 -> palegreen1
155, 48,255 -> purple1
155,205,155 -> darkseagreen3
156,156,156 -> gr[ae]y61
158,158,158 -> gr[ae]y62
159,121,238 -> mediumpurple2
159,182,205 -> slategray3
160, 32,240 -> purple
160, 82, 45 -> sienna
161,161,161 -> gr[ae]y63
162,181,205 -> lightsteelblue3
162,205, 90 -> darkolivegreen3
163,163,163 -> gr[ae]y64
164,211,238 -> lightskyblue2
165, 42, 42 -> brown
166,166,166 -> gr[ae]y65
168,168,168 -> gr[ae]y66
171,130,255 -> mediumpurple1
171,171,171 -> gr[ae]y67
173,173,173 -> gr[ae]y68
173,216,230 -> light[ \-]?blue
173,255, 47 -> green[ \-]?yellow
174,238,238 -> paleturquoise2
175,238,238 -> pale[ \-]?turquoise
176, 48, 96 -> maroon
176,176,176 -> gr[ae]y69
176,196,222 -> light[ \-]?steel[ \-]?blue
176,224,230 -> powder[ \-]?blue
176,226,255 -> lightskyblue1
178, 34, 34 -> firebrick
178, 58,238 -> darkorchid2
178,223,238 -> lightblue2
179,179,179 -> gr[ae]y70
179,238, 58 -> olivedrab2
180, 82,205 -> mediumorchid3
180,205,205 -> lightcyan3
180,238,180 -> darkseagreen2
181,181,181 -> gr[ae]y71
184,134, 11 -> dark[ \-]?goldenrod
184,184,184 -> gr[ae]y72
185,211,238 -> slategray2
186, 85,211 -> medium[ \-]?orchid
186,186,186 -> gr[ae]y73
187,255,255 -> paleturquoise1
188,143,143 -> rosy[ \-]?brown
188,210,238 -> lightsteelblue2
188,238,104 -> darkolivegreen2
189,183,107 -> dark[ \-]?khaki
189,189,189 -> gr[ae]y74
190,190,190 -> gr[ae]y
191, 62,255 -> darkorchid1
191,191,191 -> gr[ae]y75
191,239,255 -> lightblue1
192,255, 62 -> olivedrab1
193,205,193 -> honeydew3
193,205,205 -> azure3
193,255,193 -> darkseagreen1
194,194,194 -> gr[ae]y76
196,196,196 -> gr[ae]y77
198,226,255 -> slategray1
199, 21,133 -> medium[ \-]?violet[ \-]?red
199,199,199 -> gr[ae]y78
201,201,201 -> gr[ae]y79
202,225,255 -> lightsteelblue1
202,255,112 -> darkolivegreen1
204,204,204 -> gr[ae]y80
205,  0,  0 -> red3
205,  0,205 -> magenta3
205, 16,118 -> deeppink3
205, 38, 38 -> firebrick3
205, 41,144 -> maroon3
205, 50,120 -> violetred3
205, 51, 51 -> brown3
205, 55,  0 -> orangered3
205, 79, 57 -> tomato3
205, 85, 85 -> indianred3
205, 91, 69 -> coral3
205, 92, 92 -> indian[ \-]?red
205, 96,144 -> hotpink3
205,102,  0 -> darkorange3
205,102, 29 -> chocolate3
205,104, 57 -> sienna3
205,104,137 -> palevioletred3
205,105,201 -> orchid3
205,112, 84 -> salmon3
205,129, 98 -> lightsalmon3
205,133,  0 -> orange3
205,133, 63 -> peru|tan3
205,140,149 -> lightpink3
205,145,158 -> pink3
205,149, 12 -> darkgoldenrod3
205,150,205 -> plum3
205,155, 29 -> goldenrod3
205,155,155 -> rosybrown3
205,170,125 -> burlywood3
205,173,  0 -> gold3
205,175,149 -> peachpuff3
205,179,139 -> navajowhite3
205,181,205 -> thistle3
205,183,158 -> bisque3
205,183,181 -> mistyrose3
205,186,150 -> wheat3
205,190,112 -> lightgoldenrod3
205,192,176 -> antiquewhite3
205,193,197 -> lavenderblush3
205,197,191 -> seashell3
205,198,115 -> khaki3
205,200,177 -> cornsilk3
205,201,165 -> lemonchiffon3
205,201,201 -> snow3
205,205,  0 -> yellow3
205,205,180 -> lightyellow3
205,205,193 -> ivory3
207,207,207 -> gr[ae]y81
208, 32,144 -> violet[ \-]?red
209, 95,238 -> mediumorchid2
209,209,209 -> gr[ae]y82
209,238,238 -> lightcyan2
210,105, 30 -> chocolate
210,180,140 -> tan
211,211,211 -> light[ \-]?gr[ae]y
212,212,212 -> gr[ae]y83
214,214,214 -> gr[ae]y84
216,191,216 -> thistle
217,217,217 -> gr[ae]y85
218,112,214 -> orchid
218,165, 32 -> goldenrod
219,112,147 -> pale[ \-]?violet[ \-]?red
219,219,219 -> gr[ae]y86
220,220,220 -> gainsboro
221,160,221 -> plum
222,184,135 -> burlywood
222,222,222 -> gr[ae]y87
224,102,255 -> mediumorchid1
224,224,224 -> gr[ae]y88
224,238,224 -> honeydew2
224,238,238 -> azure2
224,255,255 -> light[ \-]?cyan1?
227,227,227 -> gr[ae]y89
229,229,229 -> gr[ae]y90
230,230,250 -> lavender
232,232,232 -> gr[ae]y91
233,150,122 -> dark[ \-]?salmon
235,235,235 -> gr[ae]y92
237,237,237 -> gr[ae]y93
238,  0,  0 -> red2
238,  0,238 -> magenta2
238, 18,137 -> deeppink2
238, 44, 44 -> firebrick2
238, 48,167 -> maroon2
238, 58,140 -> violetred2
238, 59, 59 -> brown2
238, 64,  0 -> orangered2
238, 92, 66 -> tomato2
238, 99, 99 -> indianred2
238,106, 80 -> coral2
238,106,167 -> hotpink2
238,118,  0 -> darkorange2
238,118, 33 -> chocolate2
238,121, 66 -> sienna2
238,121,159 -> palevioletred2
238,122,233 -> orchid2
238,130, 98 -> salmon2
238,130,238 -> violet
238,149,114 -> lightsalmon2
238,154,  0 -> orange2
238,154, 73 -> tan2
238,162,173 -> lightpink2
238,169,184 -> pink2
238,173, 14 -> darkgoldenrod2
238,174,238 -> plum2
238,180, 34 -> goldenrod2
238,180,180 -> rosybrown2
238,197,145 -> burlywood2
238,201,  0 -> gold2
238,203,173 -> peachpuff2
238,207,161 -> navajowhite2
238,210,238 -> thistle2
238,213,183 -> bisque2
238,213,210 -> mistyrose2
238,216,174 -> wheat2
238,220,130 -> lightgoldenrod2
238,221,130 -> light[ \-]?goldenrod
238,223,204 -> antiquewhite2
238,224,229 -> lavenderblush2
238,229,222 -> seashell2
238,230,133 -> khaki2
238,232,170 -> pale[ \-]?goldenrod
238,232,205 -> cornsilk2
238,233,191 -> lemonchiffon2
238,233,233 -> snow2
238,238,  0 -> yellow2
238,238,209 -> lightyellow2
238,238,224 -> ivory2
240,128,128 -> light[ \-]?coral
240,230,140 -> khaki
240,240,240 -> gr[ae]y94
240,248,255 -> alice[ \-]?blue
240,255,240 -> honeydew1?
240,255,255 -> azure1?
242,242,242 -> gr[ae]y95
244,164, 96 -> sandy[ \-]?brown
245,222,179 -> wheat
245,245,220 -> beige
245,245,245 -> white[ \-]?smoke|gr[ae]y96
245,255,250 -> mint[ \-]?cream
247,247,247 -> gr[ae]y97
248,248,255 -> ghost[ \-]?white
250,128,114 -> salmon
250,235,215 -> antique[ \-]?white
250,240,230 -> linen
250,250,210 -> light[ \-]?goldenrod[ \-]?yellow
250,250,250 -> gr[ae]y98
252,252,252 -> gr[ae]y99
253,245,230 -> old[ \-]?lace
255,  0,  0 -> red1?
255,  0,255 -> magenta1?
255, 20,147 -> deep[ \-]?pink1?
255, 48, 48 -> firebrick1
255, 52,179 -> maroon1
255, 62,150 -> violetred1
255, 64, 64 -> brown1
255, 69,  0 -> orange[ \-]?red1?
255, 99, 71 -> tomato1?
255,105,180 -> hot[ \-]?pink
255,106,106 -> indianred1
255,110,180 -> hotpink1
255,114, 86 -> coral1
255,127,  0 -> darkorange1
255,127, 36 -> chocolate1
255,127, 80 -> coral
255,130, 71 -> sienna1
255,130,171 -> palevioletred1
255,131,250 -> orchid1
255,140,  0 -> dark[ \-]?orange
255,140,105 -> salmon1
255,160,122 -> light[ \-]?salmon1?
255,165,  0 -> orange1?
255,165, 79 -> tan1
255,174,185 -> lightpink1
255,181,197 -> pink1
255,182,193 -> light[ \-]?pink
255,185, 15 -> darkgoldenrod1
255,187,255 -> plum1
255,192,203 -> pink
255,193, 37 -> goldenrod1
255,193,193 -> rosybrown1
255,211,155 -> burlywood1
255,215,  0 -> gold1?
255,218,185 -> peach[ \-]?puff1?
255,222,173 -> navajo[ \-]?white1?
255,225,255 -> thistle1
255,228,181 -> moccasin
255,228,196 -> bisque1?
255,228,225 -> misty[ \-]?rose1?
255,231,186 -> wheat1
255,235,205 -> blanched[ \-]?almond
255,236,139 -> lightgoldenrod1
255,239,213 -> papaya[ \-]?whip
255,239,219 -> antiquewhite1
255,240,245 -> lavender[ \-]?blush1?
255,245,238 -> seashell1?
255,246,143 -> khaki1
255,248,220 -> cornsilk1?
255,250,205 -> lemon[ \-]?chiffon1?
255,250,240 -> floral[ \-]?white
255,250,250 -> snow1?
255,255,  0 -> yellow1?
255,255,224 -> light[ \-]?yellow1?
255,255,240 -> ivory1?
255,255,255 -> white|gr[ae]y100
__END__
