a litte more internals documentation
[imager-graph.git] / Graph.pm
1 package Imager::Graph;
2 require 5.005;
3
4 =head1 NAME
5
6 Imager::Graph - Perl extension for producing Graphs using the Imager library.
7
8 =head1 SYNOPSIS
9
10   use Imager::Graph::SubClass;
11   my $chart = Imager::Graph::SubClass->new;
12   my $img = $chart->draw(data=> \@data, ...)
13     or die $chart->error;
14
15 =head1 DESCRIPTION
16
17 Imager::Graph provides style information to its base classes.  It
18 defines the colors, text display information and fills based on both
19 built-in styles and modifications supplied by the user to the draw()
20 method.
21
22 =over
23
24 =cut
25
26 use strict;
27 use warnings;
28 use vars qw($VERSION);
29 use Imager qw(:handy);
30 use Imager::Fountain;
31
32 $VERSION = '0.06';
33
34 # the maximum recursion depth in determining a color, fill or number
35 use constant MAX_DEPTH => 10;
36
37 my $NUM_RE = '(?:[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]\d+?)?)';
38
39 =item new
40
41 This is a simple constructor.  No parameters required.
42
43 =cut
44
45 sub new {
46   bless {}, $_[0];
47 }
48
49 =item error
50
51 Returns an error message.  Only value if the draw() method returns false.
52
53 =cut
54
55 sub error {
56   $_[0]->{_errstr};
57 }
58
59 =item draw
60
61 Creates a new image, draws the chart onto that image and returns it.
62
63 Typically you will need to supply a C<data> parameter in the format
64 required by that particular graph, and if your graph will use any
65 text, a C<font> parameter
66
67 You can also supply many different parameters which control the way
68 the graph looks.  These are supplied as keyword, value pairs, where
69 the value can be a hashref containing sub values.
70
71 The C<style> parameter will selects a basic color set, and possibly
72 sets other related parameters.  See L</"STYLES">.
73
74  my $font = Imager::Font->new(file => 'ImUgly.ttf');
75  my $img = $chart->draw(
76                  data    => \@data,
77                  font    => $font,
78                  title   => {
79                                  text  => "Hello, World!",
80                                  size  => 36,
81                                  color => 'FF0000'
82                             }
83                  );
84
85 When referring to a single sub-value this documentation will refer to
86 'title.color' rather than 'the color element of title'.
87
88 Returns the graph image on success, or false on failure.
89
90 =back
91
92 =head1 STYLES
93
94 The currently defined styles are:
95
96 =over
97
98 =item primary
99
100 a light grey background with no outlines.  Uses primary colors for the
101 data fills.
102
103 =item primary_red
104
105 a light red background with no outlines.  Uses primary colors for the
106 data fills.
107
108 Graphs drawn using this style should save well as a gif, even though
109 some graphs may perform a slight blur.
110
111 This was the default style, but the red was too loud.
112
113 =item mono
114
115 designed for monochrome output, such as most laser printers, this uses
116 hatched fills for the data, and no colors.  The returned image is a
117 one channel image (which can be overridden with the C<channels>
118 parameter.)
119
120 You can also override the colors used by all components for background
121 or drawing by supplying C<fg> and/or C<bg> parameters.  ie.  if you
122 supply C<<fg=>'FF0000', channels=>3>> then the hash fills and anything
123 else will be drawn in red.  Another use might be to set a transparent
124 background, by supplying C<<bg=>'00000000', channels=>4>>.
125
126 This style outlines the legend if present and outlines the hashed fills.
127
128 =item fount_lin
129
130 designed as a "pretty" style this uses linear fountain fills for the
131 background and data fills, and adds a drop shadow.
132
133 You can override the value used for text and outlines by setting the
134 C<fg> parameter.
135
136 This is the default style.
137
138 =item fount_rad
139
140 also designed as a "pretty" style this uses radial fountain fills for
141 the data and a linear blue to green fill for the background.
142
143 =back
144
145 =head1 FEATURES
146
147 Each graph type has a number of features.  These are used to add
148 various items that are displayed in the graph area.  Some common
149 features are:
150
151 =over
152
153 =item legend
154
155 adds a box containing boxes filled with the data filess, with
156 the labels provided to the draw method.  The legend will only be
157 displayed if both the legend feature is enabled and labels are
158 supplied.
159
160 =item labels
161
162 labels each data fill, usually by including text inside the data fill.
163 If the text does not fit in the fill, they could be displayed in some
164 other form, eg. as callouts in a pie graph.  There usually isn't much
165 point in including both labels and a legend.
166
167 =item dropshadow
168
169 a simple drop shadow is shown behind some of the graph elements.
170
171 =back
172
173 Each graph also has features specific to that graph.
174
175 =head1 COMMON PARAMETERS
176
177 When referring to a single sub-value this documentation will refer to
178 'title.color' rather than 'the color element of title'.
179
180 Normally, except for the font parameter, these are controlled by
181 styles, but these are the style parameters I'd mostly likely expect
182 you want to use:
183
184 =over
185
186 =item font
187
188 the Imager font object used to draw text on the chart.
189
190 =item back
191
192 the background fill for the graph.  Default depends on the style.
193
194 =item size
195
196 the base size of the graph image.  Default: 256
197
198 =item width
199
200 the width of the graph image.  Default: 1.5 * size (384)
201
202 =item height
203
204 the height of the graph image.  Default: size (256)
205
206 =item channels
207
208 the number of channels in the image.  Default: 3 (the 'mono' style
209 sets this to 1).
210
211 =item line
212
213 the color used for drawing lines, such as outlines or callouts.
214 Default depends on the current style.  Set to undef to remove the
215 outline from a style.
216
217 =item title
218
219 the text used for a graph title.  Default: no title.  Note: this is
220 the same as the title=>{ text => ... } field.
221
222 =over
223
224 =item halign
225
226 horizontal alignment of the title in the graph, one of 'left',
227 'center' or 'right'. Default: center
228
229 =item valign
230
231 vertical alignment of the title, one of 'top', 'center' or 'right'.
232 Default: top.  It's probably a bad idea to set this to 'center' unless
233 you have a very short title.
234
235 =back
236
237 =item text
238
239 This contains basic defaults used in drawing text.
240
241 =over
242
243 =item color
244
245 the default color used for all text, defaults to the fg color.
246
247 =item size
248
249 the base size used for text, also used to scale many graph elements.
250 Default: 14.
251
252 =back
253
254 =back
255
256 =head1 BEYOND STYLES
257
258 In most cases you will want to use just the styles, but you may want
259 to exert more control over the way your chart looks.  This section
260 describes the options you can use to control the way your chart looks.
261
262 Hopefully you don't need to read this.
263
264 =over
265
266 =item back
267
268 The background of the graph.
269
270 =item bg
271
272 =item fg
273
274 Used to define basic background and foreground colors for the graph.
275 The bg color may be used for the background of the graph, and is used
276 as a default for the background of hatcheed fills.  The fg is used as
277 the default for line and text colors.
278
279 =item font
280
281 The default font used by the graph.  Normally you should supply this
282 if your graph as any text.
283
284 =item line
285
286 The default line color.
287
288 =item text
289
290 defaults for drawing text.  Other textual graph elements will inherit
291 or modify these values.
292
293 =over
294
295 =item color
296
297 default text color, defaults to the I<fg> color.
298
299 =item size
300
301 default text size. Default: 14.  This is used to scale many graph
302 elements, including padding and leader sizes.  Other text elements
303 will either use or scale this value.
304
305 =item font
306
307 default font object.  Inherited from I<font>, which should have been
308 supplied by the caller.
309
310 =back
311
312 =item title
313
314 If you supply a scalar value for this element, it will be stored in
315 the I<text> field.
316
317 Defines the text, font and layout information for the title.
318
319 =over
320
321 =item color
322
323 The color of the title, inherited from I<text.color>.
324
325 =item font
326
327 The font object used for the title, inherited from I<text.font>.
328
329 =item size
330
331 size of the title text. Default: double I<text.size>
332
333 =item halign
334
335 =item valign
336
337 The horizontal and vertical alignment of the title.
338
339 =back
340
341 =item legend
342
343 defines attributes of the graph legend, if present.
344
345 =over
346
347 =item color
348
349 =item font
350
351 =item size
352
353 text attributes for the labels used in the legend.
354
355 =item patchsize
356
357 the width and height of the color patch in the legend.  Defaults to
358 90% of the legend text size.
359
360 =item patchgap
361
362 the minimum gap between patches in pixels.  Defaults to 30% of the
363 patchsize.
364
365 =item patchborder
366
367 the color of the border drawn around each patch.  Inherited from I<line>.
368
369 =item halign
370
371 =item valign
372
373 the horizontal and vertical alignment of the legend within the graph.
374 Defaults to 'right' and 'top'.
375
376 =item padding
377
378 the gap between the legend patches and text and the outside of it's
379 box, or to the legend border, if any.
380
381 =item outsidepadding
382
383 the gap between the border and the outside of the legend's box.  This
384 is only used if the I<legend.border> attribute is defined.
385
386 =item fill
387
388 the background fill for the legend.  Default: none
389
390 =item border
391
392 the border color of the legend.  Default: none (no border is drawn
393 around the legend.)
394
395 =item orientation
396
397 The orientation of the legend.  If this is C<vertical> the the patches
398 and labels are stacked on top of each other.  If this is C<horizontal>
399 the patchs and labels are word wrapped across the image.  Default:
400 vertical.
401
402 =back
403
404 For example to create a horizontal legend with borderless patches,
405 darker than the background, you might do:
406
407   my $im = $chart->draw
408     (...,
409     legend =>
410     {
411       patchborder => undef,
412       orientation => 'horizontal',
413       fill => { solid => Imager::Color->new(0, 0, 0, 32), }
414     },
415     ...);
416
417 =item callout
418
419 defines attributes for graph callouts, if any are present.  eg. if the
420 pie graph cannot fit the label into the pie graph segement it will
421 present it as a callout.
422
423 =over
424
425 =item color
426
427 =item font
428
429 =item size
430
431 the text attributes of the callout label.  Inherited from I<text>.
432
433 =item line
434
435 the color of the callout lines.  Inherited from I<line>
436
437 =item inside
438
439 =item outside
440
441 the length of the leader on the inside and the outside of the fill,
442 usually at some angle.  Both default to the size of the callout text.
443
444 =item leadlen
445
446 the length of the horizontal portion of the leader.  Default:
447 I<callout.size>.
448
449 =item gap
450
451 the gap between the callout leader and the callout text.  Defaults to
452 30% of the text callout size.
453
454 =back
455
456 =item label
457
458 defines attributes for labels drawn into the data areas of a graph.
459
460 =over
461
462 =item color
463
464 =item font
465
466 =item size
467
468 The text attributes of the labels.  Inherited from I<text>.
469
470 =back
471
472 =item dropshadow
473
474 the attributes of the graph's drop shadow
475
476 =over
477
478 =item fill
479
480 the fill used for the drop shadow.  Default: '404040' (dark gray)
481
482 =item off
483
484 the offset of the drop shadow.  A convenience value inherited by offx
485 and offy.  Default: 40% of I<text.size>.
486
487 =item offx
488
489 =item offy
490
491 the horizontal and vertical offsets of the drop shadow.  Both
492 inherited from I<dropshadow.off>.
493
494 =item filter
495
496 the filter description passed to Imager's filter method to blur the
497 drop shadow.  Default: an 11 element convolution filter.
498
499 =back
500
501 =item outline
502
503 describes the lines drawn around filled data areas, such as the
504 segments of a pie chart.
505
506 =over
507
508 =item line
509
510 the line color of the outlines, inherited from I<line>.
511
512 =back
513
514 =item fills
515
516 a reference to an array containing fills for each data item.
517
518 You can mix fill types, ie. using a simple color for the first item, a
519 hatched fill for the second and a fountain fill for the next.
520
521 =back
522
523 =head1 HOW VALUES WORK
524
525 Internally rather than specifying literal color, fill, or font objects
526 or literal sizes for each element, Imager::Graph uses a number of
527 special values to inherit or modify values taken from other graph
528 element names.
529
530 =head2 Specifying colors
531
532 You can specify colors by either supplying an Imager::Color object, by
533 supplying lookup of another color, or by supplying a single value that
534 Imager::Color::new can use as an initializer.  The most obvious is
535 just a 6 or 8 digit hex value representing the red, green, blue and
536 optionally alpha channels of the image.
537
538 You can lookup another color by using the lookup() "function", for
539 example if you give a color as "lookup(fg)" then Imager::Graph will
540 look for the fg element in the current style (or as overridden by
541 you.)  This is used internally by Imager::Graph to set up the
542 relationships between the colors of various elements, for example the
543 default style information contains:
544
545    text=>{
546           color=>'lookup(fg)',
547           ...
548          },
549    legend =>{
550              color=>'lookup(text.color)',
551              ...
552             },
553
554 So by setting the I<fg> color, you also set the default text color,
555 since each text element uses lookup(text.color) as its value.
556
557 =head2 Specifying fills
558
559 Fills can be used for the graph background color, the background color
560 for the legend block and for the fills used for each data element.
561
562 You can specify a fill as a L<color value|Specifying colors> or as a
563 general fill, see L<Imager::Fill> for details.
564
565 You don't need (or usually want) to call Imager::Fill::new yourself,
566 since the various fill functions will call it for you, and
567 Imager::Graph provides some hooks to make them more useful.
568
569 =over
570
571 =item *
572
573 with hatched fills, if you don't supply a 'fg' or 'bg' parameter,
574 Imager::Graph will supply the current graph fg and bg colors.
575
576 =item *
577
578 with fountain fill, you can supply the xa_ratio, ya_ratio, xb_ratio
579 and yb_ratio parameters, and they will be scaled in the fill area to
580 define the fountain fills xa, ya, xb and yb parameters.
581
582 =back
583
584 As with colors, you can use lookup(name) or lookup(name1.name2) to
585 have one element to inherit the fill of another.
586
587 Imager::Graph defaults the fill combine value to C<'normal'>.  This
588 doesn't apply to simple color fills.
589
590 =head2 Specifying numbers
591
592 You can specify various numbers, usually representing the size of
593 something, commonly text, but sometimes the length of a line or the
594 size of a gap.
595
596 You can use the same lookup mechanism as with colors and fills, but
597 you can also scale values.  For example, 'scale(0.5,text.size)' will
598 return half the size of the normal text size.
599
600 As with colors, this is used internally to scale graph elements based
601 on the base text size.  If you change the base text size then other
602 graph elements will scale as well.
603
604 =head2 Specifying other elements
605
606 Other elements, such as fonts, or parameters for a filter, can also
607 use the lookup(name) mechanism.
608
609 =head1 INTERNAL METHODS
610
611 Only useful if you need to fix bugs, add features or create a new
612 graph class.
613
614 =over
615
616 =cut
617
618 my %style_defs =
619   (
620    back=> 'lookup(bg)',
621    line=> 'lookup(fg)',
622    text=>{
623           color => 'lookup(fg)',
624           font  => 'lookup(font)',
625           size  => 14,
626          },
627    title=>{ 
628            color  => 'lookup(text.color)', 
629            font   => 'lookup(text.font)',
630            halign => 'center', 
631            valign => 'top',
632            size   => 'scale(text.size,2.0)',
633           },
634    legend =>{
635              color          => 'lookup(text.color)',
636              font           => 'lookup(text.font)',
637              size           => 'lookup(text.size)',
638              patchsize      => 'scale(legend.size,0.9)',
639              patchgap       => 'scale(legend.patchsize,0.3)',
640              patchborder    => 'lookup(line)',
641              halign         => 'right',
642              valign         => 'top',
643              padding        => 'scale(legend.size,0.3)',
644              outsidepadding => 'scale(legend.padding,0.4)',
645             },
646    callout => {
647                color    => 'lookup(text.color)',
648                font     => 'lookup(text.font)',
649                size     => 'lookup(text.size)',
650                line     => 'lookup(line)',
651                inside   => 'lookup(callout.size)',
652                outside  => 'lookup(callout.size)',
653                leadlen  => 'scale(0.8,callout.size)',
654                gap      => 'scale(callout.size,0.3)',
655               },
656    label => {
657              font          => 'lookup(text.font)',
658              size          => 'lookup(text.size)',
659              color         => 'lookup(text.color)',
660              hpad          => 'lookup(label.pad)',
661              vpad          => 'lookup(label.pad)',
662              pad           => 'scale(label.size,0.2)',
663              pcformat      => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
664              pconlyformat  => sub { sprintf "%.1f%%", $_[0] },
665              },
666    dropshadow => {
667                   fill    => { solid => Imager::Color->new(0, 0, 0, 96) },
668                   off     => 'scale(0.4,text.size)',
669                   offx    => 'lookup(dropshadow.off)',
670                   offy    => 'lookup(dropshadow.off)',
671                   filter  => { type=>'conv', 
672                               # this needs a fairly heavy blur
673                               coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2, 
674                                      0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
675                  },
676    outline => {
677                line =>'lookup(line)',
678               },
679    size=>256,
680    width=>'scale(1.5,size)',
681    height=>'lookup(size)',
682   );
683
684 =item _error($message)
685
686 Sets the error field of the object and returns an empty list or undef,
687 depending on context.  Should be used for error handling, since it may
688 provide some user hooks at some point.
689
690 The intended usage is:
691
692   some action
693     or return $self->_error("error description");
694
695 You should almost always return the result of _error() or return
696 immediately afterwards.
697
698 =cut
699
700 sub _error {
701   my ($self, $error) = @_;
702
703   $self->{_errstr} = $error;
704
705   return;
706 }
707
708
709 =item _style_defs()
710
711 Returns the style defaults, such as the relationships between line
712 color and text color.
713
714 Intended to be over-ridden by base classes to provide graph specific
715 defaults.
716
717 =cut
718
719 sub _style_defs {
720   \%style_defs;
721 }
722
723 # Let's make the default something that looks really good, so folks will be interested enough to customize the style.
724 my $def_style = 'fount_lin';
725
726 my %styles =
727   (
728    primary =>
729    {
730     fills=>
731     [
732      qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
733     ],
734     fg=>'000000',
735     bg=>'E0E0E0',
736     legend=>
737     {
738      #patchborder=>'000000'
739     },
740    },
741    primary_red =>
742    {
743     fills=>
744     [
745      qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
746     ],
747     fg=>'000000',
748     bg=>'C08080',
749     legend=>
750     {
751      patchborder=>'000000'
752     },
753    },
754    mono =>
755    {
756     fills=>
757     [
758      { hatch=>'slash2' },
759      { hatch=>'slosh2' },
760      { hatch=>'vline2' },
761      { hatch=>'hline2' },
762      { hatch=>'cross2' },
763      { hatch=>'grid2' },
764      { hatch=>'stipple3' },
765      { hatch=>'stipple2' },
766     ],
767     channels=>1,
768     bg=>'FFFFFF',
769     fg=>'000000',
770     features=>{ outline=>1 },
771     pie =>{
772            blur=>undef,
773           },
774    },
775    fount_lin =>
776    {
777     fills=>
778     [
779      { fountain=>'linear',
780        xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
781        segments => Imager::Fountain->simple(positions=>[0, 1],
782                                             colors=>[ NC('FFC0C0'), NC('FF0000') ]),
783      },
784      { fountain=>'linear',
785        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
786        segments => Imager::Fountain->simple(positions=>[0, 1],
787                                             colors=>[ NC('C0FFC0'), NC('00FF00') ]),
788      },
789      { fountain=>'linear',
790        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
791        segments => Imager::Fountain->simple(positions=>[0, 1],
792                                             colors=>[ NC('C0C0FF'), NC('0000FF') ]),
793      },
794      { fountain=>'linear',
795        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
796        segments => Imager::Fountain->simple(positions=>[0, 1],
797                                             colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
798      },
799      { fountain=>'linear',
800        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
801        segments => Imager::Fountain->simple(positions=>[0, 1],
802                                             colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
803      },
804      { fountain=>'linear',
805        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
806        segments => Imager::Fountain->simple(positions=>[0, 1],
807                                             colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
808      },
809     ],
810     back=>{ fountain=>'linear',
811             xa_ratio=>0, ya_ratio=>0,
812             xb_ratio=>1.0, yb_ratio=>1.0,
813             segments=>Imager::Fountain->simple
814             ( positions=>[0, 1],
815               colors=>[ NC('6060FF'), NC('60FF60') ]) },
816     fg=>'000000',
817     bg=>'FFFFFF',
818     features=>{ dropshadow=>1 },
819    },
820    fount_rad =>
821    {
822     fills=>
823     [
824      { fountain=>'radial',
825        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
826        segments => Imager::Fountain->simple(positions=>[0, 1],
827                                             colors=>[ NC('FF8080'), NC('FF0000') ]),
828      },
829      { fountain=>'radial',
830        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
831        segments => Imager::Fountain->simple(positions=>[0, 1],
832                                             colors=>[ NC('80FF80'), NC('00FF00') ]),
833      },
834      { fountain=>'radial',
835        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
836        segments => Imager::Fountain->simple(positions=>[0, 1],
837                                             colors=>[ NC('808080FF'), NC('0000FF') ]),
838      },
839      { fountain=>'radial',
840        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
841        segments => Imager::Fountain->simple(positions=>[0, 1],
842                                             colors=>[ NC('FFFF80'), NC('FFFF00') ]),
843      },
844      { fountain=>'radial',
845        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
846        segments => Imager::Fountain->simple(positions=>[0, 1],
847                                             colors=>[ NC('80FFFF'), NC('00FFFF') ]),
848      },
849      { fountain=>'radial',
850        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
851        segments => Imager::Fountain->simple(positions=>[0, 1],
852                                             colors=>[ NC('FF80FF'), NC('FF00FF') ]),
853      },
854     ],
855     back=>{ fountain=>'linear',
856             xa_ratio=>0, ya_ratio=>0,
857             xb_ratio=>1.0, yb_ratio=>1.0,
858             segments=>Imager::Fountain->simple
859             ( positions=>[0, 1],
860               colors=>[ NC('6060FF'), NC('60FF60') ]) },
861     fg=>'000000',
862     bg=>'FFFFFF',
863    }
864   );
865
866 =item $self->_style_setup(\%opts)
867
868 Uses the values from %opts to build a customized hash describing the
869 way the graph should be drawn.
870
871 =cut
872
873 sub _style_setup {
874   my ($self, $opts) = @_;
875   my $style_defs = $self->_style_defs;
876   my $style;
877   $style = $styles{$opts->{style}} if $opts->{style};
878   $style ||= $styles{$def_style};
879
880   my @search_list = ( $style_defs, $style, $opts);
881   my %work;
882
883   my @composite = $self->_composite();
884   my %composite;
885   @composite{@composite} = @composite;
886
887   for my $src (@search_list) {
888     for my $key (keys %$src) {
889       if ($composite{$key}) {
890         $work{$key} = {} unless exists $work{$key};
891         if (ref $src->{$key}) {
892           # some keys have sub values, especially text
893           @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
894         }
895         else {
896           # assume it's the text for a title or something
897           $work{$key}{text} = $src->{$key};
898         }
899       }
900       else {
901         $work{$key} = $src->{$key};
902       }
903     }
904   }
905
906   # features are handled specially
907   $work{features} = {};
908   for my $src (@search_list) {
909     if ($src->{features}) {
910       if (ref $src->{features}) {
911         if (ref($src->{features}) =~ /ARRAY/) {
912           # just set those features
913           for my $feature (@{$src->{features}}) {
914             $work{features}{$feature} = 1;
915           }
916         }
917         elsif (ref($src->{features}) =~ /HASH/) {
918           if ($src->{features}{reset}) {
919             $work{features} = {}; # only the ones the user specifies
920           }
921           @{$work{features}}{keys %{$src->{features}}} =
922             values(%{$src->{features}});
923         }
924       }
925       else {
926         # just set that single feature
927         $work{features}{$src->{features}} = 1;
928       }
929     }
930   }
931   #use Data::Dumper;
932   #print Dumper(\%work);
933
934   $self->{_style} = \%work;
935 }
936
937 =item $self->_get_thing($name)
938
939 Retrieve some general 'thing'.
940
941 Supports the 'lookup(foo)' mechanism.
942
943 Returns an empty list on failure.
944
945 =cut
946
947 sub _get_thing {
948   my ($self, $name, @depth) = @_;
949
950   push(@depth, $name);
951   my $what;
952   if ($name =~ /^(\w+)\.(\w+)$/) {
953     $what = $self->{_style}{$1}{$2};
954   }
955   else {
956     $what = $self->{_style}{$name};
957   }
958   defined $what or
959     return;
960   if (ref $what) {
961     return $what;
962   }
963   elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
964     @depth < MAX_DEPTH
965       or return $self->_error("too many levels of recursion in lookup(@depth)");
966     return $self->_get_thing($1, @depth);
967   }
968   else {
969     return $what;
970   }
971 }
972
973 =item $self->_get_number($name)
974
975 Retrieves a number from the style.  The value in the style can be the
976 number, or one of two functions:
977
978 =over
979
980 =item lookup(newname)
981
982 Recursively looks up I<newname> in the style.
983
984 =item scale(value1,value2)
985
986 Each value can be a number or a name.  Names are recursively looked up
987 in the style and the product is returned.
988
989 =back
990
991 =cut
992
993 sub _get_number {
994   my ($self, $name, @depth) = @_;
995
996   push(@depth, $name);
997   my $what;
998   if ($name =~ /^(\w+)\.(\w+)$/) {
999     $what = $self->{_style}{$1}{$2};
1000   }
1001   else {
1002     $what = $self->{_style}{$name};
1003   }
1004   defined $what or
1005     return $self->_error("$name is undef (@depth)");
1006
1007   if (ref $what) {
1008     if ($what =~ /CODE/) {
1009       $what = $what->($self, $name);
1010     }
1011   }
1012   else {
1013     if ($what =~ /^lookup\(([\w.]+)\)$/) {
1014       @depth < MAX_DEPTH
1015         or return $self->_error("too many levels of recursion in lookup (@depth)");
1016       return $self->_get_number($1, @depth);
1017     }
1018     elsif ($what =~ /^scale\(
1019                     ((?:[a-z][\w.]*)|$NUM_RE)
1020                     ,
1021                     ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
1022       my ($left, $right) = ($1, $2);
1023       unless ($left =~ /^$NUM_RE$/) {
1024         @depth < MAX_DEPTH 
1025           or return $self->_error("too many levels of recursion in scale (@depth)");
1026         $left = $self->_get_number($left, @depth);
1027       }
1028       unless ($right =~ /^$NUM_RE$/) {
1029         @depth < MAX_DEPTH 
1030           or return $self->_error("too many levels of recursion in scale (@depth)");
1031         $right = $self->_get_number($right, @depth);
1032       }
1033       return $left * $right;
1034     }
1035     else {
1036       return $what+0;
1037     }
1038   }
1039 }
1040
1041 =item $self->_get_integer($name)
1042
1043 Retrieves an integer from the style.  This is a simple wrapper around
1044 _get_number() that rounds the result to an integer.
1045
1046 Returns an empty list on failure.
1047
1048 =cut
1049
1050 sub _get_integer {
1051   my ($self, $name, @depth) = @_;
1052
1053   my $number = $self->_get_number($name, @depth)
1054     or return;
1055
1056   return sprintf("%.0f", $number);
1057 }
1058
1059 =item _get_color($name)
1060
1061 Returns a color object of the given name from the style hash.
1062
1063 Uses Imager::Color->new to translate normal scalars into color objects.
1064
1065 Allows the lookup(name) mechanism.
1066
1067 Returns an empty list on failure.
1068
1069 =cut
1070
1071 sub _get_color {
1072   my ($self, $name, @depth) = @_;
1073
1074   push(@depth, $name);
1075   my $what;
1076   if ($name =~ /^(\w+)\.(\w+)$/) {
1077     $what = $self->{_style}{$1}{$2};
1078   }
1079   else {
1080     $what = $self->{_style}{$name};
1081   }
1082
1083   defined($what)
1084     or return $self->_error("$name was undefined (@depth)");
1085
1086   unless (ref $what) {
1087     if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1088       @depth < MAX_DEPTH or
1089         return $self->_error("too many levels of recursion in lookup (@depth)");
1090
1091       return $self->_get_color($1, @depth);
1092     }
1093     $what = Imager::Color->new($what);
1094   }
1095
1096   $what;
1097 }
1098
1099 =item _translate_fill($what, $box)
1100
1101 Given the value of a fill, either attempts to convert it into a fill
1102 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1103 parameters }>>), or to lookup another fill that is referred to with
1104 the 'lookup(name)' mechanism.
1105
1106 This function does the fg and bg initialization for hatched fills, and
1107 translation of *_ratio for fountain fills (using the $box parameter).
1108
1109 Returns an empty list on failure.
1110
1111 =cut
1112
1113 sub _translate_fill {
1114   my ($self, $what, $box, @depth) = @_;
1115
1116   if (ref $what) {
1117     if (UNIVERSAL::isa($what, "Imager::Color")) {
1118       return ( color=>Imager::Color->new($what), filled=>1 );
1119     }
1120     else {
1121       # a general fill
1122       # default to normal combine mode
1123       my %work = ( combine => 'normal', %$what );
1124       if ($what->{hatch}) {
1125         if (!$work{fg}) {
1126           $work{fg} = $self->_get_color('fg')
1127             or return;
1128         }
1129         if (!$work{bg}) {
1130           $work{bg} = $self->_get_color('bg')
1131             or return;
1132         }
1133         return ( fill=>\%work );
1134       }
1135       elsif ($what->{fountain}) {
1136         for my $key (qw(xa ya xb yb)) {
1137           if (exists $work{"${key}_ratio"}) {
1138             if ($key =~ /^x/) {
1139               $work{$key} = $box->[0] + $work{"${key}_ratio"} 
1140                 * ($box->[2] - $box->[0]);
1141             }
1142             else {
1143               $work{$key} = $box->[1] + $work{"${key}_ratio"} 
1144                 * ($box->[3] - $box->[1]);
1145             }
1146           }
1147         }
1148         return ( fill=>\%work );
1149       }
1150       else {
1151         return ( fill=> \%work );
1152       }
1153     }
1154   }
1155   else {
1156     if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1157       return $self->_get_fill($1, $box, @depth);
1158     }
1159     else {
1160       # assumed to be an Imager::Color single value
1161       return ( color=>Imager::Color->new($what), filled=>1 );
1162     }
1163   }
1164 }
1165
1166 =item _data_fill($index, $box)
1167
1168 Retrieves the fill parameters for a data area fill.
1169
1170 =cut
1171
1172 sub _data_fill {
1173   my ($self, $index, $box) = @_;
1174
1175   my $fills = $self->{_style}{fills};
1176   return $self->_translate_fill($fills->[$index % @$fills], $box,
1177                                 "data.$index");
1178 }
1179
1180 =item _get_fill($index, $box)
1181
1182 Retrieves fill parameters for a named fill.
1183
1184 =cut
1185
1186 sub _get_fill {
1187   my ($self, $name, $box, @depth) = @_;
1188
1189   push(@depth, $name);
1190   my $what;
1191   if ($name =~ /^(\w+)\.(\w+)$/) {
1192     $what = $self->{_style}{$1}{$2};
1193   }
1194   else {
1195     $what = $self->{_style}{$name};
1196   }
1197
1198   defined($what)
1199     or return $self->_error("no fill $name found");
1200
1201   return $self->_translate_fill($what, $box, @depth);
1202 }
1203
1204 =item _make_img()
1205
1206 Builds the image object for the graph and fills it with the background
1207 fill.
1208
1209 =cut
1210
1211 sub _make_img {
1212   my ($self) = @_;
1213
1214   my $width = $self->_get_number('width') || 256;
1215   my $height = $self->_get_number('height') || 256;
1216   my $channels = $self->{_style}{channels};
1217
1218   $channels ||= 3;
1219
1220   my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1221
1222   $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1223
1224   $img;
1225 }
1226
1227 =item _text_style($name)
1228
1229 Returns parameters suitable for calls to Imager::Font's bounding_box()
1230 and draw() methods intended for use in defining text styles.
1231
1232 Returns an empty list on failure.
1233
1234 =cut
1235
1236 sub _text_style {
1237   my ($self, $name) = @_;
1238
1239   my %work;
1240
1241   if ($self->{_style}{$name}) {
1242     %work = %{$self->{_style}{$name}};
1243   }
1244   else {
1245     %work = %{$self->{_style}{text}};
1246   }
1247   $work{font}
1248     or return $self->_error("$name has no font parameter");
1249
1250   $work{font} = $self->_get_thing("$name.font")
1251     or return $self->_error("No $name.font defined, either set $name.font or font to a font");
1252   UNIVERSAL::isa($work{font}, "Imager::Font")
1253       or return $self->_error("$name.font is not a font");
1254   if ($work{color} && !ref $work{color}) {
1255     $work{color} = $self->_get_color("$name.color")
1256       or return;
1257   }
1258   $work{size} = $self->_get_number("$name.size");
1259   $work{sizew} = $self->_get_number("$name.sizew")
1260     if $work{sizew};
1261
1262   %work;
1263 }
1264
1265 =item _text_bbox($text, $name)
1266
1267 Returns a bounding box for the specified $text as styled by $name.
1268
1269 Returns an empty list on failure.
1270
1271 =cut
1272
1273 sub _text_bbox {
1274   my ($self, $text, $name) = @_;
1275
1276   my %text_info = $self->_text_style($name)
1277     or return;
1278
1279   my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1280                                             canon=>1);
1281
1282   return @bbox[0..3];
1283 }
1284
1285 sub _align_box {
1286   my ($self, $box, $chart_box, $name) = @_;
1287
1288   my $halign = $self->{_style}{$name}{halign}
1289     or $self->_error("no halign for $name");
1290   my $valign = $self->{_style}{$name}{valign};
1291
1292   if ($halign eq 'right') {
1293     $box->[0] += $chart_box->[2] - $box->[2];
1294   }
1295   elsif ($halign eq 'left') {
1296     $box->[0] = $chart_box->[0];
1297   }
1298   elsif ($halign eq 'center' || $halign eq 'centre') {
1299     $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
1300   }
1301   else {
1302     return $self->_error("invalid halign $halign for $name");
1303   }
1304
1305   if ($valign eq 'top') {
1306     $box->[1] = $chart_box->[1];
1307   }
1308   elsif ($valign eq 'bottom') {
1309     $box->[1] = $chart_box->[3] - $box->[3];
1310   }
1311   elsif ($valign eq 'center' || $valign eq 'centre') {
1312     $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
1313   }
1314   else {
1315     return $self->_error("invalid valign $valign for $name");
1316   }
1317   $box->[2] += $box->[0];
1318   $box->[3] += $box->[1];
1319 }
1320
1321 sub _remove_box {
1322   my ($self, $chart_box, $object_box) = @_;
1323
1324   my $areax;
1325   my $areay;
1326   if ($object_box->[0] - $chart_box->[0] 
1327       < $chart_box->[2] - $object_box->[2]) {
1328     $areax = ($object_box->[2] - $chart_box->[0]) 
1329       * ($chart_box->[3] - $chart_box->[1]);
1330   }
1331   else {
1332     $areax = ($chart_box->[2] - $object_box->[0]) 
1333       * ($chart_box->[3] - $chart_box->[1]);
1334   }
1335
1336   if ($object_box->[1] - $chart_box->[1] 
1337       < $chart_box->[3] - $object_box->[3]) {
1338     $areay = ($object_box->[3] - $chart_box->[1]) 
1339       * ($chart_box->[2] - $chart_box->[0]);
1340   }
1341   else {
1342     $areay = ($chart_box->[3] - $object_box->[1]) 
1343       * ($chart_box->[2] - $chart_box->[0]);
1344   }
1345
1346   if ($areay < $areax) {
1347     if ($object_box->[1] - $chart_box->[1] 
1348         < $chart_box->[3] - $object_box->[3]) {
1349       $chart_box->[1] = $object_box->[3];
1350     }
1351     else {
1352       $chart_box->[3] = $object_box->[1];
1353     }
1354   }
1355   else {
1356     if ($object_box->[0] - $chart_box->[0] 
1357         < $chart_box->[2] - $object_box->[2]) {
1358       $chart_box->[0] = $object_box->[2];
1359     }
1360     else {
1361       $chart_box->[2] = $object_box->[0];
1362     }
1363   }
1364 }
1365
1366 sub _draw_legend {
1367   my ($self, $img, $labels, $chart_box) = @_;
1368
1369   my $orient = $self->_get_thing('legend.orientation');
1370   defined $orient or $orient = 'vertical';
1371
1372   if ($orient eq 'vertical') {
1373     return $self->_draw_legend_vertical($img, $labels, $chart_box);
1374   }
1375   elsif ($orient eq 'horizontal') {
1376     return $self->_draw_legend_horizontal($img, $labels, $chart_box);
1377   }
1378   else {
1379     return $self->_error("Unknown legend.orientation $orient");
1380   }
1381 }
1382
1383 sub _draw_legend_horizontal {
1384   my ($self, $img, $labels, $chart_box) = @_;
1385
1386   defined(my $padding = $self->_get_integer('legend.padding'))
1387     or return;
1388   my $patchsize = $self->_get_integer('legend.patchsize')
1389     or return;
1390   defined(my $gap = $self->_get_integer('legend.patchgap'))
1391     or return;
1392
1393   my $minrowsize = $patchsize + $gap;
1394   my ($width, $height) = (0,0);
1395   my $row_height = $minrowsize;
1396   my $pos = 0;
1397   my @sizes;
1398   my @offsets;
1399   for my $label (@$labels) {
1400     my @text_box = $self->_text_bbox($label, 'legend')
1401       or return;
1402     push(@sizes, \@text_box);
1403     my $entry_width = $patchsize + $gap + $text_box[2];
1404     if ($pos == 0) {
1405       # never re-wrap the first entry
1406       push @offsets, [ 0, $height ];
1407     }
1408     else {
1409       if ($pos + $gap + $entry_width > $chart_box->[2]) {
1410         $pos = 0;
1411         $height += $row_height;
1412       }
1413       push @offsets, [ $pos, $height ];
1414     }
1415     my $entry_right = $pos + $entry_width;
1416     $pos += $gap + $entry_width;
1417     $entry_right > $width and $width = $entry_right;
1418     if ($text_box[3] > $row_height) {
1419       $row_height = $text_box[3];
1420     }
1421   }
1422   $height += $row_height;
1423   my @box = ( 0, 0, $width + $padding * 2, $height + $padding * 2 );
1424   my $outsidepadding = 0;
1425   if ($self->{_style}{legend}{border}) {
1426     defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
1427       or return;
1428     $box[2] += 2 * $outsidepadding;
1429     $box[3] += 2 * $outsidepadding;
1430   }
1431   $self->_align_box(\@box, $chart_box, 'legend')
1432     or return;
1433   if ($self->{_style}{legend}{fill}) {
1434     $img->box(xmin=>$box[0]+$outsidepadding, 
1435               ymin=>$box[1]+$outsidepadding, 
1436               xmax=>$box[2]-$outsidepadding, 
1437               ymax=>$box[3]-$outsidepadding,
1438              $self->_get_fill('legend.fill', \@box));
1439   }
1440   $box[0] += $outsidepadding;
1441   $box[1] += $outsidepadding;
1442   $box[2] -= $outsidepadding;
1443   $box[3] -= $outsidepadding;
1444   my %text_info = $self->_text_style('legend')
1445     or return;
1446   my $patchborder;
1447   if ($self->{_style}{legend}{patchborder}) {
1448     $patchborder = $self->_get_color('legend.patchborder')
1449       or return;
1450   }
1451   
1452   my $dataindex = 0;
1453   for my $label (@$labels) {
1454     my ($left, $top) = @{$offsets[$dataindex]};
1455     $left += $box[0] + $padding;
1456     $top += $box[1] + $padding;
1457     my $textpos = $left + $patchsize + $gap;
1458     my @patchbox = ( $left, $top,
1459                      $left + $patchsize, $top + $patchsize );
1460     my @fill = $self->_data_fill($dataindex, \@patchbox)
1461       or return;
1462     $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
1463                ymax=>$top + $patchsize, @fill);
1464     if ($self->{_style}{legend}{patchborder}) {
1465       $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
1466                 ymax=>$top + $patchsize,
1467                 color=>$patchborder);
1468     }
1469     $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize, 
1470                  text=>$label);
1471
1472     ++$dataindex;
1473   }
1474   if ($self->{_style}{legend}{border}) {
1475     my $border_color = $self->_get_color('legend.border')
1476       or return;
1477     $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
1478               color=>$border_color);
1479   }
1480   $self->_remove_box($chart_box, \@box);
1481   1;
1482 }
1483
1484 sub _draw_legend_vertical {
1485   my ($self, $img, $labels, $chart_box) = @_;
1486
1487   defined(my $padding = $self->_get_integer('legend.padding'))
1488     or return;
1489   my $patchsize = $self->_get_integer('legend.patchsize')
1490     or return;
1491   defined(my $gap = $self->_get_integer('legend.patchgap'))
1492     or return;
1493   my $minrowsize = $patchsize + $gap;
1494   my ($width, $height) = (0,0);
1495   my @sizes;
1496   for my $label (@$labels) {
1497     my @box = $self->_text_bbox($label, 'legend')
1498       or return;
1499     push(@sizes, \@box);
1500     $width = $box[2] if $box[2] > $width;
1501     if ($minrowsize > $box[3]) {
1502       $height += $minrowsize;
1503     }
1504     else {
1505       $height += $box[3];
1506     }
1507   }
1508   my @box = (0, 0, 
1509              $width + $patchsize + $padding * 2 + $gap,
1510              $height + $padding * 2 - $gap);
1511   my $outsidepadding = 0;
1512   if ($self->{_style}{legend}{border}) {
1513     defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
1514       or return;
1515     $box[2] += 2 * $outsidepadding;
1516     $box[3] += 2 * $outsidepadding;
1517   }
1518   $self->_align_box(\@box, $chart_box, 'legend')
1519     or return;
1520   if ($self->{_style}{legend}{fill}) {
1521     $img->box(xmin=>$box[0]+$outsidepadding, 
1522               ymin=>$box[1]+$outsidepadding, 
1523               xmax=>$box[2]-$outsidepadding, 
1524               ymax=>$box[3]-$outsidepadding,
1525              $self->_get_fill('legend.fill', \@box));
1526   }
1527   $box[0] += $outsidepadding;
1528   $box[1] += $outsidepadding;
1529   $box[2] -= $outsidepadding;
1530   $box[3] -= $outsidepadding;
1531   my $ypos = $box[1] + $padding;
1532   my $patchpos = $box[0]+$padding;
1533   my $textpos = $patchpos + $patchsize + $gap;
1534   my %text_info = $self->_text_style('legend')
1535     or return;
1536   my $patchborder;
1537   if ($self->{_style}{legend}{patchborder}) {
1538     $patchborder = $self->_get_color('legend.patchborder')
1539       or return;
1540   }
1541   my $dataindex = 0;
1542   for my $label (@$labels) {
1543     my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
1544                      $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
1545     my @fill = $self->_data_fill($dataindex, \@patchbox)
1546       or return;
1547     $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1548                ymax=>$ypos + $patchsize, @fill);
1549     if ($self->{_style}{legend}{patchborder}) {
1550       $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1551                 ymax=>$ypos + $patchsize,
1552                 color=>$patchborder);
1553     }
1554     $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize, 
1555                  text=>$label);
1556
1557     my $step = $patchsize + $gap;
1558     if ($minrowsize < $sizes[$dataindex][3]) {
1559       $ypos += $sizes[$dataindex][3];
1560     }
1561     else {
1562       $ypos += $minrowsize;
1563     }
1564     ++$dataindex;
1565   }
1566   if ($self->{_style}{legend}{border}) {
1567     my $border_color = $self->_get_color('legend.border')
1568       or return;
1569     $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
1570               color=>$border_color);
1571   }
1572   $self->_remove_box($chart_box, \@box);
1573   1;
1574 }
1575
1576 sub _draw_title {
1577   my ($self, $img, $chart_box) = @_;
1578
1579   my $title = $self->{_style}{title}{text};
1580   my @box = $self->_text_bbox($title, 'title')
1581     or return;
1582   my $yoff = $box[1];
1583   @box[0,1] = (0,0);
1584   $self->_align_box(\@box, $chart_box, 'title');
1585   my %text_info = $self->_text_style('title')
1586     or return;
1587   $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
1588   $self->_remove_box($chart_box, \@box);
1589   1;
1590 }
1591
1592 sub _small_extent {
1593   my ($self, $box) = @_;
1594
1595   if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
1596     return $box->[3] - $box->[1];
1597   }
1598   else {
1599     return $box->[2] - $box->[0];
1600   }
1601 }
1602
1603 =item _composite()
1604
1605 Returns a list of style fields that are stored as composites, and
1606 should be merged instead of just being replaced.
1607
1608 =cut
1609
1610 sub _composite {
1611   qw(title legend text label dropshadow outline callout);
1612 }
1613
1614 sub _filter_region {
1615   my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
1616
1617   unless (ref $filter) {
1618     my $name = $filter;
1619     $filter = $self->_get_thing($name)
1620       or return;
1621     $filter->{type}
1622       or return $self->_error("no type for filter $name");
1623   }
1624
1625   $left > 0 or $left = 0;
1626   $top > 0 or $top = 0;
1627
1628   # newer versions of Imager let you work on just part of an image
1629   if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
1630     my $masked = $img->masked(left=>$left, top=>$top,
1631                               right=>$right, bottom=>$bottom);
1632     $masked->filter(%$filter);
1633   }
1634   else {
1635     # for older versions of Imager
1636     my $subset = $img->crop(left=>$left, top=>$top,
1637                             right=>$right, bottom=>$bottom);
1638     $subset->filter(%$filter);
1639     $img->paste(left=>$left, top=>$top, img=>$subset);
1640   }
1641 }
1642
1643 1;
1644 __END__
1645
1646 =back
1647
1648 =head1 SEE ALSO
1649
1650 Imager::Graph::Pie(3), Imager(3), perl(1).
1651
1652 =head1 AUTHOR
1653
1654 Tony Cook <tony@develop-help.com>
1655
1656 =head1 LICENSE
1657
1658 Imager::Graph is licensed under the same terms as perl itself.
1659
1660 =head1 BLAME
1661
1662 Addi for producing a cool imaging module. :)
1663
1664 =cut