4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %formats $DEBUG %filters %DSOs $ERRSTR $fontstate %OPCODES $I2P $FORMATGUESS $warn_obsolete);
82 i_writetiff_wiol_faxable
146 # registered file readers
149 # registered file writers
152 # modules we attempted to autoload
153 my %attempted_to_load;
161 XSLoader::load(Imager => $VERSION);
165 push @ISA, 'DynaLoader';
166 bootstrap Imager $VERSION;
171 i_init_fonts(); # Initialize font engines
172 Imager::Font::__init();
173 for(i_list_formats()) { $formats{$_}++; }
175 if ($formats{'t1'}) {
179 if (!$formats{'t1'} and !$formats{'tt'}
180 && !$formats{'ft2'} && !$formats{'w32'}) {
181 $fontstate='no font support';
184 %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]);
188 # the members of the subhashes under %filters are:
189 # callseq - a list of the parameters to the underlying filter in the
190 # order they are passed
191 # callsub - a code ref that takes a named parameter list and calls the
193 # defaults - a hash of default values
194 # names - defines names for value of given parameters so if the names
195 # field is foo=> { bar=>1 }, and the user supplies "bar" as the
196 # foo parameter, the filter will receive 1 for the foo
199 callseq => ['image','intensity'],
200 callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); }
204 callseq => ['image', 'amount', 'subtype'],
205 defaults => { amount=>3,subtype=>0 },
206 callsub => sub { my %hsh=@_; i_noise($hsh{image},$hsh{amount},$hsh{subtype}); }
209 $filters{hardinvert} ={
210 callseq => ['image'],
212 callsub => sub { my %hsh=@_; i_hardinvert($hsh{image}); }
215 $filters{autolevels} ={
216 callseq => ['image','lsat','usat','skew'],
217 defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 },
218 callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); }
221 $filters{turbnoise} ={
222 callseq => ['image'],
223 defaults => { xo=>0.0,yo=>0.0,scale=>10.0 },
224 callsub => sub { my %hsh=@_; i_turbnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{scale}); }
227 $filters{radnoise} ={
228 callseq => ['image'],
229 defaults => { xo=>100,yo=>100,ascale=>17.0,rscale=>0.02 },
230 callsub => sub { my %hsh=@_; i_radnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{rscale},$hsh{ascale}); }
234 callseq => ['image', 'coef'],
236 callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}); }
241 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
242 defaults => { dist => 0 },
246 my @colors = @{$hsh{colors}};
249 i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist});
253 $filters{nearest_color} =
255 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
260 # make sure the segments are specified with colors
262 for my $color (@{$hsh{colors}}) {
263 my $new_color = _color($color)
264 or die $Imager::ERRSTR."\n";
265 push @colors, $new_color;
268 i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors,
270 or die Imager->_error_as_msg() . "\n";
273 $filters{gaussian} = {
274 callseq => [ 'image', 'stddev' ],
276 callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); },
280 callseq => [ qw(image size) ],
281 defaults => { size => 20 },
282 callsub => sub { my %hsh = @_; i_mosaic($hsh{image}, $hsh{size}) },
286 callseq => [ qw(image bump elevation lightx lighty st) ],
287 defaults => { elevation=>0, st=> 2 },
290 i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation},
291 $hsh{lightx}, $hsh{lighty}, $hsh{st});
294 $filters{bumpmap_complex} =
296 callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ],
307 Ia => Imager::Color->new(rgb=>[0,0,0]),
308 Il => Imager::Color->new(rgb=>[255,255,255]),
309 Is => Imager::Color->new(rgb=>[255,255,255]),
313 i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel},
314 $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz},
315 $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il},
319 $filters{postlevels} =
321 callseq => [ qw(image levels) ],
322 defaults => { levels => 10 },
323 callsub => sub { my %hsh = @_; i_postlevels($hsh{image}, $hsh{levels}); },
325 $filters{watermark} =
327 callseq => [ qw(image wmark tx ty pixdiff) ],
328 defaults => { pixdiff=>10, tx=>0, ty=>0 },
332 i_watermark($hsh{image}, $hsh{wmark}{IMG}, $hsh{tx}, $hsh{ty},
338 callseq => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ],
340 ftype => { linear => 0,
346 repeat => { none => 0,
361 multiply => 2, mult => 2,
364 subtract => 5, 'sub' => 5,
374 defaults => { ftype => 0, repeat => 0, combine => 0,
375 super_sample => 0, ssample_param => 4,
378 Imager::Color->new(0,0,0),
379 Imager::Color->new(255, 255, 255),
388 # make sure the segments are specified with colors
390 for my $segment (@{$hsh{segments}}) {
391 my @new_segment = @$segment;
393 $_ = _color($_) or die $Imager::ERRSTR."\n" for @new_segment[3,4];
394 push @segments, \@new_segment;
397 i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
398 $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
399 $hsh{ssample_param}, \@segments)
400 or die Imager->_error_as_msg() . "\n";
403 $filters{unsharpmask} =
405 callseq => [ qw(image stddev scale) ],
406 defaults => { stddev=>2.0, scale=>1.0 },
410 i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
414 $FORMATGUESS=\&def_guess_type;
424 # NOTE: this might be moved to an import override later on
428 # (look through @_ for special tags, process, and remove them);
430 # print Dumper($pack);
435 i_init_log($_[0],$_[1]);
436 i_log_entry("Imager $VERSION starting\n", 1);
441 my %parms=(loglevel=>1,@_);
443 init_log($parms{'log'},$parms{'loglevel'});
446 if (exists $parms{'warn_obsolete'}) {
447 $warn_obsolete = $parms{'warn_obsolete'};
450 # if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
451 # if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
455 if (exists $parms{'t1log'}) {
456 i_init_fonts($parms{'t1log'});
462 print "shutdown code\n";
463 # for(keys %instances) { $instances{$_}->DESTROY(); }
464 malloc_state(); # how do decide if this should be used? -- store something from the import
465 print "Imager exiting\n";
469 # Load a filter plugin
474 my ($DSO_handle,$str)=DSO_open($filename);
475 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
476 my %funcs=DSO_funclist($DSO_handle);
477 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
479 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
481 $DSOs{$filename}=[$DSO_handle,\%funcs];
484 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
485 $DEBUG && print "eval string:\n",$evstr,"\n";
497 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
498 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
499 for(keys %{$funcref}) {
501 $DEBUG && print "unloading: $_\n";
503 my $rc=DSO_close($DSO_handle);
504 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
508 # take the results of i_error() and make a message out of it
510 return join(": ", map $_->[0], i_errors());
513 # this function tries to DWIM for color parameters
514 # color objects are used as is
515 # simple scalars are simply treated as single parameters to Imager::Color->new
516 # hashrefs are treated as named argument lists to Imager::Color->new
517 # arrayrefs are treated as list arguments to Imager::Color->new iff any
519 # other arrayrefs are treated as list arguments to Imager::Color::Float
523 # perl 5.6.0 seems to do weird things to $arg if we don't make an
524 # explicitly stringified copy
525 # I vaguely remember a bug on this on p5p, but couldn't find it
526 # through bugs.perl.org (I had trouble getting it to find any bugs)
527 my $copy = $arg . "";
531 if (UNIVERSAL::isa($arg, "Imager::Color")
532 || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
536 if ($copy =~ /^HASH\(/) {
537 $result = Imager::Color->new(%$arg);
539 elsif ($copy =~ /^ARRAY\(/) {
540 $result = Imager::Color->new(@$arg);
543 $Imager::ERRSTR = "Not a color";
548 # assume Imager::Color::new knows how to handle it
549 $result = Imager::Color->new($arg);
558 $self->{IMG} and return 1;
560 $self->_set_error('empty input image');
566 # Methods to be called on objects.
569 # Create a new Imager object takes very few parameters.
570 # usually you call this method and then call open from
571 # the resulting object
578 $self->{IMG}=undef; # Just to indicate what exists
579 $self->{ERRSTR}=undef; #
580 $self->{DEBUG}=$DEBUG;
581 $self->{DEBUG} && print "Initialized Imager\n";
582 if (defined $hsh{xsize} && defined $hsh{ysize}) {
583 unless ($self->img_set(%hsh)) {
584 $Imager::ERRSTR = $self->{ERRSTR};
591 # Copy an entire image with no changes
592 # - if an image has magic the copy of it will not be magical
596 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
598 unless (defined wantarray) {
600 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
604 my $newcopy=Imager->new();
605 $newcopy->{IMG} = i_copy($self->{IMG});
614 unless ($self->{IMG}) {
615 $self->_set_error('empty input image');
618 my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_);
619 my $src = $input{img} || $input{src};
621 $self->_set_error("no source image");
624 $input{left}=0 if $input{left} <= 0;
625 $input{top}=0 if $input{top} <= 0;
627 my($r,$b)=i_img_info($src->{IMG});
628 my ($src_left, $src_top) = @input{qw/src_minx src_miny/};
629 my ($src_right, $src_bottom);
630 if ($input{src_coords}) {
631 ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}}
634 if (defined $input{src_maxx}) {
635 $src_right = $input{src_maxx};
637 elsif (defined $input{width}) {
638 if ($input{width} <= 0) {
639 $self->_set_error("paste: width must me positive");
642 $src_right = $src_left + $input{width};
647 if (defined $input{src_maxy}) {
648 $src_bottom = $input{src_maxy};
650 elsif (defined $input{height}) {
651 if ($input{height} < 0) {
652 $self->_set_error("paste: height must be positive");
655 $src_bottom = $src_top + $input{height};
662 $src_right > $r and $src_right = $r;
663 $src_bottom > $b and $src_bottom = $b;
665 if ($src_right <= $src_left
666 || $src_bottom < $src_top) {
667 $self->_set_error("nothing to paste");
671 i_copyto($self->{IMG}, $src->{IMG},
672 $src_left, $src_top, $src_right, $src_bottom,
673 $input{left}, $input{top});
675 return $self; # What should go here??
678 # Crop an image - i.e. return a new image that is smaller
682 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
684 unless (defined wantarray) {
686 warn "crop() called in void context - crop() returns the cropped image at $caller[1] line $caller[2]\n";
692 my ($w, $h, $l, $r, $b, $t) =
693 @hsh{qw(width height left right bottom top)};
695 # work through the various possibilities
700 elsif (!defined $r) {
701 $r = $self->getwidth;
713 $l = int(0.5+($self->getwidth()-$w)/2);
718 $r = $self->getwidth;
724 elsif (!defined $b) {
725 $b = $self->getheight;
737 $t=int(0.5+($self->getheight()-$h)/2);
742 $b = $self->getheight;
745 ($l,$r)=($r,$l) if $l>$r;
746 ($t,$b)=($b,$t) if $t>$b;
749 $r > $self->getwidth and $r = $self->getwidth;
751 $b > $self->getheight and $b = $self->getheight;
753 if ($l == $r || $t == $b) {
754 $self->_set_error("resulting image would have no content");
758 my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t);
760 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
765 my ($self, %opts) = @_;
767 $self->{IMG} or return $self->_set_error("Not a valid image");
769 my $x = $opts{xsize} || $self->getwidth;
770 my $y = $opts{ysize} || $self->getheight;
771 my $channels = $opts{channels} || $self->getchannels;
773 my $out = Imager->new;
774 if ($channels == $self->getchannels) {
775 $out->{IMG} = i_sametype($self->{IMG}, $x, $y);
778 $out->{IMG} = i_sametype_chans($self->{IMG}, $x, $y, $channels);
780 unless ($out->{IMG}) {
781 $self->{ERRSTR} = $self->_error_as_msg;
788 # Sets an image to a certain size and channel number
789 # if there was previously data in the image it is discarded
794 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
796 if (defined($self->{IMG})) {
797 # let IIM_DESTROY destroy it, it's possible this image is
798 # referenced from a virtual image (like masked)
799 #i_img_destroy($self->{IMG});
803 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
804 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
805 $hsh{maxcolors} || 256);
807 elsif ($hsh{bits} eq 'double') {
808 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
810 elsif ($hsh{bits} == 16) {
811 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
814 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
818 unless ($self->{IMG}) {
819 $self->{ERRSTR} = Imager->_error_as_msg();
826 # created a masked version of the current image
830 $self or return undef;
831 my %opts = (left => 0,
833 right => $self->getwidth,
834 bottom => $self->getheight,
836 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
838 my $result = Imager->new;
839 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
840 $opts{top}, $opts{right} - $opts{left},
841 $opts{bottom} - $opts{top});
842 # keep references to the mask and base images so they don't
844 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
849 # convert an RGB image into a paletted image
853 if (@_ != 1 && !ref $_[0]) {
860 unless (defined wantarray) {
862 warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n";
866 my $result = Imager->new;
867 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
869 #print "Type ", i_img_type($result->{IMG}), "\n";
871 if ($result->{IMG}) {
875 $self->{ERRSTR} = $self->_error_as_msg;
880 # convert a paletted (or any image) to an 8-bit/channel RGB images
885 unless (defined wantarray) {
887 warn "to_rgb8() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
892 $result = Imager->new;
893 $result->{IMG} = i_img_to_rgb($self->{IMG})
902 my %opts = (colors=>[], @_);
904 unless ($self->{IMG}) {
905 $self->_set_error("empty input image");
909 my @colors = @{$opts{colors}}
912 for my $color (@colors) {
913 $color = _color($color);
915 $self->_set_error($Imager::ERRSTR);
920 return i_addcolors($self->{IMG}, @colors);
925 my %opts = (start=>0, colors=>[], @_);
927 unless ($self->{IMG}) {
928 $self->_set_error("empty input image");
932 my @colors = @{$opts{colors}}
935 for my $color (@colors) {
936 $color = _color($color);
938 $self->_set_error($Imager::ERRSTR);
943 return i_setcolors($self->{IMG}, $opts{start}, @colors);
949 if (!exists $opts{start} && !exists $opts{count}) {
952 $opts{count} = $self->colorcount;
954 elsif (!exists $opts{count}) {
957 elsif (!exists $opts{start}) {
962 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
966 i_colorcount($_[0]{IMG});
970 i_maxcolors($_[0]{IMG});
976 $opts{color} or return undef;
978 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
983 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
984 if ($bits && $bits == length(pack("d", 1)) * 8) {
993 return i_img_type($self->{IMG}) ? "paletted" : "direct";
999 $self->{IMG} and i_img_virtual($self->{IMG});
1003 my ($self, %opts) = @_;
1005 $self->{IMG} or return;
1007 if (defined $opts{name}) {
1011 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
1012 push @result, (i_tags_get($self->{IMG}, $found))[1];
1015 return wantarray ? @result : $result[0];
1017 elsif (defined $opts{code}) {
1021 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
1022 push @result, (i_tags_get($self->{IMG}, $found))[1];
1029 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
1032 return i_tags_count($self->{IMG});
1041 return -1 unless $self->{IMG};
1043 if (defined $opts{value}) {
1044 if ($opts{value} =~ /^\d+$/) {
1046 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
1049 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
1052 elsif (defined $opts{data}) {
1053 # force addition as a string
1054 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
1057 $self->{ERRSTR} = "No value supplied";
1061 elsif ($opts{code}) {
1062 if (defined $opts{value}) {
1063 if ($opts{value} =~ /^\d+$/) {
1065 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
1068 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
1071 elsif (defined $opts{data}) {
1072 # force addition as a string
1073 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
1076 $self->{ERRSTR} = "No value supplied";
1089 return 0 unless $self->{IMG};
1091 if (defined $opts{'index'}) {
1092 return i_tags_delete($self->{IMG}, $opts{'index'});
1094 elsif (defined $opts{name}) {
1095 return i_tags_delbyname($self->{IMG}, $opts{name});
1097 elsif (defined $opts{code}) {
1098 return i_tags_delbycode($self->{IMG}, $opts{code});
1101 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
1107 my ($self, %opts) = @_;
1110 $self->deltag(name=>$opts{name});
1111 return $self->addtag(name=>$opts{name}, value=>$opts{value});
1113 elsif (defined $opts{code}) {
1114 $self->deltag(code=>$opts{code});
1115 return $self->addtag(code=>$opts{code}, value=>$opts{value});
1123 sub _get_reader_io {
1124 my ($self, $input) = @_;
1127 return $input->{io}, undef;
1129 elsif ($input->{fd}) {
1130 return io_new_fd($input->{fd});
1132 elsif ($input->{fh}) {
1133 my $fd = fileno($input->{fh});
1135 $self->_set_error("Handle in fh option not opened");
1138 return io_new_fd($fd);
1140 elsif ($input->{file}) {
1141 my $file = IO::File->new($input->{file}, "r");
1143 $self->_set_error("Could not open $input->{file}: $!");
1147 return (io_new_fd(fileno($file)), $file);
1149 elsif ($input->{data}) {
1150 return io_new_buffer($input->{data});
1152 elsif ($input->{callback} || $input->{readcb}) {
1153 if (!$input->{seekcb}) {
1154 $self->_set_error("Need a seekcb parameter");
1156 if ($input->{maxbuffer}) {
1157 return io_new_cb($input->{writecb},
1158 $input->{callback} || $input->{readcb},
1159 $input->{seekcb}, $input->{closecb},
1160 $input->{maxbuffer});
1163 return io_new_cb($input->{writecb},
1164 $input->{callback} || $input->{readcb},
1165 $input->{seekcb}, $input->{closecb});
1169 $self->_set_error("file/fd/fh/data/callback parameter missing");
1174 sub _get_writer_io {
1175 my ($self, $input, $type) = @_;
1178 return $input->{io};
1180 elsif ($input->{fd}) {
1181 return io_new_fd($input->{fd});
1183 elsif ($input->{fh}) {
1184 my $fd = fileno($input->{fh});
1186 $self->_set_error("Handle in fh option not opened");
1190 my $oldfh = select($input->{fh});
1191 # flush anything that's buffered, and make sure anything else is flushed
1194 return io_new_fd($fd);
1196 elsif ($input->{file}) {
1197 my $fh = new IO::File($input->{file},"w+");
1199 $self->_set_error("Could not open file $input->{file}: $!");
1202 binmode($fh) or die;
1203 return (io_new_fd(fileno($fh)), $fh);
1205 elsif ($input->{data}) {
1206 return io_new_bufchain();
1208 elsif ($input->{callback} || $input->{writecb}) {
1209 if ($input->{maxbuffer}) {
1210 return io_new_cb($input->{callback} || $input->{writecb},
1212 $input->{seekcb}, $input->{closecb},
1213 $input->{maxbuffer});
1216 return io_new_cb($input->{callback} || $input->{writecb},
1218 $input->{seekcb}, $input->{closecb});
1222 $self->_set_error("file/fd/fh/data/callback parameter missing");
1227 # Read an image from file
1233 if (defined($self->{IMG})) {
1234 # let IIM_DESTROY do the destruction, since the image may be
1235 # referenced from elsewhere
1236 #i_img_destroy($self->{IMG});
1237 undef($self->{IMG});
1240 my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
1242 unless ($input{'type'}) {
1243 $input{'type'} = i_test_format_probe($IO, -1);
1246 unless ($input{'type'}) {
1247 $self->_set_error('type parameter missing and not possible to guess from extension');
1251 _reader_autoload($input{type});
1253 if ($readers{$input{type}} && $readers{$input{type}}{single}) {
1254 return $readers{$input{type}}{single}->($self, $IO, %input);
1257 unless ($formats{$input{'type'}}) {
1258 $self->_set_error("format '$input{'type'}' not supported");
1263 if ( $input{'type'} eq 'jpeg' ) {
1264 ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
1265 if ( !defined($self->{IMG}) ) {
1266 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1268 $self->{DEBUG} && print "loading a jpeg file\n";
1272 if ( $input{'type'} eq 'tiff' ) {
1273 my $page = $input{'page'};
1274 defined $page or $page = 0;
1275 # Fixme, check if that length parameter is ever needed
1276 $self->{IMG}=i_readtiff_wiol( $IO, -1, $page );
1277 if ( !defined($self->{IMG}) ) {
1278 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1280 $self->{DEBUG} && print "loading a tiff file\n";
1284 if ( $input{'type'} eq 'pnm' ) {
1285 $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1286 if ( !defined($self->{IMG}) ) {
1287 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg();
1290 $self->{DEBUG} && print "loading a pnm file\n";
1294 if ( $input{'type'} eq 'png' ) {
1295 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1296 if ( !defined($self->{IMG}) ) {
1297 $self->{ERRSTR} = $self->_error_as_msg();
1300 $self->{DEBUG} && print "loading a png file\n";
1303 if ( $input{'type'} eq 'bmp' ) {
1304 $self->{IMG}=i_readbmp_wiol( $IO );
1305 if ( !defined($self->{IMG}) ) {
1306 $self->{ERRSTR}=$self->_error_as_msg();
1309 $self->{DEBUG} && print "loading a bmp file\n";
1312 if ( $input{'type'} eq 'gif' ) {
1313 if ($input{colors} && !ref($input{colors})) {
1314 # must be a reference to a scalar that accepts the colour map
1315 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1318 if ($input{'gif_consolidate'}) {
1319 if ($input{colors}) {
1321 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1323 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1327 $self->{IMG} =i_readgif_wiol( $IO );
1331 my $page = $input{'page'};
1332 defined $page or $page = 0;
1333 $self->{IMG} = i_readgif_single_wiol( $IO, $page );
1334 if ($input{colors}) {
1335 ${ $input{colors} } =
1336 [ i_getcolors($self->{IMG}, 0, i_colorcount($self->{IMG})) ];
1340 if ( !defined($self->{IMG}) ) {
1341 $self->{ERRSTR}=$self->_error_as_msg();
1344 $self->{DEBUG} && print "loading a gif file\n";
1347 if ( $input{'type'} eq 'tga' ) {
1348 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1349 if ( !defined($self->{IMG}) ) {
1350 $self->{ERRSTR}=$self->_error_as_msg();
1353 $self->{DEBUG} && print "loading a tga file\n";
1356 if ( $input{'type'} eq 'rgb' ) {
1357 $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1358 if ( !defined($self->{IMG}) ) {
1359 $self->{ERRSTR}=$self->_error_as_msg();
1362 $self->{DEBUG} && print "loading a tga file\n";
1366 if ( $input{'type'} eq 'raw' ) {
1367 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1369 if ( !($params{xsize} && $params{ysize}) ) {
1370 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1374 $self->{IMG} = i_readraw_wiol( $IO,
1377 $params{datachannels},
1378 $params{storechannels},
1379 $params{interleave});
1380 if ( !defined($self->{IMG}) ) {
1381 $self->{ERRSTR}=$self->_error_as_msg();
1384 $self->{DEBUG} && print "loading a raw file\n";
1390 sub register_reader {
1391 my ($class, %opts) = @_;
1394 or die "register_reader called with no type parameter\n";
1396 my $type = $opts{type};
1398 defined $opts{single} || defined $opts{multiple}
1399 or die "register_reader called with no single or multiple parameter\n";
1401 $readers{$type} = { };
1402 if ($opts{single}) {
1403 $readers{$type}{single} = $opts{single};
1405 if ($opts{multiple}) {
1406 $readers{$type}{multiple} = $opts{multiple};
1412 sub register_writer {
1413 my ($class, %opts) = @_;
1416 or die "register_writer called with no type parameter\n";
1418 my $type = $opts{type};
1420 defined $opts{single} || defined $opts{multiple}
1421 or die "register_writer called with no single or multiple parameter\n";
1423 $writers{$type} = { };
1424 if ($opts{single}) {
1425 $writers{$type}{single} = $opts{single};
1427 if ($opts{multiple}) {
1428 $writers{$type}{multiple} = $opts{multiple};
1434 # probes for an Imager::File::whatever module
1435 sub _reader_autoload {
1438 return if $formats{$type} || $readers{$type};
1440 return unless $type =~ /^\w+$/;
1442 my $file = "Imager/File/\U$type\E.pm";
1444 unless ($attempted_to_load{$file}) {
1446 ++$attempted_to_load{$file};
1450 # try to get a reader specific module
1451 my $file = "Imager/File/\U$type\EReader.pm";
1452 unless ($attempted_to_load{$file}) {
1454 ++$attempted_to_load{$file};
1462 # probes for an Imager::File::whatever module
1463 sub _writer_autoload {
1466 return if $formats{$type} || $readers{$type};
1468 return unless $type =~ /^\w+$/;
1470 my $file = "Imager/File/\U$type\E.pm";
1472 unless ($attempted_to_load{$file}) {
1474 ++$attempted_to_load{$file};
1478 # try to get a writer specific module
1479 my $file = "Imager/File/\U$type\EWriter.pm";
1480 unless ($attempted_to_load{$file}) {
1482 ++$attempted_to_load{$file};
1490 sub _fix_gif_positions {
1491 my ($opts, $opt, $msg, @imgs) = @_;
1493 my $positions = $opts->{'gif_positions'};
1495 for my $pos (@$positions) {
1496 my ($x, $y) = @$pos;
1497 my $img = $imgs[$index++];
1498 $img->settag(name=>'gif_left', value=>$x);
1499 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1501 $$msg .= "replaced with the gif_left and gif_top tags";
1506 gif_each_palette=>'gif_local_map',
1507 interlace => 'gif_interlace',
1508 gif_delays => 'gif_delay',
1509 gif_positions => \&_fix_gif_positions,
1510 gif_loop_count => 'gif_loop',
1514 my ($self, $opts, $prefix, @imgs) = @_;
1516 for my $opt (keys %$opts) {
1518 if ($obsolete_opts{$opt}) {
1519 my $new = $obsolete_opts{$opt};
1520 my $msg = "Obsolete option $opt ";
1522 $new->($opts, $opt, \$msg, @imgs);
1525 $msg .= "replaced with the $new tag ";
1528 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1529 warn $msg if $warn_obsolete && $^W;
1531 next unless $tagname =~ /^\Q$prefix/;
1532 my $value = $opts->{$opt};
1534 if (UNIVERSAL::isa($value, "Imager::Color")) {
1535 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1536 for my $img (@imgs) {
1537 $img->settag(name=>$tagname, value=>$tag);
1540 elsif (ref($value) eq 'ARRAY') {
1541 for my $i (0..$#$value) {
1542 my $val = $value->[$i];
1544 if (UNIVERSAL::isa($val, "Imager::Color")) {
1545 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1547 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1550 $self->_set_error("Unknown reference type " . ref($value) .
1551 " supplied in array for $opt");
1557 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1562 $self->_set_error("Unknown reference type " . ref($value) .
1563 " supplied for $opt");
1568 # set it as a tag for every image
1569 for my $img (@imgs) {
1570 $img->settag(name=>$tagname, value=>$value);
1578 # Write an image to file
1581 my %input=(jpegquality=>75,
1591 $self->_set_opts(\%input, "i_", $self)
1594 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1596 if (!$input{'type'} and $input{file}) {
1597 $input{'type'}=$FORMATGUESS->($input{file});
1599 if (!$input{'type'}) {
1600 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1604 _writer_autoload($input{type});
1607 if ($writers{$input{type}} && $writers{$input{type}}{single}) {
1608 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1611 $writers{$input{type}}{single}->($self, $IO, %input)
1615 if (!$formats{$input{'type'}}) {
1616 $self->{ERRSTR}='format not supported';
1620 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1623 if ($input{'type'} eq 'tiff') {
1624 $self->_set_opts(\%input, "tiff_", $self)
1626 $self->_set_opts(\%input, "exif_", $self)
1629 if (defined $input{class} && $input{class} eq 'fax') {
1630 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1631 $self->{ERRSTR} = $self->_error_as_msg();
1635 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1636 $self->{ERRSTR} = $self->_error_as_msg();
1640 } elsif ( $input{'type'} eq 'pnm' ) {
1641 $self->_set_opts(\%input, "pnm_", $self)
1643 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1644 $self->{ERRSTR} = $self->_error_as_msg();
1647 $self->{DEBUG} && print "writing a pnm file\n";
1648 } elsif ( $input{'type'} eq 'raw' ) {
1649 $self->_set_opts(\%input, "raw_", $self)
1651 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1652 $self->{ERRSTR} = $self->_error_as_msg();
1655 $self->{DEBUG} && print "writing a raw file\n";
1656 } elsif ( $input{'type'} eq 'png' ) {
1657 $self->_set_opts(\%input, "png_", $self)
1659 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1660 $self->{ERRSTR}='unable to write png image';
1663 $self->{DEBUG} && print "writing a png file\n";
1664 } elsif ( $input{'type'} eq 'jpeg' ) {
1665 $self->_set_opts(\%input, "jpeg_", $self)
1667 $self->_set_opts(\%input, "exif_", $self)
1669 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1670 $self->{ERRSTR} = $self->_error_as_msg();
1673 $self->{DEBUG} && print "writing a jpeg file\n";
1674 } elsif ( $input{'type'} eq 'bmp' ) {
1675 $self->_set_opts(\%input, "bmp_", $self)
1677 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1678 $self->{ERRSTR}='unable to write bmp image';
1681 $self->{DEBUG} && print "writing a bmp file\n";
1682 } elsif ( $input{'type'} eq 'tga' ) {
1683 $self->_set_opts(\%input, "tga_", $self)
1686 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1687 $self->{ERRSTR}=$self->_error_as_msg();
1690 $self->{DEBUG} && print "writing a tga file\n";
1691 } elsif ( $input{'type'} eq 'gif' ) {
1692 $self->_set_opts(\%input, "gif_", $self)
1694 # compatibility with the old interfaces
1695 if ($input{gifquant} eq 'lm') {
1696 $input{make_colors} = 'addi';
1697 $input{translate} = 'perturb';
1698 $input{perturb} = $input{lmdither};
1699 } elsif ($input{gifquant} eq 'gen') {
1700 # just pass options through
1702 $input{make_colors} = 'webmap'; # ignored
1703 $input{translate} = 'giflib';
1705 if (!i_writegif_wiol($IO, \%input, $self->{IMG})) {
1706 $self->{ERRSTR} = $self->_error_as_msg;
1712 if (exists $input{'data'}) {
1713 my $data = io_slurp($IO);
1715 $self->{ERRSTR}='Could not slurp from buffer';
1718 ${$input{data}} = $data;
1724 my ($class, $opts, @images) = @_;
1726 my $type = $opts->{type};
1728 if (!$type && $opts->{'file'}) {
1729 $type = $FORMATGUESS->($opts->{'file'});
1732 $class->_set_error('type parameter missing and not possible to guess from extension');
1735 # translate to ImgRaw
1736 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1737 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1740 $class->_set_opts($opts, "i_", @images)
1742 my @work = map $_->{IMG}, @images;
1744 _writer_autoload($type);
1747 if ($writers{$type} && $writers{$type}{multiple}) {
1748 ($IO, $file) = $class->_get_writer_io($opts, $type)
1751 $writers{$type}{multiple}->($class, $IO, $opts, @images)
1755 if (!$formats{$type}) {
1756 $class->_set_error("format $type not supported");
1760 ($IO, $file) = $class->_get_writer_io($opts, $type)
1763 if ($type eq 'gif') {
1764 $class->_set_opts($opts, "gif_", @images)
1766 my $gif_delays = $opts->{gif_delays};
1767 local $opts->{gif_delays} = $gif_delays;
1768 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1769 # assume the caller wants the same delay for each frame
1770 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1772 unless (i_writegif_wiol($IO, $opts, @work)) {
1773 $class->_set_error($class->_error_as_msg());
1777 elsif ($type eq 'tiff') {
1778 $class->_set_opts($opts, "tiff_", @images)
1780 $class->_set_opts($opts, "exif_", @images)
1783 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1784 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1785 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1788 $res = i_writetiff_multi_wiol($IO, @work);
1791 $class->_set_error($class->_error_as_msg());
1797 unless ($images[0]->write(%$opts, io => $IO, type => $type)) {
1802 $ERRSTR = "Sorry, write_multi doesn't support $type yet";
1808 if (exists $opts->{'data'}) {
1809 my $data = io_slurp($IO);
1811 Imager->_set_error('Could not slurp from buffer');
1814 ${$opts->{data}} = $data;
1819 # read multiple images from a file
1821 my ($class, %opts) = @_;
1823 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1826 my $type = $opts{'type'};
1828 $type = i_test_format_probe($IO, -1);
1831 if ($opts{file} && !$type) {
1833 $type = $FORMATGUESS->($opts{file});
1837 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1841 _reader_autoload($type);
1843 if ($readers{$type} && $readers{$type}{multiple}) {
1844 return $readers{$type}{multiple}->($IO, %opts);
1847 if ($type eq 'gif') {
1849 @imgs = i_readgif_multi_wiol($IO);
1852 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1856 $ERRSTR = _error_as_msg();
1860 elsif ($type eq 'tiff') {
1861 my @imgs = i_readtiff_multi_wiol($IO, -1);
1864 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1868 $ERRSTR = _error_as_msg();
1873 my $img = Imager->new;
1874 if ($img->read(%opts, io => $IO, type => $type)) {
1879 $ERRSTR = "Cannot read multiple images from $type files";
1883 # Destroy an Imager object
1887 # delete $instances{$self};
1888 if (defined($self->{IMG})) {
1889 # the following is now handled by the XS DESTROY method for
1890 # Imager::ImgRaw object
1891 # Re-enabling this will break virtual images
1892 # tested for in t/t020masked.t
1893 # i_img_destroy($self->{IMG});
1894 undef($self->{IMG});
1896 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1900 # Perform an inplace filter of an image
1901 # that is the image will be overwritten with the data
1907 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1909 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1911 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1912 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1915 if ($filters{$input{'type'}}{names}) {
1916 my $names = $filters{$input{'type'}}{names};
1917 for my $name (keys %$names) {
1918 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1919 $input{$name} = $names->{$name}{$input{$name}};
1923 if (defined($filters{$input{'type'}}{defaults})) {
1924 %hsh=( image => $self->{IMG},
1926 %{$filters{$input{'type'}}{defaults}},
1929 %hsh=( image => $self->{IMG},
1934 my @cs=@{$filters{$input{'type'}}{callseq}};
1937 if (!defined($hsh{$_})) {
1938 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1943 local $SIG{__DIE__}; # we don't want this processed by confess, etc
1944 &{$filters{$input{'type'}}{callsub}}(%hsh);
1947 chomp($self->{ERRSTR} = $@);
1953 $self->{DEBUG} && print "callseq is: @cs\n";
1954 $self->{DEBUG} && print "matching callseq is: @b\n";
1959 sub register_filter {
1961 my %hsh = ( defaults => {}, @_ );
1964 or die "register_filter() with no type\n";
1965 defined $hsh{callsub}
1966 or die "register_filter() with no callsub\n";
1967 defined $hsh{callseq}
1968 or die "register_filter() with no callseq\n";
1970 exists $filters{$hsh{type}}
1973 $filters{$hsh{type}} = \%hsh;
1978 # Scale an image to requested size and return the scaled version
1982 my %opts=('type'=>'max',qtype=>'normal',@_);
1983 my $img = Imager->new();
1984 my $tmp = Imager->new();
1985 my ($x_scale, $y_scale);
1987 unless (defined wantarray) {
1988 my @caller = caller;
1989 warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
1993 unless ($self->{IMG}) {
1994 $self->_set_error('empty input image');
1998 if ($opts{'xscalefactor'} && $opts{'yscalefactor'}) {
1999 $x_scale = $opts{'xscalefactor'};
2000 $y_scale = $opts{'yscalefactor'};
2002 elsif ($opts{'xscalefactor'}) {
2003 $x_scale = $opts{'xscalefactor'};
2004 $y_scale = $opts{'scalefactor'} || $x_scale;
2006 elsif ($opts{'yscalefactor'}) {
2007 $y_scale = $opts{'yscalefactor'};
2008 $x_scale = $opts{'scalefactor'} || $y_scale;
2011 $x_scale = $y_scale = $opts{'scalefactor'} || 0.5;
2014 # work out the scaling
2015 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
2016 my ($xpix, $ypix)=( $opts{xpixels} / $self->getwidth() ,
2017 $opts{ypixels} / $self->getheight() );
2018 if ($opts{'type'} eq 'min') {
2019 $x_scale = $y_scale = _min($xpix,$ypix);
2021 elsif ($opts{'type'} eq 'max') {
2022 $x_scale = $y_scale = _max($xpix,$ypix);
2024 elsif ($opts{'type'} eq 'nonprop' || $opts{'type'} eq 'non-proportional') {
2029 $self->_set_error('invalid value for type parameter');
2032 } elsif ($opts{xpixels}) {
2033 $x_scale = $y_scale = $opts{xpixels} / $self->getwidth();
2035 elsif ($opts{ypixels}) {
2036 $x_scale = $y_scale = $opts{ypixels}/$self->getheight();
2038 elsif ($opts{constrain} && ref $opts{constrain}
2039 && $opts{constrain}->can('constrain')) {
2040 # we've been passed an Image::Math::Constrain object or something
2041 # that looks like one
2043 (undef, undef, $scalefactor)
2044 = $opts{constrain}->constrain($self->getwidth, $self->getheight);
2045 unless ($scalefactor) {
2046 $self->_set_error('constrain method failed on constrain parameter');
2049 $x_scale = $y_scale = $scalefactor;
2052 if ($opts{qtype} eq 'normal') {
2053 $tmp->{IMG} = i_scaleaxis($self->{IMG}, $x_scale, 0);
2054 if ( !defined($tmp->{IMG}) ) {
2055 $self->{ERRSTR} = 'unable to scale image';
2058 $img->{IMG}=i_scaleaxis($tmp->{IMG}, $y_scale, 1);
2059 if ( !defined($img->{IMG}) ) {
2060 $self->{ERRSTR}='unable to scale image';
2066 elsif ($opts{'qtype'} eq 'preview') {
2067 $img->{IMG} = i_scale_nn($self->{IMG}, $x_scale, $y_scale);
2068 if ( !defined($img->{IMG}) ) {
2069 $self->{ERRSTR}='unable to scale image';
2074 elsif ($opts{'qtype'} eq 'mixing') {
2075 my $new_width = int(0.5 + $self->getwidth * $x_scale);
2076 my $new_height = int(0.5 + $self->getheight * $y_scale);
2077 $new_width >= 1 or $new_width = 1;
2078 $new_height >= 1 or $new_height = 1;
2079 $img->{IMG} = i_scale_mixing($self->{IMG}, $new_width, $new_height);
2080 unless ($img->{IMG}) {
2081 $self->_set_error(Imager->_error_as_meg);
2087 $self->_set_error('invalid value for qtype parameter');
2092 # Scales only along the X axis
2096 my %opts = ( scalefactor=>0.5, @_ );
2098 unless (defined wantarray) {
2099 my @caller = caller;
2100 warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
2104 unless ($self->{IMG}) {
2105 $self->{ERRSTR} = 'empty input image';
2109 my $img = Imager->new();
2111 my $scalefactor = $opts{scalefactor};
2113 if ($opts{pixels}) {
2114 $scalefactor = $opts{pixels} / $self->getwidth();
2117 unless ($self->{IMG}) {
2118 $self->{ERRSTR}='empty input image';
2122 $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
2124 if ( !defined($img->{IMG}) ) {
2125 $self->{ERRSTR} = 'unable to scale image';
2132 # Scales only along the Y axis
2136 my %opts = ( scalefactor => 0.5, @_ );
2138 unless (defined wantarray) {
2139 my @caller = caller;
2140 warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
2144 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2146 my $img = Imager->new();
2148 my $scalefactor = $opts{scalefactor};
2150 if ($opts{pixels}) {
2151 $scalefactor = $opts{pixels} / $self->getheight();
2154 unless ($self->{IMG}) {
2155 $self->{ERRSTR} = 'empty input image';
2158 $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
2160 if ( !defined($img->{IMG}) ) {
2161 $self->{ERRSTR} = 'unable to scale image';
2168 # Transform returns a spatial transformation of the input image
2169 # this moves pixels to a new location in the returned image.
2170 # NOTE - should make a utility function to check transforms for
2175 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2177 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
2179 # print Dumper(\%opts);
2182 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
2184 eval ("use Affix::Infix2Postfix;");
2187 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
2190 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
2191 {op=>'-',trans=>'Sub'},
2192 {op=>'*',trans=>'Mult'},
2193 {op=>'/',trans=>'Div'},
2194 {op=>'-','type'=>'unary',trans=>'u-'},
2196 {op=>'func','type'=>'unary'}],
2197 'grouping'=>[qw( \( \) )],
2198 'func'=>[qw( sin cos )],
2203 @xt=$I2P->translate($opts{'xexpr'});
2204 @yt=$I2P->translate($opts{'yexpr'});
2206 $numre=$I2P->{'numre'};
2209 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
2210 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
2211 @{$opts{'parm'}}=@pt;
2214 # print Dumper(\%opts);
2216 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
2217 $self->{ERRSTR}='transform: no xopcodes given.';
2221 @op=@{$opts{'xopcodes'}};
2223 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2224 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2227 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2233 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
2234 $self->{ERRSTR}='transform: no yopcodes given.';
2238 @op=@{$opts{'yopcodes'}};
2240 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2241 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2244 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2249 if ( !exists $opts{'parm'}) {
2250 $self->{ERRSTR}='transform: no parameter arg given.';
2254 # print Dumper(\@ropx);
2255 # print Dumper(\@ropy);
2256 # print Dumper(\@ropy);
2258 my $img = Imager->new();
2259 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
2260 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
2266 my ($opts, @imgs) = @_;
2268 require "Imager/Expr.pm";
2270 $opts->{variables} = [ qw(x y) ];
2271 my ($width, $height) = @{$opts}{qw(width height)};
2273 $width ||= $imgs[0]->getwidth();
2274 $height ||= $imgs[0]->getheight();
2276 for my $img (@imgs) {
2277 $opts->{constants}{"w$img_num"} = $img->getwidth();
2278 $opts->{constants}{"h$img_num"} = $img->getheight();
2279 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
2280 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
2285 $opts->{constants}{w} = $width;
2286 $opts->{constants}{cx} = $width/2;
2289 $Imager::ERRSTR = "No width supplied";
2293 $opts->{constants}{h} = $height;
2294 $opts->{constants}{cy} = $height/2;
2297 $Imager::ERRSTR = "No height supplied";
2300 my $code = Imager::Expr->new($opts);
2302 $Imager::ERRSTR = Imager::Expr::error();
2305 my $channels = $opts->{channels} || 3;
2306 unless ($channels >= 1 && $channels <= 4) {
2307 return Imager->_set_error("channels must be an integer between 1 and 4");
2310 my $img = Imager->new();
2311 $img->{IMG} = i_transform2($opts->{width}, $opts->{height},
2312 $channels, $code->code(),
2313 $code->nregs(), $code->cregs(),
2314 [ map { $_->{IMG} } @imgs ]);
2315 if (!defined $img->{IMG}) {
2316 $Imager::ERRSTR = Imager->_error_as_msg();
2325 my %opts=(tx => 0,ty => 0, @_);
2327 unless ($self->{IMG}) {
2328 $self->{ERRSTR}='empty input image';
2331 unless ($opts{src} && $opts{src}->{IMG}) {
2332 $self->{ERRSTR}='empty input image for src';
2336 %opts = (src_minx => 0,
2338 src_maxx => $opts{src}->getwidth(),
2339 src_maxy => $opts{src}->getheight(),
2342 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
2343 $opts{src_minx}, $opts{src_miny},
2344 $opts{src_maxx}, $opts{src_maxy})) {
2345 $self->_set_error($self->_error_as_msg());
2355 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
2357 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
2358 $dir = $xlate{$opts{'dir'}};
2359 return $self if i_flipxy($self->{IMG}, $dir);
2367 unless (defined wantarray) {
2368 my @caller = caller;
2369 warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
2373 if (defined $opts{right}) {
2374 my $degrees = $opts{right};
2376 $degrees += 360 * int(((-$degrees)+360)/360);
2378 $degrees = $degrees % 360;
2379 if ($degrees == 0) {
2380 return $self->copy();
2382 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
2383 my $result = Imager->new();
2384 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
2388 $self->{ERRSTR} = $self->_error_as_msg();
2393 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
2397 elsif (defined $opts{radians} || defined $opts{degrees}) {
2398 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
2400 my $back = $opts{back};
2401 my $result = Imager->new;
2403 $back = _color($back);
2405 $self->_set_error(Imager->errstr);
2409 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
2412 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
2414 if ($result->{IMG}) {
2418 $self->{ERRSTR} = $self->_error_as_msg();
2423 $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available";
2428 sub matrix_transform {
2432 unless (defined wantarray) {
2433 my @caller = caller;
2434 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
2438 if ($opts{matrix}) {
2439 my $xsize = $opts{xsize} || $self->getwidth;
2440 my $ysize = $opts{ysize} || $self->getheight;
2442 my $result = Imager->new;
2444 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2445 $opts{matrix}, $opts{back})
2449 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2457 $self->{ERRSTR} = "matrix parameter required";
2463 *yatf = \&matrix_transform;
2465 # These two are supported for legacy code only
2468 return Imager::Color->new(@_);
2472 return Imager::Color::set(@_);
2475 # Draws a box between the specified corner points.
2478 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2479 my $dflcl=i_color_new(255,255,255,255);
2480 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
2482 if (exists $opts{'box'}) {
2483 $opts{'xmin'} = _min($opts{'box'}->[0],$opts{'box'}->[2]);
2484 $opts{'xmax'} = _max($opts{'box'}->[0],$opts{'box'}->[2]);
2485 $opts{'ymin'} = _min($opts{'box'}->[1],$opts{'box'}->[3]);
2486 $opts{'ymax'} = _max($opts{'box'}->[1],$opts{'box'}->[3]);
2489 if ($opts{filled}) {
2490 my $color = _color($opts{'color'});
2492 $self->{ERRSTR} = $Imager::ERRSTR;
2495 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2496 $opts{ymax}, $color);
2498 elsif ($opts{fill}) {
2499 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2500 # assume it's a hash ref
2501 require 'Imager/Fill.pm';
2502 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2503 $self->{ERRSTR} = $Imager::ERRSTR;
2507 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2508 $opts{ymax},$opts{fill}{fill});
2511 my $color = _color($opts{'color'});
2513 $self->{ERRSTR} = $Imager::ERRSTR;
2516 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
2524 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2525 my $dflcl=i_color_new(255,255,255,255);
2526 my %opts=(color=>$dflcl,
2527 'r'=>_min($self->getwidth(),$self->getheight())/3,
2528 'x'=>$self->getwidth()/2,
2529 'y'=>$self->getheight()/2,
2530 'd1'=>0, 'd2'=>361, @_);
2533 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2534 # assume it's a hash ref
2535 require 'Imager/Fill.pm';
2536 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2537 $self->{ERRSTR} = $Imager::ERRSTR;
2541 i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2542 $opts{'d2'}, $opts{fill}{fill});
2545 my $color = _color($opts{'color'});
2547 $self->{ERRSTR} = $Imager::ERRSTR;
2550 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
2551 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
2555 i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2556 $opts{'d1'}, $opts{'d2'}, $color);
2562 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2563 # assume it's a hash ref
2564 require 'Imager/Fill.pm';
2565 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2566 $self->{ERRSTR} = $Imager::ERRSTR;
2570 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2571 $opts{'d2'}, $opts{fill}{fill});
2574 my $color = _color($opts{'color'});
2576 $self->{ERRSTR} = $Imager::ERRSTR;
2579 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2580 $opts{'d1'}, $opts{'d2'}, $color);
2587 # Draws a line from one point to the other
2588 # the endpoint is set if the endp parameter is set which it is by default.
2589 # to turn of the endpoint being set use endp=>0 when calling line.
2593 my $dflcl=i_color_new(0,0,0,0);
2594 my %opts=(color=>$dflcl,
2597 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2599 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2600 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2602 my $color = _color($opts{'color'});
2604 $self->{ERRSTR} = $Imager::ERRSTR;
2608 $opts{antialias} = $opts{aa} if defined $opts{aa};
2609 if ($opts{antialias}) {
2610 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2611 $color, $opts{endp});
2613 i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2614 $color, $opts{endp});
2619 # Draws a line between an ordered set of points - It more or less just transforms this
2620 # into a list of lines.
2624 my ($pt,$ls,@points);
2625 my $dflcl=i_color_new(0,0,0,0);
2626 my %opts=(color=>$dflcl,@_);
2628 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2630 if (exists($opts{points})) { @points=@{$opts{points}}; }
2631 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2632 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2635 # print Dumper(\@points);
2637 my $color = _color($opts{'color'});
2639 $self->{ERRSTR} = $Imager::ERRSTR;
2642 $opts{antialias} = $opts{aa} if defined $opts{aa};
2643 if ($opts{antialias}) {
2646 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1);
2653 i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1);
2663 my ($pt,$ls,@points);
2664 my $dflcl = i_color_new(0,0,0,0);
2665 my %opts = (color=>$dflcl, @_);
2667 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2669 if (exists($opts{points})) {
2670 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2671 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2674 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2675 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2678 if ($opts{'fill'}) {
2679 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2680 # assume it's a hash ref
2681 require 'Imager/Fill.pm';
2682 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2683 $self->{ERRSTR} = $Imager::ERRSTR;
2687 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2688 $opts{'fill'}{'fill'});
2691 my $color = _color($opts{'color'});
2693 $self->{ERRSTR} = $Imager::ERRSTR;
2696 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2703 # this the multipoint bezier curve
2704 # this is here more for testing that actual usage since
2705 # this is not a good algorithm. Usually the curve would be
2706 # broken into smaller segments and each done individually.
2710 my ($pt,$ls,@points);
2711 my $dflcl=i_color_new(0,0,0,0);
2712 my %opts=(color=>$dflcl,@_);
2714 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2716 if (exists $opts{points}) {
2717 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2718 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2721 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2722 $self->{ERRSTR}='Missing or invalid points.';
2726 my $color = _color($opts{'color'});
2728 $self->{ERRSTR} = $Imager::ERRSTR;
2731 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2737 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2740 unless (exists $opts{'x'} && exists $opts{'y'}) {
2741 $self->{ERRSTR} = "missing seed x and y parameters";
2745 if ($opts{border}) {
2746 my $border = _color($opts{border});
2748 $self->_set_error($Imager::ERRSTR);
2752 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2753 # assume it's a hash ref
2754 require Imager::Fill;
2755 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2756 $self->{ERRSTR} = $Imager::ERRSTR;
2760 $rc = i_flood_cfill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2761 $opts{fill}{fill}, $border);
2764 my $color = _color($opts{'color'});
2766 $self->{ERRSTR} = $Imager::ERRSTR;
2769 $rc = i_flood_fill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2776 $self->{ERRSTR} = $self->_error_as_msg();
2782 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2783 # assume it's a hash ref
2784 require 'Imager/Fill.pm';
2785 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2786 $self->{ERRSTR} = $Imager::ERRSTR;
2790 $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2793 my $color = _color($opts{'color'});
2795 $self->{ERRSTR} = $Imager::ERRSTR;
2798 $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2804 $self->{ERRSTR} = $self->_error_as_msg();
2813 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2815 unless (exists $opts{'x'} && exists $opts{'y'}) {
2816 $self->{ERRSTR} = 'missing x and y parameters';
2822 my $color = _color($opts{color})
2824 if (ref $x && ref $y) {
2825 unless (@$x == @$y) {
2826 $self->{ERRSTR} = 'length of x and y mismatch';
2829 if ($color->isa('Imager::Color')) {
2830 for my $i (0..$#{$opts{'x'}}) {
2831 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color);
2835 for my $i (0..$#{$opts{'x'}}) {
2836 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color);
2841 if ($color->isa('Imager::Color')) {
2842 i_ppix($self->{IMG}, $x, $y, $color);
2845 i_ppixf($self->{IMG}, $x, $y, $color);
2855 my %opts = ( "type"=>'8bit', @_);
2857 unless (exists $opts{'x'} && exists $opts{'y'}) {
2858 $self->{ERRSTR} = 'missing x and y parameters';
2864 if (ref $x && ref $y) {
2865 unless (@$x == @$y) {
2866 $self->{ERRSTR} = 'length of x and y mismatch';
2870 if ($opts{"type"} eq '8bit') {
2871 for my $i (0..$#{$opts{'x'}}) {
2872 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2876 for my $i (0..$#{$opts{'x'}}) {
2877 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2880 return wantarray ? @result : \@result;
2883 if ($opts{"type"} eq '8bit') {
2884 return i_get_pixel($self->{IMG}, $x, $y);
2887 return i_gpixf($self->{IMG}, $x, $y);
2896 my %opts = ( type => '8bit', x=>0, @_);
2898 $self->_valid_image or return;
2900 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2902 unless (defined $opts{'y'}) {
2903 $self->_set_error("missing y parameter");
2907 if ($opts{type} eq '8bit') {
2908 return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2911 elsif ($opts{type} eq 'float') {
2912 return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2915 elsif ($opts{type} eq 'index') {
2916 unless (i_img_type($self->{IMG})) {
2917 $self->_set_error("type => index only valid on paletted images");
2920 return i_gpal($self->{IMG}, $opts{x}, $opts{x} + $opts{width},
2924 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2931 my %opts = ( x=>0, @_);
2933 $self->_valid_image or return;
2935 unless (defined $opts{'y'}) {
2936 $self->_set_error("missing y parameter");
2941 if (ref $opts{pixels} && @{$opts{pixels}}) {
2942 # try to guess the type
2943 if ($opts{pixels}[0]->isa('Imager::Color')) {
2944 $opts{type} = '8bit';
2946 elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
2947 $opts{type} = 'float';
2950 $self->_set_error("missing type parameter and could not guess from pixels");
2956 $opts{type} = '8bit';
2960 if ($opts{type} eq '8bit') {
2961 if (ref $opts{pixels}) {
2962 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2965 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2968 elsif ($opts{type} eq 'float') {
2969 if (ref $opts{pixels}) {
2970 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2973 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2976 elsif ($opts{type} eq 'index') {
2977 if (ref $opts{pixels}) {
2978 return i_ppal($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2981 return i_ppal_p($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2985 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2992 my %opts = ( type => '8bit', x=>0, @_);
2994 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2996 unless (defined $opts{'y'}) {
2997 $self->_set_error("missing y parameter");
3001 unless ($opts{channels}) {
3002 $opts{channels} = [ 0 .. $self->getchannels()-1 ];
3005 if ($opts{type} eq '8bit') {
3006 return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3007 $opts{y}, @{$opts{channels}});
3009 elsif ($opts{type} eq 'float') {
3010 return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3011 $opts{y}, @{$opts{channels}});
3014 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3019 # make an identity matrix of the given size
3023 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
3024 for my $c (0 .. ($size-1)) {
3025 $matrix->[$c][$c] = 1;
3030 # general function to convert an image
3032 my ($self, %opts) = @_;
3035 unless (defined wantarray) {
3036 my @caller = caller;
3037 warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
3041 # the user can either specify a matrix or preset
3042 # the matrix overrides the preset
3043 if (!exists($opts{matrix})) {
3044 unless (exists($opts{preset})) {
3045 $self->{ERRSTR} = "convert() needs a matrix or preset";
3049 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
3050 # convert to greyscale, keeping the alpha channel if any
3051 if ($self->getchannels == 3) {
3052 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
3054 elsif ($self->getchannels == 4) {
3055 # preserve the alpha channel
3056 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
3061 $matrix = _identity($self->getchannels);
3064 elsif ($opts{preset} eq 'noalpha') {
3065 # strip the alpha channel
3066 if ($self->getchannels == 2 or $self->getchannels == 4) {
3067 $matrix = _identity($self->getchannels);
3068 pop(@$matrix); # lose the alpha entry
3071 $matrix = _identity($self->getchannels);
3074 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
3076 $matrix = [ [ 1 ] ];
3078 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
3079 $matrix = [ [ 0, 1 ] ];
3081 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
3082 $matrix = [ [ 0, 0, 1 ] ];
3084 elsif ($opts{preset} eq 'alpha') {
3085 if ($self->getchannels == 2 or $self->getchannels == 4) {
3086 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
3089 # the alpha is just 1 <shrug>
3090 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
3093 elsif ($opts{preset} eq 'rgb') {
3094 if ($self->getchannels == 1) {
3095 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
3097 elsif ($self->getchannels == 2) {
3098 # preserve the alpha channel
3099 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
3102 $matrix = _identity($self->getchannels);
3105 elsif ($opts{preset} eq 'addalpha') {
3106 if ($self->getchannels == 1) {
3107 $matrix = _identity(2);
3109 elsif ($self->getchannels == 3) {
3110 $matrix = _identity(4);
3113 $matrix = _identity($self->getchannels);
3117 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
3123 $matrix = $opts{matrix};
3126 my $new = Imager->new();
3127 $new->{IMG} = i_img_new();
3128 unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
3129 # most likely a bad matrix
3130 $self->{ERRSTR} = _error_as_msg();
3137 # general function to map an image through lookup tables
3140 my ($self, %opts) = @_;
3141 my @chlist = qw( red green blue alpha );
3143 if (!exists($opts{'maps'})) {
3144 # make maps from channel maps
3146 for $chnum (0..$#chlist) {
3147 if (exists $opts{$chlist[$chnum]}) {
3148 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
3149 } elsif (exists $opts{'all'}) {
3150 $opts{'maps'}[$chnum] = $opts{'all'};
3154 if ($opts{'maps'} and $self->{IMG}) {
3155 i_map($self->{IMG}, $opts{'maps'} );
3161 my ($self, %opts) = @_;
3163 defined $opts{mindist} or $opts{mindist} = 0;
3165 defined $opts{other}
3166 or return $self->_set_error("No 'other' parameter supplied");
3167 defined $opts{other}{IMG}
3168 or return $self->_set_error("No image data in 'other' image");
3171 or return $self->_set_error("No image data");
3173 my $result = Imager->new;
3174 $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
3176 or return $self->_set_error($self->_error_as_msg());
3181 # destructive border - image is shrunk by one pixel all around
3184 my ($self,%opts)=@_;
3185 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
3186 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
3190 # Get the width of an image
3194 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3195 return (i_img_info($self->{IMG}))[0];
3198 # Get the height of an image
3202 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3203 return (i_img_info($self->{IMG}))[1];
3206 # Get number of channels in an image
3210 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3211 return i_img_getchannels($self->{IMG});
3218 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3219 return i_img_getmask($self->{IMG});
3227 if (!defined($self->{IMG})) {
3228 $self->{ERRSTR} = 'image is empty';
3231 unless (defined $opts{mask}) {
3232 $self->_set_error("mask parameter required");
3235 i_img_setmask( $self->{IMG} , $opts{mask} );
3240 # Get number of colors in an image
3244 my %opts=('maxcolors'=>2**30,@_);
3245 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
3246 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
3247 return ($rc==-1? undef : $rc);
3250 # draw string to an image
3254 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
3256 my %input=('x'=>0, 'y'=>0, @_);
3257 defined($input{string}) or $input{string} = $input{text};
3259 unless(defined $input{string}) {
3260 $self->{ERRSTR}="missing required parameter 'string'";
3264 unless($input{font}) {
3265 $self->{ERRSTR}="missing required parameter 'font'";
3269 unless ($input{font}->draw(image=>$self, %input)) {
3281 unless ($self->{IMG}) {
3282 $self->{ERRSTR}='empty input image';
3291 my %input=('x'=>0, 'y'=>0, @_);
3292 $input{string}||=$input{text};
3294 unless(exists $input{string}) {
3295 $self->_set_error("missing required parameter 'string'");
3299 unless($input{font}) {
3300 $self->_set_error("missing required parameter 'font'");
3305 unless (@result = $input{font}->align(image=>$img, %input)) {
3309 return wantarray ? @result : $result[0];
3312 my @file_limit_names = qw/width height bytes/;
3314 sub set_file_limits {
3321 @values{@file_limit_names} = (0) x @file_limit_names;
3324 @values{@file_limit_names} = i_get_image_file_limits();
3327 for my $key (keys %values) {
3328 defined $opts{$key} and $values{$key} = $opts{$key};
3331 i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
3334 sub get_file_limits {
3335 i_get_image_file_limits();
3338 # Shortcuts that can be exported
3340 sub newcolor { Imager::Color->new(@_); }
3341 sub newfont { Imager::Font->new(@_); }
3343 *NC=*newcolour=*newcolor;
3350 #### Utility routines
3353 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
3357 my ($self, $msg) = @_;
3360 $self->{ERRSTR} = $msg;
3368 # Default guess for the type of an image from extension
3370 sub def_guess_type {
3373 $ext=($name =~ m/\.([^\.]+)$/)[0];
3374 return 'tiff' if ($ext =~ m/^tiff?$/);
3375 return 'jpeg' if ($ext =~ m/^jpe?g$/);
3376 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
3377 return 'png' if ($ext eq "png");
3378 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
3379 return 'tga' if ($ext eq "tga");
3380 return 'rgb' if ($ext eq "rgb");
3381 return 'gif' if ($ext eq "gif");
3382 return 'raw' if ($ext eq "raw");
3383 return lc $ext; # best guess
3387 # get the minimum of a list
3391 for(@_) { if ($_<$mx) { $mx=$_; }}
3395 # get the maximum of a list
3399 for(@_) { if ($_>$mx) { $mx=$_; }}
3403 # string stuff for iptc headers
3407 $str = substr($str,3);
3408 $str =~ s/[\n\r]//g;
3415 # A little hack to parse iptc headers.
3420 my($caption,$photogr,$headln,$credit);
3422 my $str=$self->{IPTCRAW};
3427 @ar=split(/8BIM/,$str);
3432 @sar=split(/\034\002/);
3433 foreach $item (@sar) {
3434 if ($item =~ m/^x/) {
3435 $caption = _clean($item);
3438 if ($item =~ m/^P/) {
3439 $photogr = _clean($item);
3442 if ($item =~ m/^i/) {
3443 $headln = _clean($item);
3446 if ($item =~ m/^n/) {
3447 $credit = _clean($item);
3453 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
3460 or die "Only C language supported";
3462 require Imager::ExtUtils;
3463 return Imager::ExtUtils->inline_config;
3468 # Below is the stub of documentation for your module. You better edit it!
3472 Imager - Perl extension for Generating 24 bit Images
3482 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
3487 my $img = Imager->new();
3488 # see Imager::Files for information on the read() method
3489 $img->read(file=>$file) or die $img->errstr();
3491 $file =~ s/\.[^.]*$//;
3493 # Create smaller version
3494 # documented in Imager::Transformations
3495 my $thumb = $img->scale(scalefactor=>.3);
3497 # Autostretch individual channels
3498 $thumb->filter(type=>'autolevels');
3500 # try to save in one of these formats
3503 for $format ( qw( png gif jpg tiff ppm ) ) {
3504 # Check if given format is supported
3505 if ($Imager::formats{$format}) {
3506 $file.="_low.$format";
3507 print "Storing image as: $file\n";
3508 # documented in Imager::Files
3509 $thumb->write(file=>$file) or
3517 Imager is a module for creating and altering images. It can read and
3518 write various image formats, draw primitive shapes like lines,and
3519 polygons, blend multiple images together in various ways, scale, crop,
3520 render text and more.
3522 =head2 Overview of documentation
3528 Imager - This document - Synopsis, Example, Table of Contents and
3533 L<Imager::Tutorial> - a brief introduction to Imager.
3537 L<Imager::Cookbook> - how to do various things with Imager.
3541 L<Imager::ImageTypes> - Basics of constructing image objects with
3542 C<new()>: Direct type/virtual images, RGB(A)/paletted images,
3543 8/16/double bits/channel, color maps, channel masks, image tags, color
3544 quantization. Also discusses basic image information methods.
3548 L<Imager::Files> - IO interaction, reading/writing images, format
3553 L<Imager::Draw> - Drawing Primitives, lines, boxes, circles, arcs,
3558 L<Imager::Color> - Color specification.
3562 L<Imager::Fill> - Fill pattern specification.
3566 L<Imager::Font> - General font rendering, bounding boxes and font
3571 L<Imager::Transformations> - Copying, scaling, cropping, flipping,
3572 blending, pasting, convert and map.
3576 L<Imager::Engines> - Programmable transformations through
3577 C<transform()>, C<transform2()> and C<matrix_transform()>.
3581 L<Imager::Filters> - Filters, sharpen, blur, noise, convolve etc. and
3586 L<Imager::Expr> - Expressions for evaluation engine used by
3591 L<Imager::Matrix2d> - Helper class for affine transformations.
3595 L<Imager::Fountain> - Helper for making gradient profiles.
3599 L<Imager::API> - using Imager's C API
3603 L<Imager::APIRef> - API function reference
3607 L<Imager::Inline> - using Imager's C API from Inline::C
3611 L<Imager::ExtUtils> - tools to get access to Imager's C API.
3615 =head2 Basic Overview
3617 An Image object is created with C<$img = Imager-E<gt>new()>.
3620 $img=Imager->new(); # create empty image
3621 $img->read(file=>'lena.png',type=>'png') or # read image from file
3622 die $img->errstr(); # give an explanation
3623 # if something failed
3625 or if you want to create an empty image:
3627 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
3629 This example creates a completely black image of width 400 and height
3632 =head1 ERROR HANDLING
3634 In general a method will return false when it fails, if it does use the errstr() method to find out why:
3640 Returns the last error message in that context.
3642 If the last error you received was from calling an object method, such
3643 as read, call errstr() as an object method to find out why:
3645 my $image = Imager->new;
3646 $image->read(file => 'somefile.gif')
3647 or die $image->errstr;
3649 If it was a class method then call errstr() as a class method:
3651 my @imgs = Imager->read_multi(file => 'somefile.gif')
3652 or die Imager->errstr;
3654 Note that in some cases object methods are implemented in terms of
3655 class methods so a failing object method may set both.
3659 The C<Imager-E<gt>new> method is described in detail in
3660 L<Imager::ImageTypes>.
3664 Where to find information on methods for Imager class objects.
3666 addcolors() - L<Imager::ImageTypes/addcolors>
3668 addtag() - L<Imager::ImageTypes/addtag> - add image tags
3670 align_string() - L<Imager::Draw/align_string>
3672 arc() - L<Imager::Draw/arc>
3674 bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
3677 box() - L<Imager::Draw/box>
3679 circle() - L<Imager::Draw/circle>
3681 colorcount() - L<Imager::Draw/colorcount>
3683 convert() - L<Imager::Transformations/"Color transformations"> -
3684 transform the color space
3686 copy() - L<Imager::Transformations/copy>
3688 crop() - L<Imager::Transformations/crop> - extract part of an image
3690 def_guess_type() - L<Imager::Files/def_guess_type>
3692 deltag() - L<Imager::ImageTypes/deltag> - delete image tags
3694 difference() - L<Imager::Filters/"Image Difference">
3696 errstr() - L<"Basic Overview">
3698 filter() - L<Imager::Filters>
3700 findcolor() - L<Imager::ImageTypes/findcolor> - search the image palette, if it
3703 flip() - L<Imager::Transformations/flip>
3705 flood_fill() - L<Imager::Draw/flood_fill>
3707 getchannels() - L<Imager::ImageTypes/getchannels>
3709 getcolorcount() - L<Imager::ImageTypes/getcolorcount>
3711 getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
3712 palette, if it has one
3714 get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3716 getheight() - L<Imager::ImageTypes/getwidth>
3718 getmask() - L<Imager::ImageTypes/getmask>
3720 getpixel() - L<Imager::Draw/getpixel>
3722 getsamples() - L<Imager::Draw/getsamples>
3724 getscanline() - L<Imager::Draw/getscanline>
3726 getwidth() - L<Imager::ImageTypes/getwidth>
3728 img_set() - L<Imager::ImageTypes/img_set>
3730 init() - L<Imager::ImageTypes/init>
3732 line() - L<Imager::Draw/line>
3734 load_plugin() - L<Imager::Filters/load_plugin>
3736 map() - L<Imager::Transformations/"Color Mappings"> - remap color
3739 masked() - L<Imager::ImageTypes/masked> - make a masked image
3741 matrix_transform() - L<Imager::Engines/matrix_transform>
3743 maxcolors() - L<Imager::ImageTypes/maxcolors>
3745 NC() - L<Imager::Handy/NC>
3747 new() - L<Imager::ImageTypes/new>
3749 newcolor() - L<Imager::Handy/newcolor>
3751 newcolour() - L<Imager::Handy/newcolour>
3753 newfont() - L<Imager::Handy/newfont>
3755 NF() - L<Imager::Handy/NF>
3757 open() - L<Imager::Files> - an alias for read()
3759 parseiptc() - L<Imager::Files/parseiptc> - parse IPTC data from a JPEG
3762 paste() - L<Imager::Transformations/paste> - draw an image onto an image
3764 polygon() - L<Imager::Draw/polygon>
3766 polyline() - L<Imager::Draw/polyline>
3768 read() - L<Imager::Files> - read a single image from an image file
3770 read_multi() - L<Imager::Files> - read multiple images from an image
3773 register_filter() - L<Imager::Filters/register_filter>
3775 register_reader() - L<Imager::Filters/register_reader>
3777 register_writer() - L<Imager::Filters/register_writer>
3779 rotate() - L<Imager::Transformations/rotate>
3781 rubthrough() - L<Imager::Transformations/rubthrough> - draw an image onto an
3782 image and use the alpha channel
3784 scale() - L<Imager::Transformations/scale>
3786 scaleX() - L<Imager::Transformations/scaleX>
3788 scaleY() - L<Imager::Transformations/scaleY>
3790 setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
3793 set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3795 setmask() - L<Imager::ImageTypes/setmask>
3797 setpixel() - L<Imager::Draw/setpixel>
3799 setscanline() - L<Imager::Draw/setscanline>
3801 settag() - L<Imager::ImageTypes/settag>
3803 string() - L<Imager::Draw/string> - draw text on an image
3805 tags() - L<Imager::ImageTypes/tags> - fetch image tags
3807 to_paletted() - L<Imager::ImageTypes/to_paletted>
3809 to_rgb8() - L<Imager::ImageTypes/to_rgb8>
3811 transform() - L<Imager::Engines/"transform">
3813 transform2() - L<Imager::Engines/"transform2">
3815 type() - L<Imager::ImageTypes/type> - type of image (direct vs paletted)
3817 unload_plugin() - L<Imager::Filters/unload_plugin>
3819 virtual() - L<Imager::ImageTypes/virtual> - whether the image has it's own
3822 write() - L<Imager::Files> - write an image to a file
3824 write_multi() - L<Imager::Files> - write multiple image to an image
3827 =head1 CONCEPT INDEX
3829 animated GIF - L<Imager::File/"Writing an animated GIF">
3831 aspect ratio - L<Imager::ImageTypes/i_xres>,
3832 L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
3834 blend - alpha blending one image onto another
3835 L<Imager::Transformations/rubthrough>
3837 blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
3839 boxes, drawing - L<Imager::Draw/box>
3841 changes between image - L<Imager::Filter/"Image Difference">
3843 color - L<Imager::Color>
3845 color names - L<Imager::Color>, L<Imager::Color::Table>
3847 combine modes - L<Imager::Fill/combine>
3849 compare images - L<Imager::Filter/"Image Difference">
3851 contrast - L<Imager::Filter/contrast>, L<Imager::Filter/autolevels>
3853 convolution - L<Imager::Filter/conv>
3855 cropping - L<Imager::Transformations/crop>
3857 C<diff> images - L<Imager::Filter/"Image Difference">
3859 dpi - L<Imager::ImageTypes/i_xres>,
3860 L<Imager::Cookbook/"Image spatial resolution">
3862 drawing boxes - L<Imager::Draw/box>
3864 drawing lines - L<Imager::Draw/line>
3866 drawing text - L<Imager::Draw/string>, L<Imager::Draw/align_string>
3868 error message - L<"Basic Overview">
3870 files, font - L<Imager::Font>
3872 files, image - L<Imager::Files>
3874 filling, types of fill - L<Imager::Fill>
3876 filling, boxes - L<Imager::Draw/box>
3878 filling, flood fill - L<Imager::Draw/flood_fill>
3880 flood fill - L<Imager::Draw/flood_fill>
3882 fonts - L<Imager::Font>
3884 fonts, drawing with - L<Imager::Draw/string>,
3885 L<Imager::Draw/align_string>, L<Imager::Font::Wrap>
3887 fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3889 fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
3891 fountain fill - L<Imager::Fill/"Fountain fills">,
3892 L<Imager::Filters/fountain>, L<Imager::Fountain>,
3893 L<Imager::Filters/gradgen>
3895 GIF files - L<Imager::Files/"GIF">
3897 GIF files, animated - L<Imager::File/"Writing an animated GIF">
3899 gradient fill - L<Imager::Fill/"Fountain fills">,
3900 L<Imager::Filters/fountain>, L<Imager::Fountain>,
3901 L<Imager::Filters/gradgen>
3903 guassian blur - L<Imager::Filter/guassian>
3905 hatch fills - L<Imager::Fill/"Hatched fills">
3907 invert image - L<Imager::Filter/hardinvert>
3909 JPEG - L<Imager::Files/"JPEG">
3911 limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
3913 lines, drawing - L<Imager::Draw/line>
3915 matrix - L<Imager::Matrix2d>,
3916 L<Imager::Transformations/"Matrix Transformations">,
3917 L<Imager::Font/transform>
3919 metadata, image - L<Imager::ImageTypes/"Tags">
3921 mosaic - L<Imager::Filter/mosaic>
3923 noise, filter - L<Imager::Filter/noise>
3925 noise, rendered - L<Imager::Filter/turbnoise>,
3926 L<Imager::Filter/radnoise>
3928 paste - L<Imager::Transformations/paste>,
3929 L<Imager::Transformations/rubthrough>
3931 pseudo-color image - L<Imager::ImageTypes/to_paletted>,
3932 L<Imager::ImageTypes/new>
3934 posterize - L<Imager::Filter/postlevels>
3936 png files - L<Imager::Files>, L<Imager::Files/"PNG">
3938 pnm - L<Imager::Files/"PNM (Portable aNy Map)">
3940 rectangles, drawing - L<Imager::Draw/box>
3942 resizing an image - L<Imager::Transformations/scale>,
3943 L<Imager::Transformations/crop>
3945 saving an image - L<Imager::Files>
3947 scaling - L<Imager::Transformations/scale>
3949 sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
3951 size, image - L<Imager::ImageTypes/getwidth>,
3952 L<Imager::ImageTypes/getheight>
3954 size, text - L<Imager::Font/bounding_box>
3956 tags, image metadata - L<Imager::ImageTypes/"Tags">
3958 text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
3959 L<Imager::Font::Wrap>
3961 text, wrapping text in an area - L<Imager::Font::Wrap>
3963 text, measuring - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3965 tiles, color - L<Imager::Filter/mosaic>
3967 unsharp mask - L<Imager::Filter/unsharpmask>
3969 watermark - L<Imager::Filter/watermark>
3971 writing an image to a file - L<Imager::Files>
3975 The best place to get help with Imager is the mailing list.
3977 To subscribe send a message with C<subscribe> in the body to:
3979 imager-devel+request@molar.is
3985 L<http://www.molar.is/en/lists/imager-devel/>
3989 where you can also find the mailing list archive.
3991 You can report bugs by pointing your browser at:
3995 L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager>
3999 Please remember to include the versions of Imager, perl, supporting
4000 libraries, and any relevant code. If you have specific images that
4001 cause the problems, please include those too.
4005 Bugs are listed individually for relevant pod pages.
4009 Arnar M. Hrafnkelsson and Tony Cook (tony@imager.perl.org) among
4010 others. See the README for a complete list.
4014 L<perl>(1), L<Imager::ImageTypes>(3), L<Imager::Files>(3),
4015 L<Imager::Draw>(3), L<Imager::Color>(3), L<Imager::Fill>(3),
4016 L<Imager::Font>(3), L<Imager::Transformations>(3),
4017 L<Imager::Engines>(3), L<Imager::Filters>(3), L<Imager::Expr>(3),
4018 L<Imager::Matrix2d>(3), L<Imager::Fountain>(3)
4020 L<http://imager.perl.org/>
4022 L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
4024 Other perl imaging modules include:
4026 L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).