]> git.imager.perl.org - imager.git/blame - Imager.pm
Specifying the bottom edge of the source image to paste was broken in
[imager.git] / Imager.pm
CommitLineData
02d1d628
AMH
1package Imager;
2
02d1d628 3use strict;
97c4effc 4use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %formats $DEBUG %filters %DSOs $ERRSTR $fontstate %OPCODES $I2P $FORMATGUESS $warn_obsolete);
02d1d628
AMH
5use IO::File;
6
7use Imager::Color;
8use Imager::Font;
9
10@EXPORT_OK = qw(
11 init
12 init_log
13 DSO_open
14 DSO_close
15 DSO_funclist
16 DSO_call
dd55acc8 17
02d1d628
AMH
18 load_plugin
19 unload_plugin
dd55acc8 20
02d1d628
AMH
21 i_list_formats
22 i_has_format
dd55acc8 23
02d1d628
AMH
24 i_color_new
25 i_color_set
26 i_color_info
dd55acc8 27
02d1d628
AMH
28 i_img_empty
29 i_img_empty_ch
30 i_img_exorcise
31 i_img_destroy
32
33 i_img_info
34
35 i_img_setmask
36 i_img_getmask
37
aa833c97 38 i_line
02d1d628
AMH
39 i_line_aa
40 i_box
41 i_box_filled
42 i_arc
18063344 43 i_circle_aa
dd55acc8 44
02d1d628
AMH
45 i_bezier_multi
46 i_poly_aa
43c5dacb 47 i_poly_aa_cfill
02d1d628
AMH
48
49 i_copyto
50 i_rubthru
51 i_scaleaxis
52 i_scale_nn
53 i_haar
54 i_count_colors
dd55acc8 55
02d1d628
AMH
56 i_gaussian
57 i_conv
dd55acc8 58
f5991c03 59 i_convert
40eba1ea 60 i_map
dd55acc8 61
02d1d628
AMH
62 i_img_diff
63
64 i_init_fonts
65 i_t1_new
66 i_t1_destroy
67 i_t1_set_aa
68 i_t1_cp
69 i_t1_text
70 i_t1_bbox
71
02d1d628
AMH
72 i_tt_set_aa
73 i_tt_cp
74 i_tt_text
75 i_tt_bbox
76
02d1d628
AMH
77 i_readjpeg_wiol
78 i_writejpeg_wiol
79
80 i_readtiff_wiol
81 i_writetiff_wiol
d2dfdcc9 82 i_writetiff_wiol_faxable
02d1d628 83
790923a4
AMH
84 i_readpng_wiol
85 i_writepng_wiol
02d1d628
AMH
86
87 i_readgif
10461f9a 88 i_readgif_wiol
02d1d628
AMH
89 i_readgif_callback
90 i_writegif
91 i_writegifmc
92 i_writegif_gen
93 i_writegif_callback
94
95 i_readpnm_wiol
067d6bdc 96 i_writeppm_wiol
02d1d628 97
895dbd34
AMH
98 i_readraw_wiol
99 i_writeraw_wiol
02d1d628
AMH
100
101 i_contrast
102 i_hardinvert
103 i_noise
104 i_bumpmap
105 i_postlevels
106 i_mosaic
107 i_watermark
dd55acc8 108
02d1d628
AMH
109 malloc_state
110
111 list_formats
dd55acc8 112
02d1d628
AMH
113 i_gifquant
114
115 newfont
116 newcolor
117 newcolour
118 NC
119 NF
02d1d628
AMH
120);
121
9982a307 122@EXPORT=qw(
02d1d628
AMH
123 init_log
124 i_list_formats
125 i_has_format
126 malloc_state
127 i_color_new
128
129 i_img_empty
130 i_img_empty_ch
131 );
132
133%EXPORT_TAGS=
134 (handy => [qw(
135 newfont
136 newcolor
137 NF
138 NC
139 )],
140 all => [@EXPORT_OK],
141 default => [qw(
142 load_plugin
143 unload_plugin
144 )]);
145
53a6bbd4
TC
146# registered file readers
147my %readers;
148
149# modules we attempted to autoload
150my %attempted_to_load;
151
02d1d628
AMH
152BEGIN {
153 require Exporter;
92bda632 154 @ISA = qw(Exporter);
cb148dda 155 $VERSION = '0.49';
92bda632
TC
156 eval {
157 require XSLoader;
158 XSLoader::load(Imager => $VERSION);
159 1;
160 } or do {
161 require DynaLoader;
162 push @ISA, 'DynaLoader';
163 bootstrap Imager $VERSION;
164 }
02d1d628
AMH
165}
166
167BEGIN {
168 i_init_fonts(); # Initialize font engines
faa9b3e7 169 Imager::Font::__init();
02d1d628
AMH
170 for(i_list_formats()) { $formats{$_}++; }
171
172 if ($formats{'t1'}) {
173 i_t1_set_aa(1);
174 }
175
faa9b3e7
TC
176 if (!$formats{'t1'} and !$formats{'tt'}
177 && !$formats{'ft2'} && !$formats{'w32'}) {
02d1d628
AMH
178 $fontstate='no font support';
179 }
180
181 %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]);
182
183 $DEBUG=0;
184
6607600c
TC
185 # the members of the subhashes under %filters are:
186 # callseq - a list of the parameters to the underlying filter in the
187 # order they are passed
188 # callsub - a code ref that takes a named parameter list and calls the
189 # underlying filter
190 # defaults - a hash of default values
191 # names - defines names for value of given parameters so if the names
192 # field is foo=> { bar=>1 }, and the user supplies "bar" as the
193 # foo parameter, the filter will receive 1 for the foo
194 # parameter
02d1d628
AMH
195 $filters{contrast}={
196 callseq => ['image','intensity'],
197 callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); }
198 };
199
200 $filters{noise} ={
201 callseq => ['image', 'amount', 'subtype'],
202 defaults => { amount=>3,subtype=>0 },
203 callsub => sub { my %hsh=@_; i_noise($hsh{image},$hsh{amount},$hsh{subtype}); }
204 };
205
206 $filters{hardinvert} ={
207 callseq => ['image'],
208 defaults => { },
209 callsub => sub { my %hsh=@_; i_hardinvert($hsh{image}); }
210 };
211
212 $filters{autolevels} ={
213 callseq => ['image','lsat','usat','skew'],
214 defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 },
215 callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); }
216 };
217
218 $filters{turbnoise} ={
219 callseq => ['image'],
220 defaults => { xo=>0.0,yo=>0.0,scale=>10.0 },
221 callsub => sub { my %hsh=@_; i_turbnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{scale}); }
222 };
223
224 $filters{radnoise} ={
225 callseq => ['image'],
226 defaults => { xo=>100,yo=>100,ascale=>17.0,rscale=>0.02 },
227 callsub => sub { my %hsh=@_; i_radnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{rscale},$hsh{ascale}); }
228 };
229
230 $filters{conv} ={
231 callseq => ['image', 'coef'],
232 defaults => { },
233 callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}); }
234 };
235
f0ddaffd
TC
236 $filters{gradgen} =
237 {
238 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
239 defaults => { dist => 0 },
240 callsub =>
241 sub {
242 my %hsh=@_;
243 my @colors = @{$hsh{colors}};
244 $_ = _color($_)
245 for @colors;
246 i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist});
247 }
248 };
02d1d628 249
e310e5f9
TC
250 $filters{nearest_color} =
251 {
252 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
253 defaults => { },
254 callsub =>
255 sub {
256 my %hsh=@_;
257 # make sure the segments are specified with colors
258 my @colors;
259 for my $color (@{$hsh{colors}}) {
260 my $new_color = _color($color)
261 or die $Imager::ERRSTR."\n";
262 push @colors, $new_color;
263 }
264
265 i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors,
266 $hsh{dist})
267 or die Imager->_error_as_msg() . "\n";
268 },
269 };
faa9b3e7
TC
270 $filters{gaussian} = {
271 callseq => [ 'image', 'stddev' ],
272 defaults => { },
273 callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); },
274 };
d08b8f85
TC
275 $filters{mosaic} =
276 {
277 callseq => [ qw(image size) ],
278 defaults => { size => 20 },
279 callsub => sub { my %hsh = @_; i_mosaic($hsh{image}, $hsh{size}) },
280 };
281 $filters{bumpmap} =
282 {
283 callseq => [ qw(image bump elevation lightx lighty st) ],
284 defaults => { elevation=>0, st=> 2 },
b2778574 285 callsub => sub {
d08b8f85
TC
286 my %hsh = @_;
287 i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation},
288 $hsh{lightx}, $hsh{lighty}, $hsh{st});
289 },
290 };
b2778574
AMH
291 $filters{bumpmap_complex} =
292 {
293 callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ],
294 defaults => {
295 channel => 0,
296 tx => 0,
297 ty => 0,
298 Lx => 0.2,
299 Ly => 0.4,
300 Lz => -1.0,
301 cd => 1.0,
302 cs => 40,
303 n => 1.3,
304 Ia => Imager::Color->new(rgb=>[0,0,0]),
305 Il => Imager::Color->new(rgb=>[255,255,255]),
306 Is => Imager::Color->new(rgb=>[255,255,255]),
307 },
308 callsub => sub {
309 my %hsh = @_;
310 i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel},
311 $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz},
312 $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il},
313 $hsh{Is});
314 },
315 };
d08b8f85
TC
316 $filters{postlevels} =
317 {
318 callseq => [ qw(image levels) ],
319 defaults => { levels => 10 },
320 callsub => sub { my %hsh = @_; i_postlevels($hsh{image}, $hsh{levels}); },
321 };
322 $filters{watermark} =
323 {
324 callseq => [ qw(image wmark tx ty pixdiff) ],
325 defaults => { pixdiff=>10, tx=>0, ty=>0 },
326 callsub =>
327 sub {
328 my %hsh = @_;
329 i_watermark($hsh{image}, $hsh{wmark}{IMG}, $hsh{tx}, $hsh{ty},
330 $hsh{pixdiff});
331 },
332 };
6607600c
TC
333 $filters{fountain} =
334 {
335 callseq => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ],
336 names => {
337 ftype => { linear => 0,
338 bilinear => 1,
339 radial => 2,
340 radial_square => 3,
341 revolution => 4,
342 conical => 5 },
343 repeat => { none => 0,
344 sawtooth => 1,
345 triangle => 2,
346 saw_both => 3,
347 tri_both => 4,
348 },
349 super_sample => {
350 none => 0,
351 grid => 1,
352 random => 2,
353 circle => 3,
354 },
efdc2568
TC
355 combine => {
356 none => 0,
357 normal => 1,
358 multiply => 2, mult => 2,
359 dissolve => 3,
360 add => 4,
9d540150 361 subtract => 5, 'sub' => 5,
efdc2568
TC
362 diff => 6,
363 lighten => 7,
364 darken => 8,
365 hue => 9,
366 sat => 10,
367 value => 11,
368 color => 12,
369 },
6607600c
TC
370 },
371 defaults => { ftype => 0, repeat => 0, combine => 0,
372 super_sample => 0, ssample_param => 4,
373 segments=>[
374 [ 0, 0.5, 1,
375 Imager::Color->new(0,0,0),
376 Imager::Color->new(255, 255, 255),
377 0, 0,
378 ],
379 ],
380 },
381 callsub =>
382 sub {
383 my %hsh = @_;
109bec2d
TC
384
385 # make sure the segments are specified with colors
386 my @segments;
387 for my $segment (@{$hsh{segments}}) {
388 my @new_segment = @$segment;
389
390 $_ = _color($_) or die $Imager::ERRSTR."\n" for @new_segment[3,4];
391 push @segments, \@new_segment;
392 }
393
6607600c
TC
394 i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
395 $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
e310e5f9
TC
396 $hsh{ssample_param}, \@segments)
397 or die Imager->_error_as_msg() . "\n";
6607600c
TC
398 },
399 };
b6381851
TC
400 $filters{unsharpmask} =
401 {
402 callseq => [ qw(image stddev scale) ],
403 defaults => { stddev=>2.0, scale=>1.0 },
404 callsub =>
405 sub {
406 my %hsh = @_;
407 i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
408 },
409 };
02d1d628
AMH
410
411 $FORMATGUESS=\&def_guess_type;
97c4effc
TC
412
413 $warn_obsolete = 1;
02d1d628
AMH
414}
415
416#
417# Non methods
418#
419
420# initlize Imager
421# NOTE: this might be moved to an import override later on
422
423#sub import {
424# my $pack = shift;
425# (look through @_ for special tags, process, and remove them);
426# use Data::Dumper;
427# print Dumper($pack);
428# print Dumper(@_);
429#}
430
f83bf98a 431sub init_log {
bf1573f9
TC
432 i_init_log($_[0],$_[1]);
433 i_log_entry("Imager $VERSION starting\n", 1);
f83bf98a
AMH
434}
435
436
02d1d628
AMH
437sub init {
438 my %parms=(loglevel=>1,@_);
439 if ($parms{'log'}) {
440 init_log($parms{'log'},$parms{'loglevel'});
441 }
f83bf98a 442
97c4effc
TC
443 if (exists $parms{'warn_obsolete'}) {
444 $warn_obsolete = $parms{'warn_obsolete'};
445 }
02d1d628
AMH
446
447# if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
448# if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
449# i_init_fonts();
450# $fontstate='ok';
451# }
4cb58f1b
TC
452 if (exists $parms{'t1log'}) {
453 i_init_fonts($parms{'t1log'});
454 }
02d1d628
AMH
455}
456
457END {
458 if ($DEBUG) {
459 print "shutdown code\n";
460 # for(keys %instances) { $instances{$_}->DESTROY(); }
461 malloc_state(); # how do decide if this should be used? -- store something from the import
462 print "Imager exiting\n";
463 }
464}
465
466# Load a filter plugin
467
468sub load_plugin {
469 my ($filename)=@_;
470 my $i;
471 my ($DSO_handle,$str)=DSO_open($filename);
472 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
473 my %funcs=DSO_funclist($DSO_handle);
474 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
475 $i=0;
476 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
477
478 $DSOs{$filename}=[$DSO_handle,\%funcs];
479
480 for(keys %funcs) {
481 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
482 $DEBUG && print "eval string:\n",$evstr,"\n";
483 eval $evstr;
484 print $@ if $@;
485 }
486 return 1;
487}
488
489# Unload a plugin
490
491sub unload_plugin {
492 my ($filename)=@_;
493
494 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
495 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
496 for(keys %{$funcref}) {
497 delete $filters{$_};
498 $DEBUG && print "unloading: $_\n";
499 }
500 my $rc=DSO_close($DSO_handle);
501 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
502 return 1;
503}
504
64606cc7
TC
505# take the results of i_error() and make a message out of it
506sub _error_as_msg {
507 return join(": ", map $_->[0], i_errors());
508}
509
3a9a4241
TC
510# this function tries to DWIM for color parameters
511# color objects are used as is
512# simple scalars are simply treated as single parameters to Imager::Color->new
513# hashrefs are treated as named argument lists to Imager::Color->new
514# arrayrefs are treated as list arguments to Imager::Color->new iff any
515# parameter is > 1
516# other arrayrefs are treated as list arguments to Imager::Color::Float
517
518sub _color {
519 my $arg = shift;
b6cfd214
TC
520 # perl 5.6.0 seems to do weird things to $arg if we don't make an
521 # explicitly stringified copy
522 # I vaguely remember a bug on this on p5p, but couldn't find it
523 # through bugs.perl.org (I had trouble getting it to find any bugs)
524 my $copy = $arg . "";
3a9a4241
TC
525 my $result;
526
527 if (ref $arg) {
528 if (UNIVERSAL::isa($arg, "Imager::Color")
529 || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
530 $result = $arg;
531 }
532 else {
b6cfd214 533 if ($copy =~ /^HASH\(/) {
3a9a4241
TC
534 $result = Imager::Color->new(%$arg);
535 }
b6cfd214 536 elsif ($copy =~ /^ARRAY\(/) {
3a9a4241
TC
537 if (grep $_ > 1, @$arg) {
538 $result = Imager::Color->new(@$arg);
539 }
540 else {
541 $result = Imager::Color::Float->new(@$arg);
542 }
543 }
544 else {
545 $Imager::ERRSTR = "Not a color";
546 }
547 }
548 }
549 else {
550 # assume Imager::Color::new knows how to handle it
551 $result = Imager::Color->new($arg);
552 }
553
554 return $result;
555}
556
557
02d1d628
AMH
558#
559# Methods to be called on objects.
560#
561
562# Create a new Imager object takes very few parameters.
563# usually you call this method and then call open from
564# the resulting object
565
566sub new {
567 my $class = shift;
568 my $self ={};
569 my %hsh=@_;
570 bless $self,$class;
571 $self->{IMG}=undef; # Just to indicate what exists
572 $self->{ERRSTR}=undef; #
573 $self->{DEBUG}=$DEBUG;
574 $self->{DEBUG} && print "Initialized Imager\n";
1501d9b3
TC
575 if (defined $hsh{xsize} && defined $hsh{ysize}) {
576 unless ($self->img_set(%hsh)) {
577 $Imager::ERRSTR = $self->{ERRSTR};
578 return;
579 }
580 }
02d1d628
AMH
581 return $self;
582}
583
02d1d628
AMH
584# Copy an entire image with no changes
585# - if an image has magic the copy of it will not be magical
586
587sub copy {
588 my $self = shift;
589 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
590
34b3f7e6
TC
591 unless (defined wantarray) {
592 my @caller = caller;
593 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
594 return;
595 }
596
02d1d628 597 my $newcopy=Imager->new();
92bda632 598 $newcopy->{IMG} = i_copy($self->{IMG});
02d1d628
AMH
599 return $newcopy;
600}
601
602# Paste a region
603
604sub paste {
605 my $self = shift;
92bda632
TC
606
607 unless ($self->{IMG}) {
608 $self->_set_error('empty input image');
609 return;
610 }
611 my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_);
612 my $src = $input{img} || $input{src};
613 unless($src) {
614 $self->_set_error("no source image");
02d1d628
AMH
615 return;
616 }
617 $input{left}=0 if $input{left} <= 0;
618 $input{top}=0 if $input{top} <= 0;
92bda632 619
02d1d628 620 my($r,$b)=i_img_info($src->{IMG});
92bda632
TC
621 my ($src_left, $src_top) = @input{qw/src_minx src_miny/};
622 my ($src_right, $src_bottom);
623 if ($input{src_coords}) {
624 ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}}
625 }
626 else {
627 if (defined $input{src_maxx}) {
628 $src_right = $input{src_maxx};
629 }
630 elsif (defined $input{width}) {
631 if ($input{width} <= 0) {
632 $self->_set_error("paste: width must me positive");
633 return;
634 }
635 $src_right = $src_left + $input{width};
636 }
637 else {
638 $src_right = $r;
639 }
35029411 640 if (defined $input{src_maxy}) {
92bda632
TC
641 $src_bottom = $input{src_maxy};
642 }
643 elsif (defined $input{height}) {
644 if ($input{height} < 0) {
645 $self->_set_error("paste: height must be positive");
646 return;
647 }
648 $src_bottom = $src_top + $input{height};
649 }
650 else {
651 $src_bottom = $b;
652 }
653 }
654
655 $src_right > $r and $src_right = $r;
35029411 656 $src_bottom > $b and $src_bottom = $b;
92bda632
TC
657
658 if ($src_right <= $src_left
659 || $src_bottom < $src_top) {
660 $self->_set_error("nothing to paste");
661 return;
662 }
02d1d628
AMH
663
664 i_copyto($self->{IMG}, $src->{IMG},
92bda632
TC
665 $src_left, $src_top, $src_right, $src_bottom,
666 $input{left}, $input{top});
667
02d1d628
AMH
668 return $self; # What should go here??
669}
670
671# Crop an image - i.e. return a new image that is smaller
672
673sub crop {
674 my $self=shift;
675 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
676d5bb5 676
34b3f7e6
TC
677 unless (defined wantarray) {
678 my @caller = caller;
679 warn "crop() called in void context - crop() returns the cropped image at $caller[1] line $caller[2]\n";
680 return;
681 }
682
676d5bb5 683 my %hsh=@_;
299a3866 684
676d5bb5
TC
685 my ($w, $h, $l, $r, $b, $t) =
686 @hsh{qw(width height left right bottom top)};
299a3866 687
676d5bb5
TC
688 # work through the various possibilities
689 if (defined $l) {
690 if (defined $w) {
691 $r = $l + $w;
692 }
693 elsif (!defined $r) {
694 $r = $self->getwidth;
695 }
696 }
697 elsif (defined $r) {
698 if (defined $w) {
699 $l = $r - $w;
700 }
701 else {
702 $l = 0;
703 }
704 }
705 elsif (defined $w) {
706 $l = int(0.5+($self->getwidth()-$w)/2);
707 $r = $l + $w;
708 }
709 else {
710 $l = 0;
711 $r = $self->getwidth;
712 }
713 if (defined $t) {
714 if (defined $h) {
715 $b = $t + $h;
716 }
717 elsif (!defined $b) {
718 $b = $self->getheight;
719 }
720 }
721 elsif (defined $b) {
722 if (defined $h) {
723 $t = $b - $h;
724 }
725 else {
726 $t = 0;
727 }
728 }
729 elsif (defined $h) {
730 $t=int(0.5+($self->getheight()-$h)/2);
731 $b=$t+$h;
732 }
733 else {
734 $t = 0;
735 $b = $self->getheight;
736 }
02d1d628
AMH
737
738 ($l,$r)=($r,$l) if $l>$r;
739 ($t,$b)=($b,$t) if $t>$b;
740
676d5bb5
TC
741 $l < 0 and $l = 0;
742 $r > $self->getwidth and $r = $self->getwidth;
743 $t < 0 and $t = 0;
744 $b > $self->getheight and $b = $self->getheight;
02d1d628 745
676d5bb5
TC
746 if ($l == $r || $t == $b) {
747 $self->_set_error("resulting image would have no content");
748 return;
749 }
02d1d628 750
676d5bb5 751 my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t);
02d1d628
AMH
752
753 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
754 return $dst;
755}
756
ec76939c
TC
757sub _sametype {
758 my ($self, %opts) = @_;
759
760 $self->{IMG} or return $self->_set_error("Not a valid image");
761
762 my $x = $opts{xsize} || $self->getwidth;
763 my $y = $opts{ysize} || $self->getheight;
764 my $channels = $opts{channels} || $self->getchannels;
765
766 my $out = Imager->new;
767 if ($channels == $self->getchannels) {
768 $out->{IMG} = i_sametype($self->{IMG}, $x, $y);
769 }
770 else {
771 $out->{IMG} = i_sametype_chans($self->{IMG}, $x, $y, $channels);
772 }
773 unless ($out->{IMG}) {
774 $self->{ERRSTR} = $self->_error_as_msg;
775 return;
776 }
777
778 return $out;
779}
780
02d1d628
AMH
781# Sets an image to a certain size and channel number
782# if there was previously data in the image it is discarded
783
784sub img_set {
785 my $self=shift;
786
faa9b3e7 787 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
02d1d628
AMH
788
789 if (defined($self->{IMG})) {
faa9b3e7
TC
790 # let IIM_DESTROY destroy it, it's possible this image is
791 # referenced from a virtual image (like masked)
792 #i_img_destroy($self->{IMG});
02d1d628
AMH
793 undef($self->{IMG});
794 }
795
faa9b3e7
TC
796 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
797 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
798 $hsh{maxcolors} || 256);
799 }
365ea842
TC
800 elsif ($hsh{bits} eq 'double') {
801 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
802 }
faa9b3e7
TC
803 elsif ($hsh{bits} == 16) {
804 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
805 }
806 else {
807 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
808 $hsh{'channels'});
809 }
1501d9b3
TC
810
811 unless ($self->{IMG}) {
812 $self->{ERRSTR} = Imager->_error_as_msg();
813 return;
814 }
815
816 $self;
faa9b3e7
TC
817}
818
819# created a masked version of the current image
820sub masked {
821 my $self = shift;
822
823 $self or return undef;
824 my %opts = (left => 0,
825 top => 0,
826 right => $self->getwidth,
827 bottom => $self->getheight,
828 @_);
829 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
830
831 my $result = Imager->new;
832 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
833 $opts{top}, $opts{right} - $opts{left},
834 $opts{bottom} - $opts{top});
835 # keep references to the mask and base images so they don't
836 # disappear on us
837 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
838
839 $result;
840}
841
842# convert an RGB image into a paletted image
843sub to_paletted {
844 my $self = shift;
845 my $opts;
846 if (@_ != 1 && !ref $_[0]) {
847 $opts = { @_ };
848 }
849 else {
850 $opts = shift;
851 }
852
34b3f7e6
TC
853 unless (defined wantarray) {
854 my @caller = caller;
855 warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n";
856 return;
857 }
858
faa9b3e7
TC
859 my $result = Imager->new;
860 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
861
862 #print "Type ", i_img_type($result->{IMG}), "\n";
863
1501d9b3
TC
864 if ($result->{IMG}) {
865 return $result;
866 }
867 else {
868 $self->{ERRSTR} = $self->_error_as_msg;
869 return;
870 }
faa9b3e7
TC
871}
872
873# convert a paletted (or any image) to an 8-bit/channel RGB images
874sub to_rgb8 {
875 my $self = shift;
876 my $result;
877
34b3f7e6
TC
878 unless (defined wantarray) {
879 my @caller = caller;
880 warn "to_rgb8() called in void context - to_rgb8() returns the cropped image at $caller[1] line $caller[2]\n";
881 return;
882 }
883
faa9b3e7
TC
884 if ($self->{IMG}) {
885 $result = Imager->new;
886 $result->{IMG} = i_img_to_rgb($self->{IMG})
887 or undef $result;
888 }
889
890 return $result;
891}
892
893sub addcolors {
894 my $self = shift;
895 my %opts = (colors=>[], @_);
896
897 @{$opts{colors}} or return undef;
898
899 $self->{IMG} and i_addcolors($self->{IMG}, @{$opts{colors}});
900}
901
902sub setcolors {
903 my $self = shift;
904 my %opts = (start=>0, colors=>[], @_);
905 @{$opts{colors}} or return undef;
906
907 $self->{IMG} and i_setcolors($self->{IMG}, $opts{start}, @{$opts{colors}});
908}
909
910sub getcolors {
911 my $self = shift;
912 my %opts = @_;
913 if (!exists $opts{start} && !exists $opts{count}) {
914 # get them all
915 $opts{start} = 0;
916 $opts{count} = $self->colorcount;
917 }
918 elsif (!exists $opts{count}) {
919 $opts{count} = 1;
920 }
921 elsif (!exists $opts{start}) {
922 $opts{start} = 0;
923 }
924
925 $self->{IMG} and
926 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
927}
928
929sub colorcount {
930 i_colorcount($_[0]{IMG});
931}
932
933sub maxcolors {
934 i_maxcolors($_[0]{IMG});
935}
936
937sub findcolor {
938 my $self = shift;
939 my %opts = @_;
940 $opts{color} or return undef;
941
942 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
943}
944
945sub bits {
946 my $self = shift;
af3c2450
TC
947 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
948 if ($bits && $bits == length(pack("d", 1)) * 8) {
949 $bits = 'double';
950 }
951 $bits;
faa9b3e7
TC
952}
953
954sub type {
955 my $self = shift;
956 if ($self->{IMG}) {
957 return i_img_type($self->{IMG}) ? "paletted" : "direct";
958 }
959}
960
961sub virtual {
962 my $self = shift;
963 $self->{IMG} and i_img_virtual($self->{IMG});
964}
965
966sub tags {
967 my ($self, %opts) = @_;
968
969 $self->{IMG} or return;
970
971 if (defined $opts{name}) {
972 my @result;
973 my $start = 0;
974 my $found;
975 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
976 push @result, (i_tags_get($self->{IMG}, $found))[1];
977 $start = $found+1;
978 }
979 return wantarray ? @result : $result[0];
980 }
981 elsif (defined $opts{code}) {
982 my @result;
983 my $start = 0;
984 my $found;
985 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
986 push @result, (i_tags_get($self->{IMG}, $found))[1];
987 $start = $found+1;
988 }
989 return @result;
990 }
991 else {
992 if (wantarray) {
993 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
994 }
995 else {
996 return i_tags_count($self->{IMG});
997 }
998 }
999}
1000
1001sub addtag {
1002 my $self = shift;
1003 my %opts = @_;
1004
1005 return -1 unless $self->{IMG};
1006 if ($opts{name}) {
1007 if (defined $opts{value}) {
1008 if ($opts{value} =~ /^\d+$/) {
1009 # add as a number
1010 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
1011 }
1012 else {
1013 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
1014 }
1015 }
1016 elsif (defined $opts{data}) {
1017 # force addition as a string
1018 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
1019 }
1020 else {
1021 $self->{ERRSTR} = "No value supplied";
1022 return undef;
1023 }
1024 }
1025 elsif ($opts{code}) {
1026 if (defined $opts{value}) {
1027 if ($opts{value} =~ /^\d+$/) {
1028 # add as a number
1029 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
1030 }
1031 else {
1032 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
1033 }
1034 }
1035 elsif (defined $opts{data}) {
1036 # force addition as a string
1037 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
1038 }
1039 else {
1040 $self->{ERRSTR} = "No value supplied";
1041 return undef;
1042 }
1043 }
1044 else {
1045 return undef;
1046 }
1047}
1048
1049sub deltag {
1050 my $self = shift;
1051 my %opts = @_;
1052
1053 return 0 unless $self->{IMG};
1054
9d540150
TC
1055 if (defined $opts{'index'}) {
1056 return i_tags_delete($self->{IMG}, $opts{'index'});
faa9b3e7
TC
1057 }
1058 elsif (defined $opts{name}) {
1059 return i_tags_delbyname($self->{IMG}, $opts{name});
1060 }
1061 elsif (defined $opts{code}) {
1062 return i_tags_delbycode($self->{IMG}, $opts{code});
1063 }
1064 else {
1065 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
1066 return 0;
1067 }
02d1d628
AMH
1068}
1069
97c4effc
TC
1070sub settag {
1071 my ($self, %opts) = @_;
1072
1073 if ($opts{name}) {
1074 $self->deltag(name=>$opts{name});
1075 return $self->addtag(name=>$opts{name}, value=>$opts{value});
1076 }
1077 elsif (defined $opts{code}) {
1078 $self->deltag(code=>$opts{code});
1079 return $self->addtag(code=>$opts{code}, value=>$opts{value});
1080 }
1081 else {
1082 return undef;
1083 }
1084}
1085
10461f9a
TC
1086
1087sub _get_reader_io {
84e51293 1088 my ($self, $input) = @_;
10461f9a 1089
84e51293
AMH
1090 if ($input->{io}) {
1091 return $input->{io}, undef;
1092 }
1093 elsif ($input->{fd}) {
10461f9a
TC
1094 return io_new_fd($input->{fd});
1095 }
1096 elsif ($input->{fh}) {
1097 my $fd = fileno($input->{fh});
1098 unless ($fd) {
1099 $self->_set_error("Handle in fh option not opened");
1100 return;
1101 }
1102 return io_new_fd($fd);
1103 }
1104 elsif ($input->{file}) {
1105 my $file = IO::File->new($input->{file}, "r");
1106 unless ($file) {
1107 $self->_set_error("Could not open $input->{file}: $!");
1108 return;
1109 }
1110 binmode $file;
1111 return (io_new_fd(fileno($file)), $file);
1112 }
1113 elsif ($input->{data}) {
1114 return io_new_buffer($input->{data});
1115 }
1116 elsif ($input->{callback} || $input->{readcb}) {
84e51293
AMH
1117 if (!$input->{seekcb}) {
1118 $self->_set_error("Need a seekcb parameter");
10461f9a
TC
1119 }
1120 if ($input->{maxbuffer}) {
1121 return io_new_cb($input->{writecb},
1122 $input->{callback} || $input->{readcb},
1123 $input->{seekcb}, $input->{closecb},
1124 $input->{maxbuffer});
1125 }
1126 else {
1127 return io_new_cb($input->{writecb},
1128 $input->{callback} || $input->{readcb},
1129 $input->{seekcb}, $input->{closecb});
1130 }
1131 }
1132 else {
1133 $self->_set_error("file/fd/fh/data/callback parameter missing");
1134 return;
1135 }
1136}
1137
1138sub _get_writer_io {
1139 my ($self, $input, $type) = @_;
1140
1141 if ($input->{fd}) {
1142 return io_new_fd($input->{fd});
1143 }
1144 elsif ($input->{fh}) {
1145 my $fd = fileno($input->{fh});
1146 unless ($fd) {
1147 $self->_set_error("Handle in fh option not opened");
1148 return;
1149 }
9d1c4956
TC
1150 # flush it
1151 my $oldfh = select($input->{fh});
1152 # flush anything that's buffered, and make sure anything else is flushed
1153 $| = 1;
1154 select($oldfh);
10461f9a
TC
1155 return io_new_fd($fd);
1156 }
1157 elsif ($input->{file}) {
1158 my $fh = new IO::File($input->{file},"w+");
1159 unless ($fh) {
1160 $self->_set_error("Could not open file $input->{file}: $!");
1161 return;
1162 }
1163 binmode($fh) or die;
1164 return (io_new_fd(fileno($fh)), $fh);
1165 }
1166 elsif ($input->{data}) {
1167 return io_new_bufchain();
1168 }
1169 elsif ($input->{callback} || $input->{writecb}) {
1170 if ($input->{maxbuffer}) {
1171 return io_new_cb($input->{callback} || $input->{writecb},
1172 $input->{readcb},
1173 $input->{seekcb}, $input->{closecb},
1174 $input->{maxbuffer});
1175 }
1176 else {
1177 return io_new_cb($input->{callback} || $input->{writecb},
1178 $input->{readcb},
1179 $input->{seekcb}, $input->{closecb});
1180 }
1181 }
1182 else {
1183 $self->_set_error("file/fd/fh/data/callback parameter missing");
1184 return;
1185 }
1186}
1187
02d1d628
AMH
1188# Read an image from file
1189
1190sub read {
1191 my $self = shift;
1192 my %input=@_;
02d1d628
AMH
1193
1194 if (defined($self->{IMG})) {
faa9b3e7
TC
1195 # let IIM_DESTROY do the destruction, since the image may be
1196 # referenced from elsewhere
1197 #i_img_destroy($self->{IMG});
02d1d628
AMH
1198 undef($self->{IMG});
1199 }
1200
84e51293
AMH
1201 my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
1202
10461f9a 1203 unless ($input{'type'}) {
66614d6e
TC
1204 $input{'type'} = i_test_format_probe($IO, -1);
1205 }
84e51293
AMH
1206
1207 unless ($input{'type'}) {
1208 $self->_set_error('type parameter missing and not possible to guess from extension');
10461f9a
TC
1209 return undef;
1210 }
02d1d628 1211
53a6bbd4
TC
1212 _reader_autoload($input{type});
1213
1214 if ($readers{$input{type}} && $readers{$input{type}}{single}) {
1215 return $readers{$input{type}}{single}->($self, $IO, %input);
1216 }
1217
66614d6e
TC
1218 unless ($formats{$input{'type'}}) {
1219 $self->_set_error("format '$input{'type'}' not supported");
1220 return;
1221 }
1222
2fe0b227 1223 # Setup data source
2fe0b227 1224 if ( $input{'type'} eq 'jpeg' ) {
527c0c3e 1225 ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
2fe0b227 1226 if ( !defined($self->{IMG}) ) {
77157728 1227 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
02d1d628 1228 }
2fe0b227
AMH
1229 $self->{DEBUG} && print "loading a jpeg file\n";
1230 return $self;
1231 }
02d1d628 1232
2fe0b227 1233 if ( $input{'type'} eq 'tiff' ) {
8f8bd9aa
TC
1234 my $page = $input{'page'};
1235 defined $page or $page = 0;
1236 # Fixme, check if that length parameter is ever needed
1237 $self->{IMG}=i_readtiff_wiol( $IO, -1, $page );
2fe0b227
AMH
1238 if ( !defined($self->{IMG}) ) {
1239 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
02d1d628 1240 }
2fe0b227
AMH
1241 $self->{DEBUG} && print "loading a tiff file\n";
1242 return $self;
1243 }
02d1d628 1244
2fe0b227
AMH
1245 if ( $input{'type'} eq 'pnm' ) {
1246 $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1247 if ( !defined($self->{IMG}) ) {
2691d220
TC
1248 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg();
1249 return undef;
790923a4 1250 }
2fe0b227
AMH
1251 $self->{DEBUG} && print "loading a pnm file\n";
1252 return $self;
1253 }
790923a4 1254
2fe0b227
AMH
1255 if ( $input{'type'} eq 'png' ) {
1256 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1257 if ( !defined($self->{IMG}) ) {
77157728 1258 $self->{ERRSTR} = $self->_error_as_msg();
2fe0b227 1259 return undef;
705fd961 1260 }
2fe0b227
AMH
1261 $self->{DEBUG} && print "loading a png file\n";
1262 }
705fd961 1263
2fe0b227
AMH
1264 if ( $input{'type'} eq 'bmp' ) {
1265 $self->{IMG}=i_readbmp_wiol( $IO );
1266 if ( !defined($self->{IMG}) ) {
1267 $self->{ERRSTR}=$self->_error_as_msg();
1268 return undef;
10461f9a 1269 }
2fe0b227
AMH
1270 $self->{DEBUG} && print "loading a bmp file\n";
1271 }
10461f9a 1272
2fe0b227
AMH
1273 if ( $input{'type'} eq 'gif' ) {
1274 if ($input{colors} && !ref($input{colors})) {
1275 # must be a reference to a scalar that accepts the colour map
1276 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1277 return undef;
1ec86afa 1278 }
f1adece7
TC
1279 if ($input{'gif_consolidate'}) {
1280 if ($input{colors}) {
1281 my $colors;
1282 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1283 if ($colors) {
1284 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1285 }
1286 }
1287 else {
1288 $self->{IMG} =i_readgif_wiol( $IO );
737a830c 1289 }
737a830c 1290 }
2fe0b227 1291 else {
f1adece7
TC
1292 my $page = $input{'page'};
1293 defined $page or $page = 0;
1294 $self->{IMG} = i_readgif_single_wiol( $IO, $page );
1295 if ($input{colors}) {
1296 ${ $input{colors} } =
1297 [ i_getcolors($self->{IMG}, 0, i_colorcount($self->{IMG})) ];
1298 }
895dbd34 1299 }
f1adece7 1300
2fe0b227
AMH
1301 if ( !defined($self->{IMG}) ) {
1302 $self->{ERRSTR}=$self->_error_as_msg();
1303 return undef;
895dbd34 1304 }
2fe0b227
AMH
1305 $self->{DEBUG} && print "loading a gif file\n";
1306 }
895dbd34 1307
2fe0b227
AMH
1308 if ( $input{'type'} eq 'tga' ) {
1309 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1310 if ( !defined($self->{IMG}) ) {
1311 $self->{ERRSTR}=$self->_error_as_msg();
1312 return undef;
895dbd34 1313 }
2fe0b227
AMH
1314 $self->{DEBUG} && print "loading a tga file\n";
1315 }
02d1d628 1316
2fe0b227
AMH
1317 if ( $input{'type'} eq 'rgb' ) {
1318 $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1319 if ( !defined($self->{IMG}) ) {
1320 $self->{ERRSTR}=$self->_error_as_msg();
a59ffd27
TC
1321 return undef;
1322 }
2fe0b227
AMH
1323 $self->{DEBUG} && print "loading a tga file\n";
1324 }
895dbd34 1325
895dbd34 1326
2fe0b227
AMH
1327 if ( $input{'type'} eq 'raw' ) {
1328 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1329
1330 if ( !($params{xsize} && $params{ysize}) ) {
1331 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1332 return undef;
895dbd34
AMH
1333 }
1334
2fe0b227
AMH
1335 $self->{IMG} = i_readraw_wiol( $IO,
1336 $params{xsize},
1337 $params{ysize},
1338 $params{datachannels},
1339 $params{storechannels},
1340 $params{interleave});
1341 if ( !defined($self->{IMG}) ) {
5f8f8e17 1342 $self->{ERRSTR}=$self->_error_as_msg();
2fe0b227 1343 return undef;
dd55acc8 1344 }
2fe0b227 1345 $self->{DEBUG} && print "loading a raw file\n";
02d1d628 1346 }
2fe0b227 1347
02d1d628 1348 return $self;
02d1d628
AMH
1349}
1350
53a6bbd4
TC
1351sub register_reader {
1352 my ($class, %opts) = @_;
1353
1354 defined $opts{type}
1355 or die "register_reader called with no type parameter\n";
1356
1357 my $type = $opts{type};
1358
1359 defined $opts{single} || defined $opts{multiple}
1360 or die "register_reader called with no single or multiple parameter\n";
1361
1362 $readers{$type} = { };
1363 if ($opts{single}) {
1364 $readers{$type}{single} = $opts{single};
1365 }
1366 if ($opts{multiple}) {
1367 $readers{$type}{multiple} = $opts{multiple};
1368 }
1369
1370 return 1;
1371}
1372
1373# probes for an Imager::File::whatever module
1374sub _reader_autoload {
1375 my $type = shift;
1376
1377 return if $formats{$type} || $readers{$type};
1378
1379 return unless $type =~ /^\w+$/;
1380
1381 my $file = "Imager/File/\U$type\E.pm";
1382
1383 unless ($attempted_to_load{$file}) {
1384 eval {
1385 ++$attempted_to_load{$file};
1386 require $file;
1387 };
1388 }
1389}
1390
97c4effc
TC
1391sub _fix_gif_positions {
1392 my ($opts, $opt, $msg, @imgs) = @_;
2fe0b227 1393
97c4effc
TC
1394 my $positions = $opts->{'gif_positions'};
1395 my $index = 0;
1396 for my $pos (@$positions) {
1397 my ($x, $y) = @$pos;
1398 my $img = $imgs[$index++];
9d1c4956
TC
1399 $img->settag(name=>'gif_left', value=>$x);
1400 $img->settag(name=>'gif_top', value=>$y) if defined $y;
97c4effc
TC
1401 }
1402 $$msg .= "replaced with the gif_left and gif_top tags";
1403}
1404
1405my %obsolete_opts =
1406 (
1407 gif_each_palette=>'gif_local_map',
1408 interlace => 'gif_interlace',
1409 gif_delays => 'gif_delay',
1410 gif_positions => \&_fix_gif_positions,
1411 gif_loop_count => 'gif_loop',
1412 );
1413
1414sub _set_opts {
1415 my ($self, $opts, $prefix, @imgs) = @_;
1416
1417 for my $opt (keys %$opts) {
1418 my $tagname = $opt;
1419 if ($obsolete_opts{$opt}) {
1420 my $new = $obsolete_opts{$opt};
1421 my $msg = "Obsolete option $opt ";
1422 if (ref $new) {
1423 $new->($opts, $opt, \$msg, @imgs);
1424 }
1425 else {
1426 $msg .= "replaced with the $new tag ";
1427 $tagname = $new;
1428 }
1429 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1430 warn $msg if $warn_obsolete && $^W;
1431 }
1432 next unless $tagname =~ /^\Q$prefix/;
1433 my $value = $opts->{$opt};
1434 if (ref $value) {
1435 if (UNIVERSAL::isa($value, "Imager::Color")) {
1436 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1437 for my $img (@imgs) {
1438 $img->settag(name=>$tagname, value=>$tag);
1439 }
1440 }
1441 elsif (ref($value) eq 'ARRAY') {
1442 for my $i (0..$#$value) {
1443 my $val = $value->[$i];
1444 if (ref $val) {
1445 if (UNIVERSAL::isa($val, "Imager::Color")) {
1446 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1447 $i < @imgs and
1448 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1449 }
1450 else {
1451 $self->_set_error("Unknown reference type " . ref($value) .
1452 " supplied in array for $opt");
1453 return;
1454 }
1455 }
1456 else {
1457 $i < @imgs
1458 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1459 }
1460 }
1461 }
1462 else {
1463 $self->_set_error("Unknown reference type " . ref($value) .
1464 " supplied for $opt");
1465 return;
1466 }
1467 }
1468 else {
1469 # set it as a tag for every image
1470 for my $img (@imgs) {
1471 $img->settag(name=>$tagname, value=>$value);
1472 }
1473 }
1474 }
1475
1476 return 1;
1477}
1478
02d1d628 1479# Write an image to file
02d1d628
AMH
1480sub write {
1481 my $self = shift;
2fe0b227
AMH
1482 my %input=(jpegquality=>75,
1483 gifquant=>'mc',
1484 lmdither=>6.0,
febba01f
AMH
1485 lmfixed=>[],
1486 idstring=>"",
1487 compress=>1,
1488 wierdpack=>0,
4c2d6970 1489 fax_fine=>1, @_);
10461f9a 1490 my $rc;
02d1d628 1491
97c4effc
TC
1492 $self->_set_opts(\%input, "i_", $self)
1493 or return undef;
1494
02d1d628
AMH
1495 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1496
9d540150
TC
1497 if (!$input{'type'} and $input{file}) {
1498 $input{'type'}=$FORMATGUESS->($input{file});
1499 }
1500 if (!$input{'type'}) {
1501 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1502 return undef;
1503 }
02d1d628 1504
9d540150 1505 if (!$formats{$input{'type'}}) { $self->{ERRSTR}='format not supported'; return undef; }
02d1d628 1506
10461f9a
TC
1507 my ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1508 or return undef;
02d1d628 1509
2fe0b227
AMH
1510 if ($input{'type'} eq 'tiff') {
1511 $self->_set_opts(\%input, "tiff_", $self)
1512 or return undef;
1513 $self->_set_opts(\%input, "exif_", $self)
1514 or return undef;
febba01f 1515
2fe0b227
AMH
1516 if (defined $input{class} && $input{class} eq 'fax') {
1517 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
2691d220 1518 $self->{ERRSTR} = $self->_error_as_msg();
1ec86afa
AMH
1519 return undef;
1520 }
2fe0b227
AMH
1521 } else {
1522 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
2691d220 1523 $self->{ERRSTR} = $self->_error_as_msg();
2fe0b227 1524 return undef;
10461f9a 1525 }
02d1d628 1526 }
2fe0b227
AMH
1527 } elsif ( $input{'type'} eq 'pnm' ) {
1528 $self->_set_opts(\%input, "pnm_", $self)
1529 or return undef;
1530 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
2691d220 1531 $self->{ERRSTR} = $self->_error_as_msg();
2fe0b227
AMH
1532 return undef;
1533 }
1534 $self->{DEBUG} && print "writing a pnm file\n";
1535 } elsif ( $input{'type'} eq 'raw' ) {
1536 $self->_set_opts(\%input, "raw_", $self)
1537 or return undef;
1538 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
5f8f8e17 1539 $self->{ERRSTR} = $self->_error_as_msg();
2fe0b227
AMH
1540 return undef;
1541 }
1542 $self->{DEBUG} && print "writing a raw file\n";
1543 } elsif ( $input{'type'} eq 'png' ) {
1544 $self->_set_opts(\%input, "png_", $self)
1545 or return undef;
1546 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1547 $self->{ERRSTR}='unable to write png image';
1548 return undef;
1549 }
1550 $self->{DEBUG} && print "writing a png file\n";
1551 } elsif ( $input{'type'} eq 'jpeg' ) {
1552 $self->_set_opts(\%input, "jpeg_", $self)
1553 or return undef;
1554 $self->_set_opts(\%input, "exif_", $self)
1555 or return undef;
1556 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1557 $self->{ERRSTR} = $self->_error_as_msg();
1558 return undef;
1559 }
1560 $self->{DEBUG} && print "writing a jpeg file\n";
1561 } elsif ( $input{'type'} eq 'bmp' ) {
1562 $self->_set_opts(\%input, "bmp_", $self)
1563 or return undef;
1564 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1565 $self->{ERRSTR}='unable to write bmp image';
1566 return undef;
1567 }
1568 $self->{DEBUG} && print "writing a bmp file\n";
1569 } elsif ( $input{'type'} eq 'tga' ) {
1570 $self->_set_opts(\%input, "tga_", $self)
1571 or return undef;
02d1d628 1572
2fe0b227
AMH
1573 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1574 $self->{ERRSTR}=$self->_error_as_msg();
1575 return undef;
930c67c8 1576 }
2fe0b227
AMH
1577 $self->{DEBUG} && print "writing a tga file\n";
1578 } elsif ( $input{'type'} eq 'gif' ) {
1579 $self->_set_opts(\%input, "gif_", $self)
1580 or return undef;
1581 # compatibility with the old interfaces
1582 if ($input{gifquant} eq 'lm') {
1583 $input{make_colors} = 'addi';
1584 $input{translate} = 'perturb';
1585 $input{perturb} = $input{lmdither};
1586 } elsif ($input{gifquant} eq 'gen') {
1587 # just pass options through
1588 } else {
1589 $input{make_colors} = 'webmap'; # ignored
1590 $input{translate} = 'giflib';
1591 }
1501d9b3
TC
1592 if (!i_writegif_wiol($IO, \%input, $self->{IMG})) {
1593 $self->{ERRSTR} = $self->_error_as_msg;
1594 return;
1595 }
02d1d628 1596 }
10461f9a 1597
2fe0b227
AMH
1598 if (exists $input{'data'}) {
1599 my $data = io_slurp($IO);
1600 if (!$data) {
1601 $self->{ERRSTR}='Could not slurp from buffer';
1602 return undef;
1603 }
1604 ${$input{data}} = $data;
1605 }
02d1d628
AMH
1606 return $self;
1607}
1608
1609sub write_multi {
1610 my ($class, $opts, @images) = @_;
1611
10461f9a
TC
1612 if (!$opts->{'type'} && $opts->{'file'}) {
1613 $opts->{'type'} = $FORMATGUESS->($opts->{'file'});
1614 }
1615 unless ($opts->{'type'}) {
1616 $class->_set_error('type parameter missing and not possible to guess from extension');
1617 return;
1618 }
1619 # translate to ImgRaw
1620 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1621 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1622 return 0;
1623 }
97c4effc
TC
1624 $class->_set_opts($opts, "i_", @images)
1625 or return;
10461f9a
TC
1626 my @work = map $_->{IMG}, @images;
1627 my ($IO, $file) = $class->_get_writer_io($opts, $opts->{'type'})
1628 or return undef;
9d540150 1629 if ($opts->{'type'} eq 'gif') {
97c4effc
TC
1630 $class->_set_opts($opts, "gif_", @images)
1631 or return;
ed88b092
TC
1632 my $gif_delays = $opts->{gif_delays};
1633 local $opts->{gif_delays} = $gif_delays;
10461f9a 1634 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
ed88b092
TC
1635 # assume the caller wants the same delay for each frame
1636 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1637 }
10461f9a
TC
1638 my $res = i_writegif_wiol($IO, $opts, @work);
1639 $res or $class->_set_error($class->_error_as_msg());
1640 return $res;
1641 }
1642 elsif ($opts->{'type'} eq 'tiff') {
97c4effc
TC
1643 $class->_set_opts($opts, "tiff_", @images)
1644 or return;
1645 $class->_set_opts($opts, "exif_", @images)
1646 or return;
10461f9a
TC
1647 my $res;
1648 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1649 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1650 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
02d1d628
AMH
1651 }
1652 else {
10461f9a 1653 $res = i_writetiff_multi_wiol($IO, @work);
02d1d628 1654 }
10461f9a
TC
1655 $res or $class->_set_error($class->_error_as_msg());
1656 return $res;
02d1d628
AMH
1657 }
1658 else {
9d540150 1659 $ERRSTR = "Sorry, write_multi doesn't support $opts->{'type'} yet";
02d1d628
AMH
1660 return 0;
1661 }
1662}
1663
faa9b3e7
TC
1664# read multiple images from a file
1665sub read_multi {
1666 my ($class, %opts) = @_;
1667
53a6bbd4
TC
1668 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1669 or return;
1670
1671 my $type = $opts{'type'};
1672 unless ($type) {
1673 $type = i_test_format_probe($IO, -1);
1674 }
1675
1676 if ($opts{file} && !$type) {
faa9b3e7 1677 # guess the type
53a6bbd4 1678 $type = $FORMATGUESS->($opts{file});
faa9b3e7 1679 }
53a6bbd4
TC
1680
1681 unless ($type) {
faa9b3e7
TC
1682 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1683 return;
1684 }
faa9b3e7 1685
53a6bbd4
TC
1686 _reader_autoload($type);
1687
1688 if ($readers{$type} && $readers{$type}{multiple}) {
1689 return $readers{$type}{multiple}->($IO, %opts);
1690 }
1691
1692 if ($type eq 'gif') {
faa9b3e7 1693 my @imgs;
10461f9a
TC
1694 @imgs = i_readgif_multi_wiol($IO);
1695 if (@imgs) {
1696 return map {
1697 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1698 } @imgs;
faa9b3e7
TC
1699 }
1700 else {
10461f9a
TC
1701 $ERRSTR = _error_as_msg();
1702 return;
faa9b3e7 1703 }
10461f9a 1704 }
53a6bbd4 1705 elsif ($type eq 'tiff') {
10461f9a 1706 my @imgs = i_readtiff_multi_wiol($IO, -1);
faa9b3e7
TC
1707 if (@imgs) {
1708 return map {
1709 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1710 } @imgs;
1711 }
1712 else {
1713 $ERRSTR = _error_as_msg();
1714 return;
1715 }
1716 }
1717
9d540150 1718 $ERRSTR = "Cannot read multiple images from $opts{'type'} files";
faa9b3e7
TC
1719 return;
1720}
1721
02d1d628
AMH
1722# Destroy an Imager object
1723
1724sub DESTROY {
1725 my $self=shift;
1726 # delete $instances{$self};
1727 if (defined($self->{IMG})) {
faa9b3e7
TC
1728 # the following is now handled by the XS DESTROY method for
1729 # Imager::ImgRaw object
1730 # Re-enabling this will break virtual images
1731 # tested for in t/t020masked.t
1732 # i_img_destroy($self->{IMG});
02d1d628
AMH
1733 undef($self->{IMG});
1734 } else {
1735# print "Destroy Called on an empty image!\n"; # why did I put this here??
1736 }
1737}
1738
1739# Perform an inplace filter of an image
1740# that is the image will be overwritten with the data
1741
1742sub filter {
1743 my $self=shift;
1744 my %input=@_;
1745 my %hsh;
1746 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1747
9d540150 1748 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
02d1d628 1749
9d540150 1750 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
02d1d628
AMH
1751 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1752 }
1753
9d540150
TC
1754 if ($filters{$input{'type'}}{names}) {
1755 my $names = $filters{$input{'type'}}{names};
6607600c
TC
1756 for my $name (keys %$names) {
1757 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1758 $input{$name} = $names->{$name}{$input{$name}};
1759 }
1760 }
1761 }
9d540150 1762 if (defined($filters{$input{'type'}}{defaults})) {
7327d4b0
TC
1763 %hsh=( image => $self->{IMG},
1764 imager => $self,
1765 %{$filters{$input{'type'}}{defaults}},
1766 %input );
02d1d628 1767 } else {
7327d4b0
TC
1768 %hsh=( image => $self->{IMG},
1769 imager => $self,
1770 %input );
02d1d628
AMH
1771 }
1772
9d540150 1773 my @cs=@{$filters{$input{'type'}}{callseq}};
02d1d628
AMH
1774
1775 for(@cs) {
1776 if (!defined($hsh{$_})) {
9d540150 1777 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
02d1d628
AMH
1778 }
1779 }
1780
109bec2d
TC
1781 eval {
1782 local $SIG{__DIE__}; # we don't want this processed by confess, etc
1783 &{$filters{$input{'type'}}{callsub}}(%hsh);
1784 };
1785 if ($@) {
1786 chomp($self->{ERRSTR} = $@);
1787 return;
1788 }
02d1d628
AMH
1789
1790 my @b=keys %hsh;
1791
1792 $self->{DEBUG} && print "callseq is: @cs\n";
1793 $self->{DEBUG} && print "matching callseq is: @b\n";
1794
1795 return $self;
1796}
1797
92bda632
TC
1798sub register_filter {
1799 my $class = shift;
1800 my %hsh = ( defaults => {}, @_ );
1801
1802 defined $hsh{type}
1803 or die "register_filter() with no type\n";
1804 defined $hsh{callsub}
1805 or die "register_filter() with no callsub\n";
1806 defined $hsh{callseq}
1807 or die "register_filter() with no callseq\n";
1808
1809 exists $filters{$hsh{type}}
1810 and return;
1811
1812 $filters{$hsh{type}} = \%hsh;
1813
1814 return 1;
1815}
1816
02d1d628
AMH
1817# Scale an image to requested size and return the scaled version
1818
1819sub scale {
1820 my $self=shift;
9d540150 1821 my %opts=(scalefactor=>0.5,'type'=>'max',qtype=>'normal',@_);
02d1d628
AMH
1822 my $img = Imager->new();
1823 my $tmp = Imager->new();
1824
4f579313
TC
1825 my $scalefactor = $opts{scalefactor};
1826
ace46df2 1827 unless (defined wantarray) {
1501d9b3
TC
1828 my @caller = caller;
1829 warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
ace46df2
TC
1830 return;
1831 }
1832
5168ca3a
TC
1833 unless ($self->{IMG}) {
1834 $self->_set_error('empty input image');
1835 return undef;
1836 }
02d1d628 1837
5168ca3a 1838 # work out the scaling
9d540150 1839 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
4f579313
TC
1840 my ($xpix, $ypix)=( $opts{xpixels} / $self->getwidth() ,
1841 $opts{ypixels} / $self->getheight() );
5168ca3a 1842 if ($opts{'type'} eq 'min') {
bf1573f9 1843 $scalefactor = _min($xpix,$ypix);
5168ca3a
TC
1844 }
1845 elsif ($opts{'type'} eq 'max') {
bf1573f9 1846 $scalefactor = _max($xpix,$ypix);
5168ca3a
TC
1847 }
1848 else {
1849 $self->_set_error('invalid value for type parameter');
1850 return undef;
1851 }
1852 } elsif ($opts{xpixels}) {
4f579313 1853 $scalefactor = $opts{xpixels} / $self->getwidth();
5168ca3a
TC
1854 }
1855 elsif ($opts{ypixels}) {
4f579313 1856 $scalefactor = $opts{ypixels}/$self->getheight();
5168ca3a 1857 }
41c7d053
TC
1858 elsif ($opts{constrain} && ref $opts{constrain}
1859 && $opts{constrain}->can('constrain')) {
1860 # we've been passed an Image::Math::Constrain object or something
1861 # that looks like one
4f579313 1862 (undef, undef, $scalefactor)
41c7d053 1863 = $opts{constrain}->constrain($self->getwidth, $self->getheight);
4f579313 1864 unless ($scalefactor) {
41c7d053
TC
1865 $self->_set_error('constrain method failed on constrain parameter');
1866 return undef;
1867 }
1868 }
02d1d628
AMH
1869
1870 if ($opts{qtype} eq 'normal') {
4f579313 1871 $tmp->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
5168ca3a 1872 if ( !defined($tmp->{IMG}) ) {
4f579313 1873 $self->{ERRSTR} = 'unable to scale image';
5168ca3a
TC
1874 return undef;
1875 }
4f579313 1876 $img->{IMG}=i_scaleaxis($tmp->{IMG}, $scalefactor, 1);
5168ca3a
TC
1877 if ( !defined($img->{IMG}) ) {
1878 $self->{ERRSTR}='unable to scale image';
1879 return undef;
1880 }
1881
02d1d628
AMH
1882 return $img;
1883 }
5168ca3a 1884 elsif ($opts{'qtype'} eq 'preview') {
4f579313 1885 $img->{IMG} = i_scale_nn($self->{IMG}, $scalefactor, $scalefactor);
5168ca3a
TC
1886 if ( !defined($img->{IMG}) ) {
1887 $self->{ERRSTR}='unable to scale image';
1888 return undef;
1889 }
02d1d628
AMH
1890 return $img;
1891 }
5168ca3a
TC
1892 else {
1893 $self->_set_error('invalid value for qtype parameter');
1894 return undef;
1895 }
02d1d628
AMH
1896}
1897
1898# Scales only along the X axis
1899
1900sub scaleX {
15327bf5
TC
1901 my $self = shift;
1902 my %opts = ( scalefactor=>0.5, @_ );
02d1d628 1903
34b3f7e6
TC
1904 unless (defined wantarray) {
1905 my @caller = caller;
1906 warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
1907 return;
1908 }
1909
15327bf5
TC
1910 unless ($self->{IMG}) {
1911 $self->{ERRSTR} = 'empty input image';
1912 return undef;
1913 }
02d1d628
AMH
1914
1915 my $img = Imager->new();
1916
15327bf5 1917 my $scalefactor = $opts{scalefactor};
02d1d628 1918
15327bf5
TC
1919 if ($opts{pixels}) {
1920 $scalefactor = $opts{pixels} / $self->getwidth();
1921 }
1922
1923 unless ($self->{IMG}) {
1924 $self->{ERRSTR}='empty input image';
1925 return undef;
1926 }
1927
1928 $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
1929
1930 if ( !defined($img->{IMG}) ) {
1931 $self->{ERRSTR} = 'unable to scale image';
1932 return undef;
1933 }
02d1d628 1934
02d1d628
AMH
1935 return $img;
1936}
1937
1938# Scales only along the Y axis
1939
1940sub scaleY {
15327bf5
TC
1941 my $self = shift;
1942 my %opts = ( scalefactor => 0.5, @_ );
02d1d628 1943
34b3f7e6
TC
1944 unless (defined wantarray) {
1945 my @caller = caller;
1946 warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
1947 return;
1948 }
1949
02d1d628
AMH
1950 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1951
1952 my $img = Imager->new();
1953
15327bf5 1954 my $scalefactor = $opts{scalefactor};
02d1d628 1955
15327bf5
TC
1956 if ($opts{pixels}) {
1957 $scalefactor = $opts{pixels} / $self->getheight();
1958 }
1959
1960 unless ($self->{IMG}) {
1961 $self->{ERRSTR} = 'empty input image';
1962 return undef;
1963 }
1964 $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
1965
1966 if ( !defined($img->{IMG}) ) {
1967 $self->{ERRSTR} = 'unable to scale image';
1968 return undef;
1969 }
02d1d628 1970
02d1d628
AMH
1971 return $img;
1972}
1973
02d1d628
AMH
1974# Transform returns a spatial transformation of the input image
1975# this moves pixels to a new location in the returned image.
1976# NOTE - should make a utility function to check transforms for
1977# stack overruns
1978
1979sub transform {
1980 my $self=shift;
1981 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1982 my %opts=@_;
1983 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
1984
1985# print Dumper(\%opts);
1986# xopcopdes
1987
1988 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
1989 if (!$I2P) {
1990 eval ("use Affix::Infix2Postfix;");
1991 print $@;
1992 if ( $@ ) {
1993 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
1994 return undef;
1995 }
1996 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
1997 {op=>'-',trans=>'Sub'},
1998 {op=>'*',trans=>'Mult'},
1999 {op=>'/',trans=>'Div'},
9d540150 2000 {op=>'-','type'=>'unary',trans=>'u-'},
02d1d628 2001 {op=>'**'},
9d540150 2002 {op=>'func','type'=>'unary'}],
02d1d628
AMH
2003 'grouping'=>[qw( \( \) )],
2004 'func'=>[qw( sin cos )],
2005 'vars'=>[qw( x y )]
2006 );
2007 }
2008
2009 @xt=$I2P->translate($opts{'xexpr'});
2010 @yt=$I2P->translate($opts{'yexpr'});
2011
2012 $numre=$I2P->{'numre'};
2013 @pt=(0,0);
2014
2015 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
2016 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
2017 @{$opts{'parm'}}=@pt;
2018 }
2019
2020# print Dumper(\%opts);
2021
2022 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
2023 $self->{ERRSTR}='transform: no xopcodes given.';
2024 return undef;
2025 }
2026
2027 @op=@{$opts{'xopcodes'}};
2028 for $iop (@op) {
2029 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2030 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2031 return undef;
2032 }
2033 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2034 }
2035
2036
2037# yopcopdes
2038
2039 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
2040 $self->{ERRSTR}='transform: no yopcodes given.';
2041 return undef;
2042 }
2043
2044 @op=@{$opts{'yopcodes'}};
2045 for $iop (@op) {
2046 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2047 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2048 return undef;
2049 }
2050 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2051 }
2052
2053#parameters
2054
2055 if ( !exists $opts{'parm'}) {
2056 $self->{ERRSTR}='transform: no parameter arg given.';
2057 return undef;
2058 }
2059
2060# print Dumper(\@ropx);
2061# print Dumper(\@ropy);
2062# print Dumper(\@ropy);
2063
2064 my $img = Imager->new();
2065 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
2066 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
2067 return $img;
2068}
2069
2070
bf94b653
TC
2071sub transform2 {
2072 my ($opts, @imgs) = @_;
2073
2074 require "Imager/Expr.pm";
2075
2076 $opts->{variables} = [ qw(x y) ];
2077 my ($width, $height) = @{$opts}{qw(width height)};
2078 if (@imgs) {
2079 $width ||= $imgs[0]->getwidth();
2080 $height ||= $imgs[0]->getheight();
2081 my $img_num = 1;
2082 for my $img (@imgs) {
2083 $opts->{constants}{"w$img_num"} = $img->getwidth();
2084 $opts->{constants}{"h$img_num"} = $img->getheight();
2085 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
2086 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
2087 ++$img_num;
02d1d628 2088 }
02d1d628 2089 }
bf94b653
TC
2090 if ($width) {
2091 $opts->{constants}{w} = $width;
2092 $opts->{constants}{cx} = $width/2;
2093 }
2094 else {
2095 $Imager::ERRSTR = "No width supplied";
2096 return;
2097 }
2098 if ($height) {
2099 $opts->{constants}{h} = $height;
2100 $opts->{constants}{cy} = $height/2;
2101 }
2102 else {
2103 $Imager::ERRSTR = "No height supplied";
2104 return;
2105 }
2106 my $code = Imager::Expr->new($opts);
2107 if (!$code) {
2108 $Imager::ERRSTR = Imager::Expr::error();
2109 return;
2110 }
e5744e01
TC
2111 my $channels = $opts->{channels} || 3;
2112 unless ($channels >= 1 && $channels <= 4) {
2113 return Imager->_set_error("channels must be an integer between 1 and 4");
2114 }
9982a307 2115
bf94b653 2116 my $img = Imager->new();
e5744e01
TC
2117 $img->{IMG} = i_transform2($opts->{width}, $opts->{height},
2118 $channels, $code->code(),
bf94b653
TC
2119 $code->nregs(), $code->cregs(),
2120 [ map { $_->{IMG} } @imgs ]);
2121 if (!defined $img->{IMG}) {
2122 $Imager::ERRSTR = Imager->_error_as_msg();
2123 return;
2124 }
9982a307 2125
bf94b653 2126 return $img;
02d1d628
AMH
2127}
2128
02d1d628
AMH
2129sub rubthrough {
2130 my $self=shift;
71dc4a83 2131 my %opts=(tx => 0,ty => 0, @_);
02d1d628 2132
e7b95388
TC
2133 unless ($self->{IMG}) {
2134 $self->{ERRSTR}='empty input image';
2135 return undef;
2136 }
2137 unless ($opts{src} && $opts{src}->{IMG}) {
2138 $self->{ERRSTR}='empty input image for src';
2139 return undef;
2140 }
02d1d628 2141
71dc4a83
AMH
2142 %opts = (src_minx => 0,
2143 src_miny => 0,
2144 src_maxx => $opts{src}->getwidth(),
2145 src_maxy => $opts{src}->getheight(),
2146 %opts);
2147
2148 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
e7b95388
TC
2149 $opts{src_minx}, $opts{src_miny},
2150 $opts{src_maxx}, $opts{src_maxy})) {
2151 $self->_set_error($self->_error_as_msg());
faa9b3e7
TC
2152 return undef;
2153 }
02d1d628
AMH
2154 return $self;
2155}
2156
2157
142c26ff
AMH
2158sub flip {
2159 my $self = shift;
2160 my %opts = @_;
9191e525 2161 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
142c26ff
AMH
2162 my $dir;
2163 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
2164 $dir = $xlate{$opts{'dir'}};
2165 return $self if i_flipxy($self->{IMG}, $dir);
2166 return ();
2167}
2168
faa9b3e7
TC
2169sub rotate {
2170 my $self = shift;
2171 my %opts = @_;
34b3f7e6
TC
2172
2173 unless (defined wantarray) {
2174 my @caller = caller;
2175 warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
2176 return;
2177 }
2178
faa9b3e7
TC
2179 if (defined $opts{right}) {
2180 my $degrees = $opts{right};
2181 if ($degrees < 0) {
2182 $degrees += 360 * int(((-$degrees)+360)/360);
2183 }
2184 $degrees = $degrees % 360;
2185 if ($degrees == 0) {
2186 return $self->copy();
2187 }
2188 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
2189 my $result = Imager->new();
2190 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
2191 return $result;
2192 }
2193 else {
2194 $self->{ERRSTR} = $self->_error_as_msg();
2195 return undef;
2196 }
2197 }
2198 else {
2199 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
2200 return undef;
2201 }
2202 }
2203 elsif (defined $opts{radians} || defined $opts{degrees}) {
2204 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
2205
7f627571 2206 my $back = $opts{back};
faa9b3e7 2207 my $result = Imager->new;
7f627571
TC
2208 if ($back) {
2209 $back = _color($back);
2210 unless ($back) {
2211 $self->_set_error(Imager->errstr);
2212 return undef;
2213 }
2214
2215 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
0d3b936e
TC
2216 }
2217 else {
2218 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
2219 }
2220 if ($result->{IMG}) {
faa9b3e7
TC
2221 return $result;
2222 }
2223 else {
2224 $self->{ERRSTR} = $self->_error_as_msg();
2225 return undef;
2226 }
2227 }
2228 else {
0d3b936e 2229 $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available";
faa9b3e7
TC
2230 return undef;
2231 }
2232}
2233
2234sub matrix_transform {
2235 my $self = shift;
2236 my %opts = @_;
2237
34b3f7e6
TC
2238 unless (defined wantarray) {
2239 my @caller = caller;
2240 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
2241 return;
2242 }
2243
faa9b3e7
TC
2244 if ($opts{matrix}) {
2245 my $xsize = $opts{xsize} || $self->getwidth;
2246 my $ysize = $opts{ysize} || $self->getheight;
142c26ff 2247
faa9b3e7 2248 my $result = Imager->new;
0d3b936e
TC
2249 if ($opts{back}) {
2250 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2251 $opts{matrix}, $opts{back})
2252 or return undef;
2253 }
2254 else {
2255 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2256 $opts{matrix})
2257 or return undef;
2258 }
faa9b3e7
TC
2259
2260 return $result;
2261 }
2262 else {
2263 $self->{ERRSTR} = "matrix parameter required";
2264 return undef;
2265 }
2266}
2267
2268# blame Leolo :)
2269*yatf = \&matrix_transform;
02d1d628
AMH
2270
2271# These two are supported for legacy code only
2272
2273sub i_color_new {
faa9b3e7 2274 return Imager::Color->new(@_);
02d1d628
AMH
2275}
2276
2277sub i_color_set {
faa9b3e7 2278 return Imager::Color::set(@_);
02d1d628
AMH
2279}
2280
02d1d628 2281# Draws a box between the specified corner points.
02d1d628
AMH
2282sub box {
2283 my $self=shift;
2284 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2285 my $dflcl=i_color_new(255,255,255,255);
2286 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
2287
2288 if (exists $opts{'box'}) {
bf1573f9
TC
2289 $opts{'xmin'} = _min($opts{'box'}->[0],$opts{'box'}->[2]);
2290 $opts{'xmax'} = _max($opts{'box'}->[0],$opts{'box'}->[2]);
2291 $opts{'ymin'} = _min($opts{'box'}->[1],$opts{'box'}->[3]);
2292 $opts{'ymax'} = _max($opts{'box'}->[1],$opts{'box'}->[3]);
02d1d628
AMH
2293 }
2294
f1ac5027 2295 if ($opts{filled}) {
3a9a4241
TC
2296 my $color = _color($opts{'color'});
2297 unless ($color) {
2298 $self->{ERRSTR} = $Imager::ERRSTR;
2299 return;
2300 }
f1ac5027 2301 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
3a9a4241 2302 $opts{ymax}, $color);
f1ac5027
TC
2303 }
2304 elsif ($opts{fill}) {
2305 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2306 # assume it's a hash ref
2307 require 'Imager/Fill.pm';
141a6114
TC
2308 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2309 $self->{ERRSTR} = $Imager::ERRSTR;
2310 return undef;
2311 }
f1ac5027
TC
2312 }
2313 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2314 $opts{ymax},$opts{fill}{fill});
2315 }
cdd23610 2316 else {
3a9a4241
TC
2317 my $color = _color($opts{'color'});
2318 unless ($color) {
cdd23610
AMH
2319 $self->{ERRSTR} = $Imager::ERRSTR;
2320 return;
3a9a4241
TC
2321 }
2322 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
2323 $color);
f1ac5027 2324 }
02d1d628
AMH
2325 return $self;
2326}
2327
02d1d628
AMH
2328sub arc {
2329 my $self=shift;
2330 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2331 my $dflcl=i_color_new(255,255,255,255);
2332 my %opts=(color=>$dflcl,
bf1573f9 2333 'r'=>_min($self->getwidth(),$self->getheight())/3,
02d1d628
AMH
2334 'x'=>$self->getwidth()/2,
2335 'y'=>$self->getheight()/2,
2336 'd1'=>0, 'd2'=>361, @_);
a8652edf
TC
2337 if ($opts{aa}) {
2338 if ($opts{fill}) {
2339 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2340 # assume it's a hash ref
2341 require 'Imager/Fill.pm';
2342 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2343 $self->{ERRSTR} = $Imager::ERRSTR;
2344 return;
2345 }
2346 }
2347 i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2348 $opts{'d2'}, $opts{fill}{fill});
2349 }
2350 else {
2351 my $color = _color($opts{'color'});
2352 unless ($color) {
2353 $self->{ERRSTR} = $Imager::ERRSTR;
2354 return;
2355 }
2356 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
2357 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
2358 $color);
2359 }
2360 else {
2361 i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2362 $opts{'d1'}, $opts{'d2'}, $color);
569795e8 2363 }
f1ac5027 2364 }
f1ac5027
TC
2365 }
2366 else {
a8652edf
TC
2367 if ($opts{fill}) {
2368 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2369 # assume it's a hash ref
2370 require 'Imager/Fill.pm';
2371 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2372 $self->{ERRSTR} = $Imager::ERRSTR;
2373 return;
2374 }
2375 }
2376 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2377 $opts{'d2'}, $opts{fill}{fill});
0d321238
TC
2378 }
2379 else {
a8652edf
TC
2380 my $color = _color($opts{'color'});
2381 unless ($color) {
2382 $self->{ERRSTR} = $Imager::ERRSTR;
2383 return;
2384 }
c5baef69
TC
2385 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2386 $opts{'d1'}, $opts{'d2'}, $color);
0d321238 2387 }
f1ac5027
TC
2388 }
2389
02d1d628
AMH
2390 return $self;
2391}
2392
aa833c97
AMH
2393# Draws a line from one point to the other
2394# the endpoint is set if the endp parameter is set which it is by default.
2395# to turn of the endpoint being set use endp=>0 when calling line.
02d1d628
AMH
2396
2397sub line {
2398 my $self=shift;
2399 my $dflcl=i_color_new(0,0,0,0);
aa833c97
AMH
2400 my %opts=(color=>$dflcl,
2401 endp => 1,
2402 @_);
02d1d628
AMH
2403 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2404
2405 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2406 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2407
3a9a4241 2408 my $color = _color($opts{'color'});
aa833c97
AMH
2409 unless ($color) {
2410 $self->{ERRSTR} = $Imager::ERRSTR;
2411 return;
3a9a4241 2412 }
aa833c97 2413
3a9a4241 2414 $opts{antialias} = $opts{aa} if defined $opts{aa};
02d1d628 2415 if ($opts{antialias}) {
aa833c97 2416 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
b437ce0a 2417 $color, $opts{endp});
02d1d628 2418 } else {
aa833c97
AMH
2419 i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2420 $color, $opts{endp});
02d1d628
AMH
2421 }
2422 return $self;
2423}
2424
2425# Draws a line between an ordered set of points - It more or less just transforms this
2426# into a list of lines.
2427
2428sub polyline {
2429 my $self=shift;
2430 my ($pt,$ls,@points);
2431 my $dflcl=i_color_new(0,0,0,0);
2432 my %opts=(color=>$dflcl,@_);
2433
2434 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2435
2436 if (exists($opts{points})) { @points=@{$opts{points}}; }
2437 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2438 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2439 }
2440
2441# print Dumper(\@points);
2442
3a9a4241
TC
2443 my $color = _color($opts{'color'});
2444 unless ($color) {
2445 $self->{ERRSTR} = $Imager::ERRSTR;
2446 return;
2447 }
2448 $opts{antialias} = $opts{aa} if defined $opts{aa};
02d1d628
AMH
2449 if ($opts{antialias}) {
2450 for $pt(@points) {
3a9a4241 2451 if (defined($ls)) {
b437ce0a 2452 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1);
3a9a4241 2453 }
02d1d628
AMH
2454 $ls=$pt;
2455 }
2456 } else {
2457 for $pt(@points) {
3a9a4241 2458 if (defined($ls)) {
aa833c97 2459 i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1);
3a9a4241 2460 }
02d1d628
AMH
2461 $ls=$pt;
2462 }
2463 }
2464 return $self;
2465}
2466
d0e7bfee
AMH
2467sub polygon {
2468 my $self = shift;
2469 my ($pt,$ls,@points);
2470 my $dflcl = i_color_new(0,0,0,0);
2471 my %opts = (color=>$dflcl, @_);
2472
2473 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2474
2475 if (exists($opts{points})) {
2476 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2477 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2478 }
2479
2480 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2481 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2482 }
2483
43c5dacb
TC
2484 if ($opts{'fill'}) {
2485 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2486 # assume it's a hash ref
2487 require 'Imager/Fill.pm';
2488 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2489 $self->{ERRSTR} = $Imager::ERRSTR;
2490 return undef;
2491 }
2492 }
2493 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2494 $opts{'fill'}{'fill'});
2495 }
2496 else {
3a9a4241
TC
2497 my $color = _color($opts{'color'});
2498 unless ($color) {
2499 $self->{ERRSTR} = $Imager::ERRSTR;
2500 return;
2501 }
2502 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
43c5dacb
TC
2503 }
2504
d0e7bfee
AMH
2505 return $self;
2506}
2507
2508
2509# this the multipoint bezier curve
02d1d628
AMH
2510# this is here more for testing that actual usage since
2511# this is not a good algorithm. Usually the curve would be
2512# broken into smaller segments and each done individually.
2513
2514sub polybezier {
2515 my $self=shift;
2516 my ($pt,$ls,@points);
2517 my $dflcl=i_color_new(0,0,0,0);
2518 my %opts=(color=>$dflcl,@_);
2519
2520 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2521
2522 if (exists $opts{points}) {
2523 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2524 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2525 }
2526
2527 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2528 $self->{ERRSTR}='Missing or invalid points.';
2529 return;
2530 }
2531
3a9a4241
TC
2532 my $color = _color($opts{'color'});
2533 unless ($color) {
2534 $self->{ERRSTR} = $Imager::ERRSTR;
2535 return;
2536 }
2537 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
02d1d628
AMH
2538 return $self;
2539}
2540
cc6483e0
TC
2541sub flood_fill {
2542 my $self = shift;
2543 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
aa833c97
AMH
2544 my $rc;
2545
9d540150 2546 unless (exists $opts{'x'} && exists $opts{'y'}) {
cc6483e0
TC
2547 $self->{ERRSTR} = "missing seed x and y parameters";
2548 return undef;
2549 }
07d70837 2550
cc6483e0
TC
2551 if ($opts{fill}) {
2552 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2553 # assume it's a hash ref
2554 require 'Imager/Fill.pm';
569795e8
TC
2555 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2556 $self->{ERRSTR} = $Imager::ERRSTR;
2557 return;
2558 }
cc6483e0 2559 }
a321d497 2560 $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
cc6483e0
TC
2561 }
2562 else {
3a9a4241 2563 my $color = _color($opts{'color'});
aa833c97
AMH
2564 unless ($color) {
2565 $self->{ERRSTR} = $Imager::ERRSTR;
2566 return;
3a9a4241 2567 }
a321d497 2568 $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
cc6483e0 2569 }
aa833c97 2570 if ($rc) { $self; } else { $self->{ERRSTR} = $self->_error_as_msg(); return (); }
cc6483e0
TC
2571}
2572
591b5954
TC
2573sub setpixel {
2574 my $self = shift;
2575
2576 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2577
2578 unless (exists $opts{'x'} && exists $opts{'y'}) {
2579 $self->{ERRSTR} = 'missing x and y parameters';
2580 return undef;
2581 }
2582
2583 my $x = $opts{'x'};
2584 my $y = $opts{'y'};
2585 my $color = _color($opts{color})
2586 or return undef;
2587 if (ref $x && ref $y) {
2588 unless (@$x == @$y) {
9650c424 2589 $self->{ERRSTR} = 'length of x and y mismatch';
591b5954
TC
2590 return undef;
2591 }
2592 if ($color->isa('Imager::Color')) {
2593 for my $i (0..$#{$opts{'x'}}) {
2594 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color);
2595 }
2596 }
2597 else {
2598 for my $i (0..$#{$opts{'x'}}) {
2599 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color);
2600 }
2601 }
2602 }
2603 else {
2604 if ($color->isa('Imager::Color')) {
2605 i_ppix($self->{IMG}, $x, $y, $color);
2606 }
2607 else {
2608 i_ppixf($self->{IMG}, $x, $y, $color);
2609 }
2610 }
2611
2612 $self;
2613}
2614
2615sub getpixel {
2616 my $self = shift;
2617
a9fa203f 2618 my %opts = ( "type"=>'8bit', @_);
591b5954
TC
2619
2620 unless (exists $opts{'x'} && exists $opts{'y'}) {
2621 $self->{ERRSTR} = 'missing x and y parameters';
2622 return undef;
2623 }
2624
2625 my $x = $opts{'x'};
2626 my $y = $opts{'y'};
2627 if (ref $x && ref $y) {
2628 unless (@$x == @$y) {
2629 $self->{ERRSTR} = 'length of x and y mismatch';
2630 return undef;
2631 }
2632 my @result;
a9fa203f 2633 if ($opts{"type"} eq '8bit') {
591b5954
TC
2634 for my $i (0..$#{$opts{'x'}}) {
2635 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2636 }
2637 }
2638 else {
2639 for my $i (0..$#{$opts{'x'}}) {
2640 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2641 }
2642 }
2643 return wantarray ? @result : \@result;
2644 }
2645 else {
a9fa203f 2646 if ($opts{"type"} eq '8bit') {
591b5954
TC
2647 return i_get_pixel($self->{IMG}, $x, $y);
2648 }
2649 else {
2650 return i_gpixf($self->{IMG}, $x, $y);
2651 }
2652 }
2653
2654 $self;
2655}
2656
ca4d914e
TC
2657sub getscanline {
2658 my $self = shift;
2659 my %opts = ( type => '8bit', x=>0, @_);
2660
2661 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2662
2663 unless (defined $opts{'y'}) {
2664 $self->_set_error("missing y parameter");
2665 return;
2666 }
2667
2668 if ($opts{type} eq '8bit') {
2669 return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2670 $opts{y});
2671 }
2672 elsif ($opts{type} eq 'float') {
2673 return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2674 $opts{y});
2675 }
2676 else {
2677 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2678 return;
2679 }
2680}
2681
2682sub setscanline {
2683 my $self = shift;
2684 my %opts = ( x=>0, @_);
2685
2686 unless (defined $opts{'y'}) {
2687 $self->_set_error("missing y parameter");
2688 return;
2689 }
2690
2691 if (!$opts{type}) {
2692 if (ref $opts{pixels} && @{$opts{pixels}}) {
2693 # try to guess the type
2694 if ($opts{pixels}[0]->isa('Imager::Color')) {
2695 $opts{type} = '8bit';
2696 }
2697 elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
2698 $opts{type} = 'float';
2699 }
2700 else {
2701 $self->_set_error("missing type parameter and could not guess from pixels");
2702 return;
2703 }
2704 }
2705 else {
2706 # default
2707 $opts{type} = '8bit';
2708 }
2709 }
2710
2711 if ($opts{type} eq '8bit') {
2712 if (ref $opts{pixels}) {
2713 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2714 }
2715 else {
2716 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2717 }
2718 }
2719 elsif ($opts{type} eq 'float') {
2720 if (ref $opts{pixels}) {
2721 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2722 }
2723 else {
2724 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2725 }
2726 }
2727 else {
2728 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2729 return;
2730 }
2731}
2732
2733sub getsamples {
2734 my $self = shift;
2735 my %opts = ( type => '8bit', x=>0, @_);
2736
2737 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2738
2739 unless (defined $opts{'y'}) {
2740 $self->_set_error("missing y parameter");
2741 return;
2742 }
2743
2744 unless ($opts{channels}) {
2745 $opts{channels} = [ 0 .. $self->getchannels()-1 ];
2746 }
2747
2748 if ($opts{type} eq '8bit') {
2749 return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2750 $opts{y}, @{$opts{channels}});
2751 }
2752 elsif ($opts{type} eq 'float') {
2753 return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2754 $opts{y}, @{$opts{channels}});
2755 }
2756 else {
2757 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2758 return;
2759 }
2760}
2761
f5991c03
TC
2762# make an identity matrix of the given size
2763sub _identity {
2764 my ($size) = @_;
2765
2766 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
2767 for my $c (0 .. ($size-1)) {
2768 $matrix->[$c][$c] = 1;
2769 }
2770 return $matrix;
2771}
2772
2773# general function to convert an image
2774sub convert {
2775 my ($self, %opts) = @_;
2776 my $matrix;
2777
34b3f7e6
TC
2778 unless (defined wantarray) {
2779 my @caller = caller;
2780 warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
2781 return;
2782 }
2783
f5991c03
TC
2784 # the user can either specify a matrix or preset
2785 # the matrix overrides the preset
2786 if (!exists($opts{matrix})) {
2787 unless (exists($opts{preset})) {
2788 $self->{ERRSTR} = "convert() needs a matrix or preset";
2789 return;
2790 }
2791 else {
2792 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
2793 # convert to greyscale, keeping the alpha channel if any
2794 if ($self->getchannels == 3) {
2795 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
2796 }
2797 elsif ($self->getchannels == 4) {
2798 # preserve the alpha channel
2799 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
2800 [ 0, 0, 0, 1 ] ];
2801 }
2802 else {
2803 # an identity
2804 $matrix = _identity($self->getchannels);
2805 }
2806 }
2807 elsif ($opts{preset} eq 'noalpha') {
2808 # strip the alpha channel
2809 if ($self->getchannels == 2 or $self->getchannels == 4) {
2810 $matrix = _identity($self->getchannels);
2811 pop(@$matrix); # lose the alpha entry
2812 }
2813 else {
2814 $matrix = _identity($self->getchannels);
2815 }
2816 }
2817 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
2818 # extract channel 0
2819 $matrix = [ [ 1 ] ];
2820 }
2821 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
2822 $matrix = [ [ 0, 1 ] ];
2823 }
2824 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
2825 $matrix = [ [ 0, 0, 1 ] ];
2826 }
2827 elsif ($opts{preset} eq 'alpha') {
2828 if ($self->getchannels == 2 or $self->getchannels == 4) {
2829 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
2830 }
2831 else {
2832 # the alpha is just 1 <shrug>
2833 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
2834 }
2835 }
2836 elsif ($opts{preset} eq 'rgb') {
2837 if ($self->getchannels == 1) {
2838 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
2839 }
2840 elsif ($self->getchannels == 2) {
2841 # preserve the alpha channel
2842 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
2843 }
2844 else {
2845 $matrix = _identity($self->getchannels);
2846 }
2847 }
2848 elsif ($opts{preset} eq 'addalpha') {
2849 if ($self->getchannels == 1) {
2850 $matrix = _identity(2);
2851 }
2852 elsif ($self->getchannels == 3) {
2853 $matrix = _identity(4);
2854 }
2855 else {
2856 $matrix = _identity($self->getchannels);
2857 }
2858 }
2859 else {
2860 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
2861 return undef;
2862 }
2863 }
2864 }
2865 else {
2866 $matrix = $opts{matrix};
2867 }
2868
2869 my $new = Imager->new();
2870 $new->{IMG} = i_img_new();
2871 unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
2872 # most likely a bad matrix
2873 $self->{ERRSTR} = _error_as_msg();
2874 return undef;
2875 }
2876 return $new;
2877}
40eba1ea
AMH
2878
2879
40eba1ea 2880# general function to map an image through lookup tables
9495ee93 2881
40eba1ea
AMH
2882sub map {
2883 my ($self, %opts) = @_;
9495ee93 2884 my @chlist = qw( red green blue alpha );
40eba1ea
AMH
2885
2886 if (!exists($opts{'maps'})) {
2887 # make maps from channel maps
2888 my $chnum;
2889 for $chnum (0..$#chlist) {
9495ee93
AMH
2890 if (exists $opts{$chlist[$chnum]}) {
2891 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
2892 } elsif (exists $opts{'all'}) {
2893 $opts{'maps'}[$chnum] = $opts{'all'};
2894 }
40eba1ea
AMH
2895 }
2896 }
2897 if ($opts{'maps'} and $self->{IMG}) {
2898 i_map($self->{IMG}, $opts{'maps'} );
2899 }
2900 return $self;
2901}
2902
dff75dee
TC
2903sub difference {
2904 my ($self, %opts) = @_;
2905
2906 defined $opts{mindist} or $opts{mindist} = 0;
2907
2908 defined $opts{other}
2909 or return $self->_set_error("No 'other' parameter supplied");
2910 defined $opts{other}{IMG}
2911 or return $self->_set_error("No image data in 'other' image");
2912
2913 $self->{IMG}
2914 or return $self->_set_error("No image data");
2915
2916 my $result = Imager->new;
2917 $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
2918 $opts{mindist})
2919 or return $self->_set_error($self->_error_as_msg());
2920
2921 return $result;
2922}
2923
02d1d628
AMH
2924# destructive border - image is shrunk by one pixel all around
2925
2926sub border {
2927 my ($self,%opts)=@_;
2928 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
2929 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
2930}
2931
2932
2933# Get the width of an image
2934
2935sub getwidth {
2936 my $self = shift;
2937 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2938 return (i_img_info($self->{IMG}))[0];
2939}
2940
2941# Get the height of an image
2942
2943sub getheight {
2944 my $self = shift;
2945 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2946 return (i_img_info($self->{IMG}))[1];
2947}
2948
2949# Get number of channels in an image
2950
2951sub getchannels {
2952 my $self = shift;
2953 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2954 return i_img_getchannels($self->{IMG});
2955}
2956
2957# Get channel mask
2958
2959sub getmask {
2960 my $self = shift;
2961 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2962 return i_img_getmask($self->{IMG});
2963}
2964
2965# Set channel mask
2966
2967sub setmask {
2968 my $self = shift;
2969 my %opts = @_;
35f40526
TC
2970 if (!defined($self->{IMG})) {
2971 $self->{ERRSTR} = 'image is empty';
2972 return undef;
2973 }
2974 unless (defined $opts{mask}) {
2975 $self->_set_error("mask parameter required");
2976 return;
2977 }
02d1d628 2978 i_img_setmask( $self->{IMG} , $opts{mask} );
35f40526
TC
2979
2980 1;
02d1d628
AMH
2981}
2982
2983# Get number of colors in an image
2984
2985sub getcolorcount {
2986 my $self=shift;
9d540150 2987 my %opts=('maxcolors'=>2**30,@_);
02d1d628
AMH
2988 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
2989 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
2990 return ($rc==-1? undef : $rc);
2991}
2992
2993# draw string to an image
2994
2995sub string {
2996 my $self = shift;
2997 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2998
2999 my %input=('x'=>0, 'y'=>0, @_);
3000 $input{string}||=$input{text};
3001
e922ae66 3002 unless(defined $input{string}) {
02d1d628
AMH
3003 $self->{ERRSTR}="missing required parameter 'string'";
3004 return;
3005 }
3006
3007 unless($input{font}) {
3008 $self->{ERRSTR}="missing required parameter 'font'";
3009 return;
3010 }
3011
faa9b3e7 3012 unless ($input{font}->draw(image=>$self, %input)) {
faa9b3e7
TC
3013 return;
3014 }
02d1d628
AMH
3015
3016 return $self;
3017}
3018
a7ccc5e2
TC
3019sub align_string {
3020 my $self = shift;
e922ae66
TC
3021
3022 my $img;
3023 if (ref $self) {
3024 unless ($self->{IMG}) {
3025 $self->{ERRSTR}='empty input image';
3026 return;
3027 }
c9cb3397 3028 $img = $self;
e922ae66
TC
3029 }
3030 else {
3031 $img = undef;
3032 }
a7ccc5e2
TC
3033
3034 my %input=('x'=>0, 'y'=>0, @_);
3035 $input{string}||=$input{text};
3036
3037 unless(exists $input{string}) {
e922ae66 3038 $self->_set_error("missing required parameter 'string'");
a7ccc5e2
TC
3039 return;
3040 }
3041
3042 unless($input{font}) {
e922ae66 3043 $self->_set_error("missing required parameter 'font'");
a7ccc5e2
TC
3044 return;
3045 }
3046
3047 my @result;
e922ae66 3048 unless (@result = $input{font}->align(image=>$img, %input)) {
a7ccc5e2
TC
3049 return;
3050 }
3051
3052 return wantarray ? @result : $result[0];
3053}
3054
77157728
TC
3055my @file_limit_names = qw/width height bytes/;
3056
3057sub set_file_limits {
3058 shift;
3059
3060 my %opts = @_;
3061 my %values;
3062
3063 if ($opts{reset}) {
3064 @values{@file_limit_names} = (0) x @file_limit_names;
3065 }
3066 else {
3067 @values{@file_limit_names} = i_get_image_file_limits();
3068 }
3069
3070 for my $key (keys %values) {
3071 defined $opts{$key} and $values{$key} = $opts{$key};
3072 }
3073
3074 i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
3075}
3076
3077sub get_file_limits {
3078 i_get_image_file_limits();
3079}
3080
02d1d628
AMH
3081# Shortcuts that can be exported
3082
3083sub newcolor { Imager::Color->new(@_); }
3084sub newfont { Imager::Font->new(@_); }
3085
3086*NC=*newcolour=*newcolor;
3087*NF=*newfont;
3088
3089*open=\&read;
3090*circle=\&arc;
3091
3092
3093#### Utility routines
3094
faa9b3e7
TC
3095sub errstr {
3096 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
3097}
02d1d628 3098
10461f9a
TC
3099sub _set_error {
3100 my ($self, $msg) = @_;
3101
3102 if (ref $self) {
3103 $self->{ERRSTR} = $msg;
3104 }
3105 else {
3106 $ERRSTR = $msg;
3107 }
dff75dee 3108 return;
10461f9a
TC
3109}
3110
02d1d628
AMH
3111# Default guess for the type of an image from extension
3112
3113sub def_guess_type {
3114 my $name=lc(shift);
3115 my $ext;
3116 $ext=($name =~ m/\.([^\.]+)$/)[0];
3117 return 'tiff' if ($ext =~ m/^tiff?$/);
3118 return 'jpeg' if ($ext =~ m/^jpe?g$/);
3119 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
3120 return 'png' if ($ext eq "png");
705fd961 3121 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
1ec86afa 3122 return 'tga' if ($ext eq "tga");
737a830c 3123 return 'rgb' if ($ext eq "rgb");
02d1d628 3124 return 'gif' if ($ext eq "gif");
10461f9a 3125 return 'raw' if ($ext eq "raw");
02d1d628
AMH
3126 return ();
3127}
3128
3129# get the minimum of a list
3130
bf1573f9 3131sub _min {
02d1d628
AMH
3132 my $mx=shift;
3133 for(@_) { if ($_<$mx) { $mx=$_; }}
3134 return $mx;
3135}
3136
3137# get the maximum of a list
3138
bf1573f9 3139sub _max {
02d1d628
AMH
3140 my $mx=shift;
3141 for(@_) { if ($_>$mx) { $mx=$_; }}
3142 return $mx;
3143}
3144
3145# string stuff for iptc headers
3146
bf1573f9 3147sub _clean {
02d1d628
AMH
3148 my($str)=$_[0];
3149 $str = substr($str,3);
3150 $str =~ s/[\n\r]//g;
3151 $str =~ s/\s+/ /g;
3152 $str =~ s/^\s//;
3153 $str =~ s/\s$//;
3154 return $str;
3155}
3156
3157# A little hack to parse iptc headers.
3158
3159sub parseiptc {
3160 my $self=shift;
3161 my(@sar,$item,@ar);
3162 my($caption,$photogr,$headln,$credit);
3163
3164 my $str=$self->{IPTCRAW};
3165
24ae6325
TC
3166 defined $str
3167 or return;
02d1d628
AMH
3168
3169 @ar=split(/8BIM/,$str);
3170
3171 my $i=0;
3172 foreach (@ar) {
3173 if (/^\004\004/) {
3174 @sar=split(/\034\002/);
3175 foreach $item (@sar) {
cdd23610 3176 if ($item =~ m/^x/) {
bf1573f9 3177 $caption = _clean($item);
02d1d628
AMH
3178 $i++;
3179 }
cdd23610 3180 if ($item =~ m/^P/) {
bf1573f9 3181 $photogr = _clean($item);
02d1d628
AMH
3182 $i++;
3183 }
cdd23610 3184 if ($item =~ m/^i/) {
bf1573f9 3185 $headln = _clean($item);
02d1d628
AMH
3186 $i++;
3187 }
cdd23610 3188 if ($item =~ m/^n/) {
bf1573f9 3189 $credit = _clean($item);
02d1d628
AMH
3190 $i++;
3191 }
3192 }
3193 }
3194 }
3195 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
3196}
3197
92bda632
TC
3198sub Inline {
3199 my ($lang) = @_;
3200
3201 $lang eq 'C'
3202 or die "Only C language supported";
3203
3204 require Imager::ExtUtils;
3205 return Imager::ExtUtils->inline_config;
3206}
02d1d628
AMH
3207
32081;
3209__END__
3210# Below is the stub of documentation for your module. You better edit it!
3211
3212=head1 NAME
3213
3214Imager - Perl extension for Generating 24 bit Images
3215
3216=head1 SYNOPSIS
3217
0e418f1e
AMH
3218 # Thumbnail example
3219
3220 #!/usr/bin/perl -w
3221 use strict;
10461f9a 3222 use Imager;
02d1d628 3223
0e418f1e
AMH
3224 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
3225 my $file = shift;
3226
3227 my $format;
3228
3229 my $img = Imager->new();
e36d02ad
TC
3230 # see Imager::Files for information on the read() method
3231 $img->read(file=>$file) or die $img->errstr();
0e418f1e
AMH
3232
3233 $file =~ s/\.[^.]*$//;
3234
3235 # Create smaller version
cf7a7d18 3236 # documented in Imager::Transformations
0e418f1e
AMH
3237 my $thumb = $img->scale(scalefactor=>.3);
3238
3239 # Autostretch individual channels
3240 $thumb->filter(type=>'autolevels');
3241
3242 # try to save in one of these formats
3243 SAVE:
3244
3245 for $format ( qw( png gif jpg tiff ppm ) ) {
3246 # Check if given format is supported
3247 if ($Imager::formats{$format}) {
3248 $file.="_low.$format";
3249 print "Storing image as: $file\n";
cf7a7d18 3250 # documented in Imager::Files
0e418f1e
AMH
3251 $thumb->write(file=>$file) or
3252 die $thumb->errstr;
3253 last SAVE;
3254 }
3255 }
3256
02d1d628
AMH
3257=head1 DESCRIPTION
3258
0e418f1e
AMH
3259Imager is a module for creating and altering images. It can read and
3260write various image formats, draw primitive shapes like lines,and
3261polygons, blend multiple images together in various ways, scale, crop,
3262render text and more.
02d1d628 3263
5df0fac7
AMH
3264=head2 Overview of documentation
3265
3266=over
3267
cf7a7d18 3268=item *
5df0fac7 3269
cf7a7d18
TC
3270Imager - This document - Synopsis Example, Table of Contents and
3271Overview.
5df0fac7 3272
cf7a7d18 3273=item *
5df0fac7 3274
985bda61
TC
3275L<Imager::Tutorial> - a brief introduction to Imager.
3276
3277=item *
3278
e1d57e9d
TC
3279L<Imager::Cookbook> - how to do various things with Imager.
3280
3281=item *
3282
cf7a7d18
TC
3283L<Imager::ImageTypes> - Basics of constructing image objects with
3284C<new()>: Direct type/virtual images, RGB(A)/paletted images,
32858/16/double bits/channel, color maps, channel masks, image tags, color
6d0ed98a 3286quantization. Also discusses basic image information methods.
5df0fac7 3287
cf7a7d18 3288=item *
5df0fac7 3289
cf7a7d18
TC
3290L<Imager::Files> - IO interaction, reading/writing images, format
3291specific tags.
5df0fac7 3292
cf7a7d18 3293=item *
5df0fac7 3294
cf7a7d18
TC
3295L<Imager::Draw> - Drawing Primitives, lines, boxes, circles, arcs,
3296flood fill.
5df0fac7 3297
cf7a7d18 3298=item *
5df0fac7 3299
cf7a7d18 3300L<Imager::Color> - Color specification.
5df0fac7 3301
cf7a7d18 3302=item *
f5fd108b 3303
cf7a7d18 3304L<Imager::Fill> - Fill pattern specification.
f5fd108b 3305
cf7a7d18 3306=item *
5df0fac7 3307
cf7a7d18
TC
3308L<Imager::Font> - General font rendering, bounding boxes and font
3309metrics.
5df0fac7 3310
cf7a7d18 3311=item *
5df0fac7 3312
cf7a7d18
TC
3313L<Imager::Transformations> - Copying, scaling, cropping, flipping,
3314blending, pasting, convert and map.
5df0fac7 3315
cf7a7d18 3316=item *
5df0fac7 3317
cf7a7d18
TC
3318L<Imager::Engines> - Programmable transformations through
3319C<transform()>, C<transform2()> and C<matrix_transform()>.
5df0fac7 3320
cf7a7d18 3321=item *
5df0fac7 3322
cf7a7d18
TC
3323L<Imager::Filters> - Filters, sharpen, blur, noise, convolve etc. and
3324filter plugins.
5df0fac7 3325
cf7a7d18 3326=item *
5df0fac7 3327
cf7a7d18
TC
3328L<Imager::Expr> - Expressions for evaluation engine used by
3329transform2().
5df0fac7 3330
cf7a7d18 3331=item *
5df0fac7 3332
cf7a7d18 3333L<Imager::Matrix2d> - Helper class for affine transformations.
5df0fac7 3334
cf7a7d18 3335=item *
5df0fac7 3336
cf7a7d18 3337L<Imager::Fountain> - Helper for making gradient profiles.
5df0fac7 3338
92bda632
TC
3339=item *
3340
3341L<Imager::API> - using Imager's C API
3342
3343=item *
3344
3345L<Imager::APIRef> - API function reference
3346
3347=item *
3348
3349L<Imager::Inline> - using Imager's C API from Inline::C
3350
3351=item *
3352
3353L<Imager::ExtUtils> - tools to get access to Imager's C API.
3354
5df0fac7
AMH
3355=back
3356
0e418f1e 3357=head2 Basic Overview
02d1d628 3358
55b287f5
AMH
3359An Image object is created with C<$img = Imager-E<gt>new()>.
3360Examples:
02d1d628 3361
55b287f5 3362 $img=Imager->new(); # create empty image
e36d02ad 3363 $img->read(file=>'lena.png',type=>'png') or # read image from file
55b287f5
AMH
3364 die $img->errstr(); # give an explanation
3365 # if something failed
02d1d628
AMH
3366
3367or if you want to create an empty image:
3368
3369 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
3370
0e418f1e
AMH
3371This example creates a completely black image of width 400 and height
3372300 and 4 channels.
3373
55b287f5
AMH
3374When an operation fails which can be directly associated with an image
3375the error message is stored can be retrieved with
3376C<$img-E<gt>errstr()>.
3377
3378In cases where no image object is associated with an operation
3379C<$Imager::ERRSTR> is used to report errors not directly associated
99958502
TC
3380with an image object. You can also call C<Imager->errstr> to get this
3381value.
55b287f5 3382
cf7a7d18
TC
3383The C<Imager-E<gt>new> method is described in detail in
3384L<Imager::ImageTypes>.
4b4f5319 3385
13fc481e
TC
3386=head1 METHOD INDEX
3387
3388Where to find information on methods for Imager class objects.
3389
4b3408a5 3390addcolors() - L<Imager::ImageTypes/addcolors>
13fc481e 3391
4b3408a5 3392addtag() - L<Imager::ImageTypes/addtag> - add image tags
13fc481e
TC
3393
3394arc() - L<Imager::Draw/arc>
3395
a7ccc5e2
TC
3396align_string() - L<Imager::Draw/align_string>
3397
4b3408a5 3398bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
13fc481e
TC
3399image
3400
3401box() - L<Imager::Draw/box>
3402
3403circle() - L<Imager::Draw/circle>
3404
feac660c
TC
3405colorcount() - L<Imager::Draw/colorcount>
3406
13fc481e
TC
3407convert() - L<Imager::Transformations/"Color transformations"> -
3408transform the color space
3409
3410copy() - L<Imager::Transformations/copy>
3411
3412crop() - L<Imager::Transformations/crop> - extract part of an image
3413
4b3408a5 3414deltag() - L<Imager::ImageTypes/deltag> - delete image tags
13fc481e
TC
3415
3416difference() - L<Imager::Filters/"Image Difference">
3417
e922ae66 3418errstr() - L<"Basic Overview">
99958502 3419
13fc481e
TC
3420filter() - L<Imager::Filters>
3421
4b3408a5 3422findcolor() - L<Imager::ImageTypes/findcolor> - search the image palette, if it
13fc481e
TC
3423has one
3424
3425flip() - L<Imager::Transformations/flip>
3426
3427flood_fill() - L<Imager::Draw/flood_fill>
3428
4b3408a5 3429getchannels() - L<Imager::ImageTypes/getchannels>
13fc481e 3430
4b3408a5 3431getcolorcount() - L<Imager::ImageTypes/getcolorcount>
13fc481e 3432
4b3408a5 3433getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
13fc481e
TC
3434palette, if it has one
3435
77157728
TC
3436get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3437
4b3408a5 3438getheight() - L<Imager::ImageTypes/getwidth>
13fc481e 3439
a7ccc5e2 3440getpixel() - L<Imager::Draw/getpixel>
13fc481e 3441
ca4d914e
TC
3442getsamples() - L<Imager::Draw/getsamples>
3443
3444getscanline() - L<Imager::Draw/getscanline>
3445
4b3408a5 3446getwidth() - L<Imager::ImageTypes/getwidth>
13fc481e 3447
4b3408a5 3448img_set() - L<Imager::ImageTypes/img_set>
13fc481e
TC
3449
3450line() - L<Imager::Draw/line>
3451
3452map() - L<Imager::Transformations/"Color Mappings"> - remap color
3453channel values
3454
4b3408a5 3455masked() - L<Imager::ImageTypes/masked> - make a masked image
13fc481e 3456
58a9ba58 3457matrix_transform() - L<Imager::Engines/matrix_transform>
13fc481e 3458
4b3408a5 3459maxcolors() - L<Imager::ImageTypes/maxcolors>
feac660c 3460
4b3408a5 3461new() - L<Imager::ImageTypes/new>
13fc481e 3462
e36d02ad
TC
3463open() - L<Imager::Files> - an alias for read()
3464
13fc481e
TC
3465paste() - L<Imager::Transformations/paste> - draw an image onto an image
3466
3467polygon() - L<Imager::Draw/polygon>
3468
3469polyline() - L<Imager::Draw/polyline>
3470
e36d02ad 3471read() - L<Imager::Files> - read a single image from an image file
13fc481e 3472
e36d02ad
TC
3473read_multi() - L<Imager::Files> - read multiple images from an image
3474file
13fc481e
TC
3475
3476rotate() - L<Imager::Transformations/rotate>
3477
3478rubthrough() - L<Imager::Transformations/rubthrough> - draw an image onto an
3479image and use the alpha channel
3480
3481scale() - L<Imager::Transformations/scale>
1adb5500
TC
3482
3483scaleX() - L<Imager::Transformations/scaleX>
3484
3485scaleY() - L<Imager::Transformations/scaleY>
13fc481e 3486
4b3408a5
TC
3487setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
3488a paletted image
13fc481e 3489
a7ccc5e2 3490setpixel() - L<Imager::Draw/setpixel>
13fc481e 3491
58a9ba58
TC
3492setscanline() - L<Imager::Draw/setscanline>
3493
3494settag() - L<Imager::ImageTypes/settag>
3495
77157728
TC
3496set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3497
a7ccc5e2 3498string() - L<Imager::Draw/string> - draw text on an image
13fc481e 3499
4b3408a5 3500tags() - L<Imager::ImageTypes/tags> - fetch image tags
13fc481e 3501
4b3408a5 3502to_paletted() - L<Imager::ImageTypes/to_paletted>
13fc481e 3503
4b3408a5 3504to_rgb8() - L<Imager::ImageTypes/to_rgb8>
13fc481e
TC
3505
3506transform() - L<Imager::Engines/"transform">
3507
3508transform2() - L<Imager::Engines/"transform2">
3509
4b3408a5 3510type() - L<Imager::ImageTypes/type> - type of image (direct vs paletted)
13fc481e 3511
4b3408a5 3512virtual() - L<Imager::ImageTypes/virtual> - whether the image has it's own
13fc481e
TC
3513data
3514
e36d02ad 3515write() - L<Imager::Files> - write an image to a file
13fc481e 3516
e36d02ad
TC
3517write_multi() - L<Imager::Files> - write multiple image to an image
3518file.
13fc481e 3519
dc67bc2f
TC
3520=head1 CONCEPT INDEX
3521
3522animated GIF - L<Imager::File/"Writing an animated GIF">
3523
3524aspect ratio - L<Imager::ImageTypes/i_xres>,
3525L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
3526
cad360aa
TC
3527blend - alpha blending one image onto another
3528L<Imager::Transformations/rubthrough>
3529
dc67bc2f
TC
3530blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
3531
3532boxes, drawing - L<Imager::Draw/box>
3533
a8652edf
TC
3534changes between image - L<Imager::Filter/"Image Difference">
3535
dc67bc2f
TC
3536color - L<Imager::Color>
3537
3538color names - L<Imager::Color>, L<Imager::Color::Table>
3539
3540combine modes - L<Imager::Fill/combine>
3541
a8652edf
TC
3542compare images - L<Imager::Filter/"Image Difference">
3543
a4e6485d
TC
3544contrast - L<Imager::Filter/contrast>, L<Imager::Filter/autolevels>
3545
3546convolution - L<Imager::Filter/conv>
3547
dc67bc2f
TC
3548cropping - L<Imager::Transformations/crop>
3549
a8652edf
TC
3550C<diff> images - L<Imager::Filter/"Image Difference">
3551
dc67bc2f
TC
3552dpi - L<Imager::ImageTypes/i_xres>
3553
3554drawing boxes - L<Imager::Draw/box>
3555
3556drawing lines - L<Imager::Draw/line>
3557
985bda61 3558drawing text - L<Imager::Font/string>, L<Imager::Font/align>
dc67bc2f 3559
e922ae66 3560error message - L<"Basic Overview">
dc67bc2f
TC
3561
3562files, font - L<Imager::Font>
3563
3564files, image - L<Imager::Files>
3565
3566filling, types of fill - L<Imager::Fill>
3567
3568filling, boxes - L<Imager::Draw/box>
3569
3570filling, flood fill - L<Imager::Draw/flood_fill>
3571
3572flood fill - L<Imager::Draw/flood_fill>
3573
3574fonts - L<Imager::Font>
3575
3576fonts, drawing with - L<Imager::Font/string>, L<Imager::Font/align>,
3577L<Imager::Font::Wrap>
3578
3579fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3580
3581fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
3582
3583fountain fill - L<Imager::Fill/"Fountain fills">,
3584L<Imager::Filters/fountain>, L<Imager::Fountain>,
3585L<Imager::Filters/gradgen>
3586
a4e6485d
TC
3587GIF files - L<Imager::Files/"GIF">
3588
3589GIF files, animated - L<Imager::File/"Writing an animated GIF">
3590
dc67bc2f
TC
3591gradient fill - L<Imager::Fill/"Fountain fills">,
3592L<Imager::Filters/fountain>, L<Imager::Fountain>,
3593L<Imager::Filters/gradgen>
3594
a4e6485d
TC
3595guassian blur - L<Imager::Filter/guassian>
3596
dc67bc2f
TC
3597hatch fills - L<Imager::Fill/"Hatched fills">
3598
a4e6485d
TC
3599invert image - L<Imager::Filter/hardinvert>
3600
dc67bc2f
TC
3601JPEG - L<Imager::Files/"JPEG">
3602
77157728
TC
3603limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
3604
dc67bc2f
TC
3605lines, drawing - L<Imager::Draw/line>
3606
a4e6485d
TC
3607matrix - L<Imager::Matrix2d>,
3608L<Imager::Transformations/"Matrix Transformations">,
3609L<Imager::Font/transform>
3610
dc67bc2f
TC
3611metadata, image - L<Imager::ImageTypes/"Tags">
3612
a4e6485d
TC
3613mosaic - L<Imager::Filter/mosaic>
3614
3615noise, filter - L<Imager::Filter/noise>
3616
3617noise, rendered - L<Imager::Filter/turbnoise>,
3618L<Imager::Filter/radnoise>
3619
cad360aa
TC
3620paste - L<Imager::Transformations/paste>,
3621L<Imager::Transformations/rubthrough>
3622
4b3408a5
TC
3623pseudo-color image - L<Imager::ImageTypes/to_paletted>,
3624L<Imager::ImageTypes/new>
3625
a4e6485d
TC
3626posterize - L<Imager::Filter/postlevels>
3627
3628png files - L<Imager::Files>, L<Imager::Files/"PNG">
dc67bc2f 3629
f75c1aeb 3630pnm - L<Imager::Files/"PNM (Portable aNy Map)">
dc67bc2f
TC
3631
3632rectangles, drawing - L<Imager::Draw/box>
3633
3634resizing an image - L<Imager::Transformations/scale>,
3635L<Imager::Transformations/crop>
3636
3637saving an image - L<Imager::Files>
3638
3639scaling - L<Imager::Transformations/scale>
3640
3641sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
3642
3643size, image - L<Imager::ImageTypes/getwidth>,
3644L<Imager::ImageTypes/getheight>
3645
3646size, text - L<Imager::Font/bounding_box>
3647
4b3408a5
TC
3648tags, image metadata - L<Imager::ImageTypes/"Tags">
3649
a7ccc5e2 3650text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
dc67bc2f
TC
3651L<Imager::Font::Wrap>
3652
3653text, wrapping text in an area - L<Imager::Font::Wrap>
3654
3655text, measuring - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3656
a4e6485d
TC
3657tiles, color - L<Imager::Filter/mosaic>
3658
3659unsharp mask - L<Imager::Filter/unsharpmask>
3660
3661watermark - L<Imager::Filter/watermark>
3662
a7ccc5e2 3663writing an image to a file - L<Imager::Files>
dc67bc2f 3664
f64132d2 3665=head1 SUPPORT
0e418f1e 3666
b6228d02 3667The best place to get help with Imager is the mailing list.
02d1d628 3668
f64132d2
TC
3669To subscribe send a message with C<subscribe> in the body to:
3670
3671 imager-devel+request@molar.is
3672
3673or use the form at:
3674
e922ae66
TC
3675=over
3676
3677L<http://www.molar.is/en/lists/imager-devel/>
3678
3679=back
f64132d2
TC
3680
3681where you can also find the mailing list archive.
10461f9a 3682
f6acebd0 3683You can report bugs by pointing your browser at:
8f22b8d8 3684
e922ae66
TC
3685=over
3686
3687L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager>
3688
3689=back
8f22b8d8
TC
3690
3691Please remember to include the versions of Imager, perl, supporting
3692libraries, and any relevant code. If you have specific images that
3693cause the problems, please include those too.
3ed96cd3 3694
02d1d628
AMH
3695=head1 BUGS
3696
0e418f1e 3697Bugs are listed individually for relevant pod pages.
02d1d628
AMH
3698
3699=head1 AUTHOR
3700
4b3408a5
TC
3701Arnar M. Hrafnkelsson and Tony Cook (tony@imager.perl.org) among
3702others. See the README for a complete list.
02d1d628 3703
9495ee93 3704=head1 SEE ALSO
02d1d628 3705
e922ae66
TC
3706L<perl>(1), L<Imager::ImageTypes>(3), L<Imager::Files>(3),
3707L<Imager::Draw>(3), L<Imager::Color>(3), L<Imager::Fill>(3),
3708L<Imager::Font>(3), L<Imager::Transformations>(3),
3709L<Imager::Engines>(3), L<Imager::Filters>(3), L<Imager::Expr>(3),
3710L<Imager::Matrix2d>(3), L<Imager::Fountain>(3)
3711
3712L<http://imager.perl.org/>
009db950 3713
e922ae66 3714L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
02d1d628 3715
35f40526
TC
3716Other perl imaging modules include:
3717
e922ae66 3718L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).
35f40526 3719
02d1d628 3720=cut