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