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