9 # It's just a front end to the XS creation functions.
11 # used in converting hsv to rgb
14 'vkm', 'nvm', 'mvk', 'mnv', 'kmv', 'vmn'
18 my ($hue, $sat, $val) = @_;
20 # HSV conversions from pages 401-403 "Procedural Elements for Computer
21 # Graphics", 1985, ISBN 0-07-053534-5.
25 return ( 255 * $val, 255 * $val, 255 * $val );
28 $val >= 0 or $val = 0;
29 $val <= 1 or $val = 1;
30 $sat <= 1 or $sat = 1;
31 $hue >= 360 and $hue %= 360;
32 $hue < 0 and $hue += 360;
37 my $m = $val * (1.0 - $sat);
38 my $n = $val * (1.0 - $sat * $f);
39 my $k = $val * (1.0 - $sat * (1 - $f));
41 my %fields = ( 'm'=>$m, 'n'=>$n, 'v'=>$v, 'k'=>$k, );
42 return @fields{split //, $hsv_map[$i]};
46 # cache of loaded gimp files
47 # each key is a filename, under each key is a hashref with the following
49 # mod_time => last mod_time of file
50 # colors => hashref name to arrayref of colors
53 # palette search locations
55 # $HOME is replaced at runtime
58 '$HOME/.gimp-1.2/palettes/Named_Colors',
59 '$HOME/.gimp-1.1/palettes/Named_Colors',
60 '$HOME/.gimp/palettes/Named_Colors',
61 '/usr/share/gimp/1.2/palettes/Named_Colors',
62 '/usr/share/gimp/1.1/palettes/Named_Colors',
63 '/usr/share/gimp/palettes/Named_Colors',
66 sub _load_gimp_palette {
69 if (open PAL, "< $filename") {
72 unless ($hdr =~ /GIMP Palette/) {
74 $Imager::ERRSTR = "$filename is not a GIMP palette file";
79 my $mod_time = (stat PAL)[9];
80 while (defined($line = <PAL>)) {
81 next if $line =~ /^#/ || $line =~ /^\s*$/;
83 my ($r,$g, $b, $name) = split ' ', $line, 4;
85 $name =~ s/\s*\([\d\s]+\)\s*$//;
86 $pal{lc $name} = [ $r, $g, $b ];
91 $gimp_cache{$filename} = { mod_time=>$mod_time, colors=>\%pal };
96 $Imager::ERRSTR = "Cannot open palette file $filename: $!";
101 sub _get_gimp_color {
105 if ($args{palette}) {
106 $filename = $args{palette};
109 # try to make one up - this is intended to die if tainting is
110 # enabled and $ENV{HOME} is tainted. To avoid that untaint $ENV{HOME}
111 # or set the palette parameter
112 for my $attempt (@gimp_search) {
113 my $work = $attempt; # don't modify the source array
114 $work =~ /\$HOME/ && !defined $ENV{HOME}
116 $work =~ s/\$HOME/$ENV{HOME}/;
123 $Imager::ERRSTR = "No GIMP palette found";
128 if ((!$gimp_cache{$filename}
129 || (stat $filename)[9] != $gimp_cache{$filename})
130 && !_load_gimp_palette($filename)) {
134 if (!$gimp_cache{$filename}{colors}{lc $args{name}}) {
135 $Imager::ERRSTR = "Color '$args{name}' isn't in $filename";
139 return @{$gimp_cache{$filename}{colors}{lc $args{name}}};
144 '/usr/lib/X11/rgb.txt', # seems fairly standard
145 '/usr/local/lib/X11/rgb.txt', # seems possible
146 '/usr/X11R6/lib/X11/rgb.txt', # probably the same as the first
147 '/usr/openwin/lib/rgb.txt',
148 '/usr/openwin/lib/X11/rgb.txt',
152 # same structure as %gimp_cache
159 if (open RGB, "< $filename") {
162 my $mod_time = (stat RGB)[9];
163 while (defined($line = <RGB>)) {
164 # the version of rgb.txt supplied with GNU Emacs uses # for comments
165 next if $line =~ /^[!#]/ || $line =~ /^\s*$/;
167 my ($r,$g, $b, $name) = split ' ', $line, 4;
169 $pal{lc $name} = [ $r, $g, $b ];
174 $x_cache{$filename} = { mod_time=>$mod_time, colors=>\%pal };
179 $Imager::ERRSTR = "Cannot open palette file $filename: $!";
188 if ($args{palette}) {
189 $filename = $args{palette};
192 for my $attempt (@x_search) {
194 $filename = $attempt;
199 $Imager::ERRSTR = "No X rgb.txt palette found";
204 if ((!$x_cache{$filename}
205 || (stat $filename)[9] != $x_cache{$filename})
206 && !_load_x_rgb($filename)) {
210 if (!$x_cache{$filename}{colors}{lc $args{name}}) {
211 $Imager::ERRSTR = "Color '$args{name}' isn't in $filename";
215 return @{$x_cache{$filename}{colors}{lc $args{name}}};
218 # Parse color spec into an a set of 4 colors
221 return (@_,255) if @_ == 3 && !grep /[^\d.+eE-]/, @_;
222 return (@_ ) if @_ == 4 && !grep /[^\d.+eE-]/, @_;
224 /^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) {
225 return (hex($1),hex($2),hex($3),hex($4));
227 if ($_[0] =~ /^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) {
228 return (hex($1),hex($2),hex($3),255);
230 if ($_[0] =~ /^\#([\da-f])([\da-f])([\da-f])$/i) {
231 return (hex($1) * 17, hex($2) * 17, hex($3) * 17, 255);
236 %args = ( name => @_ );
242 if (exists $args{gray}) {
243 @result = $args{gray};
245 elsif (exists $args{grey}) {
246 @result = $args{grey};
248 elsif ((exists $args{red} || exists $args{r})
249 && (exists $args{green} || exists $args{g})
250 && (exists $args{blue} || exists $args{b})) {
251 @result = ( exists $args{red} ? $args{red} : $args{r},
252 exists $args{green} ? $args{green} : $args{g},
253 exists $args{blue} ? $args{blue} : $args{b} );
255 elsif ((exists $args{hue} || exists $args{h})
256 && (exists $args{saturation} || exists $args{'s'})
257 && (exists $args{value} || exists $args{v})) {
258 my $hue = exists $args{hue} ? $args{hue} : $args{h};
259 my $sat = exists $args{saturation} ? $args{saturation} : $args{'s'};
260 my $val = exists $args{value} ? $args{value} : $args{v};
262 @result = _hsv_to_rgb($hue, $sat, $val);
264 elsif (exists $args{web}) {
265 if ($args{web} =~ /^#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])$/i) {
266 @result = (hex($1),hex($2),hex($3));
268 elsif ($args{web} =~ /^#?([\da-f])([\da-f])([\da-f])$/i) {
269 @result = (hex($1) * 17, hex($2) * 17, hex($3) * 17);
272 elsif ($args{name}) {
273 unless (@result = _get_gimp_color(%args)) {
274 unless (@result = _get_x_color(%args)) {
275 require Imager::Color::Table;
276 unless (@result = Imager::Color::Table->get($args{name})) {
277 $Imager::ERRSTR = "No color named $args{name} found";
283 elsif ($args{gimp}) {
284 @result = _get_gimp_color(name=>$args{gimp}, %args);
286 elsif ($args{xname}) {
287 @result = _get_x_color(name=>$args{xname}, %args);
289 elsif ($args{builtin}) {
290 require Imager::Color::Table;
291 @result = Imager::Color::Table->get($args{builtin});
294 @result = @{$args{rgb}};
296 elsif ($args{rgba}) {
297 @result = @{$args{rgba}};
298 return @result if @result == 4;
301 @result = _hsv_to_rgb(@{$args{hsv}});
303 elsif ($args{channels}) {
304 return @{$args{channels}};
306 elsif (exists $args{channel0} || $args{c0}) {
308 while (exists $args{"channel$i"} || exists $args{"c$i"}) {
310 exists $args{"channel$i"} ? $args{"channel$i"} : $args{"c$i"});
315 $Imager::ERRSTR = "No color specification found";
319 if (exists $args{alpha} || exists $args{a}) {
320 push(@result, exists $args{alpha} ? $args{alpha} : $args{a});
322 while (@result < 4) {
331 shift; # get rid of class name.
332 my @arg = _pspec(@_);
333 return @arg ? new_internal($arg[0],$arg[1],$arg[2],$arg[3]) : ();
338 my @arg = _pspec(@_);
339 return @arg ? set_internal($self, $arg[0],$arg[1],$arg[2],$arg[3]) : ();
343 my ($self, %opts) = @_;
345 my $other = $opts{other}
346 or return Imager->_set_error("'other' parameter required");
347 my $ignore_alpha = $opts{ignore_alpha} || 0;
349 my @left = $self->rgba;
350 my @right = $other->rgba;
351 my $last_chan = $ignore_alpha ? 2 : 3;
352 for my $ch (0 .. $last_chan) {
353 $left[$ch] == $right[$ch]
366 Imager::Color - Color handling for Imager.
370 $color = Imager::Color->new($red, $green, $blue);
371 $color = Imager::Color->new($red, $green, $blue, $alpha);
372 $color = Imager::Color->new("#C0C0FF"); # html color specification
374 $color->set($red, $green, $blue);
375 $color->set($red, $green, $blue, $alpha);
376 $color->set("#C0C0FF"); # html color specification
378 ($red, $green, $blue, $alpha) = $color->rgba();
379 @hsv = $color->hsv(); # not implemented but proposed
383 if ($color->equals(other=>$other_color)) {
390 This module handles creating color objects used by imager. The idea is
391 that in the future this module will be able to handle colorspace calculations
398 This creates a color object to pass to functions that need a color argument.
402 This changes an already defined color. Note that this does not affect any places
403 where the color has been used previously.
407 This returns the rgba code of the color the object contains.
411 Calling info merely dumps the relevant colorcode to the log.
413 =item equals(other=>$other_color)
415 =item equals(other=>$other_color, ignore_alpha=>1)
417 Compares $self and color $other_color returning true if the color
418 components are the same.
420 Compares all four channels unless C<ignore_alpha> is set. If
421 C<ignore_alpha> is set only the first three channels are compared.
425 You can specify colors in several different ways, you can just supply
432 simple numeric parameters - if you supply 3 or 4 numeric arguments, you get a color made up of those RGB (and possibly A) components.
436 a six hex digit web color, either 'RRGGBB' or '#RRGGBB'
440 an eight hex digit web color, either 'RRGGBBAA' or '#RRGGBBAA'.
444 a 3 hex digit web color, '#RGB' - a value of F becomes 255.
448 a color name, from whichever of the gimp Named_Colors file or X
449 rgb.txt is found first. The same as using the name keyword.
453 You can supply named parameters:
459 'red', 'green' and 'blue', optionally shortened to 'r', 'g' and 'b'.
460 The color components in the range 0 to 255.
462 # all of the following are equivalent
463 my $c1 = Imager::Color->new(red=>100, blue=>255, green=>0);
464 my $c2 = Imager::Color->new(r=>100, b=>255, g=>0);
465 my $c3 = Imager::Color->new(r=>100, blue=>255, g=>0);
469 'hue', 'saturation' and 'value', optionally shortened to 'h', 's' and
470 'v', to specify a HSV color. 0 <= hue < 360, 0 <= s <= 1 and 0 <= v
473 # the same as RGB(127,255,127)
474 my $c1 = Imager::Color->new(hue=>120, v=>1, s=>0.5);
475 my $c1 = Imager::Color->new(hue=>120, value=>1, saturation=>0.5);
479 'web', which can specify a 6 or 3 hex digit web color, in any of the
480 forms '#RRGGBB', '#RGB', 'RRGGBB' or 'RGB'.
482 my $c1 = Imager::Color->new(web=>'#FFC0C0'); # pale red
486 'gray' or 'grey' which specifies a single channel, from 0 to 255.
489 my $c1 = Imager::Color->new(gray=>128);
490 my $c1 = Imager::Color->new(grey=>128);
494 'rgb' which takes a 3 member arrayref, containing each of the red,
495 green and blue values.
498 my $c1 = Imager::Color->new(rgb=>[255, 100, 0]);
499 my $c1 = Imager::Color->new(r=>255, g=>100, b=>0);
503 'hsv' which takes a 3 member arrayref, containting each of hue,
504 saturation and value.
507 my $c1 = Imager::Color->new(hsv=>[120, 0.5, 1]);
508 my $c1 = Imager::Color->new(hue=>120, v=>1, s=>0.5);
512 'gimp' which specifies a color from a GIMP palette file. You can
513 specify the filename of the palette file with the 'palette' parameter,
514 or let Imager::Color look in various places, typically
515 "$HOME/gimp-1.x/palettes/Named_Colors" with and without the version
516 number, and in /usr/share/gimp/palettes/. The palette file must have
519 my $c1 = Imager::Color->new(gimp=>'snow');
520 my $c1 = Imager::Color->new(gimp=>'snow', palette=>'testimg/test_gimp_pal);
524 'xname' which specifies a color from an X11 rgb.txt file. You can
525 specify the filename of the rgb.txt file with the 'palette' parameter,
526 or let Imager::Color look in various places, typically
527 '/usr/lib/X11/rgb.txt'.
529 my $c1 = Imager::Color->new(xname=>'blue') # usually RGB(0, 0, 255)
533 'builtin' which specifies a color from the built-in color table in
534 Imager::Color::Table. The colors in this module are the same as the
535 default X11 rgb.txt file.
537 my $c1 = Imager::Color->new(builtin=>'black') # always RGB(0, 0, 0)
541 'name' which specifies a name from either a GIMP palette, an X rgb.txt
542 file or the built-in color table, whichever is found first.
546 'channel0', 'channel1', etc, each of which specifies a single channel. These can be abbreviated to 'c0', 'c1' etc.
550 'channels' which takes an arrayref of the channel values.
554 Optionally you can add an alpha channel to a color with the 'alpha' or
557 These color specifications can be used for both constructing new
558 colors with the new() method and modifying existing colors with the
563 Arnar M. Hrafnkelsson, addi@umich.edu
564 And a great deal of help from others - see the README for a complete
570 http://imager.perl.org/