File Coverage

blib/lib/Imager.pm
Criterion Covered Total %
statement 1679 2246 74.7
branch 980 1410 69.5
condition 189 338 55.9
subroutine 141 159 88.6
pod 1 105 0.9
total 2990 4258 70.2


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