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