Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | package Pastel::Color;\r |
2 | @ISA = qw (Pastel::Mixin::Mixin);\r | |
3 | use Carp;\r | |
4 | use strict;\r | |
5 | \r | |
6 | # Perl module for Pastel::Color\r | |
7 | # Cared for by Malay<curiouser@ccmb.ap.nic.in>\r | |
8 | # Copyright 2001, Malay Kumar Basu\r | |
9 | # You may distribute this module under the same terms as perl itself\r | |
10 | \r | |
11 | =head1 NAME\r | |
12 | \r | |
13 | Pastel::Color\r | |
14 | \r | |
15 | The Pastel::Color class encapsulates colors in the default sRGB color space. At present\r | |
16 | sRGB is the only Colorspace implemented.\r | |
17 | \r | |
18 | =head1 Description\r | |
19 | \r | |
20 | Every color has an implicit alpha value of 1.0 or an explicit one provided in the\r | |
21 | constructor. The alpha value defines the transparency of a color and can be represented\r | |
22 | by a float value in the range 0.0 - 1.0 . An alpha value of 1.0 \r | |
23 | means that the color is completely opaque and an alpha value of 0 or 0.0 means that\r | |
24 | the color is completely transparent.\r | |
25 | \r | |
26 | The default color space for the Pastel::Color API is sRGB (at present the only colorspace\r | |
27 | implemented). For further information on sRGB, see\r | |
28 | L<http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html>.\r | |
29 | \r | |
30 | =head1 Synopsis\r | |
31 | \r | |
32 | use Pastel::Graphics;\r | |
33 | use strict;\r | |
34 | \r | |
35 | my $color = Pastel::Color->new (10, 20, 30);\r | |
36 | my $color1 = Pastel::Color->new (-r=>10, -g=>20, -b=>30, -a=>0.5);\r | |
37 | my $color2 = Pastel::Color->new (10, 20, 30, 0.5); # $color now 50% transparent\r | |
38 | \r | |
39 | my $graphics = Pastel::Graphics->new(-width=>800, -height=>600);\r | |
40 | $graphics->set_paint($color); # All the drawing from now on will be in $color\r | |
41 | ...\r | |
42 | ...\r | |
43 | \r | |
44 | =head1 CONSTRUCTOR\r | |
45 | \r | |
46 | =over 4\r | |
47 | \r | |
48 | =item Pastel::Color->new( $int, $int, $int);\r | |
49 | \r | |
50 | Creates an sRGB color with the specified red, green, blue in the range (0 - 255).\r | |
51 | The tranparency is set to 1.0. Fully opaque.\r | |
52 | \r | |
53 | =item Pastel::Color->new( $int, $int, $int, $float_alpha)\r | |
54 | \r | |
55 | Creates an sRGB color with the specified red, green, blue in the range (0 - 255).\r | |
56 | Alpha values in the range (0.0 - 1.0). \r | |
57 | \r | |
58 | =item Pastel::Color->new(-r=>$int, -g=>$int, -b=>$int, -a=>$float);\r | |
59 | \r | |
60 | With Perl style named parameters.\r | |
61 | -r = Red, -g = Green , -b = Blue, -a = Alpha\r | |
62 | \r | |
63 | =back\r | |
64 | \r | |
65 | =head1 FIELDS\r | |
66 | \r | |
67 | =over 4\r | |
68 | \r | |
69 | =item _rgb_value\r | |
70 | \r | |
71 | Private.A value calculated from the Red, Green and the Blue integers supplied in the\r | |
72 | constructors. Alpha value supplied is not stored in this value because of rounding\r | |
73 | problems is Perl.\r | |
74 | \r | |
75 | =item _alpha\r | |
76 | \r | |
77 | Private. Stores the transparency float value.\r | |
78 | \r | |
79 | =back\r | |
80 | \r | |
81 | =cut\r | |
82 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r | |
83 | \r | |
84 | sub new {\r | |
85 | my $class = shift;\r | |
86 | my $self = {};\r | |
87 | bless $self, ref($class) || $class;\r | |
88 | $self->_init(@_);\r | |
89 | return $self;\r | |
90 | }\r | |
91 | \r | |
92 | sub _init {\r | |
93 | my ($self, @args) = @_;\r | |
94 | \r | |
95 | if ( (@args < 3) || (@args > 4) ){\r | |
96 | croak "Too many parameters\n";\r | |
97 | return 0;\r | |
98 | }\r | |
99 | \r | |
100 | # Get the parameters in order by calling Pastel::Mixin::Mixin::_rearrange()\r | |
101 | my ($r, $g, $b, $a) = $self->_rearrange(["R", "G", "B", "A"], @args);\r | |
102 | \r | |
103 | # Check for the correct range\r | |
104 | \r | |
105 | if ( defined($r) ){\r | |
106 | croak "Illegal value for red channel!!! I prefer B/W !!!\n"\r | |
107 | if ( ($r < 0) || ($r > 255) );\r | |
108 | }\r | |
109 | \r | |
110 | if ( defined($g) ){\r | |
111 | croak "Illegal value for the green channel!!! Trying to be too young!\n"\r | |
112 | if ( ($g< 0) || ($g > 255) );\r | |
113 | \r | |
114 | }\r | |
115 | \r | |
116 | if (defined($b)){\r | |
117 | croak "Illegal value for the blue channel!!! \n"\r | |
118 | if ( ($b< 0) || ($b > 255) );\r | |
119 | }\r | |
120 | \r | |
121 | if (defined($a)){\r | |
122 | if ( ($a < 0) ||($a > 1.0) ){\r | |
123 | croak "Illegal Alpha value in Color.pm";\r | |
124 | }\r | |
125 | else {\r | |
126 | $self->{_alpha} = $a;\r | |
127 | }\r | |
128 | \r | |
129 | }\r | |
130 | else {\r | |
131 | $self->{_alpha} = 1.0;\r | |
132 | }\r | |
133 | \r | |
134 | $self->{_rgb_value} = ( ($r & 0xFF) << 16 ) |\r | |
135 | ( ($g & 0xFF) << 8 ) |\r | |
136 | ( ($b & 0xFF) << 0 );\r | |
137 | return $self;\r | |
138 | } # Init\r | |
139 | \r | |
140 | ###################################################################\r | |
141 | \r | |
142 | =head1 ACCESSORS\r | |
143 | \r | |
144 | =cut\r | |
145 | \r | |
146 | =head2 get_rgb()\r | |
147 | \r | |
148 | Returns RGB value of the color. Red channel by bits 16-23, Green by bits 8-15\r | |
149 | and Blue by bits 0-7. Transparency value is not stored at bits 24-32, unlike the\r | |
150 | Java implementation, to avoid rounding error problems in Perl. To get Transparency\r | |
151 | (alpha) value use get_alpha() method.\r | |
152 | \r | |
153 | Usage: $color->get_rgb()\r | |
154 | \r | |
155 | =cut\r | |
156 | \r | |
157 | sub get_rgb { $_[0]->{_rgb_value}; }\r | |
158 | \r | |
159 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r | |
160 | \r | |
161 | =head2 get_red()\r | |
162 | \r | |
163 | Return the Red chaneel value in integer in the range 0-255.\r | |
164 | \r | |
165 | Usage: $color->get_red()\r | |
166 | \r | |
167 | =cut\r | |
168 | \r | |
169 | sub get_red { ($_[0]->get_rgb() >> 16) & 0xFF ; }\r | |
170 | \r | |
171 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r | |
172 | \r | |
173 | =head2 get_green()\r | |
174 | \r | |
175 | Return the Green chaneel value in integer in the range 0-255.\r | |
176 | \r | |
177 | Usage: $color->get_green()\r | |
178 | \r | |
179 | =cut\r | |
180 | \r | |
181 | sub get_green { ($_[0]->get_rgb() >> 8) & 0xFF ; }\r | |
182 | \r | |
183 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r | |
184 | \r | |
185 | =head2 get_blue()\r | |
186 | \r | |
187 | Return the Blue chaneel value in integer in the range 0-255.\r | |
188 | \r | |
189 | Usage: $color->get_blue()\r | |
190 | \r | |
191 | =cut\r | |
192 | \r | |
193 | sub get_blue { ($_[0]->get_rgb() >> 0) & 0xFF ; }\r | |
194 | \r | |
195 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r | |
196 | \r | |
197 | =head2 get_alpha()\r | |
198 | \r | |
199 | Return the Alpha (transparency) value in the range 0.0 - 1.0.\r | |
200 | \r | |
201 | Usage: $color->get_alpha()\r | |
202 | \r | |
203 | =cut\r | |
204 | \r | |
205 | sub get_alpha {\r | |
206 | if ( ($_[0]->{_alpha} == 1) ||\r | |
207 | !(defined ($_[0]->{_alpha}))\r | |
208 | )\r | |
209 | {\r | |
210 | return undef;\r | |
211 | }else {\r | |
212 | return $_[0]->{_alpha};\r | |
213 | }\r | |
214 | }\r | |
215 | \r | |
216 | ###################################################################\r | |
217 | \r | |
218 | =head1 METHODS\r | |
219 | \r | |
220 | =head2 brighter()\r | |
221 | \r | |
222 | Return a brighter version of the present Color object.\r | |
223 | \r | |
224 | Usage: my $brighter = $color->brighter();\r | |
225 | \r | |
226 | =cut\r | |
227 | \r | |
228 | sub brighter {\r | |
229 | my $self = shift;\r | |
230 | my $r = $self->get_red();\r | |
231 | my $g = $self->get_green();\r | |
232 | my $b = $self->get_blue();\r | |
233 | \r | |
234 | my $factor = 0.7; \r | |
235 | my $check = int (1.0/ (1.0 - $factor) );\r | |
236 | \r | |
237 | if ( ($r == 0) && ($g == 0) && ($b == 0) ){\r | |
238 | return $self->new($check, $check, $check);\r | |
239 | }\r | |
240 | \r | |
241 | if ( ($r > 0) && ($r < $check) ){ $r = $check; }\r | |
242 | if ( ($g > 0) && ($g < $check) ){ $g = $check; }\r | |
243 | if ( ($b > 0) && ($b < $check) ){ $b = $check; }\r | |
244 | \r | |
245 | # Function _min is defined in Pastel::Mixin::Mixin.pm\r | |
246 | # It returns the lower of the two value passed \r | |
247 | \r | |
248 | my $newr = $self->_min( int(($r/$factor)), 255);\r | |
249 | my $newg = $self->_min( int(($g/$factor)), 255);\r | |
250 | my $newb = $self->_min( int(($b/$factor)), 255);\r | |
251 | \r | |
252 | return $self->new( $newr, $newg, $newb );\r | |
253 | }\r | |
254 | \r | |
255 | \r | |
256 | =head2 darker()\r | |
257 | \r | |
258 | Return a darker version of the present color object.\r | |
259 | \r | |
260 | Usage: my $darker_color = $color->darker();\r | |
261 | \r | |
262 | =cut\r | |
263 | \r | |
264 | sub darker {\r | |
265 | my $self = shift;\r | |
266 | my $r = $self->get_red();\r | |
267 | my $g = $self->get_green();\r | |
268 | my $b = $self->get_blue();\r | |
269 | \r | |
270 | my $factor = 0.7;\r | |
271 | my $newr = $self->_max( int( $r * $factor), 0 );\r | |
272 | my $newg = $self->_max( int( $g * $factor), 0 );\r | |
273 | my $newb = $self->_max( int( $b * $factor), 0 );\r | |
274 | \r | |
275 | return $self->new( $newr, $newg, $newb);\r | |
276 | }\r | |
277 | \r | |
278 | \r | |
279 | =head2 black()\r | |
280 | \r | |
281 | Return a color object "black".\r | |
282 | \r | |
283 | Usage: my $graphics->set_paint( Pastel::Color->black() );\r | |
284 | \r | |
285 | =cut\r | |
286 | \r | |
287 | sub black {\r | |
288 | \r | |
289 | my $class = ref( $_[0]) || $_[0];\r | |
290 | my $self = {};\r | |
291 | bless $self, $class;\r | |
292 | $self->_init(0, 0, 0);\r | |
293 | return $self;\r | |
294 | \r | |
295 | } \r | |
296 | \r | |
297 | =head2 blue()\r | |
298 | \r | |
299 | Return a color object "blue"\r | |
300 | \r | |
301 | Usage: my $graphics->set_paint ( Pastel::Color->blue());\r | |
302 | \r | |
303 | =cut\r | |
304 | \r | |
305 | sub blue {\r | |
306 | my $class = ref( $_[0]) || $_[0];\r | |
307 | my $self = {};\r | |
308 | bless $self, $class;\r | |
309 | $self->_init(0, 0, 255);\r | |
310 | return $self;\r | |
311 | \r | |
312 | }\r | |
313 | \r | |
314 | =head2 red()\r | |
315 | \r | |
316 | Returns a color object "red".\r | |
317 | \r | |
318 | Usage: my $graphics->set_paint ( Pastel::Color->red());\r | |
319 | \r | |
320 | =cut\r | |
321 | \r | |
322 | sub red {\r | |
323 | my $class = ref( $_[0]) || $_[0];\r | |
324 | my $self = {};\r | |
325 | bless $self, $class;\r | |
326 | $self->_init(255, 0, 0);\r | |
327 | return $self;\r | |
328 | \r | |
329 | }\r | |
330 | \r | |
331 | =head2 white()\r | |
332 | \r | |
333 | Returns a color object "white".\r | |
334 | \r | |
335 | Usage: my $graphics->set_paint ( Pastel::Color->white());\r | |
336 | \r | |
337 | =cut\r | |
338 | \r | |
339 | sub white {\r | |
340 | my $class = ref( $_[0]) || $_[0];\r | |
341 | my $self = {};\r | |
342 | bless $self, $class;\r | |
343 | $self->_init(255, 255, 255);\r | |
344 | return $self;\r | |
345 | \r | |
346 | }\r | |
347 | \r | |
348 | =head2 light_gray()\r | |
349 | \r | |
350 | Returns a color object "light_gray".\r | |
351 | \r | |
352 | Usage: my $graphics->set_paint ( Pastel::Color->light_gray());\r | |
353 | \r | |
354 | =cut\r | |
355 | \r | |
356 | sub light_gray {\r | |
357 | my $class = ref( $_[0]) || $_[0];\r | |
358 | my $self = {};\r | |
359 | bless $self, $class;\r | |
360 | $self->_init(192, 192, 192);\r | |
361 | return $self;\r | |
362 | \r | |
363 | }\r | |
364 | \r | |
365 | =head2 gray()\r | |
366 | \r | |
367 | Returns a color object "gray".\r | |
368 | \r | |
369 | Usage: my $graphics->set_paint ( Pastel::Color->gray());\r | |
370 | \r | |
371 | =cut\r | |
372 | \r | |
373 | sub gray {\r | |
374 | my $class = ref( $_[0]) || $_[0];\r | |
375 | my $self = {};\r | |
376 | bless $self, $class;\r | |
377 | $self->_init(128, 128, 128);\r | |
378 | return $self;\r | |
379 | \r | |
380 | }\r | |
381 | \r | |
382 | =head2 dark_gray()\r | |
383 | \r | |
384 | Returns a color object "dark_gray".\r | |
385 | \r | |
386 | Usage: my $graphics->set_paint ( Pastel::Color->dark_gray());\r | |
387 | \r | |
388 | =cut\r | |
389 | \r | |
390 | sub dark_gray {\r | |
391 | my $class = ref( $_[0]) || $_[0];\r | |
392 | my $self = {};\r | |
393 | bless $self, $class;\r | |
394 | $self->_init(64, 64, 64);\r | |
395 | return $self;\r | |
396 | \r | |
397 | }\r | |
398 | \r | |
399 | \r | |
400 | =head2 pink()\r | |
401 | \r | |
402 | Returns a color object "pink".\r | |
403 | \r | |
404 | Usage: my $graphics->set_paint ( Pastel::Color->pink());\r | |
405 | \r | |
406 | =cut\r | |
407 | \r | |
408 | sub pink {\r | |
409 | my $class = ref( $_[0]) || $_[0];\r | |
410 | my $self = {};\r | |
411 | bless $self, $class;\r | |
412 | $self->_init(255, 175, 175);\r | |
413 | return $self;\r | |
414 | \r | |
415 | }\r | |
416 | \r | |
417 | =head2 orange()\r | |
418 | \r | |
419 | Returns a color object "red".\r | |
420 | \r | |
421 | Usage: my $graphics->set_paint ( Pastel::Color->orange());\r | |
422 | \r | |
423 | =cut\r | |
424 | \r | |
425 | sub orange {\r | |
426 | my $class = ref( $_[0]) || $_[0];\r | |
427 | my $self = {};\r | |
428 | bless $self, $class;\r | |
429 | $self->_init(255, 200, 0);\r | |
430 | return $self;\r | |
431 | \r | |
432 | }\r | |
433 | \r | |
434 | =head2 yellow()\r | |
435 | \r | |
436 | Returns a color object "yellow".\r | |
437 | \r | |
438 | Usage: my $graphics->set_paint ( Pastel::Color->yellow());\r | |
439 | \r | |
440 | =cut\r | |
441 | \r | |
442 | sub yellow {\r | |
443 | my $class = ref( $_[0]) || $_[0];\r | |
444 | my $self = {};\r | |
445 | bless $self, $class;\r | |
446 | $self->_init(255, 255, 0);\r | |
447 | return $self;\r | |
448 | \r | |
449 | }\r | |
450 | \r | |
451 | =head2 green()\r | |
452 | \r | |
453 | Returns a color object "green".\r | |
454 | \r | |
455 | Usage: my $graphics->set_paint ( Pastel::Color->green());\r | |
456 | \r | |
457 | =cut\r | |
458 | \r | |
459 | sub green {\r | |
460 | my $class = ref( $_[0]) || $_[0];\r | |
461 | my $self = {};\r | |
462 | bless $self, $class;\r | |
463 | $self->_init(0, 255, 0);\r | |
464 | return $self;\r | |
465 | \r | |
466 | }\r | |
467 | \r | |
468 | =head2 magenta()\r | |
469 | \r | |
470 | Returns a color object "magenta".\r | |
471 | \r | |
472 | Usage: my $graphics->set_paint ( Pastel::Color->magenta());\r | |
473 | \r | |
474 | =cut\r | |
475 | \r | |
476 | sub magenta {\r | |
477 | my $class = ref( $_[0]) || $_[0];\r | |
478 | my $self = {};\r | |
479 | bless $self, $class;\r | |
480 | $self->_init(255, 0, 255);\r | |
481 | return $self;\r | |
482 | \r | |
483 | }\r | |
484 | \r | |
485 | =head2 cyan()\r | |
486 | \r | |
487 | Returns a color object "cyan".\r | |
488 | \r | |
489 | Usage: my $graphics->set_paint ( Pastel::Color->cyan());\r | |
490 | \r | |
491 | =cut\r | |
492 | \r | |
493 | sub cyan {\r | |
494 | my $class = ref( $_[0]) || $_[0];\r | |
495 | my $self = {};\r | |
496 | bless $self, $class;\r | |
497 | $self->_init(0, 255, 255);\r | |
498 | return $self;\r | |
499 | \r | |
500 | }\r | |
501 | \r | |
502 | =head2 equals(Color $color)\r | |
503 | \r | |
504 | Returns true if $color is equivalent to the present color. This method\r | |
505 | compares the "red", "green", "blue" and the "alpha" value of the two colors\r | |
506 | and return 1 if both are same or returns 0 if they are diffrent.\r | |
507 | \r | |
508 | Usage: my $color1 = Pastel::Color->new(255, 255, 255);\r | |
509 | my $white = Pastel::Color->white();\r | |
510 | print "They are same" if $color1->equals($white);\r | |
511 | \r | |
512 | =cut\r | |
513 | \r | |
514 | sub equals {\r | |
515 | my $self = shift;\r | |
516 | my $color = shift;\r | |
517 | \r | |
518 | if ( ($self->get_rgb() == $color->get_rgb() ) &&\r | |
519 | ($self->get_alpha() == $color->get_alpha() )\r | |
520 | ) {\r | |
521 | return 1;\r | |
522 | }\r | |
523 | \r | |
524 | else {\r | |
525 | return 0;\r | |
526 | }\r | |
527 | }\r | |
528 | \r | |
529 | \r | |
530 | =head2 to_string()\r | |
531 | \r | |
532 | Returns the string representation of the object.\r | |
533 | \r | |
534 | Usage: $color->to_string();\r | |
535 | \r | |
536 | =cut\r | |
537 | \r | |
538 | sub to_string {\r | |
539 | my $self =shift;\r | |
540 | return ref($self)."[r=".$self->get_red().",g=".$self->get_green().",b=".$self->get_blue()."]";\r | |
541 | }\r | |
542 | \r | |
543 | =head1 PRIVATE METHODS\r | |
544 | \r | |
545 | =head2 to_svg()\r | |
546 | \r | |
547 | Return the string Pastel coded form of this object. Called by any object with\r | |
548 | style color.\r | |
549 | \r | |
550 | =cut\r | |
551 | \r | |
552 | sub to_svg {\r | |
553 | my $self =shift;\r | |
554 | $self->to_svg_stroke();\r | |
555 | }\r | |
556 | \r | |
557 | sub to_hex {\r | |
558 | my $self = shift;\r | |
559 | my $red = unpack ("H2", pack("I",$self->get_red()));\r | |
560 | my $green = unpack ("H2", pack("I",$self->get_green()));\r | |
561 | my $blue = unpack ("H2", pack("I",$self->get_blue()));\r | |
562 | return "\#".$red.$green.$blue;\r | |
563 | }\r | |
564 | \r | |
565 | sub to_svg_fill {\r | |
566 | my $self = shift;\r | |
567 | my $red = unpack ("H2", pack("I",$self->get_red()));\r | |
568 | my $green = unpack ("H2", pack("I",$self->get_green()));\r | |
569 | my $blue = unpack ("H2", pack("I",$self->get_blue()));\r | |
570 | my $s = "fill:\#".$red.$green.$blue;\r | |
571 | if ($self->get_alpha()){\r | |
572 | $s .= ';'. "fill-opacity:". $self->get_alpha();\r | |
573 | }\r | |
574 | return $s;\r | |
575 | }\r | |
576 | \r | |
577 | sub to_svg_stroke {\r | |
578 | my $self = shift;\r | |
579 | my $red = unpack ("H2", pack("I",$self->get_red()));\r | |
580 | my $green = unpack ("H2", pack("I",$self->get_green()));\r | |
581 | my $blue = unpack ("H2", pack("I",$self->get_blue()));\r | |
582 | my $s = "stroke:\#".$red.$green.$blue;\r | |
583 | if ($self->get_alpha()){\r | |
584 | $s .= ';'. "stroke-opacity:".$self->get_alpha();\r | |
585 | }else {\r | |
586 | $s .= ';';\r | |
587 | }\r | |
588 | return $s;\r | |
589 | }\r | |
590 | \r | |
591 | \r | |
592 | 1;\r |