File Coverage

blib/lib/Imager.pm
Criterion Covered Total %
statement 1683 2250 74.8
branch 980 1410 69.5
condition 196 350 56.0
subroutine 142 160 88.7
pod 1 105 0.9
total 3002 4275 70.2


line stmt bran cond sub pod time code
1             package Imager;
2 57     57   3361537 use 5.006;
  57         165  
3              
4 57     57   281 use strict;
  57         93  
  57         1720  
5 57     57   225 use Scalar::Util;
  57         87  
  57         2407  
6 57     57   23115 use Imager::Color;
  57         162  
  57         1983  
7 57     57   21306 use Imager::Color::Float;
  57         122  
  57         1853  
8 57     57   24219 use Imager::Font;
  57         119  
  57         1843  
9 57     57   22401 use Imager::TrimColorList;
  57         129  
  57         1950  
10 57     57   285 use POSIX qw(INT_MIN INT_MAX);
  57         72  
  57         300  
11 57     57   74110 use if $] >= 5.014, "warnings::register" => qw(tagcodes channelmask);
  57         74  
  57         20561  
12              
13             our $ERRSTR;
14              
15             our @EXPORT_OK = qw(
16             init
17             init_log
18             DSO_open
19             DSO_close
20             DSO_funclist
21             DSO_call
22              
23             load_plugin
24             unload_plugin
25              
26             i_list_formats
27              
28             i_color_new
29             i_color_set
30             i_color_info
31              
32             i_img_info
33              
34             i_img_setmask
35             i_img_getmask
36              
37             i_line
38             i_line_aa
39             i_box
40             i_box_filled
41             i_arc
42             i_circle_aa
43              
44             i_bezier_multi
45             i_poly_aa
46             i_poly_aa_cfill
47              
48             i_copyto
49             i_rubthru
50             i_scaleaxis
51             i_scale_nn
52             i_haar
53             i_count_colors
54              
55             i_gaussian
56             i_conv
57              
58             i_convert
59             i_map
60              
61             i_img_diff
62              
63             i_tt_set_aa
64             i_tt_cp
65             i_tt_text
66             i_tt_bbox
67              
68             i_readpnm_wiol
69             i_writeppm_wiol
70              
71             i_readraw_wiol
72             i_writeraw_wiol
73              
74             i_contrast
75             i_hardinvert
76             i_noise
77             i_bumpmap
78             i_postlevels
79             i_mosaic
80             i_watermark
81              
82             malloc_state
83              
84             list_formats
85              
86             i_gifquant
87              
88             newfont
89             newcolor
90             newcolour
91             NC
92             NF
93             NCF
94             );
95              
96             our @EXPORT=qw(
97             );
98              
99             our %EXPORT_TAGS=
100             (handy => [qw(
101             newfont
102             newcolor
103             NF
104             NC
105             NCF
106             )],
107             all => [@EXPORT_OK],
108             default => [qw(
109             load_plugin
110             unload_plugin
111             )]);
112              
113             # registered file readers
114             my %readers;
115              
116             # registered file writers
117             my %writers;
118              
119             # modules we attempted to autoload
120             my %attempted_to_load;
121              
122             # errors from loading files
123             my %file_load_errors;
124              
125             # what happened when we tried to load
126             my %reader_load_errors;
127             my %writer_load_errors;
128              
129             # library keys that are image file formats
130             my %file_formats = map { $_ => 1 } qw/tiff pnm gif png jpeg raw bmp tga/;
131              
132             # image pixel combine types
133             my @combine_types =
134             qw/none normal multiply dissolve add subtract diff lighten darken
135             hue saturation value color/;
136             my %combine_types;
137             @combine_types{@combine_types} = 0 .. $#combine_types;
138             $combine_types{mult} = $combine_types{multiply};
139             $combine_types{'sub'} = $combine_types{subtract};
140             $combine_types{sat} = $combine_types{saturation};
141              
142             # this will be used to store global defaults at some point
143             my %defaults;
144              
145             our $VERSION;
146              
147             BEGIN {
148 57     57   314 require Exporter;
149 57         3353 my $ex_version = eval $Exporter::VERSION;
150 57 50       298 if ($ex_version < 5.57) {
151 0         0 our @ISA = qw(Exporter);
152             }
153 57         93 $VERSION = '1.030';
154 57         174 require XSLoader;
155 57         160472 XSLoader::load(Imager => $VERSION);
156             }
157              
158             my %formats_low;
159             my %format_classes =
160             (
161             png => "Imager::File::PNG",
162             gif => "Imager::File::GIF",
163             tiff => "Imager::File::TIFF",
164             jpeg => "Imager::File::JPEG",
165             w32 => "Imager::Font::W32",
166             ft2 => "Imager::Font::FT2",
167             t1 => "Imager::Font::T1",
168             );
169              
170             our %formats;
171              
172             tie %formats, "Imager::FORMATS", \%formats_low, \%format_classes;
173              
174             our %filters;
175              
176             our $DEBUG;
177             our %OPCODES;
178             our $FORMATGUESS;
179             our $warn_obsolete;
180              
181             BEGIN {
182 57     57   1611 for(i_list_formats()) { $formats_low{$_}++; }
  285         575  
183              
184 57         662 %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]);
185              
186 57         126 $DEBUG=0;
187              
188             # the members of the subhashes under %filters are:
189             # callseq - a list of the parameters to the underlying filter in the
190             # order they are passed
191             # callsub - a code ref that takes a named parameter list and calls the
192             # underlying filter
193             # defaults - a hash of default values
194             # names - defines names for value of given parameters so if the names
195             # field is foo=> { bar=>1 }, and the user supplies "bar" as the
196             # foo parameter, the filter will receive 1 for the foo
197             # parameter
198             $filters{contrast}={
199             callseq => ['image','intensity'],
200 1         3 callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); }
  1         1617  
201 57         492 };
202              
203             $filters{noise} ={
204             callseq => ['image', 'amount', 'subtype'],
205             defaults => { amount=>3,subtype=>0 },
206 1         3 callsub => sub { my %hsh=@_; i_noise($hsh{image},$hsh{amount},$hsh{subtype}); }
  1         2185  
207 57         380 };
208              
209             $filters{hardinvert} ={
210             callseq => ['image'],
211             defaults => { },
212 3         7 callsub => sub { my %hsh=@_; i_hardinvert($hsh{image}); }
  3         1096  
213 57         260 };
214              
215             $filters{hardinvertall} =
216             {
217             callseq => ['image'],
218             defaults => { },
219 2         7 callsub => sub { my %hsh=@_; i_hardinvertall($hsh{image}); }
  2         263  
220 57         214 };
221              
222             $filters{autolevels_skew} ={
223             callseq => ['image','lsat','usat','skew'],
224             defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 },
225 1         3 callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); }
  1         3198  
226 57         365 };
227              
228             $filters{autolevels} ={
229             callseq => ['image','lsat','usat'],
230             defaults => { lsat=>0.1,usat=>0.1 },
231 3         17 callsub => sub { my %hsh=@_; i_autolevels_mono($hsh{image},$hsh{lsat},$hsh{usat}); }
  3         2063  
232 57         311 };
233              
234             $filters{turbnoise} ={
235             callseq => ['image'],
236             defaults => { xo=>0.0,yo=>0.0,scale=>10.0 },
237 1         4 callsub => sub { my %hsh=@_; i_turbnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{scale}); }
  1         62041  
238 57         287 };
239              
240             $filters{radnoise} ={
241             callseq => ['image'],
242             defaults => { xo=>100,yo=>100,ascale=>17.0,rscale=>0.02 },
243 1         5 callsub => sub { my %hsh=@_; i_radnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{rscale},$hsh{ascale}); }
  1         62594  
244 57         241 };
245              
246             $filters{conv} =
247             {
248             callseq => ['image', 'coef'],
249             defaults => { },
250             callsub =>
251             sub {
252 47         173 my %hsh=@_;
253             i_conv($hsh{image},$hsh{coef})
254 47 100       486650 or die Imager->_error_as_msg() . "\n";
255             }
256 57         301 };
257              
258             $filters{gradgen} =
259             {
260             callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
261             defaults => { dist => 0 },
262             callsub =>
263             sub {
264 1         5 my %hsh=@_;
265 1         2 my @colors = @{$hsh{colors}};
  1         23  
266             $_ = _color($_)
267 1         4 for @colors;
268 1         3718 i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist});
269             }
270 57         342 };
271              
272             $filters{nearest_color} =
273             {
274             callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
275             defaults => { },
276             callsub =>
277             sub {
278 1         5 my %hsh=@_;
279             # make sure the segments are specified with colors
280 1         2 my @colors;
281 1         1 for my $color (@{$hsh{colors}}) {
  1         3  
282 3 50       5 my $new_color = _color($color)
283             or die $Imager::ERRSTR."\n";
284 3         6 push @colors, $new_color;
285             }
286              
287             i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors,
288             $hsh{dist})
289 1 50       3266 or die Imager->_error_as_msg() . "\n";
290             },
291 57         347 };
292             $filters{gaussian} = {
293             callseq => [ 'image', 'stddev' ],
294             defaults => { },
295 2         7 callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); },
  2         121364  
296 57         270 };
297             $filters{gaussian2} = {
298             callseq => [ 'image', 'stddevX', 'stddevY' ],
299             defaults => { },
300 5         16 callsub => sub { my %hsh = @_; i_gaussian2($hsh{image}, $hsh{stddevX}, $hsh{stddevY}); },
  5         156338  
301 57         311 };
302             $filters{mosaic} =
303             {
304             callseq => [ qw(image size) ],
305             defaults => { size => 20 },
306 1         3 callsub => sub { my %hsh = @_; i_mosaic($hsh{image}, $hsh{size}) },
  1         1836  
307 57         238 };
308             $filters{bumpmap} =
309             {
310             callseq => [ qw(image bump elevation lightx lighty st) ],
311             defaults => { elevation=>0, st=> 2 },
312             callsub => sub {
313 1         4 my %hsh = @_;
314             i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation},
315 1         5434 $hsh{lightx}, $hsh{lighty}, $hsh{st});
316             },
317 57         358 };
318             $filters{bumpmap_complex} =
319             {
320             callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ],
321             defaults => {
322             channel => 0,
323             tx => 0,
324             ty => 0,
325             Lx => 0.2,
326             Ly => 0.4,
327             Lz => -1.0,
328             cd => 1.0,
329             cs => 40,
330             n => 1.3,
331             Ia => [0,0,0],
332             Il => [255,255,255],
333             Is => [255,255,255],
334             },
335             callsub => sub {
336 1         5 my %hsh = @_;
337 1         3 for my $cname (qw/Ia Il Is/) {
338 3         4 my $old = $hsh{$cname};
339 3 50       5 my $new_color = _color($old)
340             or die $Imager::ERRSTR, "\n";
341 3         7 $hsh{$cname} = $new_color;
342             }
343             i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel},
344             $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz},
345             $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il},
346 1         7748 $hsh{Is});
347             },
348 57         760 };
349             $filters{postlevels} =
350             {
351             callseq => [ qw(image levels) ],
352             defaults => { levels => 10 },
353 1         3 callsub => sub { my %hsh = @_; i_postlevels($hsh{image}, $hsh{levels}); },
  1         1888  
354 57         242 };
355             $filters{watermark} =
356             {
357             callseq => [ qw(image wmark tx ty pixdiff) ],
358             defaults => { pixdiff=>10, tx=>0, ty=>0 },
359             callsub =>
360             sub {
361 1         7 my %hsh = @_;
362             i_watermark($hsh{image}, $hsh{wmark}{IMG}, $hsh{tx}, $hsh{ty},
363 1         2626 $hsh{pixdiff});
364             },
365 57         285 };
366             $filters{fountain} =
367             {
368             callseq => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ],
369             names => {
370             ftype => { linear => 0,
371             bilinear => 1,
372             radial => 2,
373             radial_square => 3,
374             revolution => 4,
375             conical => 5 },
376             repeat => { none => 0,
377             sawtooth => 1,
378             triangle => 2,
379             saw_both => 3,
380             tri_both => 4,
381             },
382             super_sample => {
383             none => 0,
384             grid => 1,
385             random => 2,
386             circle => 3,
387             },
388             combine => {
389             none => 0,
390             normal => 1,
391             multiply => 2, mult => 2,
392             dissolve => 3,
393             add => 4,
394             subtract => 5, 'sub' => 5,
395             diff => 6,
396             lighten => 7,
397             darken => 8,
398             hue => 9,
399             sat => 10,
400             value => 11,
401             color => 12,
402             },
403             },
404             defaults => { ftype => 0, repeat => 0, combine => 0,
405             super_sample => 0, ssample_param => 4,
406             segments=>[
407             [ 0, 0.5, 1,
408             [0,0,0],
409             [255, 255, 255],
410             0, 0,
411             ],
412             ],
413             },
414             callsub =>
415             sub {
416 10         45 my %hsh = @_;
417              
418             # make sure the segments are specified with colors
419 10         14 my @segments;
420 10         11 for my $segment (@{$hsh{segments}}) {
  10         23  
421 13         32 my @new_segment = @$segment;
422            
423 13   100     38 $_ = _color($_) or die $Imager::ERRSTR."\n" for @new_segment[3,4];
424 12         81 push @segments, \@new_segment;
425             }
426              
427             i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
428             $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
429 9 50       95019 $hsh{ssample_param}, \@segments)
430             or die Imager->_error_as_msg() . "\n";
431             },
432 57         1743 };
433             $filters{unsharpmask} =
434             {
435             callseq => [ qw(image stddev scale) ],
436             defaults => { stddev=>2.0, scale=>1.0 },
437             callsub =>
438             sub {
439 1         5 my %hsh = @_;
440 1         22827 i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
441             },
442 57         372 };
443              
444 57         154 $FORMATGUESS=\&def_guess_type;
445              
446 57         1233474 $warn_obsolete = 1;
447             }
448              
449             #
450             # Non methods
451             #
452              
453             # initialize Imager
454             # NOTE: this might be moved to an import override later on
455              
456             sub import {
457 99     99   1069 my $i = 1;
458 99         393 while ($i < @_) {
459 30 50       107 if ($_[$i] eq '-log-stderr') {
460 0         0 init_log(undef, 4);
461 0         0 splice(@_, $i, 1);
462             }
463             else {
464 30         66 ++$i;
465             }
466             }
467 99         24862 goto &Exporter::import;
468             }
469              
470             sub init_log {
471 7     7 0 1126357 Imager->open_log(log => $_[0], level => $_[1]);
472             }
473              
474              
475             sub init {
476 8     8 0 1159190 my %parms=(loglevel=>1,@_);
477              
478 8 50       44 if (exists $parms{'warn_obsolete'}) {
479 0         0 $warn_obsolete = $parms{'warn_obsolete'};
480             }
481              
482 8 50       27 if ($parms{'log'}) {
483             Imager->open_log(log => $parms{log}, level => $parms{loglevel})
484 8 50       66 or return;
485             }
486              
487 8 50       29 if (exists $parms{'t1log'}) {
488 0 0       0 if ($formats{t1}) {
489 0 0       0 if (Imager::Font::T1::i_init_t1($parms{'t1log'})) {
490 0         0 Imager->_set_error(Imager->_error_as_msg);
491 0         0 return;
492             }
493             }
494             }
495              
496 8         28 return 1;
497             }
498              
499             {
500             my $is_logging = 0;
501              
502             sub open_log {
503 34     34 0 2982085 my $class = shift;
504 34         174 my (%opts) = ( loglevel => 1, @_ );
505              
506 34         12264 $is_logging = i_init_log($opts{log}, $opts{loglevel});
507 34 50       208 unless ($is_logging) {
508 0         0 Imager->_set_error(Imager->_error_as_msg());
509 0         0 return;
510             }
511              
512 34         262 Imager->log("Imager $VERSION starting\n", 1);
513              
514 34         186 return $is_logging;
515             }
516              
517             sub close_log {
518 18     18 0 44171 i_init_log(undef, -1);
519 18         411 $is_logging = 0;
520             }
521              
522             sub log {
523 35     35 0 107 my ($class, $message, $level) = @_;
524              
525 35 100       121 defined $level or $level = 1;
526              
527 35         1243 i_log_entry($message, $level);
528             }
529              
530             sub is_logging {
531 0     0 0 0 return $is_logging;
532             }
533             }
534              
535             END {
536 57 50   57   1088065 if ($DEBUG) {
537 0         0 print "shutdown code\n";
538             # for(keys %instances) { $instances{$_}->DESTROY(); }
539 0         0 malloc_state(); # how do decide if this should be used? -- store something from the import
540 0         0 print "Imager exiting\n";
541             }
542             }
543              
544             # Load a filter plugin
545              
546             our %DSOs;
547              
548             sub load_plugin {
549 0     0 0 0 my ($filename)=@_;
550 0         0 my $i;
551              
552 0 0       0 if ($^O eq 'android') {
553 0         0 require File::Spec;
554 0         0 $filename = File::Spec->rel2abs($filename);
555             }
556              
557 0         0 my ($DSO_handle,$str)=DSO_open($filename);
558 0 0       0 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
  0         0  
  0         0  
559 0         0 my %funcs=DSO_funclist($DSO_handle);
560 0 0       0 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
  0         0  
  0         0  
  0         0  
  0         0  
561 0         0 $i=0;
562 0 0       0 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
  0         0  
  0         0  
  0         0  
  0         0  
563              
564 0         0 $DSOs{$filename}=[$DSO_handle,\%funcs];
565              
566 0         0 for(keys %funcs) {
567 0         0 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
568 0 0       0 $DEBUG && print "eval string:\n",$evstr,"\n";
569 0         0 eval $evstr;
570 0 0       0 print $@ if $@;
571             }
572 0         0 return 1;
573             }
574              
575             # Unload a plugin
576              
577             sub unload_plugin {
578 0     0 0 0 my ($filename)=@_;
579              
580 0 0       0 if ($^O eq 'android') {
581 0         0 require File::Spec;
582 0         0 $filename = File::Spec->rel2abs($filename);
583             }
584              
585 0 0       0 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
  0         0  
  0         0  
586 0         0 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
  0         0  
587 0         0 for(keys %{$funcref}) {
  0         0  
588 0         0 delete $filters{$_};
589 0 0       0 $DEBUG && print "unloading: $_\n";
590             }
591 0         0 my $rc=DSO_close($DSO_handle);
592 0 0       0 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
  0         0  
  0         0  
593 0         0 return 1;
594             }
595              
596             # take the results of i_error() and make a message out of it
597             sub _error_as_msg {
598 184     184   207067 return join(": ", map $_->[0], i_errors());
599             }
600              
601             # this function tries to DWIM for color parameters
602             # color objects are used as is
603             # simple scalars are simply treated as single parameters to Imager::Color->new
604             # hashrefs are treated as named argument lists to Imager::Color->new
605             # arrayrefs are treated as list arguments to Imager::Color->new iff any
606             # parameter is > 1
607             # other arrayrefs are treated as list arguments to Imager::Color::Float
608              
609             sub _color {
610 1024     1024   1170 my $arg = shift;
611             # perl 5.6.0 seems to do weird things to $arg if we don't make an
612             # explicitly stringified copy
613             # I vaguely remember a bug on this on p5p, but couldn't find it
614             # through bugs.perl.org (I had trouble getting it to find any bugs)
615 1024         2175 my $copy = $arg . "";
616 1024         1069 my $result;
617              
618 1024 100       1407 if (ref $arg) {
619 660 100 100     1880 if (UNIVERSAL::isa($arg, "Imager::Color")
620             || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
621 521         616 $result = $arg;
622             }
623             else {
624 139 100       463 if ($copy =~ /^HASH\(/) {
    50          
625 3         15 $result = Imager::Color->new(%$arg);
626             }
627             elsif ($copy =~ /^ARRAY\(/) {
628 136         473 $result = Imager::Color->new(@$arg);
629             }
630             else {
631 0         0 $Imager::ERRSTR = "Not a color";
632             }
633             }
634             }
635             else {
636             # assume Imager::Color::new knows how to handle it
637 364         1102 $result = Imager::Color->new($arg);
638             }
639              
640 1024         2299 return $result;
641             }
642              
643             sub _combine {
644 123     123   323 my ($self, $combine, $default) = @_;
645              
646 123 100 100     404 if (!defined $combine && ref $self) {
647 55         82 $combine = $self->{combine};
648             }
649 123 100       239 defined $combine or $combine = $defaults{combine};
650 123 100       204 defined $combine or $combine = $default;
651              
652 123 100       248 if (exists $combine_types{$combine}) {
653 85         121 $combine = $combine_types{$combine};
654             }
655            
656 123         289 return $combine;
657             }
658              
659             sub _valid_image {
660 8673     8673   12160 my ($self, $method) = @_;
661              
662 8673 50       13236 ref $self
663             or return Imager->_set_error("$method needs an image object");
664              
665 8673 100 66     30009 $self->{IMG} && Scalar::Util::blessed($self->{IMG}) and return 1;
666              
667 68 50       204 my $msg = $self->{IMG} ? "images do not cross threads" : "empty input image";
668 68 50       223 $msg = "$method: $msg" if $method;
669 68         215 $self->_set_error($msg);
670              
671 68         509 return;
672             }
673              
674             # returns first defined parameter
675             sub _first {
676 76     76   130 for (@_) {
677 162 100       280 return $_ if defined $_;
678             }
679 1         2 return undef;
680             }
681              
682             #
683             # Methods to be called on objects.
684             #
685              
686             # Create a new Imager object takes very few parameters.
687             # usually you call this method and then call open from
688             # the resulting object
689              
690             sub new {
691 1278     1278 0 961523 my $class = shift;
692 1278         1804 my $self ={};
693 1278         2873 my %hsh=@_;
694 1278         1987 bless $self,$class;
695 1278         2667 $self->{IMG}=undef; # Just to indicate what exists
696 1278         1805 $self->{ERRSTR}=undef; #
697 1278         2699 $self->{DEBUG}=$DEBUG;
698 1278 50       2661 $self->{DEBUG} and print "Initialized Imager\n";
699 1278 100 100     13598 if (defined $hsh{file} ||
    100 66        
    50 66        
      33        
      66        
      66        
      66        
700             defined $hsh{fh} ||
701             defined $hsh{fd} ||
702             defined $hsh{callback} ||
703             defined $hsh{readcb} ||
704             defined $hsh{data} ||
705             defined $hsh{io}) {
706             # allow $img = Imager->new(file => $filename)
707 14         23 my %extras;
708            
709             # type is already used as a parameter to new(), rename it for the
710             # call to read()
711 14 100       37 if ($hsh{filetype}) {
712 6         70 $extras{type} = $hsh{filetype};
713             }
714 14 100       86 unless ($self->read(%hsh, %extras)) {
715 5         15 $Imager::ERRSTR = $self->{ERRSTR};
716 5         30 return;
717             }
718             }
719             elsif (defined $hsh{xsize} || defined $hsh{ysize}) {
720 552 100       1758 unless ($self->img_set(%hsh)) {
721 25         43 $Imager::ERRSTR = $self->{ERRSTR};
722 25         88 return;
723             }
724             }
725             elsif (%hsh) {
726 0         0 Imager->_set_error("new: supply xsize and ysize or a file access parameter or no parameters");
727 0         0 return;
728             }
729              
730 1248         3142 return $self;
731             }
732              
733             # Copy an entire image with no changes
734             # - if an image has magic the copy of it will not be magical
735              
736             sub copy {
737 217     217 0 26964 my $self = shift;
738              
739 217 100       450 $self->_valid_image("copy")
740             or return;
741              
742 216 100       404 unless (defined wantarray) {
743 1         4 my @caller = caller;
744 1         14 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
745 1         35 return;
746             }
747              
748 215         531 my $newcopy=Imager->new();
749 215         114926 $newcopy->{IMG} = i_copy($self->{IMG});
750 215         849 return $newcopy;
751             }
752              
753             # Paste a region
754              
755             sub paste {
756 29     29 0 389 my $self = shift;
757              
758 29 100       68 $self->_valid_image("paste")
759             or return;
760              
761 28         125 my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_);
762 28   100     73 my $src = $input{img} || $input{src};
763 28 100       43 unless($src) {
764 1         3 $self->_set_error("no source image");
765 1         3 return;
766             }
767 27 100       36 unless ($src->_valid_image("paste")) {
768 1         2 $self->{ERRSTR} = $src->{ERRSTR} . " (for src)";
769 1         4 return;
770             }
771 26 100       60 $input{left}=0 if $input{left} <= 0;
772 26 100       37 $input{top}=0 if $input{top} <= 0;
773              
774 26         1752 my($r,$b)=i_img_info($src->{IMG});
775 26         63 my ($src_left, $src_top) = @input{qw/src_minx src_miny/};
776 26         31 my ($src_right, $src_bottom);
777 26 100       46 if ($input{src_coords}) {
778 1         2 ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}}
  1         3  
779             }
780             else {
781 25 100       42 if (defined $input{src_maxx}) {
    100          
782 2         3 $src_right = $input{src_maxx};
783             }
784             elsif (defined $input{width}) {
785 1 50       4 if ($input{width} <= 0) {
786 0         0 $self->_set_error("paste: width must me positive");
787 0         0 return;
788             }
789 1         2 $src_right = $src_left + $input{width};
790             }
791             else {
792 22         26 $src_right = $r;
793             }
794 25 100       41 if (defined $input{src_maxy}) {
    100          
795 3         5 $src_bottom = $input{src_maxy};
796             }
797             elsif (defined $input{height}) {
798 1 50       2 if ($input{height} < 0) {
799 0         0 $self->_set_error("paste: height must be positive");
800 0         0 return;
801             }
802 1         2 $src_bottom = $src_top + $input{height};
803             }
804             else {
805 21         21 $src_bottom = $b;
806             }
807             }
808              
809 26 50       42 $src_right > $r and $src_right = $r;
810 26 50       39 $src_bottom > $b and $src_bottom = $b;
811              
812 26 50 33     62 if ($src_right <= $src_left
813             || $src_bottom < $src_top) {
814 0         0 $self->_set_error("nothing to paste");
815 0         0 return;
816             }
817              
818             i_copyto($self->{IMG}, $src->{IMG},
819             $src_left, $src_top, $src_right, $src_bottom,
820 26         4945 $input{left}, $input{top});
821              
822 26         159 return $self; # What should go here??
823             }
824              
825             # Crop an image - i.e. return a new image that is smaller
826              
827             sub crop {
828 48     48 0 5958 my $self=shift;
829              
830 48 100       122 $self->_valid_image("crop")
831             or return;
832            
833 47 100       103 unless (defined wantarray) {
834 1         6 my @caller = caller;
835 1         13 warn "crop() called in void context - crop() returns the cropped image at $caller[1] line $caller[2]\n";
836 1         41 return;
837             }
838              
839 46         167 my %hsh=@_;
840              
841             my ($w, $h, $l, $r, $b, $t) =
842 46         140 @hsh{qw(width height left right bottom top)};
843              
844             # work through the various possibilities
845 46 100       98 if (defined $l) {
    100          
    100          
846 34 100       135 if (defined $w) {
    100          
847 1         4 $r = $l + $w;
848             }
849             elsif (!defined $r) {
850 1         5 $r = $self->getwidth;
851             }
852             }
853             elsif (defined $r) {
854 3 100       8 if (defined $w) {
855 2         5 $l = $r - $w;
856             }
857             else {
858 1         3 $l = 0;
859             }
860             }
861             elsif (defined $w) {
862 1         3 $l = int(0.5+($self->getwidth()-$w)/2);
863 1         2 $r = $l + $w;
864             }
865             else {
866 8         9 $l = 0;
867 8         21 $r = $self->getwidth;
868             }
869 46 100       78 if (defined $t) {
    100          
    100          
870 36 100       83 if (defined $h) {
    100          
871 4         6 $b = $t + $h;
872             }
873             elsif (!defined $b) {
874 1         5 $b = $self->getheight;
875             }
876             }
877             elsif (defined $b) {
878 3 100       5 if (defined $h) {
879 2         4 $t = $b - $h;
880             }
881             else {
882 1         3 $t = 0;
883             }
884             }
885             elsif (defined $h) {
886 1         3 $t=int(0.5+($self->getheight()-$h)/2);
887 1         2 $b=$t+$h;
888             }
889             else {
890 6         10 $t = 0;
891 6         13 $b = $self->getheight;
892             }
893              
894 46 50       85 ($l,$r)=($r,$l) if $l>$r;
895 46 50       71 ($t,$b)=($b,$t) if $t>$b;
896              
897 46 100       84 $l < 0 and $l = 0;
898 46 100       141 $r > $self->getwidth and $r = $self->getwidth;
899 46 100       96 $t < 0 and $t = 0;
900 46 100       106 $b > $self->getheight and $b = $self->getheight;
901              
902 46 100 100     158 if ($l == $r || $t == $b) {
903 2         10 $self->_set_error("resulting image would have no content");
904 2         13 return;
905             }
906 44 100 100     141 if( $r < $l or $b < $t ) {
907 2         8 $self->_set_error("attempting to crop outside of the image");
908 2         13 return;
909             }
910 42         131 my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t);
911              
912 42         11114 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
913 42         186 return $dst;
914             }
915              
916             my $empty_trim_colors = Imager::TrimColorList->new();
917              
918             sub _trim_rect {
919 15     15   26 my ($self, $name, %hsh) = @_;
920              
921 15 50       26 $self->_valid_image($name)
922             or return;
923              
924 15         21 my $auto = delete $hsh{auto};
925 15   66     40 my $colors = delete $hsh{colors} || $empty_trim_colors;
926 15   50     33 my $alpha = delete $hsh{alpha} || 0;
927 15         17 my $tolerance = delete $hsh{tolerance};
928 15 50       27 defined $tolerance or $tolerance = 0.01;
929              
930 15 50       21 if (keys %hsh) {
931 0         0 $self->_set_error("$name: unexpected arguments:".join(", ", sort keys %hsh));
932 0         0 return;
933             }
934              
935 15 100       28 if ($auto) {
936 5 50       10 if ($colors != $empty_trim_colors) {
937 0         0 $self->_set_error("$name: only one of auto and colors can be supplied");
938 0         0 return;
939             }
940 5 50       10 if ($tolerance < 0) {
941 0         0 $self->_set_error("$name: tolerance must be non-negative");
942 0         0 return;
943             }
944              
945 5         18 $colors = Imager::TrimColorList->auto
946             (
947             auto => $auto,
948             tolerance => $tolerance,
949             name => $name,
950             image => $self,
951             );
952 5 50       8 unless ($colors) {
953 0         0 $self->_set_error(Imager->errstr);
954 0         0 return;
955             }
956             }
957              
958 15 50       18 unless (ref $colors) {
959 0         0 $self->_set_error("$name: colors must be an arrayref or an Imager::TrimColorList object");
960 0         0 return;
961             }
962 15 100       34 unless (UNIVERSAL::isa($colors, "Imager::TrimColorList")) {
963 5 50       12 unless (Scalar::Util::reftype($colors) eq "ARRAY") {
964 0         0 $self->_set_error("$name: colors must be an arrayref or an Imager::TrimColorList object");
965 0         0 return;
966             }
967 5         22 $colors = Imager::TrimColorList->new(@$colors);
968             }
969              
970 15         14899 return i_trim_rect($self->{IMG}, $alpha, $colors);
971             }
972              
973             sub trim_rect {
974 11     11 0 66 my ($self, %hsh) = @_;
975              
976 11         29 return $self->_trim_rect("trim_rect", %hsh);
977             }
978              
979             sub trim {
980 4     4 0 2634 my ($self, %hsh) = @_;
981              
982 4 50       11 my ($left, $top, $right, $bottom) = $self->_trim_rect("trim", %hsh)
983             or return;
984              
985 4 50       16 if ($left == $self->getwidth) {
986             # the whole image would be trimmed, but we don't support zero
987             # width or height images.
988 0         0 return $self->crop(width => 1, height => 1);
989             }
990             else {
991 4         13 my ($w, $h) = i_img_info($self->{IMG});
992 4         15 return $self->crop(left => $left, right => $w - $right,
993             top => $top, bottom => $h - $bottom);
994             }
995             }
996              
997             sub _sametype {
998 42     42   105 my ($self, %opts) = @_;
999              
1000 42 50       85 $self->_valid_image
1001             or return;
1002              
1003 42   33     121 my $x = $opts{xsize} || $self->getwidth;
1004 42   33     84 my $y = $opts{ysize} || $self->getheight;
1005 42   33     153 my $channels = $opts{channels} || $self->getchannels;
1006            
1007 42         133 my $out = Imager->new;
1008 42 50       77 if ($channels == $self->getchannels) {
1009 42         5052 $out->{IMG} = i_sametype($self->{IMG}, $x, $y);
1010             }
1011             else {
1012 0         0 $out->{IMG} = i_sametype_chans($self->{IMG}, $x, $y, $channels);
1013             }
1014 42 50       124 unless ($out->{IMG}) {
1015 0         0 $self->{ERRSTR} = $self->_error_as_msg;
1016 0         0 return;
1017             }
1018            
1019 42         160 return $out;
1020             }
1021              
1022             # Sets an image to a certain size and channel number
1023             # if there was previously data in the image it is discarded
1024              
1025             my %model_channels =
1026             (
1027             gray => 1,
1028             graya => 2,
1029             rgb => 3,
1030             rgba => 4,
1031             );
1032              
1033             sub img_set {
1034 552     552 0 652 my $self=shift;
1035              
1036 552         2115 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
1037              
1038 552         877 undef($self->{IMG});
1039              
1040 552 100       1059 if ($hsh{model}) {
1041 4 50       16 if (my $channels = $model_channels{$hsh{model}}) {
1042 4         8 $hsh{channels} = $channels;
1043             }
1044             else {
1045 0         0 $self->_set_error("new: unknown value for model '$hsh{model}'");
1046 0         0 return;
1047             }
1048             }
1049              
1050 552 100 100     2722 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
    100          
    100          
1051             $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
1052 25   50     2259 $hsh{maxcolors} || 256);
1053             }
1054             elsif ($hsh{bits} eq 'double') {
1055 70         9784 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
1056             }
1057             elsif ($hsh{bits} == 16) {
1058 22         2947 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
1059             }
1060             else {
1061             $self->{IMG}= i_img_8_new($hsh{'xsize'}, $hsh{'ysize'},
1062 435         43988 $hsh{'channels'});
1063             }
1064              
1065 552 100       1829 unless ($self->{IMG}) {
1066 25         70 $self->_set_error(Imager->_error_as_msg());
1067 25         129 return;
1068             }
1069              
1070 527         1713 $self;
1071             }
1072              
1073             # created a masked version of the current image
1074             sub masked {
1075 17     17 0 3023 my $self = shift;
1076              
1077 17 100       49 $self->_valid_image("masked")
1078             or return;
1079              
1080 16         54 my %opts = (left => 0,
1081             top => 0,
1082             right => $self->getwidth,
1083             bottom => $self->getheight,
1084             @_);
1085 16 100       52 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
1086              
1087 16         50 my ($left, $top, $right, $bottom) = @opts{qw(left top right bottom)};
1088 16         33 for my $val ($left, $right) {
1089 32 100       98 if ($val < 0) {
1090 3         11 $val = $self->getwidth() + $val;
1091             }
1092             }
1093 16         23 for my $val ($top, $bottom) {
1094 32 100       74 if ($val < 0) {
1095 3         9 $val = $self->getheight() + $val;
1096             }
1097             }
1098              
1099 16         54 my $result = Imager->new;
1100 16         1197 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $left,
1101             $top, $right - $left,
1102             $bottom - $top);
1103 16 100       110 unless ($result->{IMG}) {
1104 7         28 $self->_set_error(Imager->_error_as_msg);
1105 7         32 return;
1106             }
1107              
1108             # keep references to the mask and base images so they don't
1109             # disappear on us
1110 9         33 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
1111              
1112 9         40 return $result;
1113             }
1114              
1115             # convert an RGB image into a paletted image
1116             sub to_paletted {
1117 14     14 0 815 my $self = shift;
1118 14         21 my $opts;
1119 14 100 66     78 if (@_ != 1 && !ref $_[0]) {
1120 13         47 $opts = { @_ };
1121             }
1122             else {
1123 1         2 $opts = shift;
1124             }
1125              
1126 14 100       34 unless (defined wantarray) {
1127 1         5 my @caller = caller;
1128 1         8 warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n";
1129 1         34 return;
1130             }
1131              
1132 13 100       35 $self->_valid_image("to_paletted")
1133             or return;
1134              
1135 12         35 my $result = Imager->new;
1136 12 100       96758 unless ($result->{IMG} = i_img_to_pal($self->{IMG}, $opts)) {
1137 2         11 $self->_set_error(Imager->_error_as_msg);
1138 2         11 return;
1139             }
1140              
1141 10         80 return $result;
1142             }
1143              
1144             sub make_palette {
1145 7     7 0 1666 my ($class, $quant, @images) = @_;
1146              
1147 7 100       21 unless (@images) {
1148 1         6 Imager->_set_error("make_palette: supply at least one image");
1149 1         3 return;
1150             }
1151 6         11 my $index = 1;
1152 6         13 for my $img (@images) {
1153 7 100       20 unless ($img->{IMG}) {
1154 1         6 Imager->_set_error("make_palette: image $index is empty");
1155 1         4 return;
1156             }
1157 6         11 ++$index;
1158             }
1159              
1160 5         5042 my @cols = i_img_make_palette($quant, map $_->{IMG}, @images);
1161 5 100       18 unless (@cols) {
1162 1         8 Imager->_set_error(Imager->_error_as_msg);
1163 1         3 return;
1164             }
1165 4         32 return @cols;
1166             }
1167              
1168             # convert a paletted (or any image) to an 8-bit/channel RGB image
1169             sub to_rgb8 {
1170 3     3 0 254 my $self = shift;
1171              
1172 3 100       10 unless (defined wantarray) {
1173 1         5 my @caller = caller;
1174 1         14 warn "to_rgb8() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
1175 1         36 return;
1176             }
1177              
1178 2 100       5 $self->_valid_image("to_rgb8")
1179             or return;
1180              
1181 1         3 my $result = Imager->new;
1182 1 50       1102 unless ($result->{IMG} = i_img_to_rgb($self->{IMG})) {
1183 0         0 $self->_set_error(Imager->_error_as_msg());
1184 0         0 return;
1185             }
1186              
1187 1         5 return $result;
1188             }
1189              
1190             # convert a paletted (or any image) to a 16-bit/channel RGB image
1191             sub to_rgb16 {
1192 9     9 0 958 my $self = shift;
1193              
1194 9 50       32 unless (defined wantarray) {
1195 0         0 my @caller = caller;
1196 0         0 warn "to_rgb16() called in void context - to_rgb16() returns the converted image at $caller[1] line $caller[2]\n";
1197 0         0 return;
1198             }
1199              
1200 9 100       28 $self->_valid_image("to_rgb16")
1201             or return;
1202              
1203 8         37 my $result = Imager->new;
1204 8 50       11518 unless ($result->{IMG} = i_img_to_rgb16($self->{IMG})) {
1205 0         0 $self->_set_error(Imager->_error_as_msg());
1206 0         0 return;
1207             }
1208              
1209 8         46 return $result;
1210             }
1211              
1212             # convert a paletted (or any image) to an double/channel RGB image
1213             sub to_rgb_double {
1214 3     3 0 292 my $self = shift;
1215              
1216 3 50       9 unless (defined wantarray) {
1217 0         0 my @caller = caller;
1218 0         0 warn "to_rgb16() called in void context - to_rgb_double() returns the converted image at $caller[1] line $caller[2]\n";
1219 0         0 return;
1220             }
1221              
1222 3 100       8 $self->_valid_image("to_rgb_double")
1223             or return;
1224              
1225 2         15 my $result = Imager->new;
1226 2 50       1495 unless ($result->{IMG} = i_img_to_drgb($self->{IMG})) {
1227 0         0 $self->_set_error(Imager->_error_as_msg());
1228 0         0 return;
1229             }
1230              
1231 2         9 return $result;
1232             }
1233              
1234             sub addcolors {
1235 24     24 0 1555 my $self = shift;
1236 24         88 my %opts = (colors=>[], @_);
1237              
1238 24 100       81 $self->_valid_image("addcolors")
1239             or return -1;
1240              
1241 23 50       34 my @colors = @{$opts{colors}}
  23         172  
1242             or return undef;
1243              
1244 23         59 for my $color (@colors) {
1245 49         122 $color = _color($color);
1246 49 100       101 unless ($color) {
1247 1         6 $self->_set_error($Imager::ERRSTR);
1248 1         5 return;
1249             }
1250             }
1251              
1252 22         1916 return i_addcolors($self->{IMG}, @colors);
1253             }
1254              
1255             sub setcolors {
1256 12     12 0 483 my $self = shift;
1257 12         45 my %opts = (start=>0, colors=>[], @_);
1258              
1259 12 100       89 $self->_valid_image("setcolors")
1260             or return;
1261              
1262 11 100       15 my @colors = @{$opts{colors}}
  11         27  
1263             or return undef;
1264              
1265 10         17 for my $color (@colors) {
1266 14         20 $color = _color($color);
1267 14 100       50 unless ($color) {
1268 1         3 $self->_set_error($Imager::ERRSTR);
1269 1         3 return;
1270             }
1271             }
1272              
1273 9         685 return i_setcolors($self->{IMG}, $opts{start}, @colors);
1274             }
1275              
1276             sub getcolors {
1277 15     15 0 2995 my $self = shift;
1278 15         32 my %opts = @_;
1279              
1280 15 100       42 $self->_valid_image("getcolors")
1281             or return;
1282              
1283 14 100 66     74 if (!exists $opts{start} && !exists $opts{count}) {
    50          
    0          
1284             # get them all
1285 9         22 $opts{start} = 0;
1286 9         26 $opts{count} = $self->colorcount;
1287             }
1288             elsif (!exists $opts{count}) {
1289 5         7 $opts{count} = 1;
1290             }
1291             elsif (!exists $opts{start}) {
1292 0         0 $opts{start} = 0;
1293             }
1294              
1295 14         3727 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
1296             }
1297              
1298             sub colorcount {
1299 15     15 0 1140 my ($self) = @_;
1300              
1301 15 100       34 $self->_valid_image("colorcount")
1302             or return -1;
1303              
1304 14         80 return i_colorcount($self->{IMG});
1305             }
1306              
1307             sub maxcolors {
1308 3     3 0 8 my $self = shift;
1309              
1310 3 100       10 $self->_valid_image("maxcolors")
1311             or return -1;
1312              
1313 2         14 i_maxcolors($self->{IMG});
1314             }
1315              
1316             sub findcolor {
1317 9     9 0 497 my $self = shift;
1318 9         23 my %opts = @_;
1319              
1320 9 100       20 $self->_valid_image("findcolor")
1321             or return;
1322              
1323 8 50       14 unless ($opts{color}) {
1324 0         0 $self->_set_error("findcolor: no color parameter");
1325 0         0 return;
1326             }
1327              
1328             my $color = _color($opts{color})
1329 8 50       15 or return;
1330              
1331 8         41 return i_findcolor($self->{IMG}, $color);
1332             }
1333              
1334             sub bits {
1335 55     55 0 1228 my $self = shift;
1336              
1337 55 100       141 $self->_valid_image("bits")
1338             or return;
1339              
1340 54         354 my $bits = i_img_bits($self->{IMG});
1341 54 100 66     200 if ($bits && $bits == length(pack("d", 1)) * 8) {
1342 12         22 $bits = 'double';
1343             }
1344 54         194 return $bits;
1345             }
1346              
1347             sub type {
1348 57     57 0 18894 my $self = shift;
1349              
1350 57 100       144 $self->_valid_image("type")
1351             or return;
1352              
1353 56 100       487 return i_img_type($self->{IMG}) ? "paletted" : "direct";
1354             }
1355              
1356             sub virtual {
1357 2     2 0 5 my $self = shift;
1358              
1359 2 100       7 $self->_valid_image("virtual")
1360             or return;
1361              
1362 1         12 return i_img_virtual($self->{IMG});
1363             }
1364              
1365             sub is_bilevel {
1366 25     25 0 49 my ($self) = @_;
1367              
1368 25 100       59 $self->_valid_image("is_bilevel")
1369             or return;
1370              
1371 24         200 return i_img_is_monochrome($self->{IMG});
1372             }
1373              
1374             sub tags {
1375 98     98 0 2161 my ($self, %opts) = @_;
1376              
1377 98 100       273 $self->_valid_image("tags")
1378             or return;
1379              
1380 97 50       222 if (defined $opts{name}) {
    0          
1381 97         109 my @result;
1382 97         121 my $start = 0;
1383 97         113 my $found;
1384 97         590 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
1385 97         398 push @result, (i_tags_get($self->{IMG}, $found))[1];
1386 97         325 $start = $found+1;
1387             }
1388 97 100       504 return wantarray ? @result : $result[0];
1389             }
1390             elsif (defined $opts{code}) {
1391 0         0 my @result;
1392 0         0 my $start = 0;
1393 0         0 my $found;
1394 0         0 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
1395 0         0 push @result, (i_tags_get($self->{IMG}, $found))[1];
1396 0         0 $start = $found+1;
1397             }
1398 0         0 return @result;
1399             }
1400             else {
1401 0 0       0 if (wantarray) {
1402 0         0 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
  0         0  
1403             }
1404             else {
1405 0         0 return i_tags_count($self->{IMG});
1406             }
1407             }
1408             }
1409              
1410             my $int_re = qr/^(?:0|-[1-9][0-9]*|[1-9][0-9]*)$/;
1411              
1412             sub addtag {
1413 35     35 0 11174 my $self = shift;
1414 35         132 my %opts = @_;
1415              
1416 35 100       103 $self->_valid_image("addtag")
1417             or return;
1418              
1419 34         68 my $value = $opts{value};
1420 34 100       96 if ($opts{name}) {
    50          
1421 32 50       90 if (defined $value) {
    0          
1422 32 100 66     400 if ($value =~ $int_re && $value >= INT_MIN && $value <= INT_MAX) {
      100        
1423             # add as an int
1424 21         1413 return i_tags_addn($self->{IMG}, $opts{name}, 0, $value);
1425             }
1426             else {
1427 11         1309 return i_tags_add($self->{IMG}, $opts{name}, 0, $value, 0);
1428             }
1429             }
1430             elsif (defined $opts{data}) {
1431             # force addition as a string
1432 0         0 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
1433             }
1434             else {
1435 0         0 $self->{ERRSTR} = "No value supplied";
1436 0         0 return undef;
1437             }
1438             }
1439             elsif ($opts{code}) {
1440 2 50       303 warnings::warnif("Imager::tagcodes", "addtag: code parameter is deprecated")
1441             if $] >= 5.014;
1442 2 50       16 if (defined $value) {
    0          
1443 2 50 33     32 if ($value =~ $int_re && $value >= INT_MIN && $value <= INT_MAX) {
      33        
1444             # add as a number
1445 2         243 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
1446             }
1447             else {
1448 0         0 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
1449             }
1450             }
1451             elsif (defined $opts{data}) {
1452             # force addition as a string
1453 0         0 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
1454             }
1455             else {
1456 0         0 $self->{ERRSTR} = "No value supplied";
1457 0         0 return undef;
1458             }
1459             }
1460             else {
1461 0         0 return undef;
1462             }
1463             }
1464              
1465             sub deltag {
1466 21     21 0 28 my $self = shift;
1467 21         49 my %opts = @_;
1468              
1469 21 100       38 $self->_valid_image("deltag")
1470             or return 0;
1471              
1472 20 50       70 if (defined $opts{'index'}) {
    50          
    0          
1473 0         0 return i_tags_delete($self->{IMG}, $opts{'index'});
1474             }
1475             elsif (defined $opts{name}) {
1476 20         247 return i_tags_delbyname($self->{IMG}, $opts{name});
1477             }
1478             elsif (defined $opts{code}) {
1479 0 0       0 warnings::warnif("Imager::tagcodes", "deltag: code parameter is deprecated")
1480             if $] >= 5.014;
1481 0         0 return i_tags_delbycode($self->{IMG}, $opts{code});
1482             }
1483             else {
1484 0         0 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
1485 0         0 return 0;
1486             }
1487             }
1488              
1489             sub settag {
1490 23     23 0 1522 my ($self, %opts) = @_;
1491              
1492 23 100       57 $self->_valid_image("settag")
1493             or return;
1494              
1495 22 100       70 if ($opts{name}) {
    50          
1496 20         65 $self->deltag(name=>$opts{name});
1497 20         69 return $self->addtag(name=>$opts{name}, value=>$opts{value});
1498             }
1499             elsif (defined $opts{code}) {
1500 2 50       305 warnings::warnif("Imager::tagcodes", "settag: code parameter is deprecated")
1501             if $] >= 5.014;
1502 2         18 i_tags_delbycode($self->{IMG}, $opts{code});
1503 2 50       5 if (defined $opts{value}) {
    0          
1504 2 50       13 if ($opts{value} =~ /^\d+$/) {
1505             # add as a number
1506 2         138 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
1507             }
1508             else {
1509 0         0 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
1510             }
1511             }
1512             elsif (defined $opts{data}) {
1513             # force addition as a string
1514 0         0 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
1515             }
1516             else {
1517 0         0 $self->{ERRSTR} = "No value supplied";
1518 0         0 return undef;
1519             }
1520             }
1521             else {
1522 0         0 return undef;
1523             }
1524             }
1525              
1526              
1527             sub _get_reader_io {
1528 221     221   403 my ($self, $input) = @_;
1529              
1530 221 50 33     909 if ($input->{io}) {
    100          
    100          
    100          
    100          
    50          
1531 0         0 return $input->{io}, undef;
1532             }
1533             elsif ($input->{fd}) {
1534 4         327 return io_new_fd($input->{fd});
1535             }
1536             elsif ($input->{fh}) {
1537 11 50       42 unless (Scalar::Util::openhandle($input->{fh})) {
1538 0         0 $self->_set_error("Handle in fh option not opened");
1539 0         0 return;
1540             }
1541 11         46 return Imager::IO->new_fh($input->{fh});
1542             }
1543             elsif ($input->{file}) {
1544 135         157 my $file;
1545 135 50       6700 unless (open $file, "<", $input->{file}) {
1546 0         0 $self->_set_error("Could not open $input->{file}: $!");
1547 0         0 return;
1548             }
1549 135         368 binmode $file;
1550 135         13133 return (io_new_fd(fileno($file)), $file);
1551             }
1552             elsif ($input->{data}) {
1553 63         5704 return io_new_buffer($input->{data});
1554             }
1555             elsif ($input->{callback} || $input->{readcb}) {
1556 8 50       19 if (!$input->{seekcb}) {
1557 0         0 $self->_set_error("Need a seekcb parameter");
1558             }
1559 8 50       18 if ($input->{maxbuffer}) {
1560             return io_new_cb($input->{writecb},
1561             $input->{callback} || $input->{readcb},
1562             $input->{seekcb}, $input->{closecb},
1563 0   0     0 $input->{maxbuffer});
1564             }
1565             else {
1566             return io_new_cb($input->{writecb},
1567             $input->{callback} || $input->{readcb},
1568 8   33     1374 $input->{seekcb}, $input->{closecb});
1569             }
1570             }
1571             else {
1572 0         0 $self->_set_error("file/fd/fh/data/callback parameter missing");
1573 0         0 return;
1574             }
1575             }
1576              
1577             sub _get_writer_io {
1578 168     168   344 my ($self, $input) = @_;
1579              
1580 168 100       402 my $buffered = exists $input->{buffered} ? $input->{buffered} : 1;
1581              
1582 168         288 my $io;
1583             my @extras;
1584 168 100 66     836 if ($input->{io}) {
    50          
    100          
    100          
    100          
    50          
1585 19         37 $io = $input->{io};
1586             }
1587             elsif ($input->{fd}) {
1588 0         0 $io = io_new_fd($input->{fd});
1589             }
1590             elsif ($input->{fh}) {
1591 6 50       37 unless (Scalar::Util::openhandle($input->{fh})) {
1592 0         0 $self->_set_error("Handle in fh option not opened");
1593 0         0 return;
1594             }
1595 6         46 $io = Imager::IO->new_fh($input->{fh});
1596             }
1597             elsif ($input->{file}) {
1598 113         192 my $fh;
1599 113 50       22947 unless (open $fh, "+>", $input->{file}) {
1600 0         0 $self->_set_error("Could not open file $input->{file}: $!");
1601 0         0 return;
1602             }
1603 113 50       605 binmode($fh) or die;
1604 113         9778 $io = io_new_fd(fileno($fh));
1605 113         389 push @extras, $fh;
1606             }
1607             elsif ($input->{data}) {
1608 20         2225 $io = io_new_bufchain();
1609             }
1610             elsif ($input->{callback} || $input->{writecb}) {
1611 10 100 66     46 if ($input->{maxbuffer} && $input->{maxbuffer} == 1) {
1612 4         6 $buffered = 0;
1613             }
1614             $io = io_new_cb($input->{callback} || $input->{writecb},
1615             $input->{readcb},
1616 10   66     1797 $input->{seekcb}, $input->{closecb});
1617             }
1618             else {
1619 0         0 $self->_set_error("file/fd/fh/data/callback parameter missing");
1620 0         0 return;
1621             }
1622              
1623 168 100       432 unless ($buffered) {
1624 5         27 $io->set_buffered(0);
1625             }
1626              
1627 168         680 return ($io, @extras);
1628             }
1629              
1630             sub _test_format {
1631 146     146   22404 my ($io) = @_;
1632              
1633 146         8248 return i_test_format_probe($io, -1);
1634             }
1635              
1636             sub add_file_magic {
1637 1     1 0 905 my ($class, %opts) = @_;
1638              
1639 1         5 my $name = delete $opts{name};
1640 1         3 my $bits = delete $opts{bits};
1641 1         4 my $mask = delete $opts{mask};
1642              
1643 1 50       10 unless (i_add_file_magic($name, $bits, $mask)) {
1644 0         0 Imager->_set_error(Imager->_error_as_msg);
1645 0         0 return;
1646             }
1647              
1648 1         8 1;
1649             }
1650              
1651             # Read an image from file
1652              
1653             sub read {
1654 218     218 0 19092 my $self = shift;
1655 218         687 my %input=@_;
1656              
1657 218 100       489 if (defined($self->{IMG})) {
1658             # let IIM_DESTROY do the destruction, since the image may be
1659             # referenced from elsewhere
1660             #i_img_destroy($self->{IMG});
1661 22         5577 undef($self->{IMG});
1662             }
1663              
1664 218 50       712 my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
1665              
1666 218         674 my $type = $input{'type'};
1667 218 100       391 unless ($type) {
1668 112         252 $type = _test_format($IO);
1669             }
1670              
1671 218 100 100     935 if ($input{file} && !$type) {
1672             # guess the type
1673 1         5 $type = $FORMATGUESS->($input{file});
1674             }
1675              
1676 218 100       373 unless ($type) {
1677 2         3 my $msg = "type parameter missing and it couldn't be determined from the file contents";
1678 2 100       13 $input{file} and $msg .= " or file name";
1679 2         6 $self->_set_error($msg);
1680 2         180 return undef;
1681             }
1682              
1683 216         654 _reader_autoload($type);
1684              
1685 216 0 33     398 if ($readers{$type} && $readers{$type}{single}) {
1686 0         0 return $readers{$type}{single}->($self, $IO, %input);
1687             }
1688              
1689 216 100       370 unless ($formats_low{$type}) {
1690 3         14 my $read_types = join ', ', sort Imager->read_types();
1691 3         19 $self->_set_error("format '$type' not supported - formats $read_types available for reading - $reader_load_errors{$type}");
1692 3         335 return;
1693             }
1694              
1695 213         294 my $allow_incomplete = $input{allow_incomplete};
1696 213 100       417 defined $allow_incomplete or $allow_incomplete = 0;
1697              
1698 213 100       432 if ( $type eq 'pnm' ) {
1699 75         43496 $self->{IMG}=i_readpnm_wiol( $IO, $allow_incomplete );
1700 75 100       3101 if ( !defined($self->{IMG}) ) {
1701 20         50 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg();
1702 20         1609 return undef;
1703             }
1704 55 50       174 $self->{DEBUG} && print "loading a pnm file\n";
1705 55         4708 return $self;
1706             }
1707              
1708 138 100       196 if ( $type eq 'bmp' ) {
1709 98         43209 $self->{IMG}=i_readbmp_wiol( $IO, $allow_incomplete );
1710 98 100       1115 if ( !defined($self->{IMG}) ) {
1711 46         109 $self->{ERRSTR}=$self->_error_as_msg();
1712 46         4217 return undef;
1713             }
1714 52 50       101 $self->{DEBUG} && print "loading a bmp file\n";
1715             }
1716              
1717 92 100       170 if ( $type eq 'tga' ) {
1718 22         34193 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1719 22 100       5305 if ( !defined($self->{IMG}) ) {
1720 4         16 $self->{ERRSTR}=$self->_error_as_msg();
1721 4         357 return undef;
1722             }
1723 18 50       41 $self->{DEBUG} && print "loading a tga file\n";
1724             }
1725              
1726 88 100       143 if ( $type eq 'raw' ) {
1727 18 50 33     63 unless ( $input{xsize} && $input{ysize} ) {
1728 0         0 $self->_set_error('missing xsize or ysize parameter for raw');
1729 0         0 return undef;
1730             }
1731              
1732 18         54 my $interleave = _first($input{raw_interleave}, $input{interleave});
1733 18 100       39 unless (defined $interleave) {
1734 1         4 my @caller = caller;
1735 1         13 warn "read(type => 'raw') $caller[2] line $caller[1]: supply interleave or raw_interleave for future compatibility\n";
1736 1         7 $interleave = 1;
1737             }
1738 18         48 my $data_ch = _first($input{raw_datachannels}, $input{datachannels}, 3);
1739 18         44 my $store_ch = _first($input{raw_storechannels}, $input{storechannels}, 3);
1740              
1741             $self->{IMG} = i_readraw_wiol( $IO,
1742             $input{xsize},
1743             $input{ysize},
1744 18         4821 $data_ch,
1745             $store_ch,
1746             $interleave);
1747 18 100       325 if ( !defined($self->{IMG}) ) {
1748 4         11 $self->{ERRSTR}=$self->_error_as_msg();
1749 4         318 return undef;
1750             }
1751 14 50       33 $self->{DEBUG} && print "loading a raw file\n";
1752             }
1753              
1754 84         7298 return $self;
1755             }
1756              
1757             sub register_reader {
1758 3     3 0 11 my ($class, %opts) = @_;
1759              
1760             defined $opts{type}
1761 3 50       9 or die "register_reader called with no type parameter\n";
1762              
1763 3         4 my $type = $opts{type};
1764              
1765             defined $opts{single} || defined $opts{multiple}
1766 3 50 33     6 or die "register_reader called with no single or multiple parameter\n";
1767              
1768 3         7 $readers{$type} = { };
1769 3 50       6 if ($opts{single}) {
1770 3         6 $readers{$type}{single} = $opts{single};
1771             }
1772 3 100       6 if ($opts{multiple}) {
1773 2         3 $readers{$type}{multiple} = $opts{multiple};
1774             }
1775              
1776 3         7 return 1;
1777             }
1778              
1779             sub register_writer {
1780 3     3 0 4 my ($class, %opts) = @_;
1781              
1782             defined $opts{type}
1783 3 50       6 or die "register_writer called with no type parameter\n";
1784              
1785 3         3 my $type = $opts{type};
1786              
1787             defined $opts{single} || defined $opts{multiple}
1788 3 50 33     5 or die "register_writer called with no single or multiple parameter\n";
1789              
1790 3         4 $writers{$type} = { };
1791 3 50       5 if ($opts{single}) {
1792 3         5 $writers{$type}{single} = $opts{single};
1793             }
1794 3 100       4 if ($opts{multiple}) {
1795 2         3 $writers{$type}{multiple} = $opts{multiple};
1796             }
1797              
1798 3         9 return 1;
1799             }
1800              
1801             sub read_types {
1802             my %types =
1803             (
1804 48         109 map { $_ => 1 }
1805             keys %readers,
1806 8     8 0 117 grep($file_formats{$_}, keys %formats),
1807             qw(ico sgi), # formats not handled directly, but supplied with Imager
1808             );
1809              
1810 8         83 return keys %types;
1811             }
1812              
1813             sub write_types {
1814             my %types =
1815             (
1816 48         100 map { $_ => 1 }
1817             keys %writers,
1818 8     8 0 42 grep($file_formats{$_}, keys %formats),
1819             qw(ico sgi), # formats not handled directly, but supplied with Imager
1820             );
1821              
1822 8         66 return keys %types;
1823             }
1824              
1825             sub _load_file {
1826 60     60   111 my ($file, $error) = @_;
1827              
1828 60 100       100 if ($attempted_to_load{$file}) {
1829 3 50       6 if ($file_load_errors{$file}) {
1830 3         5 $$error = $file_load_errors{$file};
1831 3         6 return 0;
1832             }
1833             else {
1834 0         0 return 1;
1835             }
1836             }
1837             else {
1838 57         128 local $SIG{__DIE__};
1839 57         67 my $loaded = eval {
1840 57         205 local @INC = @INC;
1841 57 100       115 pop @INC if $INC[-1] eq '.';
1842 57         144 ++$attempted_to_load{$file};
1843 57         5433 require $file;
1844 0         0 return 1;
1845             };
1846 57 50       258 if ($loaded) {
1847 0         0 return 1;
1848             }
1849             else {
1850 57   50     140 my $work = $@ || "Unknown error";
1851 57         94 chomp $work;
1852 57         110 $work =~ s/\n?Compilation failed in require at .*Imager\.pm line .*\z//m;
1853 57         70 $work =~ s/\n/\\n/g;
1854 57         4118 $work =~ s/\s*\.?\z/ loading $file/;
1855 57         121 $file_load_errors{$file} = $work;
1856 57         117 $$error = $work;
1857 57         174 return 0;
1858             }
1859             }
1860             }
1861              
1862             # probes for an Imager::File::whatever module
1863             sub _reader_autoload {
1864 217     217   315 my $type = shift;
1865              
1866 217 100 66     673 return if $formats_low{$type} || $readers{$type};
1867              
1868 3 50       28 return unless $type =~ /^\w+$/;
1869              
1870 3         8 my $file = "Imager/File/\U$type\E.pm";
1871              
1872 3         4 my $error;
1873 3         10 my $loaded = _load_file($file, \$error);
1874 3 100 66     22 if (!$loaded && $error =~ /^Can't locate /) {
1875 2         4 my $filer = "Imager/File/\U$type\EReader.pm";
1876 2         6 $loaded = _load_file($filer, \$error);
1877 2 50       10 if ($error =~ /^Can't locate /) {
1878 2         4 $error = "Can't locate $file or $filer";
1879             }
1880             }
1881 3 50       6 unless ($loaded) {
1882 3         23 $reader_load_errors{$type} = $error;
1883             }
1884             }
1885              
1886             # probes for an Imager::File::whatever module
1887             sub _writer_autoload {
1888 171     171   262 my $type = shift;
1889              
1890 171 100 66     704 return if $formats_low{$type} || $writers{$type};
1891              
1892 3 50       37 return unless $type =~ /^\w+$/;
1893              
1894 3         7 my $file = "Imager/File/\U$type\E.pm";
1895              
1896 3         4 my $error;
1897 3         6 my $loaded = _load_file($file, \$error);
1898 3 100 66     16 if (!$loaded && $error =~ /^Can't locate /) {
1899 2         5 my $filew = "Imager/File/\U$type\EWriter.pm";
1900 2         4 $loaded = _load_file($filew, \$error);
1901 2 50       7 if ($error =~ /^Can't locate /) {
1902 2         4 $error = "Can't locate $file or $filew";
1903             }
1904             }
1905 3 50       5 unless ($loaded) {
1906 3         9 $writer_load_errors{$type} = $error;
1907             }
1908             }
1909              
1910             sub _fix_gif_positions {
1911 0     0   0 my ($opts, $opt, $msg, @imgs) = @_;
1912              
1913 0         0 my $positions = $opts->{'gif_positions'};
1914 0         0 my $index = 0;
1915 0         0 for my $pos (@$positions) {
1916 0         0 my ($x, $y) = @$pos;
1917 0         0 my $img = $imgs[$index++];
1918 0         0 $img->settag(name=>'gif_left', value=>$x);
1919 0 0       0 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1920             }
1921 0         0 $$msg .= "replaced with the gif_left and gif_top tags";
1922             }
1923              
1924             my %obsolete_opts =
1925             (
1926             gif_each_palette=>'gif_local_map',
1927             interlace => 'gif_interlace',
1928             gif_delays => 'gif_delay',
1929             gif_positions => \&_fix_gif_positions,
1930             gif_loop_count => 'gif_loop',
1931             );
1932              
1933             # options that should be converted to colors
1934             my %color_opts = map { $_ => 1 } qw/i_background/;
1935              
1936             sub _set_opts {
1937 339     339   838 my ($self, $opts, $prefix, @imgs) = @_;
1938              
1939 339         1226 for my $opt (keys %$opts) {
1940 3292         3754 my $tagname = $opt;
1941 3292 50       4972 if ($obsolete_opts{$opt}) {
1942 0         0 my $new = $obsolete_opts{$opt};
1943 0         0 my $msg = "Obsolete option $opt ";
1944 0 0       0 if (ref $new) {
1945 0         0 $new->($opts, $opt, \$msg, @imgs);
1946             }
1947             else {
1948 0         0 $msg .= "replaced with the $new tag ";
1949 0         0 $tagname = $new;
1950             }
1951 0         0 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1952 0 0 0     0 warn $msg if $warn_obsolete && $^W;
1953             }
1954 3292 100       13208 next unless $tagname =~ /^\Q$prefix/;
1955 19         32 my $value = $opts->{$opt};
1956 19 100       48 if ($color_opts{$opt}) {
1957 3         7 $value = _color($value);
1958 3 50       11 unless ($value) {
1959 0         0 $self->_set_error($Imager::ERRSTR);
1960 0         0 return;
1961             }
1962             }
1963 19 100       39 if (ref $value) {
1964 3 50       19 if (UNIVERSAL::isa($value, "Imager::Color")) {
    0          
1965 3         19 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1966 3         7 for my $img (@imgs) {
1967 3         13 $img->settag(name=>$tagname, value=>$tag);
1968             }
1969             }
1970             elsif (ref($value) eq 'ARRAY') {
1971 0         0 for my $i (0..$#$value) {
1972 0         0 my $val = $value->[$i];
1973 0 0       0 if (ref $val) {
1974 0 0       0 if (UNIVERSAL::isa($val, "Imager::Color")) {
1975 0         0 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1976 0 0       0 $i < @imgs and
1977             $imgs[$i]->settag(name=>$tagname, value=>$tag);
1978             }
1979             else {
1980 0         0 $self->_set_error("Unknown reference type " . ref($value) .
1981             " supplied in array for $opt");
1982 0         0 return;
1983             }
1984             }
1985             else {
1986 0 0       0 $i < @imgs
1987             and $imgs[$i]->settag(name=>$tagname, value=>$val);
1988             }
1989             }
1990             }
1991             else {
1992 0         0 $self->_set_error("Unknown reference type " . ref($value) .
1993             " supplied for $opt");
1994 0         0 return;
1995             }
1996             }
1997             else {
1998             # set it as a tag for every image
1999 16         27 for my $img (@imgs) {
2000 16         41 $img->settag(name=>$tagname, value=>$value);
2001             }
2002             }
2003             }
2004              
2005 339         1215 return 1;
2006             }
2007              
2008             # Write an image to file
2009             sub write {
2010 172     172 0 29149 my $self = shift;
2011 172         1614 my %input=(jpegquality=>75,
2012             gifquant=>'mc',
2013             lmdither=>6.0,
2014             lmfixed=>[],
2015             idstring=>"",
2016             compress=>1,
2017             wierdpack=>0,
2018             fax_fine=>1, @_);
2019 172         284 my $rc;
2020              
2021 172 100       497 $self->_valid_image("write")
2022             or return;
2023              
2024 171 50       569 $self->_set_opts(\%input, "i_", $self)
2025             or return undef;
2026              
2027 171         387 my $type = $input{'type'};
2028 171 50 66     673 if (!$type and $input{file}) {
2029 95         357 $type = $FORMATGUESS->($input{file});
2030             }
2031 171 50       474 unless ($type) {
2032 0         0 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
2033 0         0 return undef;
2034             }
2035              
2036 171         613 _writer_autoload($type);
2037              
2038 171         2460 my ($IO, $fh);
2039 171 50 33     545 if ($writers{$type} && $writers{$type}{single}) {
2040 0 0       0 ($IO, $fh) = $self->_get_writer_io(\%input)
2041             or return undef;
2042              
2043 0 0       0 $writers{$type}{single}->($self, $IO, %input, type => $type)
2044             or return undef;
2045             }
2046             else {
2047 171 100       387 if (!$formats_low{$type}) {
2048 3         10 my $write_types = join ', ', sort Imager->write_types();
2049 3         16 $self->_set_error("format '$type' not supported - formats $write_types available for writing - $writer_load_errors{$type}");
2050 3         23 return undef;
2051             }
2052            
2053 168 50       602 ($IO, $fh) = $self->_get_writer_io(\%input, $type)
2054             or return undef;
2055            
2056 168 100       542 if ( $type eq 'pnm' ) {
    100          
    100          
    50          
2057 121 50       357 $self->_set_opts(\%input, "pnm_", $self)
2058             or return undef;
2059 121 100       33992 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
2060 5         751 $self->{ERRSTR} = $self->_error_as_msg();
2061 5         52 return undef;
2062             }
2063 116 50       834 $self->{DEBUG} && print "writing a pnm file\n";
2064             }
2065             elsif ( $type eq 'raw' ) {
2066 10 50       25 $self->_set_opts(\%input, "raw_", $self)
2067             or return undef;
2068 10 100       2294 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
2069 4         408 $self->{ERRSTR} = $self->_error_as_msg();
2070 4         107 return undef;
2071             }
2072 6 50       343 $self->{DEBUG} && print "writing a raw file\n";
2073             }
2074             elsif ( $type eq 'bmp' ) {
2075 21 50       63 $self->_set_opts(\%input, "bmp_", $self)
2076             or return undef;
2077 21 100       6230 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
2078 12         5622 $self->{ERRSTR} = $self->_error_as_msg;
2079 12         287 return undef;
2080             }
2081 9 50       2275 $self->{DEBUG} && print "writing a bmp file\n";
2082             }
2083             elsif ( $type eq 'tga' ) {
2084 16 50       36 $self->_set_opts(\%input, "tga_", $self)
2085             or return undef;
2086            
2087 16 100       27043 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
2088 4         218 $self->{ERRSTR}=$self->_error_as_msg();
2089 4         359 return undef;
2090             }
2091 12 50       14079 $self->{DEBUG} && print "writing a tga file\n";
2092             }
2093             }
2094              
2095 143 100       357 if (exists $input{'data'}) {
2096 17         3677 my $data = io_slurp($IO);
2097 17 50       81 if (!$data) {
2098 0         0 $self->{ERRSTR}='Could not slurp from buffer';
2099 0         0 return undef;
2100             }
2101 17         29 ${$input{data}} = $data;
  17         86  
2102             }
2103 143         16073 return $self;
2104             }
2105              
2106             sub write_multi {
2107 3     3 0 29 my ($class, $opts, @images) = @_;
2108              
2109 3         4 my $type = $opts->{type};
2110              
2111 3 0 33     8 if (!$type && $opts->{'file'}) {
2112 0         0 $type = $FORMATGUESS->($opts->{'file'});
2113             }
2114 3 50       6 unless ($type) {
2115 0         0 $class->_set_error('type parameter missing and not possible to guess from extension');
2116 0         0 return;
2117             }
2118             # translate to ImgRaw
2119 3         4 my $index = 1;
2120 3         10 for my $img (@images) {
2121 4 100 66     37 unless (ref $img && Scalar::Util::blessed($img) && $img->isa("Imager")) {
      100        
2122 2         7 $class->_set_error("write_multi: image $index is not an Imager image object");
2123 2         8 return;
2124             }
2125 2 100       6 unless ($img->_valid_image("write_multi")) {
2126 1         3 $class->_set_error($img->errstr . " (image $index)");
2127 1         7 return;
2128             }
2129 1         2 ++$index;
2130             }
2131 0 0       0 $class->_set_opts($opts, "i_", @images)
2132             or return;
2133 0         0 my @work = map $_->{IMG}, @images;
2134              
2135 0         0 _writer_autoload($type);
2136              
2137 0         0 my ($IO, $file);
2138 0 0 0     0 if ($writers{$type} && $writers{$type}{multiple}) {
2139 0 0       0 ($IO, $file) = $class->_get_writer_io($opts, $type)
2140             or return undef;
2141              
2142 0 0       0 $writers{$type}{multiple}->($class, $IO, $opts, @images)
2143             or return undef;
2144             }
2145             else {
2146 0 0       0 if (!$formats{$type}) {
2147 0         0 my $write_types = join ', ', sort Imager->write_types();
2148 0         0 $class->_set_error("format '$type' not supported - formats $write_types available for writing");
2149 0         0 return undef;
2150             }
2151            
2152 0 0       0 ($IO, $file) = $class->_get_writer_io($opts, $type)
2153             or return undef;
2154            
2155 0         0 if (0) { # eventually PNM in here, now that TIFF/GIF are elsewhere
2156             }
2157             else {
2158 0 0       0 if (@images == 1) {
2159 0 0       0 unless ($images[0]->write(%$opts, io => $IO, type => $type)) {
2160 0         0 return 1;
2161             }
2162             }
2163             else {
2164 0         0 $ERRSTR = "Sorry, write_multi doesn't support $type yet";
2165 0         0 return 0;
2166             }
2167             }
2168             }
2169              
2170 0 0       0 if (exists $opts->{'data'}) {
2171 0         0 my $data = io_slurp($IO);
2172 0 0       0 if (!$data) {
2173 0         0 Imager->_set_error('Could not slurp from buffer');
2174 0         0 return undef;
2175             }
2176 0         0 ${$opts->{data}} = $data;
  0         0  
2177             }
2178 0         0 return 1;
2179             }
2180              
2181             # read multiple images from a file
2182             sub read_multi {
2183 3     3 0 74 my ($class, %opts) = @_;
2184              
2185 3 50       23 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
2186             or return;
2187              
2188 3         12 my $type = $opts{'type'};
2189 3 50       11 unless ($type) {
2190 3         9 $type = _test_format($IO);
2191             }
2192              
2193 3 100 100     25 if ($opts{file} && !$type) {
2194             # guess the type
2195 1         8 $type = $FORMATGUESS->($opts{file});
2196             }
2197              
2198 3 100       9 unless ($type) {
2199 2         10 my $msg = "type parameter missing and it couldn't be determined from the file contents";
2200 2 100       7 $opts{file} and $msg .= " or file name";
2201 2         12 Imager->_set_error($msg);
2202 2         204 return;
2203             }
2204              
2205 1         3 _reader_autoload($type);
2206              
2207 1 0 33     3 if ($readers{$type} && $readers{$type}{multiple}) {
2208 0         0 return $readers{$type}{multiple}->($IO, %opts);
2209             }
2210              
2211 1 50       10 unless ($formats{$type}) {
2212 0         0 my $read_types = join ', ', sort Imager->read_types();
2213 0         0 Imager->_set_error("format '$type' not supported - formats $read_types available for reading");
2214 0         0 return;
2215             }
2216              
2217 1         3 my @imgs;
2218 1 50       3 if ($type eq 'pnm') {
2219 1   50     2020 @imgs = i_readpnm_multi_wiol($IO, $opts{allow_incomplete}||0);
2220             }
2221             else {
2222 0         0 my $img = Imager->new;
2223 0 0       0 if ($img->read(%opts, io => $IO, type => $type)) {
2224 0         0 return ( $img );
2225             }
2226 0         0 Imager->_set_error($img->errstr);
2227 0         0 return;
2228             }
2229              
2230 1 50       5 if (!@imgs) {
2231 0         0 $ERRSTR = _error_as_msg();
2232 0         0 return;
2233             }
2234             return map {
2235 1         78 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
  3         93  
2236             } @imgs;
2237             }
2238              
2239             # Destroy an Imager object
2240              
2241             sub DESTROY {
2242 1281     1281   276286 my $self=shift;
2243             # delete $instances{$self};
2244 1281 100       4155 if (defined($self->{IMG})) {
2245             # the following is now handled by the XS DESTROY method for
2246             # Imager::ImgRaw object
2247             # Re-enabling this will break virtual images
2248             # tested for in t/t020masked.t
2249             # i_img_destroy($self->{IMG});
2250 1120         138808 undef($self->{IMG});
2251             } else {
2252             # print "Destroy Called on an empty image!\n"; # why did I put this here??
2253             }
2254             }
2255              
2256             # Perform an inplace filter of an image
2257             # that is the image will be overwritten with the data
2258              
2259             sub filter {
2260 87     87 0 1194 my $self=shift;
2261 87         345 my %input=@_;
2262 87         129 my %hsh;
2263              
2264 87 100       213 $self->_valid_image("filter")
2265             or return;
2266              
2267 86 50       219 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
  0         0  
  0         0  
2268              
2269 86 50       281 if (!exists $filters{$input{'type'}}) {
2270 0         0 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
  0         0  
2271             }
2272              
2273 86 100       293 if ($filters{$input{'type'}}{names}) {
2274 10         18 my $names = $filters{$input{'type'}}{names};
2275 10         35 for my $name (keys %$names) {
2276 40 100 66     104 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
2277 12         23 $input{$name} = $names->{$name}{$input{$name}};
2278             }
2279             }
2280             }
2281 86 100       223 if (defined($filters{$input{'type'}}{defaults})) {
2282             %hsh=( image => $self->{IMG},
2283             imager => $self,
2284 85         166 %{$filters{$input{'type'}}{defaults}},
  85         457  
2285             %input );
2286             } else {
2287             %hsh=( image => $self->{IMG},
2288 1         4 imager => $self,
2289             %input );
2290             }
2291              
2292 86         156 my @cs=@{$filters{$input{'type'}}{callseq}};
  86         296  
2293              
2294 86         175 for(@cs) {
2295 292 50       503 if (!defined($hsh{$_})) {
2296 0         0 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
  0         0  
2297             }
2298             }
2299              
2300 86         143 eval {
2301 86         386 local $SIG{__DIE__}; # we don't want this processed by confess, etc
2302 86         167 &{$filters{$input{'type'}}{callsub}}(%hsh);
  86         209  
2303             };
2304 86 100       354 if ($@) {
2305 4         11 chomp($self->{ERRSTR} = $@);
2306 4         25 return;
2307             }
2308              
2309 82         311 my @b=keys %hsh;
2310              
2311 82 50       280 $self->{DEBUG} && print "callseq is: @cs\n";
2312 82 50       180 $self->{DEBUG} && print "matching callseq is: @b\n";
2313              
2314 82         591 return $self;
2315             }
2316              
2317             sub register_filter {
2318 1     1 0 15 my $class = shift;
2319 1         9 my %hsh = ( defaults => {}, @_ );
2320              
2321             defined $hsh{type}
2322 1 50       7 or die "register_filter() with no type\n";
2323             defined $hsh{callsub}
2324 1 50       4 or die "register_filter() with no callsub\n";
2325             defined $hsh{callseq}
2326 1 50       4 or die "register_filter() with no callseq\n";
2327              
2328             exists $filters{$hsh{type}}
2329 1 50       6 and return;
2330              
2331 1         3 $filters{$hsh{type}} = \%hsh;
2332              
2333 1         4 return 1;
2334             }
2335              
2336             sub scale_calculate {
2337 61     61 0 91 my $self = shift;
2338              
2339 61         158 my %opts = ('type'=>'max', @_);
2340              
2341             # none of these should be references
2342 61         103 for my $name (qw/xpixels ypixels xscalefactor yscalefactor width height/) {
2343 361 100 100     583 if (defined $opts{$name} && ref $opts{$name}) {
2344 1         4 $self->_set_error("scale_calculate: $name parameter cannot be a reference");
2345 1         5 return;
2346             }
2347             }
2348              
2349 60         75 my ($x_scale, $y_scale);
2350 60         72 my $width = $opts{width};
2351 60         57 my $height = $opts{height};
2352 60 100       71 if (ref $self) {
2353 58 50       160 defined $width or $width = $self->getwidth;
2354 58 50       146 defined $height or $height = $self->getheight;
2355             }
2356             else {
2357 2 100 66     9 unless (defined $width && defined $height) {
2358 1         5 $self->_set_error("scale_calculate: width and height parameters must be supplied when called as a class method");
2359 1         65 return;
2360             }
2361             }
2362              
2363 59 100 100     169 if ($opts{'xscalefactor'} && $opts{'yscalefactor'}) {
    100          
    100          
2364 8         10 $x_scale = $opts{'xscalefactor'};
2365 8         10 $y_scale = $opts{'yscalefactor'};
2366             }
2367             elsif ($opts{'xscalefactor'}) {
2368 3         5 $x_scale = $opts{'xscalefactor'};
2369 3   33     12 $y_scale = $opts{'scalefactor'} || $x_scale;
2370             }
2371             elsif ($opts{'yscalefactor'}) {
2372 3         4 $y_scale = $opts{'yscalefactor'};
2373 3   33     10 $x_scale = $opts{'scalefactor'} || $y_scale;
2374             }
2375             else {
2376 45   100     104 $x_scale = $y_scale = $opts{'scalefactor'} || 0.5;
2377             }
2378              
2379             # work out the scaling
2380 59 100 100     227 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
    100 66        
    100 33        
    50 33        
2381             my ($xpix, $ypix)=( $opts{xpixels} / $width ,
2382 19         51 $opts{ypixels} / $height );
2383 19 100 66     48 if ($opts{'type'} eq 'min') {
    100          
    100          
2384 3         7 $x_scale = $y_scale = _min($xpix,$ypix);
2385             }
2386             elsif ($opts{'type'} eq 'max') {
2387 9         25 $x_scale = $y_scale = _max($xpix,$ypix);
2388             }
2389             elsif ($opts{'type'} eq 'nonprop' || $opts{'type'} eq 'non-proportional') {
2390 6         9 $x_scale = $xpix;
2391 6         8 $y_scale = $ypix;
2392             }
2393             else {
2394 1         4 $self->_set_error('invalid value for type parameter');
2395 1         4 return;
2396             }
2397             } elsif ($opts{xpixels}) {
2398 6         14 $x_scale = $y_scale = $opts{xpixels} / $width;
2399             }
2400             elsif ($opts{ypixels}) {
2401 3         8 $x_scale = $y_scale = $opts{ypixels}/$height;
2402             }
2403             elsif ($opts{constrain} && ref $opts{constrain}
2404             && $opts{constrain}->can('constrain')) {
2405             # we've been passed an Image::Math::Constrain object or something
2406             # that looks like one
2407 0         0 my $scalefactor;
2408             (undef, undef, $scalefactor)
2409 0         0 = $opts{constrain}->constrain($self->getwidth, $self->getheight);
2410 0 0       0 unless ($scalefactor) {
2411 0         0 $self->_set_error('constrain method failed on constrain parameter');
2412 0         0 return;
2413             }
2414 0         0 $x_scale = $y_scale = $scalefactor;
2415             }
2416              
2417 58         158 my $new_width = int($x_scale * $width + 0.5);
2418 58 100       89 $new_width > 0 or $new_width = 1;
2419 58         72 my $new_height = int($y_scale * $height + 0.5);
2420 58 100       89 $new_height > 0 or $new_height = 1;
2421              
2422 58         199 return ($x_scale, $y_scale, $new_width, $new_height);
2423            
2424             }
2425              
2426             # Scale an image to requested size and return the scaled version
2427              
2428             sub scale {
2429 60     60 0 1561 my $self=shift;
2430 60         275 my %opts = (qtype=>'normal' ,@_);
2431 60         198 my $img = Imager->new();
2432 60         89 my $tmp = Imager->new();
2433              
2434 60 100       138 unless (defined wantarray) {
2435 1         3 my @caller = caller;
2436 1         13 warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
2437 1         27 return;
2438             }
2439              
2440 59 100       123 $self->_valid_image("scale")
2441             or return;
2442              
2443 58 100       187 my ($x_scale, $y_scale, $new_width, $new_height) =
2444             $self->scale_calculate(%opts)
2445             or return;
2446              
2447 56 100       190 if ($opts{qtype} eq 'normal') {
    100          
    100          
2448 17         50064 $tmp->{IMG} = i_scaleaxis($self->{IMG}, $x_scale, 0);
2449 17 50       55 if ( !defined($tmp->{IMG}) ) {
2450 0         0 $self->{ERRSTR} = 'unable to scale image: ' . $self->_error_as_msg;
2451 0         0 return undef;
2452             }
2453 17         31263 $img->{IMG}=i_scaleaxis($tmp->{IMG}, $y_scale, 1);
2454 17 50       91 if ( !defined($img->{IMG}) ) {
2455 0         0 $self->{ERRSTR}='unable to scale image: ' . $self->_error_as_msg;
2456 0         0 return undef;
2457             }
2458              
2459 17         81 return $img;
2460             }
2461             elsif ($opts{'qtype'} eq 'preview') {
2462 18         9539 $img->{IMG} = i_scale_nn($self->{IMG}, $x_scale, $y_scale);
2463 18 50       61 if ( !defined($img->{IMG}) ) {
2464 0         0 $self->{ERRSTR}='unable to scale image';
2465 0         0 return undef;
2466             }
2467 18         64 return $img;
2468             }
2469             elsif ($opts{'qtype'} eq 'mixing') {
2470 20         19638 $img->{IMG} = i_scale_mixing($self->{IMG}, $new_width, $new_height);
2471 20 50       70 unless ($img->{IMG}) {
2472 0         0 $self->_set_error(Imager->_error_as_msg);
2473 0         0 return;
2474             }
2475 20         81 return $img;
2476             }
2477             else {
2478 1         4 $self->_set_error('invalid value for qtype parameter');
2479 1         3 return undef;
2480             }
2481             }
2482              
2483             # Scales only along the X axis
2484              
2485             sub scaleX {
2486 11     11 0 1108 my $self = shift;
2487 11         43 my %opts = ( scalefactor=>0.5, @_ );
2488              
2489 11 100       29 unless (defined wantarray) {
2490 1         3 my @caller = caller;
2491 1         29 warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
2492 1         20 return;
2493             }
2494              
2495 10 100       26 $self->_valid_image("scaleX")
2496             or return;
2497              
2498 9         24 my $img = Imager->new();
2499              
2500 9         16 my $scalefactor = $opts{scalefactor};
2501              
2502 9 100       16 if ($opts{pixels}) {
2503 3         9 $scalefactor = $opts{pixels} / $self->getwidth();
2504             }
2505              
2506 9 50       19 unless ($self->{IMG}) {
2507 0         0 $self->{ERRSTR}='empty input image';
2508 0         0 return undef;
2509             }
2510              
2511 9         29137 $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
2512              
2513 9 50       37 if ( !defined($img->{IMG}) ) {
2514 0         0 $self->{ERRSTR} = 'unable to scale image';
2515 0         0 return undef;
2516             }
2517              
2518 9         44 return $img;
2519             }
2520              
2521             # Scales only along the Y axis
2522              
2523             sub scaleY {
2524 11     11 0 1051 my $self = shift;
2525 11         40 my %opts = ( scalefactor => 0.5, @_ );
2526              
2527 11 100       28 unless (defined wantarray) {
2528 1         3 my @caller = caller;
2529 1         9 warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
2530 1         67 return;
2531             }
2532              
2533 10 100       41 $self->_valid_image("scaleY")
2534             or return;
2535              
2536 9         20 my $img = Imager->new();
2537              
2538 9         11 my $scalefactor = $opts{scalefactor};
2539              
2540 9 100       19 if ($opts{pixels}) {
2541 3         8 $scalefactor = $opts{pixels} / $self->getheight();
2542             }
2543              
2544 9 50       18 unless ($self->{IMG}) {
2545 0         0 $self->{ERRSTR} = 'empty input image';
2546 0         0 return undef;
2547             }
2548 9         46046 $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
2549              
2550 9 50       34 if ( !defined($img->{IMG}) ) {
2551 0         0 $self->{ERRSTR} = 'unable to scale image';
2552 0         0 return undef;
2553             }
2554              
2555 9         41 return $img;
2556             }
2557              
2558             # Transform returns a spatial transformation of the input image
2559             # this moves pixels to a new location in the returned image.
2560             # NOTE - should make a utility function to check transforms for
2561             # stack overruns
2562              
2563             our $I2P;
2564              
2565             sub transform {
2566 0     0 0 0 my $self=shift;
2567 0         0 my %opts=@_;
2568 0         0 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
2569              
2570             # print Dumper(\%opts);
2571             # xopcopdes
2572              
2573 0 0       0 $self->_valid_image("transform")
2574             or return;
2575              
2576 0 0 0     0 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
2577 0 0       0 if (!$I2P) {
2578             {
2579 0         0 local @INC = @INC;
  0         0  
2580 0 0       0 pop @INC if $INC[-1] eq '.';
2581 0         0 eval ("use Affix::Infix2Postfix;");
2582             }
2583              
2584 0 0       0 if ( $@ ) {
2585 0         0 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
2586 0         0 return undef;
2587             }
2588 0         0 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
2589             {op=>'-',trans=>'Sub'},
2590             {op=>'*',trans=>'Mult'},
2591             {op=>'/',trans=>'Div'},
2592             {op=>'-','type'=>'unary',trans=>'u-'},
2593             {op=>'**'},
2594             {op=>'func','type'=>'unary'}],
2595             'grouping'=>[qw( \( \) )],
2596             'func'=>[qw( sin cos )],
2597             'vars'=>[qw( x y )]
2598             );
2599             }
2600              
2601 0         0 @xt=$I2P->translate($opts{'xexpr'});
2602 0         0 @yt=$I2P->translate($opts{'yexpr'});
2603              
2604 0         0 $numre=$I2P->{'numre'};
2605 0         0 @pt=(0,0);
2606              
2607 0 0       0 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
2608 0 0       0 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
2609 0         0 @{$opts{'parm'}}=@pt;
  0         0  
2610             }
2611              
2612             # print Dumper(\%opts);
2613              
2614 0 0 0     0 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
  0         0  
2615 0         0 $self->{ERRSTR}='transform: no xopcodes given.';
2616 0         0 return undef;
2617             }
2618              
2619 0         0 @op=@{$opts{'xopcodes'}};
  0         0  
2620 0         0 for $iop (@op) {
2621 0 0 0     0 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2622 0         0 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2623 0         0 return undef;
2624             }
2625 0 0       0 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
  0         0  
2626             }
2627              
2628              
2629             # yopcopdes
2630              
2631 0 0 0     0 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
  0         0  
2632 0         0 $self->{ERRSTR}='transform: no yopcodes given.';
2633 0         0 return undef;
2634             }
2635              
2636 0         0 @op=@{$opts{'yopcodes'}};
  0         0  
2637 0         0 for $iop (@op) {
2638 0 0 0     0 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2639 0         0 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2640 0         0 return undef;
2641             }
2642 0 0       0 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
  0         0  
2643             }
2644              
2645             #parameters
2646              
2647 0 0       0 if ( !exists $opts{'parm'}) {
2648 0         0 $self->{ERRSTR}='transform: no parameter arg given.';
2649 0         0 return undef;
2650             }
2651              
2652             # print Dumper(\@ropx);
2653             # print Dumper(\@ropy);
2654             # print Dumper(\@ropy);
2655              
2656 0         0 my $img = Imager->new();
2657 0         0 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
2658 0 0       0 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
  0         0  
  0         0  
2659 0         0 return $img;
2660             }
2661              
2662              
2663             sub transform2 {
2664 30     30 0 1760 my ($opts, @imgs) = @_;
2665            
2666 30         159 require "Imager/Expr.pm";
2667              
2668 30         63 $opts->{variables} = [ qw(x y) ];
2669 30         38 my ($width, $height) = @{$opts}{qw(width height)};
  30         66  
2670 30 100       55 if (@imgs) {
2671 26         30 my $index = 1;
2672 26         40 for my $img (@imgs) {
2673 28 100       46 unless ($img->_valid_image("transform2")) {
2674 1         3 Imager->_set_error($img->errstr . " (input image $index)");
2675 1         20 return;
2676             }
2677 27         39 ++$index;
2678             }
2679              
2680 25   33     124 $width ||= $imgs[0]->getwidth();
2681 25   33     56 $height ||= $imgs[0]->getheight();
2682 25         25 my $img_num = 1;
2683 25         25 for my $img (@imgs) {
2684 26         30 $opts->{constants}{"w$img_num"} = $img->getwidth();
2685 26         53 $opts->{constants}{"h$img_num"} = $img->getheight();
2686 26         31 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
2687 26         29 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
2688 26         62 ++$img_num;
2689             }
2690             }
2691 29 100       40 if ($width) {
2692 28         47 $opts->{constants}{w} = $width;
2693 28         41 $opts->{constants}{cx} = $width/2;
2694             }
2695             else {
2696 1         2 $Imager::ERRSTR = "No width supplied";
2697 1         3 return;
2698             }
2699 28 50       46 if ($height) {
2700 28         66 $opts->{constants}{h} = $height;
2701 28         37 $opts->{constants}{cy} = $height/2;
2702             }
2703             else {
2704 0         0 $Imager::ERRSTR = "No height supplied";
2705 0         0 return;
2706             }
2707 28         115 my $code = Imager::Expr->new($opts);
2708 28 50       69 if (!$code) {
2709 0         0 $Imager::ERRSTR = Imager::Expr::error();
2710 0         0 return;
2711             }
2712 28   100     70 my $channels = $opts->{channels} || 3;
2713 28 50 33     98 unless ($channels >= 1 && $channels <= 4) {
2714 0         0 return Imager->_set_error("channels must be an integer between 1 and 4");
2715             }
2716              
2717 28         68 my $img = Imager->new();
2718             $img->{IMG} = i_transform2($opts->{width}, $opts->{height},
2719             $channels, $code->code(),
2720             $code->nregs(), $code->cregs(),
2721 28         88 [ map { $_->{IMG} } @imgs ]);
  26         20643  
2722 28 100       126 if (!defined $img->{IMG}) {
2723 1         5 $Imager::ERRSTR = Imager->_error_as_msg();
2724 1         15 return;
2725             }
2726              
2727 27         272 return $img;
2728             }
2729              
2730             sub rubthrough {
2731 22     22 0 102 my $self=shift;
2732 22         78 my %opts= @_;
2733              
2734 22 100       42 $self->_valid_image("rubthrough")
2735             or return;
2736              
2737 21 100 66     53 unless ($opts{src} && $opts{src}->_valid_image("rubthrough")) {
2738 1         2 $self->{ERRSTR} = $opts{src}{ERRSTR} . ' (for src)';
2739 1         5 return;
2740             }
2741              
2742             %opts = (src_minx => 0,
2743             src_miny => 0,
2744             src_maxx => $opts{src}->getwidth(),
2745 20         56 src_maxy => $opts{src}->getheight(),
2746             %opts);
2747              
2748 20         30 my $tx = $opts{tx};
2749 20 100       40 defined $tx or $tx = $opts{left};
2750 20 100       28 defined $tx or $tx = 0;
2751              
2752 20         21 my $ty = $opts{ty};
2753 20 100       30 defined $ty or $ty = $opts{top};
2754 20 100       45 defined $ty or $ty = 0;
2755              
2756 20 50       4413 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $tx, $ty,
2757             $opts{src_minx}, $opts{src_miny},
2758             $opts{src_maxx}, $opts{src_maxy})) {
2759 0         0 $self->_set_error($self->_error_as_msg());
2760 0         0 return undef;
2761             }
2762              
2763 20         115 return $self;
2764             }
2765              
2766             sub compose {
2767 58     58 0 252 my $self = shift;
2768 58         288 my %opts =
2769             (
2770             opacity => 1.0,
2771             mask_left => 0,
2772             mask_top => 0,
2773             @_
2774             );
2775              
2776 58 100       132 $self->_valid_image("compose")
2777             or return;
2778              
2779 57 50       115 unless ($opts{src}) {
2780 0         0 $self->_set_error("compose: src parameter missing");
2781 0         0 return;
2782             }
2783            
2784 57 100       90 unless ($opts{src}->_valid_image("compose")) {
2785 1         3 $self->_set_error($opts{src}->errstr . " (for src)");
2786 1         5 return;
2787             }
2788 56         61 my $src = $opts{src};
2789              
2790 56         59 my $left = $opts{left};
2791 56 50       98 defined $left or $left = $opts{tx};
2792 56 100       74 defined $left or $left = 0;
2793              
2794 56         64 my $top = $opts{top};
2795 56 50       79 defined $top or $top = $opts{ty};
2796 56 100       114 defined $top or $top = 0;
2797              
2798 56         62 my $src_left = $opts{src_left};
2799 56 100       75 defined $src_left or $src_left = $opts{src_minx};
2800 56 100       68 defined $src_left or $src_left = 0;
2801              
2802 56         68 my $src_top = $opts{src_top};
2803 56 100       73 defined $src_top or $src_top = $opts{src_miny};
2804 56 100       71 defined $src_top or $src_top = 0;
2805              
2806 56         55 my $width = $opts{width};
2807 56 50 66     174 if (!defined $width && defined $opts{src_maxx}) {
2808 0         0 $width = $opts{src_maxx} - $src_left;
2809             }
2810 56 100       119 defined $width or $width = $src->getwidth() - $src_left;
2811              
2812 56         60 my $height = $opts{height};
2813 56 50 66     150 if (!defined $height && defined $opts{src_maxy}) {
2814 0         0 $height = $opts{src_maxy} - $src_top;
2815             }
2816 56 100       133 defined $height or $height = $src->getheight() - $src_top;
2817              
2818 56         196 my $combine = $self->_combine($opts{combine}, 'normal');
2819              
2820 56 100       127 if ($opts{mask}) {
2821 31 100       56 unless ($opts{mask}->_valid_image("compose")) {
2822 1         3 $self->_set_error($opts{mask}->errstr . " (for mask)");
2823 1         5 return;
2824             }
2825              
2826 30         38 my $mask_left = $opts{mask_left};
2827 30 50       47 defined $mask_left or $mask_left = $opts{mask_minx};
2828 30 50       45 defined $mask_left or $mask_left = 0;
2829            
2830 30         35 my $mask_top = $opts{mask_top};
2831 30 50       43 defined $mask_top or $mask_top = $opts{mask_miny};
2832 30 50       35 defined $mask_top or $mask_top = 0;
2833              
2834 30 100       6052 unless (i_compose_mask($self->{IMG}, $src->{IMG}, $opts{mask}{IMG},
2835             $left, $top, $src_left, $src_top,
2836             $mask_left, $mask_top, $width, $height,
2837             $combine, $opts{opacity})) {
2838 10         42 $self->_set_error(Imager->_error_as_msg);
2839 10         80 return;
2840             }
2841             }
2842             else {
2843 25 100       8336 unless (i_compose($self->{IMG}, $src->{IMG}, $left, $top, $src_left, $src_top,
2844             $width, $height, $combine, $opts{opacity})) {
2845 10         35 $self->_set_error(Imager->_error_as_msg);
2846 10         88 return;
2847             }
2848             }
2849              
2850 35         293 return $self;
2851             }
2852              
2853             sub flip {
2854 144     144 0 857 my $self = shift;
2855 144         255 my %opts = @_;
2856              
2857 144 100       190 $self->_valid_image("flip")
2858             or return;
2859              
2860 143         326 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
2861 143         135 my $dir;
2862 143 50 33     338 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
2863 143         157 $dir = $xlate{$opts{'dir'}};
2864 143 50       14023 return $self if i_flipxy($self->{IMG}, $dir);
2865 0         0 return ();
2866             }
2867              
2868             sub rotate {
2869 43     43 0 4444 my $self = shift;
2870 43         112 my %opts = @_;
2871              
2872 43 100       95 unless (defined wantarray) {
2873 1         4 my @caller = caller;
2874 1         8 warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
2875 1         18 return;
2876             }
2877              
2878 42 100       73 $self->_valid_image("rotate")
2879             or return;
2880              
2881 41 100 33     109 if (defined $opts{right}) {
    50          
2882 30         37 my $degrees = $opts{right};
2883 30 50       48 if ($degrees < 0) {
2884 0         0 $degrees += 360 * int(((-$degrees)+360)/360);
2885             }
2886 30         40 $degrees = $degrees % 360;
2887 30 100 100     89 if ($degrees == 0) {
    50 66        
2888 2         5 return $self->copy();
2889             }
2890             elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
2891 28         62 my $result = Imager->new();
2892 28 50       22948 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
2893 28         118 return $result;
2894             }
2895             else {
2896 0         0 $self->{ERRSTR} = $self->_error_as_msg();
2897 0         0 return undef;
2898             }
2899             }
2900             else {
2901 0         0 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
2902 0         0 return undef;
2903             }
2904             }
2905             elsif (defined $opts{radians} || defined $opts{degrees}) {
2906 11   33     47 my $amount = $opts{radians} || $opts{degrees} * 3.14159265358979 / 180;
2907              
2908 11         18 my $back = $opts{back};
2909 11         30 my $result = Imager->new;
2910 11 100       24 if ($back) {
2911 6         14 $back = _color($back);
2912 6 100       16 unless ($back) {
2913 1         5 $self->_set_error(Imager->errstr);
2914 1         4 return undef;
2915             }
2916              
2917 5         17163 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
2918             }
2919             else {
2920 5         8545 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
2921             }
2922 10 50       41 if ($result->{IMG}) {
2923 10         190 return $result;
2924             }
2925             else {
2926 0         0 $self->{ERRSTR} = $self->_error_as_msg();
2927 0         0 return undef;
2928             }
2929             }
2930             else {
2931 0         0 $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available";
2932 0         0 return undef;
2933             }
2934             }
2935              
2936             sub matrix_transform {
2937 5     5 0 1098 my $self = shift;
2938 5         14 my %opts = @_;
2939              
2940 5 100       13 $self->_valid_image("matrix_transform")
2941             or return;
2942              
2943 4 100       10 unless (defined wantarray) {
2944 1         3 my @caller = caller;
2945 1         10 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
2946 1         20 return;
2947             }
2948              
2949 3 50       6 if ($opts{matrix}) {
2950 3   33     14 my $xsize = $opts{xsize} || $self->getwidth;
2951 3   33     10 my $ysize = $opts{ysize} || $self->getheight;
2952              
2953 3         9 my $result = Imager->new;
2954 3 100       6 if ($opts{back}) {
2955             $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2956             $opts{matrix}, $opts{back})
2957 1 50       1210 or return undef;
2958             }
2959             else {
2960             $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2961             $opts{matrix})
2962 2 50       1499 or return undef;
2963             }
2964              
2965 3         16 return $result;
2966             }
2967             else {
2968 0         0 $self->{ERRSTR} = "matrix parameter required";
2969 0         0 return undef;
2970             }
2971             }
2972              
2973             # blame Leolo :)
2974             *yatf = \&matrix_transform;
2975              
2976             # These two are supported for legacy code only
2977              
2978             sub i_color_new {
2979 254     254 0 25311 return Imager::Color->new(@_);
2980             }
2981              
2982             sub i_color_set {
2983 0     0 0 0 return Imager::Color::set(@_);
2984             }
2985              
2986             # Draws a box between the specified corner points.
2987             sub box {
2988 983     983 0 15360 my $self=shift;
2989 983         1283 my $raw = $self->{IMG};
2990              
2991 983 100       1632 $self->_valid_image("box")
2992             or return;
2993              
2994 982         2279 my %opts = @_;
2995              
2996 982         1218 my ($xmin, $ymin, $xmax, $ymax);
2997 982 100       1503 if (exists $opts{'box'}) {
2998 567         954 $xmin = _min($opts{'box'}->[0],$opts{'box'}->[2]);
2999 567         948 $xmax = _max($opts{'box'}->[0],$opts{'box'}->[2]);
3000 567         722 $ymin = _min($opts{'box'}->[1],$opts{'box'}->[3]);
3001 567         744 $ymax = _max($opts{'box'}->[1],$opts{'box'}->[3]);
3002             }
3003             else {
3004 415 100       984 defined($xmin = $opts{xmin}) or $xmin = 0;
3005 415 100       1194 defined($xmax = $opts{xmax}) or $xmax = $self->getwidth()-1;
3006 415 100       827 defined($ymin = $opts{ymin}) or $ymin = 0;
3007 415 100       1016 defined($ymax = $opts{ymax}) or $ymax = $self->getheight()-1;
3008             }
3009              
3010 982 100       1555 if ($opts{filled}) {
    100          
3011 865         928 my $color = $opts{'color'};
3012              
3013 865 100       1134 if (defined $color) {
3014 863 100       2351 unless (_is_color_object($color)) {
3015 145         272 $color = _color($color);
3016 145 50       302 unless ($color) {
3017 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3018 0         0 return;
3019             }
3020             }
3021             }
3022             else {
3023 2         16 $color = i_color_new(255,255,255,255);
3024             }
3025              
3026 865 100       1829 if ($color->isa("Imager::Color")) {
3027 828         56115 i_box_filled($raw, $xmin, $ymin,$xmax, $ymax, $color);
3028             }
3029             else {
3030 37         2714 i_box_filledf($raw, $xmin, $ymin,$xmax, $ymax, $color);
3031             }
3032             }
3033             elsif ($opts{fill}) {
3034 113 100       339 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
3035             # assume it's a hash ref
3036 6         1514 require 'Imager/Fill.pm';
3037 6 50       11 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
  6         32  
3038 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3039 0         0 return undef;
3040             }
3041             }
3042 113         29766 i_box_cfill($raw, $xmin, $ymin, $xmax, $ymax, $opts{fill}{fill});
3043             }
3044             else {
3045 4         5 my $color = $opts{'color'};
3046 4 100       14 if (defined $color) {
3047 3 100       35 unless (_is_color_object($color)) {
3048 2         7 $color = _color($color);
3049 2 50       8 unless ($color) {
3050 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3051 0         0 return;
3052             }
3053             }
3054             }
3055             else {
3056 1         4 $color = i_color_new(255, 255, 255, 255);
3057             }
3058 4 50       10 unless ($color) {
3059 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3060 0         0 return;
3061             }
3062 4         302 i_box($raw, $xmin, $ymin, $xmax, $ymax, $color);
3063             }
3064              
3065 982         2976 return $self;
3066             }
3067              
3068             sub arc {
3069 258     258 0 939 my $self=shift;
3070              
3071 258 100       519 $self->_valid_image("arc")
3072             or return;
3073              
3074 257         494 my $dflcl= [ 255, 255, 255, 255];
3075 257         327 my $good = 1;
3076 257         566 my %opts=
3077             (
3078             color=>$dflcl,
3079             'r'=>_min($self->getwidth(),$self->getheight())/3,
3080             'x'=>$self->getwidth()/2,
3081             'y'=>$self->getheight()/2,
3082             'd1'=>0, 'd2'=>361,
3083             filled => 1,
3084             @_,
3085             );
3086 257 100       604 if ($opts{aa}) {
3087 133 100       305 if ($opts{fill}) {
    100          
3088 2 50       10 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
3089             # assume it's a hash ref
3090 2         10 require 'Imager/Fill.pm';
3091 2 50       3 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
  2         9  
3092 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3093 0         0 return;
3094             }
3095             }
3096 2 100 66     10 if ($opts{d1} == 0 && $opts{d2} == 361) {
3097             i_circle_aa_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
3098 1         462 $opts{fill}{fill});
3099             }
3100             else {
3101             i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
3102 1         763 $opts{'d2'}, $opts{fill}{fill});
3103             }
3104             }
3105             elsif ($opts{filled}) {
3106 33         73 my $color = _color($opts{'color'});
3107 33 50       75 unless ($color) {
3108 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3109 0         0 return;
3110             }
3111 33 100 100     128 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
      66        
3112 8         3388 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
3113             $color);
3114             }
3115             else {
3116             i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
3117 25         108881 $opts{'d1'}, $opts{'d2'}, $color);
3118             }
3119             }
3120             else {
3121 98         158 my $color = _color($opts{'color'});
3122 98 100       229 if ($opts{d2} - $opts{d1} >= 360) {
3123 25         4002 $good = i_circle_out_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, $color);
3124             }
3125             else {
3126 73         8363 $good = i_arc_out_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, $opts{'d1'}, $opts{'d2'}, $color);
3127             }
3128             }
3129             }
3130             else {
3131 124 100       204 if ($opts{fill}) {
3132 10 50       33 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
3133             # assume it's a hash ref
3134 10         850 require 'Imager/Fill.pm';
3135 10 100       13 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
  10         73  
3136 1         2 $self->{ERRSTR} = $Imager::ERRSTR;
3137 1         7 return;
3138             }
3139             }
3140             i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
3141 9         43434 $opts{'d2'}, $opts{fill}{fill});
3142             }
3143             else {
3144 114         311 my $color = _color($opts{'color'});
3145 114 50       264 unless ($color) {
3146 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3147 0         0 return;
3148             }
3149 114 100       251 if ($opts{filled}) {
3150             i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
3151 52         209590 $opts{'d1'}, $opts{'d2'}, $color);
3152             }
3153             else {
3154 62 100 100     155 if ($opts{d1} == 0 && $opts{d2} == 361) {
3155 13         1346 $good = i_circle_out($self->{IMG}, $opts{x}, $opts{y}, $opts{r}, $color);
3156             }
3157             else {
3158 49         4299 $good = i_arc_out($self->{IMG}, $opts{x}, $opts{y}, $opts{r}, $opts{d1}, $opts{d2}, $color);
3159             }
3160             }
3161             }
3162             }
3163 255 50       2741 unless ($good) {
3164 0         0 $self->_set_error($self->_error_as_msg);
3165 0         0 return;
3166             }
3167              
3168 255         2070 return $self;
3169             }
3170              
3171             # Draws a line from one point to the other
3172             # the endpoint is set if the endp parameter is set which it is by default.
3173             # to turn of the endpoint being set use endp=>0 when calling line.
3174              
3175             sub line {
3176 212     212 0 1919 my $self=shift;
3177 212         306 my $dflcl=i_color_new(0,0,0,0);
3178 212         890 my %opts=(color=>$dflcl,
3179             endp => 1,
3180             @_);
3181              
3182 212 100       407 $self->_valid_image("line")
3183             or return;
3184              
3185 211 50 33     523 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
  0         0  
  0         0  
3186 211 50 33     465 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
  0         0  
  0         0  
3187              
3188 211         287 my $color = _color($opts{'color'});
3189 211 50       301 unless ($color) {
3190 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3191 0         0 return;
3192             }
3193              
3194 211 100       369 $opts{antialias} = $opts{aa} if defined $opts{aa};
3195 211 100       298 if ($opts{antialias}) {
3196             i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
3197 146         4335 $color, $opts{endp});
3198             } else {
3199             i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
3200 65         525 $color, $opts{endp});
3201             }
3202 211         9759 return $self;
3203             }
3204              
3205             # Draws a line between an ordered set of points - It more or less just transforms this
3206             # into a list of lines.
3207              
3208             sub polyline {
3209 6     6 0 652 my $self=shift;
3210 6         6 my ($pt,$ls,@points);
3211 6         12 my $dflcl=i_color_new(0,0,0,0);
3212 6         30 my %opts=(color=>$dflcl,@_);
3213              
3214 6 100       16 $self->_valid_image("polyline")
3215             or return;
3216              
3217 5 100       13 if (exists($opts{points})) { @points=@{$opts{points}}; }
  1         1  
  1         3  
3218 5 50 66     27 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
      33        
3219 4         7 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
  269         298  
  4         15  
3220             }
3221              
3222             # print Dumper(\@points);
3223              
3224 5         15 my $color = _color($opts{'color'});
3225 5 50       22 unless ($color) {
3226 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3227 0         0 return;
3228             }
3229 5 100       13 $opts{antialias} = $opts{aa} if defined $opts{aa};
3230 5 100       10 if ($opts{antialias}) {
3231 2         4 for $pt(@points) {
3232 6 100       11 if (defined($ls)) {
3233 4         46 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1);
3234             }
3235 6         7 $ls=$pt;
3236             }
3237             } else {
3238 3         6 for $pt(@points) {
3239 266 100       303 if (defined($ls)) {
3240 263         785 i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1);
3241             }
3242 266         244 $ls=$pt;
3243             }
3244             }
3245 5         355 return $self;
3246             }
3247              
3248             sub polygon {
3249 11     11 0 6646 my $self = shift;
3250 11         17 my ($pt,$ls,@points);
3251 11         36 my $dflcl = i_color_new(0,0,0,0);
3252 11         52 my %opts = (color=>$dflcl, @_);
3253              
3254 11 100       53 $self->_valid_image("polygon")
3255             or return;
3256              
3257 10 100       25 if (exists($opts{points})) {
3258 8         11 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
  1044         989  
  8         50  
3259 8         25 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
  1044         928  
  8         16  
3260             }
3261              
3262 10 50 33     63 if (!exists $opts{'x'} or !exists $opts{'y'}) {
3263 0         0 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
  0         0  
3264             }
3265              
3266 10         37 my $mode = _first($opts{mode}, 0);
3267              
3268 10 100       31 if ($opts{'fill'}) {
3269 4 100       17 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
3270             # assume it's a hash ref
3271 3         842 require 'Imager/Fill.pm';
3272 3 50       4 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
  3         21  
3273 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3274 0         0 return undef;
3275             }
3276             }
3277 4 100       7080 unless (i_poly_aa_cfill_m($self->{IMG}, $opts{'x'}, $opts{'y'},
3278             $mode, $opts{'fill'}{'fill'})) {
3279 1         4 return $self->_set_error($self->_error_as_msg);
3280             }
3281             }
3282             else {
3283 6         16 my $color = _color($opts{'color'});
3284 6 50       15 unless ($color) {
3285 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3286 0         0 return;
3287             }
3288 6 100       8740 unless (i_poly_aa_m($self->{IMG}, $opts{'x'}, $opts{'y'}, $mode, $color)) {
3289 1         6 return $self->_set_error($self->_error_as_msg);
3290             }
3291             }
3292              
3293 8         489 return $self;
3294             }
3295              
3296             sub polypolygon {
3297 6     6 0 81 my ($self, %opts) = @_;
3298              
3299 6 50       16 $self->_valid_image("polypolygon")
3300             or return;
3301              
3302 6         9 my $points = $opts{points};
3303 6 50       14 $points
3304             or return $self->_set_error("polypolygon: missing required points");
3305              
3306 6         17 my $mode = _first($opts{mode}, "evenodd");
3307              
3308 6 50       15 if ($opts{filled}) {
    0          
3309 6 50       19 my $color = _color(_first($opts{color}, [ 0, 0, 0, 0 ]))
3310             or return $self->_set_error($Imager::ERRSTR);
3311              
3312 6 50       5972 i_poly_poly_aa($self->{IMG}, $points, $mode, $color)
3313             or return $self->_set_error($self->_error_as_msg);
3314             }
3315             elsif ($opts{fill}) {
3316 0         0 my $fill = $opts{fill};
3317 0 0       0 $self->_valid_fill($fill, "polypolygon")
3318             or return;
3319              
3320             i_poly_poly_aa_cfill($self->{IMG}, $points, $mode, $fill->{fill})
3321 0 0       0 or return $self->_set_error($self->_error_as_msg);
3322             }
3323             else {
3324 0 0       0 my $color = _color(_first($opts{color}, [ 0, 0, 0, 255 ]))
3325             or return $self->_set_error($Imager::ERRSTR);
3326              
3327 0         0 my $rimg = $self->{IMG};
3328              
3329 0 0       0 if (_first($opts{aa}, 1)) {
3330 0         0 for my $poly (@$points) {
3331 0         0 my $xp = $poly->[0];
3332 0         0 my $yp = $poly->[1];
3333 0         0 for my $i (0 .. $#$xp - 1) {
3334 0         0 i_line_aa($rimg, $xp->[$i], $yp->[$i], $xp->[$i+1], $yp->[$i+1],
3335             $color, 0);
3336             }
3337 0         0 i_line_aa($rimg, $xp->[$#$xp], $yp->[$#$yp], $xp->[0], $yp->[0],
3338             $color, 0);
3339             }
3340             }
3341             else {
3342 0         0 for my $poly (@$points) {
3343 0         0 my $xp = $poly->[0];
3344 0         0 my $yp = $poly->[1];
3345 0         0 for my $i (0 .. $#$xp - 1) {
3346 0         0 i_line($rimg, $xp->[$i], $yp->[$i], $xp->[$i+1], $yp->[$i+1],
3347             $color, 0);
3348             }
3349 0         0 i_line($rimg, $xp->[$#$xp], $yp->[$#$yp], $xp->[0], $yp->[0],
3350             $color, 0);
3351             }
3352             }
3353             }
3354              
3355 6         58 return $self;
3356             }
3357              
3358             # this the multipoint bezier curve
3359             # this is here more for testing that actual usage since
3360             # this is not a good algorithm. Usually the curve would be
3361             # broken into smaller segments and each done individually.
3362              
3363             sub polybezier {
3364 0     0 0 0 my $self=shift;
3365 0         0 my ($pt,$ls,@points);
3366 0         0 my $dflcl=i_color_new(0,0,0,0);
3367 0         0 my %opts=(color=>$dflcl,@_);
3368              
3369 0 0       0 $self->_valid_image("polybezier")
3370             or return;
3371              
3372 0 0       0 if (exists $opts{points}) {
3373 0         0 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
  0         0  
  0         0  
3374 0         0 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
  0         0  
  0         0  
3375             }
3376              
3377 0 0 0     0 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
  0         0  
  0         0  
  0         0  
3378 0         0 $self->{ERRSTR}='Missing or invalid points.';
3379 0         0 return;
3380             }
3381              
3382 0         0 my $color = _color($opts{'color'});
3383 0 0       0 unless ($color) {
3384 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3385 0         0 return;
3386             }
3387 0         0 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
3388 0         0 return $self;
3389             }
3390              
3391             sub flood_fill {
3392 90     90 0 516 my $self = shift;
3393 90         235 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
3394 90         287 my $rc;
3395              
3396 90 100       125 $self->_valid_image("flood_fill")
3397             or return;
3398              
3399 89 50 33     266 unless (exists $opts{'x'} && exists $opts{'y'}) {
3400 0         0 $self->{ERRSTR} = "missing seed x and y parameters";
3401 0         0 return undef;
3402             }
3403              
3404 89 100       130 if ($opts{border}) {
3405 2         10 my $border = _color($opts{border});
3406 2 50       10 unless ($border) {
3407 0         0 $self->_set_error($Imager::ERRSTR);
3408 0         0 return;
3409             }
3410 2 100       8 if ($opts{fill}) {
3411 1 50       9 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
3412             # assume it's a hash ref
3413 1         13 require Imager::Fill;
3414 1 50       2 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
  1         15  
3415 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3416 0         0 return;
3417             }
3418             }
3419             $rc = i_flood_cfill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
3420 1         13134 $opts{fill}{fill}, $border);
3421             }
3422             else {
3423 1         3 my $color = _color($opts{'color'});
3424 1 50       2 unless ($color) {
3425 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3426 0         0 return;
3427             }
3428 1         13003 $rc = i_flood_fill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
3429             $color, $border);
3430             }
3431 2 50       18 if ($rc) {
3432 2         369 return $self;
3433             }
3434             else {
3435 0         0 $self->{ERRSTR} = $self->_error_as_msg();
3436 0         0 return;
3437             }
3438             }
3439             else {
3440 87 100       104 if ($opts{fill}) {
3441 1 50       7 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
3442             # assume it's a hash ref
3443 1         13 require 'Imager/Fill.pm';
3444 1 50       3 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
  1         11  
3445 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3446 0         0 return;
3447             }
3448             }
3449 1         12857 $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
3450             }
3451             else {
3452 86         164 my $color = _color($opts{'color'});
3453 86 50       143 unless ($color) {
3454 0         0 $self->{ERRSTR} = $Imager::ERRSTR;
3455 0         0 return;
3456             }
3457 86         15271 $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
3458             }
3459 87 50       152 if ($rc) {
3460 87         442 return $self;
3461             }
3462             else {
3463 0         0 $self->{ERRSTR} = $self->_error_as_msg();
3464 0         0 return;
3465             }
3466             }
3467             }
3468              
3469             sub setpixel {
3470 128     128 0 1010 my ($self, %opts) = @_;
3471              
3472 128 100       320 $self->_valid_image("setpixel")
3473             or return;
3474              
3475 127         228 my $color = $opts{color};
3476 127 100       245 unless (defined $color) {
3477 1         4 $color = $self->{fg};
3478 1 50       9 defined $color or $color = NC(255, 255, 255);
3479             }
3480              
3481 127 100 100     570 unless (ref $color && UNIVERSAL::isa($color, "Imager::Color")) {
3482 84 100       176 unless ($color = _color($color, 'setpixel')) {
3483 1         5 $self->_set_error("setpixel: " . Imager->errstr);
3484 1         7 return;
3485             }
3486             }
3487              
3488 126 100 100     493 unless (exists $opts{'x'} && exists $opts{'y'}) {
3489 2         9 $self->_set_error('setpixel: missing x or y parameter');
3490 2         14 return;
3491             }
3492              
3493 124         175 my $x = $opts{'x'};
3494 124         177 my $y = $opts{'y'};
3495 124 100 100     393 if (ref $x || ref $y) {
3496 9 100       31 $x = ref $x ? $x : [ $x ];
3497 9 100       24 $y = ref $y ? $y : [ $y ];
3498 9 100       20 unless (@$x) {
3499 1         4 $self->_set_error("setpixel: x is a reference to an empty array");
3500 1         6 return;
3501             }
3502 8 100       19 unless (@$y) {
3503 1         3 $self->_set_error("setpixel: y is a reference to an empty array");
3504 1         5 return;
3505             }
3506              
3507             # make both the same length, replicating the last element
3508 7 100       22 if (@$x < @$y) {
    100          
3509 1         7 $x = [ @$x, ($x->[-1]) x (@$y - @$x) ];
3510             }
3511             elsif (@$y < @$x) {
3512 1         6 $y = [ @$y, ($y->[-1]) x (@$x - @$y) ];
3513             }
3514              
3515 7         12 my $set = 0;
3516 7 100       27 if ($color->isa('Imager::Color')) {
3517 5         17 for my $i (0..$#$x) {
3518 17 100       67 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color)
3519             or ++$set;
3520             }
3521             }
3522             else {
3523 2         9 for my $i (0..$#$x) {
3524 8 100       31 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color)
3525             or ++$set;
3526             }
3527             }
3528              
3529 7         104 return $set;
3530             }
3531             else {
3532 115 100       367 if ($color->isa('Imager::Color')) {
3533 84 100       476 i_ppix($self->{IMG}, $x, $y, $color)
3534             and return "0 but true";
3535             }
3536             else {
3537 31 100       246 i_ppixf($self->{IMG}, $x, $y, $color)
3538             and return "0 but true";
3539             }
3540              
3541 79         2326 return 1;
3542             }
3543             }
3544              
3545             sub getpixel {
3546 239     239 0 5265 my $self = shift;
3547              
3548 239         979 my %opts = ( "type"=>'8bit', @_);
3549              
3550 239 100       582 $self->_valid_image("getpixel")
3551             or return;
3552              
3553 238 100 100     841 unless (exists $opts{'x'} && exists $opts{'y'}) {
3554 2         9 $self->_set_error('getpixel: missing x or y parameter');
3555 2         13 return;
3556             }
3557              
3558 236         358 my $x = $opts{'x'};
3559 236         331 my $y = $opts{'y'};
3560 236         317 my $type = $opts{'type'};
3561 236 100 100     736 if (ref $x || ref $y) {
3562 19 100       45 $x = ref $x ? $x : [ $x ];
3563 19 100       40 $y = ref $y ? $y : [ $y ];
3564 19 100       43 unless (@$x) {
3565 1         4 $self->_set_error("getpixel: x is a reference to an empty array");
3566 1         6 return;
3567             }
3568 18 100       49 unless (@$y) {
3569 1         4 $self->_set_error("getpixel: y is a reference to an empty array");
3570 1         6 return;
3571             }
3572              
3573             # make both the same length, replicating the last element
3574 17 100       62 if (@$x < @$y) {
    100          
3575 1         6 $x = [ @$x, ($x->[-1]) x (@$y - @$x) ];
3576             }
3577             elsif (@$y < @$x) {
3578 3         16 $y = [ @$y, ($y->[-1]) x (@$x - @$y) ];
3579             }
3580              
3581 17         26 my @result;
3582 17 100 66     54 if ($type eq '8bit') {
    100          
3583 13         43 for my $i (0..$#$x) {
3584 40         1773 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
3585             }
3586             }
3587             elsif ($type eq 'float' || $type eq 'double') {
3588 3         12 for my $i (0..$#$x) {
3589 10         376 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
3590             }
3591             }
3592             else {
3593 1         4 $self->_set_error("getpixel: type must be '8bit' or 'float'");
3594 1         6 return;
3595             }
3596 16 50       217 return wantarray ? @result : \@result;
3597             }
3598             else {
3599 217 100 100     537 if ($type eq '8bit') {
    100          
3600 195         9876 return i_get_pixel($self->{IMG}, $x, $y);
3601             }
3602             elsif ($type eq 'float' || $type eq 'double') {
3603 21         1461 return i_gpixf($self->{IMG}, $x, $y);
3604             }
3605             else {
3606 1         5 $self->_set_error("getpixel: type must be '8bit' or 'float'");
3607 1         6 return;
3608             }
3609             }
3610             }
3611              
3612             sub getscanline {
3613 39     39 0 3821 my $self = shift;
3614 39         192 my %opts = ( type => '8bit', x=>0, @_);
3615              
3616 39 100       104 $self->_valid_image("getscanline")
3617             or return;
3618              
3619 38 100       134 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
3620              
3621 38 100       128 unless (defined $opts{'y'}) {
3622 1         5 $self->_set_error("missing y parameter");
3623 1         4 return;
3624             }
3625              
3626 37 100       124 if ($opts{type} eq '8bit') {
    100          
    100          
3627             return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3628 16         3907 $opts{'y'});
3629             }
3630             elsif ($opts{type} eq 'float') {
3631             return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3632 12         2512 $opts{'y'});
3633             }
3634             elsif ($opts{type} eq 'index') {
3635 8 50       31 unless (i_img_type($self->{IMG})) {
3636 0         0 $self->_set_error("type => index only valid on paletted images");
3637 0         0 return;
3638             }
3639             return i_gpal($self->{IMG}, $opts{x}, $opts{x} + $opts{width},
3640 8         832 $opts{'y'});
3641             }
3642             else {
3643 1         3 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3644 1         4 return;
3645             }
3646             }
3647              
3648             sub setscanline {
3649 215     215 0 6797 my $self = shift;
3650 215         586 my %opts = ( x=>0, @_);
3651              
3652 215 100       326 $self->_valid_image("setscanline")
3653             or return;
3654              
3655 214 50       359 unless (defined $opts{'y'}) {
3656 0         0 $self->_set_error("missing y parameter");
3657 0         0 return;
3658             }
3659              
3660 214 100       372 if (!$opts{type}) {
3661 200 100 66     329 if (ref $opts{pixels} && @{$opts{pixels}}) {
  49         123  
3662             # try to guess the type
3663 49 100       255 if ($opts{pixels}[0]->isa('Imager::Color')) {
    50          
3664 32         81 $opts{type} = '8bit';
3665             }
3666             elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
3667 17         44 $opts{type} = 'float';
3668             }
3669             else {
3670 0         0 $self->_set_error("missing type parameter and could not guess from pixels");
3671 0         0 return;
3672             }
3673             }
3674             else {
3675             # default
3676 151         181 $opts{type} = '8bit';
3677             }
3678             }
3679              
3680 214 100       422 if ($opts{type} eq '8bit') {
    100          
    50          
3681 183 100       244 if (ref $opts{pixels}) {
3682 32         60 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
  32         2437  
3683             }
3684             else {
3685 151         784 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3686             }
3687             }
3688             elsif ($opts{type} eq 'float') {
3689 18 100       33 if (ref $opts{pixels}) {
3690 17         36 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
  17         1531  
3691             }
3692             else {
3693 1         8 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3694             }
3695             }
3696             elsif ($opts{type} eq 'index') {
3697 13 100       24 if (ref $opts{pixels}) {
3698 9         18 return i_ppal($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
  9         119  
3699             }
3700             else {
3701 4         45 return i_ppal_p($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3702             }
3703             }
3704             else {
3705 0         0 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3706 0         0 return;
3707             }
3708             }
3709              
3710             sub getsamples {
3711 313     313 0 8181 my $self = shift;
3712 313         785 my %opts = ( type => '8bit', x=>0, offset => 0, @_);
3713              
3714 313 100       448 $self->_valid_image("getsamples")
3715             or return;
3716              
3717 312 100       674 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
3718              
3719 312 50       496 unless (defined $opts{'y'}) {
3720 0         0 $self->_set_error("missing y parameter");
3721 0         0 return;
3722             }
3723            
3724 312 100       425 if ($opts{target}) {
3725 3         7 my $target = $opts{target};
3726 3         4 my $offset = $opts{offset};
3727 3 100       21 if ($opts{type} eq '8bit') {
    100          
    50          
3728             my @samples = i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3729             $opts{y}, $opts{channels})
3730 1 50       114 or return;
3731 1         6 @{$target}[$offset .. $offset + @samples - 1] = @samples;
  1         6  
3732 1         9 return scalar(@samples);
3733             }
3734             elsif ($opts{type} eq 'float') {
3735             my @samples = i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3736 1         111 $opts{y}, $opts{channels});
3737 1         7 @{$target}[$offset .. $offset + @samples - 1] = @samples;
  1         6  
3738 1         10 return scalar(@samples);
3739             }
3740             elsif ($opts{type} =~ /^(\d+)bit$/) {
3741 1         2 my $bits = $1;
3742              
3743 1         2 my @data;
3744             my $count = i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3745             $opts{y}, $bits, $target,
3746 1         121 $offset, $opts{channels});
3747 1 50       6 unless (defined $count) {
3748 0         0 $self->_set_error(Imager->_error_as_msg);
3749 0         0 return;
3750             }
3751              
3752 1         6 return $count;
3753             }
3754             else {
3755 0         0 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3756 0         0 return;
3757             }
3758             }
3759             else {
3760 309 100       481 if ($opts{type} eq '8bit') {
    50          
    0          
3761             return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3762 297         15458 $opts{y}, $opts{channels});
3763             }
3764             elsif ($opts{type} eq 'float') {
3765             return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3766 12         1629 $opts{y}, $opts{channels});
3767             }
3768             elsif ($opts{type} =~ /^(\d+)bit$/) {
3769 0         0 my $bits = $1;
3770              
3771 0         0 my @data;
3772             i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3773             $opts{y}, $bits, \@data, 0, $opts{channels})
3774 0 0       0 or return;
3775 0         0 return @data;
3776             }
3777             else {
3778 0         0 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3779 0         0 return;
3780             }
3781             }
3782             }
3783              
3784             sub setsamples {
3785 15     15 0 115 my $self = shift;
3786              
3787 15 100       45 $self->_valid_image("setsamples")
3788             or return;
3789              
3790 14         75 my %opts = ( x => 0, offset => 0 );
3791 14         22 my $data_index;
3792             # avoid duplicating the data parameter, it may be a large scalar
3793 14         24 my $i = 0;
3794 14         39 while ($i < @_ -1) {
3795 48 100       97 if ($_[$i] eq 'data') {
3796 13         25 $data_index = $i+1;
3797             }
3798             else {
3799 35         75 $opts{$_[$i]} = $_[$i+1];
3800             }
3801              
3802 48         120 $i += 2;
3803             }
3804              
3805 14 100       32 unless(defined $data_index) {
3806 1         6 $self->_set_error('setsamples: data parameter missing');
3807 1         6 return;
3808             }
3809 13 100       30 unless (defined $_[$data_index]) {
3810 1         6 $self->_set_error('setsamples: data parameter not defined');
3811 1         6 return;
3812             }
3813              
3814 12         21 my $type = $opts{type};
3815 12 100       56 defined $type or $type = '8bit';
3816              
3817             my $width = defined $opts{width} ? $opts{width}
3818 12 50       48 : $self->getwidth() - $opts{x};
3819              
3820 12         17 my $count;
3821 12 100       49 if ($type eq '8bit') {
    100          
    100          
3822             $count = i_psamp($self->{IMG}, $opts{x}, $opts{y}, $opts{channels},
3823 5         45 $_[$data_index], $opts{offset}, $width);
3824             }
3825             elsif ($type eq 'float') {
3826             $count = i_psampf($self->{IMG}, $opts{x}, $opts{y}, $opts{channels},
3827 5         52 $_[$data_index], $opts{offset}, $width);
3828             }
3829             elsif ($type =~ /^([0-9]+)bit$/) {
3830 1         2 my $bits = $1;
3831              
3832 1 50       3 unless (ref $_[$data_index]) {
3833 0         0 $self->_set_error("setsamples: data must be an array ref for type not 8bit or float");
3834 0         0 return;
3835             }
3836              
3837             $count = i_psamp_bits($self->{IMG}, $opts{x}, $opts{y}, $bits,
3838             $opts{channels}, $_[$data_index], $opts{offset},
3839 1         73 $width);
3840             }
3841             else {
3842 1         4 $self->_set_error('setsamples: type parameter invalid');
3843 1         8 return;
3844             }
3845              
3846 11 100       36 unless (defined $count) {
3847 4         17 $self->_set_error(Imager->_error_as_msg);
3848 4         33 return;
3849             }
3850              
3851 7         41 return $count;
3852             }
3853              
3854             # make an identity matrix of the given size
3855             sub _identity {
3856 2     2   5 my ($size) = @_;
3857              
3858 2         7 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
  8         20  
3859 2         9 for my $c (0 .. ($size-1)) {
3860 8         11 $matrix->[$c][$c] = 1;
3861             }
3862 2         5 return $matrix;
3863             }
3864              
3865             # general function to convert an image
3866             sub convert {
3867 18     18 0 112 my ($self, %opts) = @_;
3868 18         23 my $matrix;
3869              
3870 18 100       47 $self->_valid_image("convert")
3871             or return;
3872              
3873 17 100       40 unless (defined wantarray) {
3874 1         4 my @caller = caller;
3875 1         12 warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
3876 1         35 return;
3877             }
3878              
3879             # the user can either specify a matrix or preset
3880             # the matrix overrides the preset
3881 16 100       82 if (!exists($opts{matrix})) {
3882 14 50       31 unless (exists($opts{preset})) {
3883 0         0 $self->{ERRSTR} = "convert() needs a matrix or preset";
3884 0         0 return;
3885             }
3886             else {
3887 14 100 100     175 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
    100 33        
    50 33        
    50 66        
    100          
    50          
    100          
    50          
3888             # convert to greyscale, keeping the alpha channel if any
3889 3 50       14 if ($self->getchannels == 3) {
    0          
3890 3         9 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
3891             }
3892             elsif ($self->getchannels == 4) {
3893             # preserve the alpha channel
3894 0         0 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
3895             [ 0, 0, 0, 1 ] ];
3896             }
3897             else {
3898             # an identity
3899 0         0 $matrix = _identity($self->getchannels);
3900             }
3901             }
3902             elsif ($opts{preset} eq 'noalpha') {
3903             # strip the alpha channel
3904 1 50 33     3 if ($self->getchannels == 2 or $self->getchannels == 4) {
3905 1         1 $matrix = _identity($self->getchannels);
3906 1         2 pop(@$matrix); # lose the alpha entry
3907             }
3908             else {
3909 0         0 $matrix = _identity($self->getchannels);
3910             }
3911             }
3912             elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
3913             # extract channel 0
3914 0         0 $matrix = [ [ 1 ] ];
3915             }
3916             elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
3917 0         0 $matrix = [ [ 0, 1 ] ];
3918             }
3919             elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
3920 3         11 $matrix = [ [ 0, 0, 1 ] ];
3921             }
3922             elsif ($opts{preset} eq 'alpha') {
3923 0 0 0     0 if ($self->getchannels == 2 or $self->getchannels == 4) {
3924 0         0 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
3925             }
3926             else {
3927             # the alpha is just 1
3928 0         0 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
3929             }
3930             }
3931             elsif ($opts{preset} eq 'rgb') {
3932 6 50       32 if ($self->getchannels == 1) {
    0          
3933 6         14 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
3934             }
3935             elsif ($self->getchannels == 2) {
3936             # preserve the alpha channel
3937 0         0 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
3938             }
3939             else {
3940 0         0 $matrix = _identity($self->getchannels);
3941             }
3942             }
3943             elsif ($opts{preset} eq 'addalpha') {
3944 1 50       5 if ($self->getchannels == 1) {
    50          
3945 0         0 $matrix = _identity(2);
3946             }
3947             elsif ($self->getchannels == 3) {
3948 1         3 $matrix = _identity(4);
3949             }
3950             else {
3951 0         0 $matrix = _identity($self->getchannels);
3952             }
3953             }
3954             else {
3955 0         0 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
3956 0         0 return undef;
3957             }
3958             }
3959             }
3960             else {
3961 2         3 $matrix = $opts{matrix};
3962             }
3963              
3964 16         49 my $new = Imager->new;
3965 16         6798 $new->{IMG} = i_convert($self->{IMG}, $matrix);
3966 16 100       61 unless ($new->{IMG}) {
3967             # most likely a bad matrix
3968 1         25 i_push_error(0, "convert");
3969 1         5 $self->{ERRSTR} = _error_as_msg();
3970 1         4 return undef;
3971             }
3972 15         72 return $new;
3973             }
3974              
3975             # combine channels from multiple input images, a class method
3976             sub combine {
3977 14     14 0 4497 my ($class, %opts) = @_;
3978              
3979 14         32 my $src = delete $opts{src};
3980 14 100       43 unless ($src) {
3981 1         7 $class->_set_error("src parameter missing");
3982 1         5 return;
3983             }
3984 13         21 my @imgs;
3985 13         19 my $index = 0;
3986 13         28 for my $img (@$src) {
3987 21 100       39 unless (eval { $img->isa("Imager") }) {
  21         97  
3988 1         4 $class->_set_error("src must contain image objects");
3989 1         5 return;
3990             }
3991 20 100       51 unless ($img->_valid_image("combine")) {
3992 1         4 $Imager::ERRSTR = $img->{ERRSTR} . " (src->[$index])";
3993 1         7 return;
3994             }
3995 19         41 push @imgs, $img->{IMG};
3996             }
3997 11         18 my $result;
3998 11 100       27 if (my $channels = delete $opts{channels}) {
3999 4         1075 $result = i_combine(\@imgs, $channels);
4000             }
4001             else {
4002 7         5259 $result = i_combine(\@imgs);
4003             }
4004 11 100       39 unless ($result) {
4005 4         15 $class->_set_error($class->_error_as_msg);
4006 4         45 return;
4007             }
4008              
4009 7         23 my $img = $class->new;
4010 7         12 $img->{IMG} = $result;
4011              
4012 7         20 return $img;
4013             }
4014              
4015              
4016             # general function to map an image through lookup tables
4017              
4018             sub map {
4019 6     6 0 118 my ($self, %opts) = @_;
4020 6         29 my @chlist = qw( red green blue alpha );
4021              
4022 6 100       16 $self->_valid_image("map")
4023             or return;
4024              
4025 5 100       12 if (!exists($opts{'maps'})) {
4026             # make maps from channel maps
4027 1         1 my $chnum;
4028 1         4 for $chnum (0..$#chlist) {
4029 4 100       10 if (exists $opts{$chlist[$chnum]}) {
    50          
4030 3         5 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
4031             } elsif (exists $opts{'all'}) {
4032 0         0 $opts{'maps'}[$chnum] = $opts{'all'};
4033             }
4034             }
4035             }
4036 5 50 33     16 if ($opts{'maps'} and $self->{IMG}) {
4037 5         2535 i_map($self->{IMG}, $opts{'maps'} );
4038             }
4039 5         33 return $self;
4040             }
4041              
4042             sub difference {
4043 7     7 0 614 my ($self, %opts) = @_;
4044              
4045 7 100       19 $self->_valid_image("difference")
4046             or return;
4047              
4048 6 100       19 defined $opts{mindist} or $opts{mindist} = 0;
4049              
4050             defined $opts{other}
4051 6 50       12 or return $self->_set_error("No 'other' parameter supplied");
4052 6 100       13 unless ($opts{other}->_valid_image("difference")) {
4053 1         3 $self->_set_error($opts{other}->errstr . " (other image)");
4054 1         5 return;
4055             }
4056              
4057 5         15 my $result = Imager->new;
4058             $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
4059             $opts{mindist})
4060 5 50       2354 or return $self->_set_error($self->_error_as_msg());
4061              
4062 5         22 return $result;
4063             }
4064              
4065             sub rgb_difference {
4066 1     1 0 6 my ($self, %opts) = @_;
4067              
4068 1 50       4 $self->_valid_image("rgb_difference")
4069             or return;
4070              
4071             defined $opts{other}
4072 1 50       3 or return $self->_set_error("No 'other' parameter supplied");
4073 1 50       3 unless ($opts{other}->_valid_image("rgb_difference")) {
4074 0         0 $self->_set_error($opts{other}->errstr . " (other image)");
4075 0         0 return;
4076             }
4077              
4078 1         3 my $result = Imager->new;
4079             $result->{IMG} = i_rgbdiff_image($self->{IMG}, $opts{other}{IMG})
4080 1 50       179 or return $self->_set_error($self->_error_as_msg());
4081              
4082 1         3 return $result;
4083             }
4084              
4085             # destructive border - image is shrunk by one pixel all around
4086              
4087             sub border {
4088 0     0 0 0 my ($self,%opts)=@_;
4089 0         0 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
4090 0         0 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
4091             }
4092              
4093              
4094             # Get the width of an image
4095              
4096             sub getwidth {
4097 2057     2057 0 22097 my $self = shift;
4098              
4099 2057 100       2874 $self->_valid_image("getwidth")
4100             or return;
4101              
4102 2056         6804 return i_img_get_width($self->{IMG});
4103             }
4104              
4105             # Get the height of an image
4106              
4107             sub getheight {
4108 1754     1754 0 2554 my $self = shift;
4109              
4110 1754 100       2351 $self->_valid_image("getheight")
4111             or return;
4112              
4113 1753         5822 return i_img_get_height($self->{IMG});
4114             }
4115              
4116             # Get number of channels in an image
4117              
4118             sub getchannels {
4119 653     653 0 2966 my $self = shift;
4120              
4121 653 100       875 $self->_valid_image("getchannels")
4122             or return;
4123              
4124 652         1844 return i_img_getchannels($self->{IMG});
4125             }
4126              
4127             my @model_names = qw(unknown gray graya rgb rgba);
4128              
4129             sub colormodel {
4130 7     7 0 1364 my ($self, %opts) = @_;
4131              
4132 7 100       25 $self->_valid_image("colormodel")
4133             or return;
4134              
4135 6         33 my $model = i_img_color_model($self->{IMG});
4136              
4137 6 100       49 return $opts{numeric} ? $model : $model_names[$model];
4138             }
4139              
4140             sub colorchannels {
4141 6     6 0 522 my ($self) = @_;
4142              
4143 6 100       20 $self->_valid_image("colorchannels")
4144             or return;
4145              
4146 5         37 return i_img_color_channels($self->{IMG});
4147             }
4148              
4149             sub alphachannel {
4150 6     6 0 18 my ($self) = @_;
4151              
4152 6 100       17 $self->_valid_image("alphachannel")
4153             or return;
4154              
4155 5         41 return scalar(i_img_alpha_channel($self->{IMG}));
4156             }
4157              
4158             # Get channel mask
4159              
4160             sub getmask {
4161 2     2 0 5 my $self = shift;
4162              
4163 2 100       5 $self->_valid_image("getmask")
4164             or return;
4165              
4166 1         7 return i_img_getmask($self->{IMG});
4167             }
4168              
4169             # Set channel mask
4170              
4171             sub setmask {
4172 28     28 0 3974 my $self = shift;
4173 28         89 my %opts = @_;
4174              
4175 28 50       2582 warnings::warnif("Imager::channelmask", "setmask: image channel masks are deprecated")
4176             if $] >= 5.014;
4177              
4178 28 100       110 $self->_valid_image("setmask")
4179             or return;
4180              
4181 27 50       64 unless (defined $opts{mask}) {
4182 0         0 $self->_set_error("mask parameter required");
4183 0         0 return;
4184             }
4185              
4186 27         124 i_img_setmask( $self->{IMG} , $opts{mask} );
4187              
4188 27         122 1;
4189             }
4190              
4191             # Get number of colors in an image
4192              
4193             sub getcolorcount {
4194 10     10 0 58 my $self=shift;
4195 10         45 my %opts=('maxcolors'=>2**30,@_);
4196              
4197 10 100       39 $self->_valid_image("getcolorcount")
4198             or return;
4199              
4200 9         65490 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
4201 9 100       171 return ($rc==-1? undef : $rc);
4202             }
4203              
4204             # Returns a reference to a hash. The keys are colour named (packed) and the
4205             # values are the number of pixels in this colour.
4206             sub getcolorusagehash {
4207 4     4 0 1159 my $self = shift;
4208              
4209 4 100       12 $self->_valid_image("getcolorusagehash")
4210             or return;
4211              
4212 3         8 my %opts = ( maxcolors => 2**30, @_ );
4213 3         5 my $max_colors = $opts{maxcolors};
4214 3 50 33     12 unless (defined $max_colors && $max_colors > 0) {
4215 0         0 $self->_set_error('maxcolors must be a positive integer');
4216 0         0 return;
4217             }
4218              
4219 3         8 my $channels= $self->getchannels;
4220             # We don't want to look at the alpha channel, because some gifs using it
4221             # doesn't define it for every colour (but only for some)
4222 3 50 33     12 $channels -= 1 if $channels == 2 or $channels == 4;
4223 3         50 my %color_use;
4224 3         8 my $height = $self->getheight;
4225 3         7 for my $y (0 .. $height - 1) {
4226 126         264 my $colors = $self->getsamples('y' => $y, channels => [ 0 .. $channels - 1 ]);
4227 126         282 while (length $colors) {
4228 6300         7206 $color_use{ substr($colors, 0, $channels, '') }++;
4229             }
4230 126 100       235 keys %color_use > $max_colors
4231             and return;
4232             }
4233 2         10 return \%color_use;
4234             }
4235              
4236             # This will return a ordered array of the colour usage. Kind of the sorted
4237             # version of the values of the hash returned by getcolorusagehash.
4238             # You might want to add safety checks and change the names, etc...
4239             sub getcolorusage {
4240 6     6 0 3609 my $self = shift;
4241              
4242 6 100       19 $self->_valid_image("getcolorusage")
4243             or return;
4244              
4245 5         20 my %opts = ( maxcolors => 2**30, @_ );
4246 5         10 my $max_colors = $opts{maxcolors};
4247 5 50 33     27 unless (defined $max_colors && $max_colors > 0) {
4248 0         0 $self->_set_error('maxcolors must be a positive integer');
4249 0         0 return;
4250             }
4251              
4252 5         6530 return i_get_anonymous_color_histo($self->{IMG}, $max_colors);
4253             }
4254              
4255             # draw string to an image
4256              
4257             sub string {
4258 1     1 0 8 my $self = shift;
4259              
4260 1 50       5 $self->_valid_image("string")
4261             or return;
4262              
4263 0         0 my %input=('x'=>0, 'y'=>0, @_);
4264 0 0       0 defined($input{string}) or $input{string} = $input{text};
4265              
4266 0 0       0 unless(defined $input{string}) {
4267 0         0 $self->{ERRSTR}="missing required parameter 'string'";
4268 0         0 return;
4269             }
4270              
4271 0 0       0 unless($input{font}) {
4272 0         0 $self->{ERRSTR}="missing required parameter 'font'";
4273 0         0 return;
4274             }
4275              
4276 0 0       0 unless ($input{font}->draw(image=>$self, %input)) {
4277 0         0 return;
4278             }
4279              
4280 0         0 return $self;
4281             }
4282              
4283             sub align_string {
4284 1     1 0 3 my $self = shift;
4285              
4286 1         2 my $img;
4287 1 50       4 if (ref $self) {
4288 1 50       4 $self->_valid_image("align_string")
4289             or return;
4290              
4291 0         0 $img = $self;
4292             }
4293             else {
4294 0         0 $img = undef;
4295             }
4296              
4297 0         0 my %input=('x'=>0, 'y'=>0, @_);
4298             defined $input{string}
4299 0 0       0 or $input{string} = $input{text};
4300              
4301 0 0       0 unless(exists $input{string}) {
4302 0         0 $self->_set_error("missing required parameter 'string'");
4303 0         0 return;
4304             }
4305              
4306 0 0       0 unless($input{font}) {
4307 0         0 $self->_set_error("missing required parameter 'font'");
4308 0         0 return;
4309             }
4310              
4311 0         0 my @result;
4312 0 0       0 unless (@result = $input{font}->align(image=>$img, %input)) {
4313 0         0 return;
4314             }
4315              
4316 0 0       0 return wantarray ? @result : $result[0];
4317             }
4318              
4319             my @file_limit_names = qw/width height bytes/;
4320              
4321             sub set_file_limits {
4322 25     25 0 827 shift;
4323              
4324 25         98 my %opts = @_;
4325 25         39 my %values;
4326            
4327 25 100       295 if ($opts{reset}) {
4328 23         108 @values{@file_limit_names} = (0) x @file_limit_names;
4329             }
4330             else {
4331 2         13 @values{@file_limit_names} = i_get_image_file_limits();
4332             }
4333              
4334 25         70 for my $key (keys %values) {
4335 75 100       148 defined $opts{$key} and $values{$key} = $opts{$key};
4336             }
4337              
4338 25         228 i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
4339             }
4340              
4341             sub get_file_limits {
4342 5     5 0 2274355 i_get_image_file_limits();
4343             }
4344              
4345             my @check_args = qw(width height channels sample_size);
4346              
4347             sub check_file_limits {
4348 11     11 0 26 my $class = shift;
4349              
4350 11         59 my %opts =
4351             (
4352             channels => 3,
4353             sample_size => 1,
4354             @_,
4355             );
4356              
4357 11 100 100     52 if ($opts{sample_size} && $opts{sample_size} eq 'float') {
4358 1         5 $opts{sample_size} = length(pack("d", 0));
4359             }
4360              
4361 11         26 for my $name (@check_args) {
4362 38 100       57 unless (defined $opts{$name}) {
4363 1         3 $class->_set_error("check_file_limits: $name must be defined");
4364 1         5 return;
4365             }
4366 37 100       65 unless ($opts{$name} == int($opts{$name})) {
4367 1         4 $class->_set_error("check_file_limits: $name must be a positive integer");
4368 1         5 return;
4369             }
4370             }
4371              
4372 9         144 my $result = i_int_check_image_file_limits(@opts{@check_args});
4373 9 100       18 unless ($result) {
4374 6         22 $class->_set_error($class->_error_as_msg());
4375             }
4376              
4377 9         48 return $result;
4378             }
4379              
4380             # Shortcuts that can be exported
4381              
4382 277     277 0 103472 sub newcolor { Imager::Color->new(@_); }
4383 0     0 0 0 sub newfont { Imager::Font->new(@_); }
4384             sub NCF {
4385 33     33 0 13504 require Imager::Color::Float;
4386 33         132 return Imager::Color::Float->new(@_);
4387             }
4388              
4389             *NC=*newcolour=*newcolor;
4390             *NF=*newfont;
4391              
4392             *open=\&read;
4393             *circle=\&arc;
4394              
4395              
4396             #### Utility routines
4397              
4398             sub errstr {
4399 321 100   321 1 10311 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
4400             }
4401              
4402             sub _set_error {
4403 199     199   431 my ($self, $msg) = @_;
4404              
4405 199 100       395 if (ref $self) {
4406 169         291 $self->{ERRSTR} = $msg;
4407             }
4408             else {
4409 30         78 $ERRSTR = $msg;
4410             }
4411 199         467 return;
4412             }
4413              
4414             # Default guess for the type of an image from extension
4415              
4416             my @simple_types = qw(png tga gif raw ico cur xpm mng jng ilbm pcx psd eps webp xwd xpm dng ras qoi jxl);
4417              
4418             my %ext_types =
4419             (
4420             ( map { $_ => $_ } @simple_types ),
4421             tiff => "tiff",
4422             tif => "tiff",
4423             pbm => "pnm",
4424             pgm => "pnm",
4425             ppm => "pnm",
4426             pnm => "pnm", # technically wrong, but historically it works in Imager
4427             jpeg => "jpeg",
4428             jpg => "jpeg",
4429             bmp => "bmp",
4430             dib => "bmp",
4431             rgb => "sgi",
4432             bw => "sgi",
4433             sgi => "sgi",
4434             fit => "fits",
4435             fits => "fits",
4436             rle => "utah",
4437             avifs => "avif", # AVIF image sequence
4438             avif => "avif",
4439             );
4440              
4441             sub def_guess_type {
4442 115     115 0 12409 my $name=lc(shift);
4443              
4444 115 50       935 my ($ext) = $name =~ /\.([^.]+)$/
4445             or return;
4446              
4447 115         397 my $type = $ext_types{$ext};
4448 115 100       257 unless ($type) {
4449 2         5 $type = $ext_types{lc $ext};
4450             }
4451              
4452 115 50 66     359 if (!defined $type && $ext =~ /\A[a-zA-Z0-9_]{2,}\z/) {
4453             # maybe a reasonable assumption
4454 0         0 $type = lc $ext;
4455             }
4456              
4457 115         287 return $type;
4458             }
4459              
4460             sub add_type_extensions {
4461 1     1 0 733 my ($class, $type, @exts) = @_;
4462              
4463 1         7 for my $ext (@exts) {
4464 1 50       13 exists $ext_types{lc $ext} or $ext_types{lc $ext} = lc $type;
4465             }
4466 1         4 1;
4467             }
4468              
4469             sub combines {
4470 1     1 0 8 return @combine_types;
4471             }
4472              
4473             # get the minimum of a list
4474              
4475             sub _min {
4476 1394     1394   1300 my $mx=shift;
4477 1394 50       1558 for(@_) { if ($_<$mx) { $mx=$_; }}
  1394         2046  
  0         0  
4478 1394         1694 return $mx;
4479             }
4480              
4481             # get the maximum of a list
4482              
4483             sub _max {
4484 1143     1143   1035 my $mx=shift;
4485 1143 100       1034 for(@_) { if ($_>$mx) { $mx=$_; }}
  1143         1327  
  1124         1081  
4486 1143         1067 return $mx;
4487             }
4488              
4489             # string stuff for iptc headers
4490              
4491             sub _clean {
4492 0     0   0 my($str)=$_[0];
4493 0         0 $str = substr($str,3);
4494 0         0 $str =~ s/[\n\r]//g;
4495 0         0 $str =~ s/\s+/ /g;
4496 0         0 $str =~ s/^\s//;
4497 0         0 $str =~ s/\s$//;
4498 0         0 return $str;
4499             }
4500              
4501             # A little hack to parse iptc headers.
4502              
4503             sub parseiptc {
4504 0     0 0 0 my $self=shift;
4505 0         0 my(@sar,$item,@ar);
4506 0         0 my($caption,$photogr,$headln,$credit);
4507              
4508 0         0 my $str=$self->{IPTCRAW};
4509              
4510 0 0       0 defined $str
4511             or return;
4512              
4513 0         0 @ar=split(/8BIM/,$str);
4514              
4515 0         0 my $i=0;
4516 0         0 foreach (@ar) {
4517 0 0       0 if (/^\004\004/) {
4518 0         0 @sar=split(/\034\002/);
4519 0         0 foreach $item (@sar) {
4520 0 0       0 if ($item =~ m/^x/) {
4521 0         0 $caption = _clean($item);
4522 0         0 $i++;
4523             }
4524 0 0       0 if ($item =~ m/^P/) {
4525 0         0 $photogr = _clean($item);
4526 0         0 $i++;
4527             }
4528 0 0       0 if ($item =~ m/^i/) {
4529 0         0 $headln = _clean($item);
4530 0         0 $i++;
4531             }
4532 0 0       0 if ($item =~ m/^n/) {
4533 0         0 $credit = _clean($item);
4534 0         0 $i++;
4535             }
4536             }
4537             }
4538             }
4539 0         0 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
4540             }
4541              
4542             sub Inline {
4543             # Inline added a new argument at the beginning
4544 0     0 0 0 my $lang = $_[-1];
4545              
4546 0 0 0     0 $lang eq 'C' || $lang eq 'CPP'
4547             or die "Only C or C++ (CPP) language supported";
4548              
4549 0         0 require Imager::ExtUtils;
4550 0         0 return Imager::ExtUtils->inline_config;
4551             }
4552              
4553             # threads shouldn't try to close raw Imager objects
4554 0     0   0 sub Imager::ImgRaw::CLONE_SKIP { 1 }
4555              
4556             sub preload {
4557             # this serves two purposes:
4558             # - a class method to load the file support modules included with Imager
4559             # (or were included, once the library dependent modules are split out)
4560             # - something for Module::ScanDeps to analyze
4561             # https://rt.cpan.org/Ticket/Display.html?id=6566
4562 1     1 0 223878 local $@;
4563 1         6 local @INC = @INC;
4564 1 50       5 pop @INC if $INC[-1] eq '.';
4565 1         2 eval { require Imager::File::GIF };
  1         109  
4566 1         2 eval { require Imager::File::JPEG };
  1         52  
4567 1         1 eval { require Imager::File::PNG };
  1         49  
4568 1         1 eval { require Imager::File::SGI };
  1         470  
4569 1         2 eval { require Imager::File::TIFF };
  1         106  
4570 1         2 eval { require Imager::File::ICO };
  1         394  
4571 1         2 eval { require Imager::Font::W32 };
  1         87  
4572 1         3 eval { require Imager::Font::FT2 };
  1         71  
4573 1         5 eval { require Imager::Font::T1 };
  1         55  
4574 1         1 eval { require Imager::Color::Table };
  1         408  
4575              
4576 1         10 1;
4577             }
4578              
4579             package Imager::IO;
4580 57     57   28354 use IO::Seekable;
  57         355017  
  57         12549  
4581              
4582             sub new_fh {
4583 19     19   5705 my ($class, $fh) = @_;
4584              
4585 19 100       48 if (tied(*$fh)) {
4586             return $class->new_cb
4587             (
4588             sub {
4589 2     2   2651 local $\;
4590              
4591 2         10 return print $fh $_[0];
4592             },
4593             sub {
4594 2     2   761 my $tmp;
4595 2         11 my $count = CORE::read $fh, $tmp, $_[1];
4596 2 50       40 defined $count
4597             or return undef;
4598 2 100       11 $count
4599             or return "";
4600 1         4 return $tmp;
4601             },
4602             sub {
4603 2 50 33 2   72 if ($_[1] != SEEK_CUR || $_[0] != 0) {
4604 2 50       10 unless (CORE::seek $fh, $_[0], $_[1]) {
4605 0         0 return -1;
4606             }
4607             }
4608              
4609 2         35 return tell $fh;
4610             },
4611             undef,
4612 1         117 );
4613             }
4614             else {
4615 18         2249 return $class->_new_perlio($fh);
4616             }
4617             }
4618              
4619             # backward compatibility for %formats
4620             package Imager::FORMATS;
4621 57     57   394 use strict;
  57         126  
  57         1304  
4622 57     57   212 use constant IX_FORMATS => 0;
  57         86  
  57         4990  
4623 57     57   265 use constant IX_LIST => 1;
  57         86  
  57         2119  
4624 57     57   214 use constant IX_INDEX => 2;
  57         76  
  57         1974  
4625 57     57   211 use constant IX_CLASSES => 3;
  57         93  
  57         42519  
4626              
4627             sub TIEHASH {
4628 57     57   129 my ($class, $formats, $classes) = @_;
4629              
4630 57         256 return bless [ $formats, [ ], 0, $classes ], $class;
4631             }
4632              
4633             sub _check {
4634 50     50   78 my ($self, $key) = @_;
4635              
4636 50         190 (my $file = $self->[IX_CLASSES]{$key} . ".pm") =~ s(::)(/)g;
4637 50         57 my $value;
4638             my $error;
4639 50         133 my $loaded = Imager::_load_file($file, \$error);
4640 50 50       75 if ($loaded) {
4641 0         0 $value = 1;
4642             }
4643             else {
4644 50 50       103 if ($error =~ /^Can't locate /) {
4645 50         70 $error = "Can't locate $file";
4646             }
4647 50         134 $reader_load_errors{$key} = $writer_load_errors{$key} = $error;
4648 50         59 $value = undef;
4649             }
4650 50         78 $self->[IX_FORMATS]{$key} = $value;
4651              
4652 50         104 return $value;
4653             }
4654              
4655             sub FETCH {
4656 11     11   139566 my ($self, $key) = @_;
4657              
4658 11 100       61 exists $self->[IX_FORMATS]{$key} and return $self->[IX_FORMATS]{$key};
4659              
4660 5 100       19 $self->[IX_CLASSES]{$key} or return undef;
4661              
4662 1         5 return $self->_check($key);
4663             }
4664              
4665             sub STORE {
4666 0     0   0 die "%Imager::formats is not user monifiable";
4667             }
4668              
4669             sub DELETE {
4670 0     0   0 die "%Imager::formats is not user monifiable";
4671             }
4672              
4673             sub CLEAR {
4674 0     0   0 die "%Imager::formats is not user monifiable";
4675             }
4676              
4677             sub EXISTS {
4678 0     0   0 my ($self, $key) = @_;
4679              
4680 0 0       0 if (exists $self->[IX_FORMATS]{$key}) {
4681 0 0       0 my $value = $self->[IX_FORMATS]{$key}
4682             or return;
4683 0         0 return 1;
4684             }
4685              
4686 0 0       0 $self->_check($key) or return 1==0;
4687              
4688 0         0 return 1==1;
4689             }
4690              
4691             sub FIRSTKEY {
4692 17     17   219 my ($self) = @_;
4693              
4694 17 100       24 unless (@{$self->[IX_LIST]}) {
  17         92  
4695             # full populate it
4696 7         22 @{$self->[IX_LIST]} = grep $self->[IX_FORMATS]{$_},
4697 7         14 keys %{$self->[IX_FORMATS]};
  7         67  
4698              
4699 7         15 for my $key (keys %{$self->[IX_CLASSES]}) {
  7         50  
4700 49 50       90 $self->[IX_FORMATS]{$key} and next;
4701             $self->_check($key)
4702 49 50       118 and push @{$self->[IX_LIST]}, $key;
  0         0  
4703             }
4704             }
4705              
4706 17 50       31 @{$self->[IX_LIST]} or return;
  17         90  
4707 17         28 $self->[IX_INDEX] = 1;
4708 17         76 return $self->[IX_LIST][0];
4709             }
4710              
4711             sub NEXTKEY {
4712 85     85   104 my ($self) = @_;
4713              
4714 85 100       90 $self->[IX_INDEX] < @{$self->[IX_LIST]}
  85         190  
4715             or return;
4716              
4717 68         151 return $self->[IX_LIST][$self->[IX_INDEX]++];
4718             }
4719              
4720             sub SCALAR {
4721 0     0     my ($self) = @_;
4722              
4723 0           return scalar @{$self->[IX_LIST]};
  0            
4724             }
4725              
4726             1;
4727             __END__