#!/usr/local/bin/perl
#
# xpmnamecolor
#
# Copyright (C) 1998,2000 Taiji Yamada <taiji@aihara.co.jp>

#$opt_s = "/usr/X11R5/lib/X11/rgb.txt:/usr/X11R6/lib/X11/rgb.txt";
$opt_s = undef;
#$opt_d = "/usr/X11R5/lib/X11/rgb.txt";
$opt_d = "/usr/X11R6/lib/X11/rgb.txt";
require 'getopts.pl';
&Getopts('s:d:uvpPtT')
    || die "usage: $0 [[-s rgb.txt] -d rgb.txt] [-u] [-v] < in > out\n".
    "\trgb.txt ... RGB color name database ($opt_d).\n".
    "-u ... use only colors in database\n".
    "-v ... print color value, otherwise color name.\n".
    "-p ... database output mode, sorted by color value only for source.\n".
    "-P ... database output mode, sorted by color name  only for source.\n".
    "-t ... database output mode, sorted by color value.\n".
    "-T ... database output mode, sorted by color name.\n";

if ($opt_d) {
  %color_value_names = ();
  %color_name_values = ();
  foreach $f (split(/:/,$opt_d)) {
    open(RGB,"$f") || print STDERR "can't open $f\n";
    while (<RGB>) {
      next if (/^!/);
      if (/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(.+)/) {
        ($r,$g,$b,$name) = ($1,$2,$3,$4);
        $value = sprintf("%02x%02x%02x",$r,$g,$b);
        $color_value_names{$value} = $name if (!$color_value_names{$value});
        $color_name_values{$name} = $value;
      }
    }
    close(RGB);
  }
}
if ($opt_s) {
  %Color_value_names = ();
  %Color_name_values = ();
  foreach $f (split(/:/,$opt_s)) {
    open(RGB,"$f") || print STDERR "can't open $f\n";
    while (<RGB>) {
      next if (/^!/);
      if (/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(.+)/) {
        ($r,$g,$b,$name) = ($1,$2,$3,$4);
        $value = sprintf("%02x%02x%02x",$r,$g,$b);
        $Color_value_names{$value} = $name if (!$Color_value_names{$value});
        $Color_name_values{$name} = $value;
      }
    }
    close(RGB);
  }
}
else {
  %Color_value_names = %color_value_names;
  %Color_name_values = %color_name_values;
}

sub hex2rgb {
  local($c) = @_;
  local($r,$g,$b) = $c =~ /(.{2,2})(.{2,2})(.{2,2})/;
  (hex($r),hex($g),hex($b));
}

if ($opt_p) {
  foreach $value (sort keys %Color_value_names) {
    printf("%3d %3d %3d\t\t%s\n",&hex2rgb($value),$Color_value_names{$value});
  }
  exit;
}
if ($opt_P) {
  foreach $name (sort keys %Color_name_values) {
    printf("%3d %3d %3d\t\t%s\n",&hex2rgb($Color_name_values{$name}),$name);
  }
  exit;
}

if ($opt_t) {
  foreach $value (sort keys %color_value_names) {
    printf("%3d %3d %3d\t\t%s\n",&hex2rgb($value),$color_value_names{$value});
  }
  exit;
}
if ($opt_T) {
  foreach $name (sort keys %color_name_values) {
    printf("%3d %3d %3d\t\t%s\n",&hex2rgb($color_name_values{$name}),$name);
  }
  exit;
}

sub colordistance {
  local($c1,$c2) = @_;
  local($r1,$g1,$b1) = &hex2rgb($c1);
  local($r2,$g2,$b2) = &hex2rgb($c2);
  abs($r1-$r2) + abs($g1-$g2) + abs($b1-$b2);
}

sub dbcolor {
  local($dbcolor) = @_;
  if (!$color_value_names{$dbcolor}) {
    local(@values) = keys %color_value_names;
    local($min_index) = 0;
    local($min_value) = $values[$min_index];
    local($min) = &colordistance($min_value,$dbcolor);
    local($value,$distance);
    for ($min_index=1; $min_index<@values; $min_index++) {
      $value = $values[$min_index];
      $distance = &colordistance($value,$dbcolor);
      if ($min > $distance) {
        $min = $distance; 
        $min_value = $value;
      }
    }
    $dbcolor = $min_value;
  }
  $dbcolor;
}

$header = 0;
$name = ""; $chars_per_pixel = 0; $chars_per_line = 0;
$colors = 0;
$pixels = 0;
$pixels_flag = 0;
$y = 0;
$mask = "";
%pixel_values = ();
while (<>) {
  if (/\/\*\s*XPM\s\*\//) {
    $header = !0;
  }
  elsif ($header && $chars_per_pixel
         && (/\/\*\s*colors\s\*\//
             || /\"[^\"]{$chars_per_pixel,$chars_per_pixel}\s+((c|m|g|g4|s)\s+[^\"]+)+\"/)) {
    $colors = !0;
  }
  elsif ($header && $colors && $chars_per_line
         && (/\/\*\s*pixels\s\*\//
             || /\"[^\"]{$chars_per_line,$chars_per_line}\"/)) {
    $pixels = !0;
  }
  if ($header && !$colors && !$pixels) {
    if (/static\s+char\s+\*\s*(.*)\[\]\s*=\s*\{/) {
      $name = $1;
      print "/* XPM */\n";
      print "static char *$name\[\] = {\n";
    }
    elsif (/\"\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*\"/) {
      ($width,$height,$num_colors,$chars_per_pixel) = ($1,$2,$3,$4);
      $chars_per_line = $width*$chars_per_pixel;
      print "/* width height num_colors chars_per_pixel */\n";
    }
  }
  elsif ($colors && !$pixels) {
    if (/\"([^\"]{$chars_per_pixel,$chars_per_pixel})\s+((c|m|g|g4|s)\s+[^\"]+)+\"/) {
      ($pixel,$value) = ($1,$2);
      $pixel_values{$pixel} = $value;
    }
  }
  elsif ($pixels) {
    if (!$pixels_flag) {
      %value_pixels = ();
      $num_colors = 0;
      foreach $pixel (sort keys %pixel_values) {
        $value = $pixel_values{$pixel};
        if ($value =~ /[nN]one/ || $value =~ /[tT]ransparent/) {
          $mask = $pixel;
	  $value =~ s/([tT]ransparent|none)/None/;
        }
        elsif ($value =~ /#\S+/) {
          ($value) = $value =~ /#(\S+)/;
          if ($opt_v) {
            if (!$opt_u) {
              $value = "c #$value";
            }
            else {
              if ($Color_value_names{($dbc=&dbcolor($value))}) {
                $value = $Color_value_names{$dbc};
                $value = "c #$Color_name_values{$value}";
              }
              else {
                $value = "c #$dbc"; # !
              }
            }
          }
          else {
            if (!$opt_u) {
              if ($Color_value_names{$value}) {
                $value = "c $Color_value_names{$value}";
              }
              else {
                $value = "c #$value";
              }
            }
            else {
              if ($Color_value_names{($dbc=&dbcolor($value))}) {
                $value = "c $Color_value_names{$dbc}";
              }
              else {
                $value = "c #$dbc"; # !
              }
            }
          }
        }
        elsif ($value =~ /c\s+.+((m|g|g4|s)\s+[^\"]+)*/) {
          ($name,$other) = $value =~ /c\s+(.+)((m|g|g4|s)\s+[^\"]+)*/;
          if ($Color_name_values{$name}) {
            $value = $Color_name_values{$name};
            $value = $Color_value_names{$value};
            $value = "#$Color_name_values{$value}" if ($opt_v);
            goto escape;
          }
          $name =~ y/A-Z/a-z/;
          if ($Color_name_values{$name}) {
            $value = $Color_name_values{$name};
            $value = $Color_value_names{$value};
            $value = "#$Color_name_values{$value}" if ($opt_v);
            goto escape;
          }
          $name =~ s/\s//g;
          if ($Color_name_values{$name}) {
            $value = $Color_name_values{$name};
            $value = $Color_value_names{$value};
            $value = "#$Color_name_values{$value}" if ($opt_v);
            goto escape;
          }
          {
            $value = $name;     # as is
          }
escape:
          $value = "c $value";
        }
        else {
          ;                     # as is
        }
        $pixel_values{$pixel} = $value;
        $value_pixels{$value} = $pixel;
      }
      foreach $value (keys %value_pixels) {
	$num_colors++;
      }
      print "\"$width $height $num_colors $chars_per_pixel\",\n";
      print "/* colors */\n";
      foreach $value (sort keys %value_pixels) {
        print "\"$value_pixels{$value} $value\",\n";
      }
      print "/* pixels */\n";
      $pixels_flag = !0;
    }
    if (/\"([^\"]*)\"/) {
      $buf = $1;
      print "\"";
      for ($x=0; $x<$width; $x++) {
        $pixel = substr($buf,$x*$chars_per_pixel,$chars_per_pixel);
        print $value_pixels{$pixel_values{$pixel}};
      }
      print "\",\n";
      $y++;
    }
  } 
}
print "};\n";
