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");
757 if( $r < $l or $b < $t ) {
758 $self->_set_error("attempting to crop outside of the image");
761 my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t);
763 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
768 my ($self, %opts) = @_;
770 $self->{IMG} or return $self->_set_error("Not a valid image");
772 my $x = $opts{xsize} || $self->getwidth;
773 my $y = $opts{ysize} || $self->getheight;
774 my $channels = $opts{channels} || $self->getchannels;
776 my $out = Imager->new;
777 if ($channels == $self->getchannels) {
778 $out->{IMG} = i_sametype($self->{IMG}, $x, $y);
781 $out->{IMG} = i_sametype_chans($self->{IMG}, $x, $y, $channels);
783 unless ($out->{IMG}) {
784 $self->{ERRSTR} = $self->_error_as_msg;
791 # Sets an image to a certain size and channel number
792 # if there was previously data in the image it is discarded
797 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
799 if (defined($self->{IMG})) {
800 # let IIM_DESTROY destroy it, it's possible this image is
801 # referenced from a virtual image (like masked)
802 #i_img_destroy($self->{IMG});
806 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
807 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
808 $hsh{maxcolors} || 256);
810 elsif ($hsh{bits} eq 'double') {
811 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
813 elsif ($hsh{bits} == 16) {
814 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
817 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
821 unless ($self->{IMG}) {
822 $self->{ERRSTR} = Imager->_error_as_msg();
829 # created a masked version of the current image
833 $self or return undef;
834 my %opts = (left => 0,
836 right => $self->getwidth,
837 bottom => $self->getheight,
839 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
841 my $result = Imager->new;
842 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
843 $opts{top}, $opts{right} - $opts{left},
844 $opts{bottom} - $opts{top});
845 # keep references to the mask and base images so they don't
847 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
852 # convert an RGB image into a paletted image
856 if (@_ != 1 && !ref $_[0]) {
863 unless (defined wantarray) {
865 warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n";
869 my $result = Imager->new;
870 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
872 #print "Type ", i_img_type($result->{IMG}), "\n";
874 if ($result->{IMG}) {
878 $self->{ERRSTR} = $self->_error_as_msg;
883 # convert a paletted (or any image) to an 8-bit/channel RGB images
888 unless (defined wantarray) {
890 warn "to_rgb8() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
895 $result = Imager->new;
896 $result->{IMG} = i_img_to_rgb($self->{IMG})
903 # convert a paletted (or any image) to an 8-bit/channel RGB images
908 unless (defined wantarray) {
910 warn "to_rgb16() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
915 $result = Imager->new;
916 $result->{IMG} = i_img_to_rgb16($self->{IMG})
925 my %opts = (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_addcolors($self->{IMG}, @colors);
948 my %opts = (start=>0, colors=>[], @_);
950 unless ($self->{IMG}) {
951 $self->_set_error("empty input image");
955 my @colors = @{$opts{colors}}
958 for my $color (@colors) {
959 $color = _color($color);
961 $self->_set_error($Imager::ERRSTR);
966 return i_setcolors($self->{IMG}, $opts{start}, @colors);
972 if (!exists $opts{start} && !exists $opts{count}) {
975 $opts{count} = $self->colorcount;
977 elsif (!exists $opts{count}) {
980 elsif (!exists $opts{start}) {
985 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
989 i_colorcount($_[0]{IMG});
993 i_maxcolors($_[0]{IMG});
999 $opts{color} or return undef;
1001 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
1006 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
1007 if ($bits && $bits == length(pack("d", 1)) * 8) {
1016 return i_img_type($self->{IMG}) ? "paletted" : "direct";
1022 $self->{IMG} and i_img_virtual($self->{IMG});
1026 my ($self, %opts) = @_;
1028 $self->{IMG} or return;
1030 if (defined $opts{name}) {
1034 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
1035 push @result, (i_tags_get($self->{IMG}, $found))[1];
1038 return wantarray ? @result : $result[0];
1040 elsif (defined $opts{code}) {
1044 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
1045 push @result, (i_tags_get($self->{IMG}, $found))[1];
1052 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
1055 return i_tags_count($self->{IMG});
1064 return -1 unless $self->{IMG};
1066 if (defined $opts{value}) {
1067 if ($opts{value} =~ /^\d+$/) {
1069 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
1072 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
1075 elsif (defined $opts{data}) {
1076 # force addition as a string
1077 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
1080 $self->{ERRSTR} = "No value supplied";
1084 elsif ($opts{code}) {
1085 if (defined $opts{value}) {
1086 if ($opts{value} =~ /^\d+$/) {
1088 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
1091 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
1094 elsif (defined $opts{data}) {
1095 # force addition as a string
1096 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
1099 $self->{ERRSTR} = "No value supplied";
1112 return 0 unless $self->{IMG};
1114 if (defined $opts{'index'}) {
1115 return i_tags_delete($self->{IMG}, $opts{'index'});
1117 elsif (defined $opts{name}) {
1118 return i_tags_delbyname($self->{IMG}, $opts{name});
1120 elsif (defined $opts{code}) {
1121 return i_tags_delbycode($self->{IMG}, $opts{code});
1124 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
1130 my ($self, %opts) = @_;
1133 $self->deltag(name=>$opts{name});
1134 return $self->addtag(name=>$opts{name}, value=>$opts{value});
1136 elsif (defined $opts{code}) {
1137 $self->deltag(code=>$opts{code});
1138 return $self->addtag(code=>$opts{code}, value=>$opts{value});
1146 sub _get_reader_io {
1147 my ($self, $input) = @_;
1150 return $input->{io}, undef;
1152 elsif ($input->{fd}) {
1153 return io_new_fd($input->{fd});
1155 elsif ($input->{fh}) {
1156 my $fd = fileno($input->{fh});
1158 $self->_set_error("Handle in fh option not opened");
1161 return io_new_fd($fd);
1163 elsif ($input->{file}) {
1164 my $file = IO::File->new($input->{file}, "r");
1166 $self->_set_error("Could not open $input->{file}: $!");
1170 return (io_new_fd(fileno($file)), $file);
1172 elsif ($input->{data}) {
1173 return io_new_buffer($input->{data});
1175 elsif ($input->{callback} || $input->{readcb}) {
1176 if (!$input->{seekcb}) {
1177 $self->_set_error("Need a seekcb parameter");
1179 if ($input->{maxbuffer}) {
1180 return io_new_cb($input->{writecb},
1181 $input->{callback} || $input->{readcb},
1182 $input->{seekcb}, $input->{closecb},
1183 $input->{maxbuffer});
1186 return io_new_cb($input->{writecb},
1187 $input->{callback} || $input->{readcb},
1188 $input->{seekcb}, $input->{closecb});
1192 $self->_set_error("file/fd/fh/data/callback parameter missing");
1197 sub _get_writer_io {
1198 my ($self, $input, $type) = @_;
1201 return $input->{io};
1203 elsif ($input->{fd}) {
1204 return io_new_fd($input->{fd});
1206 elsif ($input->{fh}) {
1207 my $fd = fileno($input->{fh});
1209 $self->_set_error("Handle in fh option not opened");
1213 my $oldfh = select($input->{fh});
1214 # flush anything that's buffered, and make sure anything else is flushed
1217 return io_new_fd($fd);
1219 elsif ($input->{file}) {
1220 my $fh = new IO::File($input->{file},"w+");
1222 $self->_set_error("Could not open file $input->{file}: $!");
1225 binmode($fh) or die;
1226 return (io_new_fd(fileno($fh)), $fh);
1228 elsif ($input->{data}) {
1229 return io_new_bufchain();
1231 elsif ($input->{callback} || $input->{writecb}) {
1232 if ($input->{maxbuffer}) {
1233 return io_new_cb($input->{callback} || $input->{writecb},
1235 $input->{seekcb}, $input->{closecb},
1236 $input->{maxbuffer});
1239 return io_new_cb($input->{callback} || $input->{writecb},
1241 $input->{seekcb}, $input->{closecb});
1245 $self->_set_error("file/fd/fh/data/callback parameter missing");
1250 # Read an image from file
1256 if (defined($self->{IMG})) {
1257 # let IIM_DESTROY do the destruction, since the image may be
1258 # referenced from elsewhere
1259 #i_img_destroy($self->{IMG});
1260 undef($self->{IMG});
1263 my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
1265 unless ($input{'type'}) {
1266 $input{'type'} = i_test_format_probe($IO, -1);
1269 unless ($input{'type'}) {
1270 $self->_set_error('type parameter missing and not possible to guess from extension');
1274 _reader_autoload($input{type});
1276 if ($readers{$input{type}} && $readers{$input{type}}{single}) {
1277 return $readers{$input{type}}{single}->($self, $IO, %input);
1280 unless ($formats{$input{'type'}}) {
1281 $self->_set_error("format '$input{'type'}' not supported");
1286 if ( $input{'type'} eq 'jpeg' ) {
1287 ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
1288 if ( !defined($self->{IMG}) ) {
1289 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1291 $self->{DEBUG} && print "loading a jpeg file\n";
1295 my $allow_incomplete = $input{allow_incomplete};
1296 defined $allow_incomplete or $allow_incomplete = 0;
1298 if ( $input{'type'} eq 'tiff' ) {
1299 my $page = $input{'page'};
1300 defined $page or $page = 0;
1301 $self->{IMG}=i_readtiff_wiol( $IO, $allow_incomplete, $page );
1302 if ( !defined($self->{IMG}) ) {
1303 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1305 $self->{DEBUG} && print "loading a tiff file\n";
1309 if ( $input{'type'} eq 'pnm' ) {
1310 $self->{IMG}=i_readpnm_wiol( $IO, $allow_incomplete );
1311 if ( !defined($self->{IMG}) ) {
1312 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg();
1315 $self->{DEBUG} && print "loading a pnm file\n";
1319 if ( $input{'type'} eq 'png' ) {
1320 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1321 if ( !defined($self->{IMG}) ) {
1322 $self->{ERRSTR} = $self->_error_as_msg();
1325 $self->{DEBUG} && print "loading a png file\n";
1328 if ( $input{'type'} eq 'bmp' ) {
1329 $self->{IMG}=i_readbmp_wiol( $IO, $allow_incomplete );
1330 if ( !defined($self->{IMG}) ) {
1331 $self->{ERRSTR}=$self->_error_as_msg();
1334 $self->{DEBUG} && print "loading a bmp file\n";
1337 if ( $input{'type'} eq 'gif' ) {
1338 if ($input{colors} && !ref($input{colors})) {
1339 # must be a reference to a scalar that accepts the colour map
1340 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1343 if ($input{'gif_consolidate'}) {
1344 if ($input{colors}) {
1346 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1348 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1352 $self->{IMG} =i_readgif_wiol( $IO );
1356 my $page = $input{'page'};
1357 defined $page or $page = 0;
1358 $self->{IMG} = i_readgif_single_wiol( $IO, $page );
1359 if ($input{colors}) {
1360 ${ $input{colors} } =
1361 [ i_getcolors($self->{IMG}, 0, i_colorcount($self->{IMG})) ];
1365 if ( !defined($self->{IMG}) ) {
1366 $self->{ERRSTR}=$self->_error_as_msg();
1369 $self->{DEBUG} && print "loading a gif file\n";
1372 if ( $input{'type'} eq 'tga' ) {
1373 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1374 if ( !defined($self->{IMG}) ) {
1375 $self->{ERRSTR}=$self->_error_as_msg();
1378 $self->{DEBUG} && print "loading a tga file\n";
1381 if ( $input{'type'} eq 'rgb' ) {
1382 $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1383 if ( !defined($self->{IMG}) ) {
1384 $self->{ERRSTR}=$self->_error_as_msg();
1387 $self->{DEBUG} && print "loading a tga file\n";
1391 if ( $input{'type'} eq 'raw' ) {
1392 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1394 if ( !($params{xsize} && $params{ysize}) ) {
1395 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1399 $self->{IMG} = i_readraw_wiol( $IO,
1402 $params{datachannels},
1403 $params{storechannels},
1404 $params{interleave});
1405 if ( !defined($self->{IMG}) ) {
1406 $self->{ERRSTR}=$self->_error_as_msg();
1409 $self->{DEBUG} && print "loading a raw file\n";
1415 sub register_reader {
1416 my ($class, %opts) = @_;
1419 or die "register_reader called with no type parameter\n";
1421 my $type = $opts{type};
1423 defined $opts{single} || defined $opts{multiple}
1424 or die "register_reader called with no single or multiple parameter\n";
1426 $readers{$type} = { };
1427 if ($opts{single}) {
1428 $readers{$type}{single} = $opts{single};
1430 if ($opts{multiple}) {
1431 $readers{$type}{multiple} = $opts{multiple};
1437 sub register_writer {
1438 my ($class, %opts) = @_;
1441 or die "register_writer called with no type parameter\n";
1443 my $type = $opts{type};
1445 defined $opts{single} || defined $opts{multiple}
1446 or die "register_writer called with no single or multiple parameter\n";
1448 $writers{$type} = { };
1449 if ($opts{single}) {
1450 $writers{$type}{single} = $opts{single};
1452 if ($opts{multiple}) {
1453 $writers{$type}{multiple} = $opts{multiple};
1459 # probes for an Imager::File::whatever module
1460 sub _reader_autoload {
1463 return if $formats{$type} || $readers{$type};
1465 return unless $type =~ /^\w+$/;
1467 my $file = "Imager/File/\U$type\E.pm";
1469 unless ($attempted_to_load{$file}) {
1471 ++$attempted_to_load{$file};
1475 # try to get a reader specific module
1476 my $file = "Imager/File/\U$type\EReader.pm";
1477 unless ($attempted_to_load{$file}) {
1479 ++$attempted_to_load{$file};
1487 # probes for an Imager::File::whatever module
1488 sub _writer_autoload {
1491 return if $formats{$type} || $readers{$type};
1493 return unless $type =~ /^\w+$/;
1495 my $file = "Imager/File/\U$type\E.pm";
1497 unless ($attempted_to_load{$file}) {
1499 ++$attempted_to_load{$file};
1503 # try to get a writer specific module
1504 my $file = "Imager/File/\U$type\EWriter.pm";
1505 unless ($attempted_to_load{$file}) {
1507 ++$attempted_to_load{$file};
1515 sub _fix_gif_positions {
1516 my ($opts, $opt, $msg, @imgs) = @_;
1518 my $positions = $opts->{'gif_positions'};
1520 for my $pos (@$positions) {
1521 my ($x, $y) = @$pos;
1522 my $img = $imgs[$index++];
1523 $img->settag(name=>'gif_left', value=>$x);
1524 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1526 $$msg .= "replaced with the gif_left and gif_top tags";
1531 gif_each_palette=>'gif_local_map',
1532 interlace => 'gif_interlace',
1533 gif_delays => 'gif_delay',
1534 gif_positions => \&_fix_gif_positions,
1535 gif_loop_count => 'gif_loop',
1539 my ($self, $opts, $prefix, @imgs) = @_;
1541 for my $opt (keys %$opts) {
1543 if ($obsolete_opts{$opt}) {
1544 my $new = $obsolete_opts{$opt};
1545 my $msg = "Obsolete option $opt ";
1547 $new->($opts, $opt, \$msg, @imgs);
1550 $msg .= "replaced with the $new tag ";
1553 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1554 warn $msg if $warn_obsolete && $^W;
1556 next unless $tagname =~ /^\Q$prefix/;
1557 my $value = $opts->{$opt};
1559 if (UNIVERSAL::isa($value, "Imager::Color")) {
1560 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1561 for my $img (@imgs) {
1562 $img->settag(name=>$tagname, value=>$tag);
1565 elsif (ref($value) eq 'ARRAY') {
1566 for my $i (0..$#$value) {
1567 my $val = $value->[$i];
1569 if (UNIVERSAL::isa($val, "Imager::Color")) {
1570 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1572 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1575 $self->_set_error("Unknown reference type " . ref($value) .
1576 " supplied in array for $opt");
1582 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1587 $self->_set_error("Unknown reference type " . ref($value) .
1588 " supplied for $opt");
1593 # set it as a tag for every image
1594 for my $img (@imgs) {
1595 $img->settag(name=>$tagname, value=>$value);
1603 # Write an image to file
1606 my %input=(jpegquality=>75,
1616 $self->_set_opts(\%input, "i_", $self)
1619 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1621 if (!$input{'type'} and $input{file}) {
1622 $input{'type'}=$FORMATGUESS->($input{file});
1624 if (!$input{'type'}) {
1625 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1629 _writer_autoload($input{type});
1632 if ($writers{$input{type}} && $writers{$input{type}}{single}) {
1633 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1636 $writers{$input{type}}{single}->($self, $IO, %input)
1640 if (!$formats{$input{'type'}}) {
1641 $self->{ERRSTR}='format not supported';
1645 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1648 if ($input{'type'} eq 'tiff') {
1649 $self->_set_opts(\%input, "tiff_", $self)
1651 $self->_set_opts(\%input, "exif_", $self)
1654 if (defined $input{class} && $input{class} eq 'fax') {
1655 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1656 $self->{ERRSTR} = $self->_error_as_msg();
1660 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1661 $self->{ERRSTR} = $self->_error_as_msg();
1665 } elsif ( $input{'type'} eq 'pnm' ) {
1666 $self->_set_opts(\%input, "pnm_", $self)
1668 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1669 $self->{ERRSTR} = $self->_error_as_msg();
1672 $self->{DEBUG} && print "writing a pnm file\n";
1673 } elsif ( $input{'type'} eq 'raw' ) {
1674 $self->_set_opts(\%input, "raw_", $self)
1676 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1677 $self->{ERRSTR} = $self->_error_as_msg();
1680 $self->{DEBUG} && print "writing a raw file\n";
1681 } elsif ( $input{'type'} eq 'png' ) {
1682 $self->_set_opts(\%input, "png_", $self)
1684 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1685 $self->{ERRSTR}='unable to write png image';
1688 $self->{DEBUG} && print "writing a png file\n";
1689 } elsif ( $input{'type'} eq 'jpeg' ) {
1690 $self->_set_opts(\%input, "jpeg_", $self)
1692 $self->_set_opts(\%input, "exif_", $self)
1694 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1695 $self->{ERRSTR} = $self->_error_as_msg();
1698 $self->{DEBUG} && print "writing a jpeg file\n";
1699 } elsif ( $input{'type'} eq 'bmp' ) {
1700 $self->_set_opts(\%input, "bmp_", $self)
1702 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1703 $self->{ERRSTR} = $self->_error_as_msg;
1706 $self->{DEBUG} && print "writing a bmp file\n";
1707 } elsif ( $input{'type'} eq 'tga' ) {
1708 $self->_set_opts(\%input, "tga_", $self)
1711 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1712 $self->{ERRSTR}=$self->_error_as_msg();
1715 $self->{DEBUG} && print "writing a tga file\n";
1716 } elsif ( $input{'type'} eq 'gif' ) {
1717 $self->_set_opts(\%input, "gif_", $self)
1719 # compatibility with the old interfaces
1720 if ($input{gifquant} eq 'lm') {
1721 $input{make_colors} = 'addi';
1722 $input{translate} = 'perturb';
1723 $input{perturb} = $input{lmdither};
1724 } elsif ($input{gifquant} eq 'gen') {
1725 # just pass options through
1727 $input{make_colors} = 'webmap'; # ignored
1728 $input{translate} = 'giflib';
1730 if (!i_writegif_wiol($IO, \%input, $self->{IMG})) {
1731 $self->{ERRSTR} = $self->_error_as_msg;
1737 if (exists $input{'data'}) {
1738 my $data = io_slurp($IO);
1740 $self->{ERRSTR}='Could not slurp from buffer';
1743 ${$input{data}} = $data;
1749 my ($class, $opts, @images) = @_;
1751 my $type = $opts->{type};
1753 if (!$type && $opts->{'file'}) {
1754 $type = $FORMATGUESS->($opts->{'file'});
1757 $class->_set_error('type parameter missing and not possible to guess from extension');
1760 # translate to ImgRaw
1761 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1762 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1765 $class->_set_opts($opts, "i_", @images)
1767 my @work = map $_->{IMG}, @images;
1769 _writer_autoload($type);
1772 if ($writers{$type} && $writers{$type}{multiple}) {
1773 ($IO, $file) = $class->_get_writer_io($opts, $type)
1776 $writers{$type}{multiple}->($class, $IO, $opts, @images)
1780 if (!$formats{$type}) {
1781 $class->_set_error("format $type not supported");
1785 ($IO, $file) = $class->_get_writer_io($opts, $type)
1788 if ($type eq 'gif') {
1789 $class->_set_opts($opts, "gif_", @images)
1791 my $gif_delays = $opts->{gif_delays};
1792 local $opts->{gif_delays} = $gif_delays;
1793 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1794 # assume the caller wants the same delay for each frame
1795 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1797 unless (i_writegif_wiol($IO, $opts, @work)) {
1798 $class->_set_error($class->_error_as_msg());
1802 elsif ($type eq 'tiff') {
1803 $class->_set_opts($opts, "tiff_", @images)
1805 $class->_set_opts($opts, "exif_", @images)
1808 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1809 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1810 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1813 $res = i_writetiff_multi_wiol($IO, @work);
1816 $class->_set_error($class->_error_as_msg());
1822 unless ($images[0]->write(%$opts, io => $IO, type => $type)) {
1827 $ERRSTR = "Sorry, write_multi doesn't support $type yet";
1833 if (exists $opts->{'data'}) {
1834 my $data = io_slurp($IO);
1836 Imager->_set_error('Could not slurp from buffer');
1839 ${$opts->{data}} = $data;
1844 # read multiple images from a file
1846 my ($class, %opts) = @_;
1848 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1851 my $type = $opts{'type'};
1853 $type = i_test_format_probe($IO, -1);
1856 if ($opts{file} && !$type) {
1858 $type = $FORMATGUESS->($opts{file});
1862 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1866 _reader_autoload($type);
1868 if ($readers{$type} && $readers{$type}{multiple}) {
1869 return $readers{$type}{multiple}->($IO, %opts);
1872 if ($type eq 'gif') {
1874 @imgs = i_readgif_multi_wiol($IO);
1877 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1881 $ERRSTR = _error_as_msg();
1885 elsif ($type eq 'tiff') {
1886 my @imgs = i_readtiff_multi_wiol($IO, -1);
1889 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1893 $ERRSTR = _error_as_msg();
1898 my $img = Imager->new;
1899 if ($img->read(%opts, io => $IO, type => $type)) {
1904 $ERRSTR = "Cannot read multiple images from $type files";
1908 # Destroy an Imager object
1912 # delete $instances{$self};
1913 if (defined($self->{IMG})) {
1914 # the following is now handled by the XS DESTROY method for
1915 # Imager::ImgRaw object
1916 # Re-enabling this will break virtual images
1917 # tested for in t/t020masked.t
1918 # i_img_destroy($self->{IMG});
1919 undef($self->{IMG});
1921 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1925 # Perform an inplace filter of an image
1926 # that is the image will be overwritten with the data
1932 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1934 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1936 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1937 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1940 if ($filters{$input{'type'}}{names}) {
1941 my $names = $filters{$input{'type'}}{names};
1942 for my $name (keys %$names) {
1943 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1944 $input{$name} = $names->{$name}{$input{$name}};
1948 if (defined($filters{$input{'type'}}{defaults})) {
1949 %hsh=( image => $self->{IMG},
1951 %{$filters{$input{'type'}}{defaults}},
1954 %hsh=( image => $self->{IMG},
1959 my @cs=@{$filters{$input{'type'}}{callseq}};
1962 if (!defined($hsh{$_})) {
1963 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1968 local $SIG{__DIE__}; # we don't want this processed by confess, etc
1969 &{$filters{$input{'type'}}{callsub}}(%hsh);
1972 chomp($self->{ERRSTR} = $@);
1978 $self->{DEBUG} && print "callseq is: @cs\n";
1979 $self->{DEBUG} && print "matching callseq is: @b\n";
1984 sub register_filter {
1986 my %hsh = ( defaults => {}, @_ );
1989 or die "register_filter() with no type\n";
1990 defined $hsh{callsub}
1991 or die "register_filter() with no callsub\n";
1992 defined $hsh{callseq}
1993 or die "register_filter() with no callseq\n";
1995 exists $filters{$hsh{type}}
1998 $filters{$hsh{type}} = \%hsh;
2003 # Scale an image to requested size and return the scaled version
2007 my %opts=('type'=>'max',qtype=>'normal',@_);
2008 my $img = Imager->new();
2009 my $tmp = Imager->new();
2010 my ($x_scale, $y_scale);
2012 unless (defined wantarray) {
2013 my @caller = caller;
2014 warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
2018 unless ($self->{IMG}) {
2019 $self->_set_error('empty input image');
2023 if ($opts{'xscalefactor'} && $opts{'yscalefactor'}) {
2024 $x_scale = $opts{'xscalefactor'};
2025 $y_scale = $opts{'yscalefactor'};
2027 elsif ($opts{'xscalefactor'}) {
2028 $x_scale = $opts{'xscalefactor'};
2029 $y_scale = $opts{'scalefactor'} || $x_scale;
2031 elsif ($opts{'yscalefactor'}) {
2032 $y_scale = $opts{'yscalefactor'};
2033 $x_scale = $opts{'scalefactor'} || $y_scale;
2036 $x_scale = $y_scale = $opts{'scalefactor'} || 0.5;
2039 # work out the scaling
2040 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
2041 my ($xpix, $ypix)=( $opts{xpixels} / $self->getwidth() ,
2042 $opts{ypixels} / $self->getheight() );
2043 if ($opts{'type'} eq 'min') {
2044 $x_scale = $y_scale = _min($xpix,$ypix);
2046 elsif ($opts{'type'} eq 'max') {
2047 $x_scale = $y_scale = _max($xpix,$ypix);
2049 elsif ($opts{'type'} eq 'nonprop' || $opts{'type'} eq 'non-proportional') {
2054 $self->_set_error('invalid value for type parameter');
2057 } elsif ($opts{xpixels}) {
2058 $x_scale = $y_scale = $opts{xpixels} / $self->getwidth();
2060 elsif ($opts{ypixels}) {
2061 $x_scale = $y_scale = $opts{ypixels}/$self->getheight();
2063 elsif ($opts{constrain} && ref $opts{constrain}
2064 && $opts{constrain}->can('constrain')) {
2065 # we've been passed an Image::Math::Constrain object or something
2066 # that looks like one
2068 (undef, undef, $scalefactor)
2069 = $opts{constrain}->constrain($self->getwidth, $self->getheight);
2070 unless ($scalefactor) {
2071 $self->_set_error('constrain method failed on constrain parameter');
2074 $x_scale = $y_scale = $scalefactor;
2077 if ($opts{qtype} eq 'normal') {
2078 $tmp->{IMG} = i_scaleaxis($self->{IMG}, $x_scale, 0);
2079 if ( !defined($tmp->{IMG}) ) {
2080 $self->{ERRSTR} = 'unable to scale image';
2083 $img->{IMG}=i_scaleaxis($tmp->{IMG}, $y_scale, 1);
2084 if ( !defined($img->{IMG}) ) {
2085 $self->{ERRSTR}='unable to scale image';
2091 elsif ($opts{'qtype'} eq 'preview') {
2092 $img->{IMG} = i_scale_nn($self->{IMG}, $x_scale, $y_scale);
2093 if ( !defined($img->{IMG}) ) {
2094 $self->{ERRSTR}='unable to scale image';
2099 elsif ($opts{'qtype'} eq 'mixing') {
2100 my $new_width = int(0.5 + $self->getwidth * $x_scale);
2101 my $new_height = int(0.5 + $self->getheight * $y_scale);
2102 $new_width >= 1 or $new_width = 1;
2103 $new_height >= 1 or $new_height = 1;
2104 $img->{IMG} = i_scale_mixing($self->{IMG}, $new_width, $new_height);
2105 unless ($img->{IMG}) {
2106 $self->_set_error(Imager->_error_as_meg);
2112 $self->_set_error('invalid value for qtype parameter');
2117 # Scales only along the X axis
2121 my %opts = ( scalefactor=>0.5, @_ );
2123 unless (defined wantarray) {
2124 my @caller = caller;
2125 warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
2129 unless ($self->{IMG}) {
2130 $self->{ERRSTR} = 'empty input image';
2134 my $img = Imager->new();
2136 my $scalefactor = $opts{scalefactor};
2138 if ($opts{pixels}) {
2139 $scalefactor = $opts{pixels} / $self->getwidth();
2142 unless ($self->{IMG}) {
2143 $self->{ERRSTR}='empty input image';
2147 $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
2149 if ( !defined($img->{IMG}) ) {
2150 $self->{ERRSTR} = 'unable to scale image';
2157 # Scales only along the Y axis
2161 my %opts = ( scalefactor => 0.5, @_ );
2163 unless (defined wantarray) {
2164 my @caller = caller;
2165 warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
2169 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2171 my $img = Imager->new();
2173 my $scalefactor = $opts{scalefactor};
2175 if ($opts{pixels}) {
2176 $scalefactor = $opts{pixels} / $self->getheight();
2179 unless ($self->{IMG}) {
2180 $self->{ERRSTR} = 'empty input image';
2183 $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
2185 if ( !defined($img->{IMG}) ) {
2186 $self->{ERRSTR} = 'unable to scale image';
2193 # Transform returns a spatial transformation of the input image
2194 # this moves pixels to a new location in the returned image.
2195 # NOTE - should make a utility function to check transforms for
2200 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2202 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
2204 # print Dumper(\%opts);
2207 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
2209 eval ("use Affix::Infix2Postfix;");
2212 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
2215 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
2216 {op=>'-',trans=>'Sub'},
2217 {op=>'*',trans=>'Mult'},
2218 {op=>'/',trans=>'Div'},
2219 {op=>'-','type'=>'unary',trans=>'u-'},
2221 {op=>'func','type'=>'unary'}],
2222 'grouping'=>[qw( \( \) )],
2223 'func'=>[qw( sin cos )],
2228 @xt=$I2P->translate($opts{'xexpr'});
2229 @yt=$I2P->translate($opts{'yexpr'});
2231 $numre=$I2P->{'numre'};
2234 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
2235 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
2236 @{$opts{'parm'}}=@pt;
2239 # print Dumper(\%opts);
2241 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
2242 $self->{ERRSTR}='transform: no xopcodes given.';
2246 @op=@{$opts{'xopcodes'}};
2248 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2249 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2252 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2258 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
2259 $self->{ERRSTR}='transform: no yopcodes given.';
2263 @op=@{$opts{'yopcodes'}};
2265 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2266 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2269 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2274 if ( !exists $opts{'parm'}) {
2275 $self->{ERRSTR}='transform: no parameter arg given.';
2279 # print Dumper(\@ropx);
2280 # print Dumper(\@ropy);
2281 # print Dumper(\@ropy);
2283 my $img = Imager->new();
2284 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
2285 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
2291 my ($opts, @imgs) = @_;
2293 require "Imager/Expr.pm";
2295 $opts->{variables} = [ qw(x y) ];
2296 my ($width, $height) = @{$opts}{qw(width height)};
2298 $width ||= $imgs[0]->getwidth();
2299 $height ||= $imgs[0]->getheight();
2301 for my $img (@imgs) {
2302 $opts->{constants}{"w$img_num"} = $img->getwidth();
2303 $opts->{constants}{"h$img_num"} = $img->getheight();
2304 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
2305 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
2310 $opts->{constants}{w} = $width;
2311 $opts->{constants}{cx} = $width/2;
2314 $Imager::ERRSTR = "No width supplied";
2318 $opts->{constants}{h} = $height;
2319 $opts->{constants}{cy} = $height/2;
2322 $Imager::ERRSTR = "No height supplied";
2325 my $code = Imager::Expr->new($opts);
2327 $Imager::ERRSTR = Imager::Expr::error();
2330 my $channels = $opts->{channels} || 3;
2331 unless ($channels >= 1 && $channels <= 4) {
2332 return Imager->_set_error("channels must be an integer between 1 and 4");
2335 my $img = Imager->new();
2336 $img->{IMG} = i_transform2($opts->{width}, $opts->{height},
2337 $channels, $code->code(),
2338 $code->nregs(), $code->cregs(),
2339 [ map { $_->{IMG} } @imgs ]);
2340 if (!defined $img->{IMG}) {
2341 $Imager::ERRSTR = Imager->_error_as_msg();
2350 my %opts=(tx => 0,ty => 0, @_);
2352 unless ($self->{IMG}) {
2353 $self->{ERRSTR}='empty input image';
2356 unless ($opts{src} && $opts{src}->{IMG}) {
2357 $self->{ERRSTR}='empty input image for src';
2361 %opts = (src_minx => 0,
2363 src_maxx => $opts{src}->getwidth(),
2364 src_maxy => $opts{src}->getheight(),
2367 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
2368 $opts{src_minx}, $opts{src_miny},
2369 $opts{src_maxx}, $opts{src_maxy})) {
2370 $self->_set_error($self->_error_as_msg());
2380 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
2382 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
2383 $dir = $xlate{$opts{'dir'}};
2384 return $self if i_flipxy($self->{IMG}, $dir);
2392 unless (defined wantarray) {
2393 my @caller = caller;
2394 warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
2398 if (defined $opts{right}) {
2399 my $degrees = $opts{right};
2401 $degrees += 360 * int(((-$degrees)+360)/360);
2403 $degrees = $degrees % 360;
2404 if ($degrees == 0) {
2405 return $self->copy();
2407 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
2408 my $result = Imager->new();
2409 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
2413 $self->{ERRSTR} = $self->_error_as_msg();
2418 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
2422 elsif (defined $opts{radians} || defined $opts{degrees}) {
2423 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
2425 my $back = $opts{back};
2426 my $result = Imager->new;
2428 $back = _color($back);
2430 $self->_set_error(Imager->errstr);
2434 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
2437 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
2439 if ($result->{IMG}) {
2443 $self->{ERRSTR} = $self->_error_as_msg();
2448 $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available";
2453 sub matrix_transform {
2457 unless (defined wantarray) {
2458 my @caller = caller;
2459 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
2463 if ($opts{matrix}) {
2464 my $xsize = $opts{xsize} || $self->getwidth;
2465 my $ysize = $opts{ysize} || $self->getheight;
2467 my $result = Imager->new;
2469 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2470 $opts{matrix}, $opts{back})
2474 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2482 $self->{ERRSTR} = "matrix parameter required";
2488 *yatf = \&matrix_transform;
2490 # These two are supported for legacy code only
2493 return Imager::Color->new(@_);
2497 return Imager::Color::set(@_);
2500 # Draws a box between the specified corner points.
2503 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2504 my $dflcl=i_color_new(255,255,255,255);
2505 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
2507 if (exists $opts{'box'}) {
2508 $opts{'xmin'} = _min($opts{'box'}->[0],$opts{'box'}->[2]);
2509 $opts{'xmax'} = _max($opts{'box'}->[0],$opts{'box'}->[2]);
2510 $opts{'ymin'} = _min($opts{'box'}->[1],$opts{'box'}->[3]);
2511 $opts{'ymax'} = _max($opts{'box'}->[1],$opts{'box'}->[3]);
2514 if ($opts{filled}) {
2515 my $color = _color($opts{'color'});
2517 $self->{ERRSTR} = $Imager::ERRSTR;
2520 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2521 $opts{ymax}, $color);
2523 elsif ($opts{fill}) {
2524 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2525 # assume it's a hash ref
2526 require 'Imager/Fill.pm';
2527 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2528 $self->{ERRSTR} = $Imager::ERRSTR;
2532 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2533 $opts{ymax},$opts{fill}{fill});
2536 my $color = _color($opts{'color'});
2538 $self->{ERRSTR} = $Imager::ERRSTR;
2541 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
2549 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2550 my $dflcl=i_color_new(255,255,255,255);
2551 my %opts=(color=>$dflcl,
2552 'r'=>_min($self->getwidth(),$self->getheight())/3,
2553 'x'=>$self->getwidth()/2,
2554 'y'=>$self->getheight()/2,
2555 'd1'=>0, 'd2'=>361, @_);
2558 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2559 # assume it's a hash ref
2560 require 'Imager/Fill.pm';
2561 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2562 $self->{ERRSTR} = $Imager::ERRSTR;
2566 i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2567 $opts{'d2'}, $opts{fill}{fill});
2570 my $color = _color($opts{'color'});
2572 $self->{ERRSTR} = $Imager::ERRSTR;
2575 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
2576 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
2580 i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2581 $opts{'d1'}, $opts{'d2'}, $color);
2587 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2588 # assume it's a hash ref
2589 require 'Imager/Fill.pm';
2590 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2591 $self->{ERRSTR} = $Imager::ERRSTR;
2595 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2596 $opts{'d2'}, $opts{fill}{fill});
2599 my $color = _color($opts{'color'});
2601 $self->{ERRSTR} = $Imager::ERRSTR;
2604 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2605 $opts{'d1'}, $opts{'d2'}, $color);
2612 # Draws a line from one point to the other
2613 # the endpoint is set if the endp parameter is set which it is by default.
2614 # to turn of the endpoint being set use endp=>0 when calling line.
2618 my $dflcl=i_color_new(0,0,0,0);
2619 my %opts=(color=>$dflcl,
2622 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2624 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2625 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2627 my $color = _color($opts{'color'});
2629 $self->{ERRSTR} = $Imager::ERRSTR;
2633 $opts{antialias} = $opts{aa} if defined $opts{aa};
2634 if ($opts{antialias}) {
2635 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2636 $color, $opts{endp});
2638 i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2639 $color, $opts{endp});
2644 # Draws a line between an ordered set of points - It more or less just transforms this
2645 # into a list of lines.
2649 my ($pt,$ls,@points);
2650 my $dflcl=i_color_new(0,0,0,0);
2651 my %opts=(color=>$dflcl,@_);
2653 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2655 if (exists($opts{points})) { @points=@{$opts{points}}; }
2656 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2657 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2660 # print Dumper(\@points);
2662 my $color = _color($opts{'color'});
2664 $self->{ERRSTR} = $Imager::ERRSTR;
2667 $opts{antialias} = $opts{aa} if defined $opts{aa};
2668 if ($opts{antialias}) {
2671 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1);
2678 i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1);
2688 my ($pt,$ls,@points);
2689 my $dflcl = i_color_new(0,0,0,0);
2690 my %opts = (color=>$dflcl, @_);
2692 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2694 if (exists($opts{points})) {
2695 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2696 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2699 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2700 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2703 if ($opts{'fill'}) {
2704 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2705 # assume it's a hash ref
2706 require 'Imager/Fill.pm';
2707 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2708 $self->{ERRSTR} = $Imager::ERRSTR;
2712 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2713 $opts{'fill'}{'fill'});
2716 my $color = _color($opts{'color'});
2718 $self->{ERRSTR} = $Imager::ERRSTR;
2721 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2728 # this the multipoint bezier curve
2729 # this is here more for testing that actual usage since
2730 # this is not a good algorithm. Usually the curve would be
2731 # broken into smaller segments and each done individually.
2735 my ($pt,$ls,@points);
2736 my $dflcl=i_color_new(0,0,0,0);
2737 my %opts=(color=>$dflcl,@_);
2739 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2741 if (exists $opts{points}) {
2742 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2743 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2746 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2747 $self->{ERRSTR}='Missing or invalid points.';
2751 my $color = _color($opts{'color'});
2753 $self->{ERRSTR} = $Imager::ERRSTR;
2756 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2762 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2765 unless (exists $opts{'x'} && exists $opts{'y'}) {
2766 $self->{ERRSTR} = "missing seed x and y parameters";
2770 if ($opts{border}) {
2771 my $border = _color($opts{border});
2773 $self->_set_error($Imager::ERRSTR);
2777 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2778 # assume it's a hash ref
2779 require Imager::Fill;
2780 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2781 $self->{ERRSTR} = $Imager::ERRSTR;
2785 $rc = i_flood_cfill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2786 $opts{fill}{fill}, $border);
2789 my $color = _color($opts{'color'});
2791 $self->{ERRSTR} = $Imager::ERRSTR;
2794 $rc = i_flood_fill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2801 $self->{ERRSTR} = $self->_error_as_msg();
2807 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2808 # assume it's a hash ref
2809 require 'Imager/Fill.pm';
2810 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2811 $self->{ERRSTR} = $Imager::ERRSTR;
2815 $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2818 my $color = _color($opts{'color'});
2820 $self->{ERRSTR} = $Imager::ERRSTR;
2823 $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2829 $self->{ERRSTR} = $self->_error_as_msg();
2838 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2840 unless (exists $opts{'x'} && exists $opts{'y'}) {
2841 $self->{ERRSTR} = 'missing x and y parameters';
2847 my $color = _color($opts{color})
2849 if (ref $x && ref $y) {
2850 unless (@$x == @$y) {
2851 $self->{ERRSTR} = 'length of x and y mismatch';
2855 if ($color->isa('Imager::Color')) {
2856 for my $i (0..$#{$opts{'x'}}) {
2857 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color)
2862 for my $i (0..$#{$opts{'x'}}) {
2863 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color)
2871 if ($color->isa('Imager::Color')) {
2872 i_ppix($self->{IMG}, $x, $y, $color)
2876 i_ppixf($self->{IMG}, $x, $y, $color)
2887 my %opts = ( "type"=>'8bit', @_);
2889 unless (exists $opts{'x'} && exists $opts{'y'}) {
2890 $self->{ERRSTR} = 'missing x and y parameters';
2896 if (ref $x && ref $y) {
2897 unless (@$x == @$y) {
2898 $self->{ERRSTR} = 'length of x and y mismatch';
2902 if ($opts{"type"} eq '8bit') {
2903 for my $i (0..$#{$opts{'x'}}) {
2904 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2908 for my $i (0..$#{$opts{'x'}}) {
2909 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2912 return wantarray ? @result : \@result;
2915 if ($opts{"type"} eq '8bit') {
2916 return i_get_pixel($self->{IMG}, $x, $y);
2919 return i_gpixf($self->{IMG}, $x, $y);
2928 my %opts = ( type => '8bit', x=>0, @_);
2930 $self->_valid_image or return;
2932 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2934 unless (defined $opts{'y'}) {
2935 $self->_set_error("missing y parameter");
2939 if ($opts{type} eq '8bit') {
2940 return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2943 elsif ($opts{type} eq 'float') {
2944 return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2947 elsif ($opts{type} eq 'index') {
2948 unless (i_img_type($self->{IMG})) {
2949 $self->_set_error("type => index only valid on paletted images");
2952 return i_gpal($self->{IMG}, $opts{x}, $opts{x} + $opts{width},
2956 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2963 my %opts = ( x=>0, @_);
2965 $self->_valid_image or return;
2967 unless (defined $opts{'y'}) {
2968 $self->_set_error("missing y parameter");
2973 if (ref $opts{pixels} && @{$opts{pixels}}) {
2974 # try to guess the type
2975 if ($opts{pixels}[0]->isa('Imager::Color')) {
2976 $opts{type} = '8bit';
2978 elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
2979 $opts{type} = 'float';
2982 $self->_set_error("missing type parameter and could not guess from pixels");
2988 $opts{type} = '8bit';
2992 if ($opts{type} eq '8bit') {
2993 if (ref $opts{pixels}) {
2994 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2997 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3000 elsif ($opts{type} eq 'float') {
3001 if (ref $opts{pixels}) {
3002 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3005 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3008 elsif ($opts{type} eq 'index') {
3009 if (ref $opts{pixels}) {
3010 return i_ppal($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3013 return i_ppal_p($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3017 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3024 my %opts = ( type => '8bit', x=>0, @_);
3026 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
3028 unless (defined $opts{'y'}) {
3029 $self->_set_error("missing y parameter");
3033 unless ($opts{channels}) {
3034 $opts{channels} = [ 0 .. $self->getchannels()-1 ];
3037 if ($opts{type} eq '8bit') {
3038 return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3039 $opts{y}, @{$opts{channels}});
3041 elsif ($opts{type} eq 'float') {
3042 return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3043 $opts{y}, @{$opts{channels}});
3046 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3051 # make an identity matrix of the given size
3055 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
3056 for my $c (0 .. ($size-1)) {
3057 $matrix->[$c][$c] = 1;
3062 # general function to convert an image
3064 my ($self, %opts) = @_;
3067 unless (defined wantarray) {
3068 my @caller = caller;
3069 warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
3073 # the user can either specify a matrix or preset
3074 # the matrix overrides the preset
3075 if (!exists($opts{matrix})) {
3076 unless (exists($opts{preset})) {
3077 $self->{ERRSTR} = "convert() needs a matrix or preset";
3081 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
3082 # convert to greyscale, keeping the alpha channel if any
3083 if ($self->getchannels == 3) {
3084 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
3086 elsif ($self->getchannels == 4) {
3087 # preserve the alpha channel
3088 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
3093 $matrix = _identity($self->getchannels);
3096 elsif ($opts{preset} eq 'noalpha') {
3097 # strip the alpha channel
3098 if ($self->getchannels == 2 or $self->getchannels == 4) {
3099 $matrix = _identity($self->getchannels);
3100 pop(@$matrix); # lose the alpha entry
3103 $matrix = _identity($self->getchannels);
3106 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
3108 $matrix = [ [ 1 ] ];
3110 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
3111 $matrix = [ [ 0, 1 ] ];
3113 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
3114 $matrix = [ [ 0, 0, 1 ] ];
3116 elsif ($opts{preset} eq 'alpha') {
3117 if ($self->getchannels == 2 or $self->getchannels == 4) {
3118 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
3121 # the alpha is just 1 <shrug>
3122 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
3125 elsif ($opts{preset} eq 'rgb') {
3126 if ($self->getchannels == 1) {
3127 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
3129 elsif ($self->getchannels == 2) {
3130 # preserve the alpha channel
3131 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
3134 $matrix = _identity($self->getchannels);
3137 elsif ($opts{preset} eq 'addalpha') {
3138 if ($self->getchannels == 1) {
3139 $matrix = _identity(2);
3141 elsif ($self->getchannels == 3) {
3142 $matrix = _identity(4);
3145 $matrix = _identity($self->getchannels);
3149 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
3155 $matrix = $opts{matrix};
3158 my $new = Imager->new();
3159 $new->{IMG} = i_img_new();
3160 unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
3161 # most likely a bad matrix
3162 $self->{ERRSTR} = _error_as_msg();
3169 # general function to map an image through lookup tables
3172 my ($self, %opts) = @_;
3173 my @chlist = qw( red green blue alpha );
3175 if (!exists($opts{'maps'})) {
3176 # make maps from channel maps
3178 for $chnum (0..$#chlist) {
3179 if (exists $opts{$chlist[$chnum]}) {
3180 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
3181 } elsif (exists $opts{'all'}) {
3182 $opts{'maps'}[$chnum] = $opts{'all'};
3186 if ($opts{'maps'} and $self->{IMG}) {
3187 i_map($self->{IMG}, $opts{'maps'} );
3193 my ($self, %opts) = @_;
3195 defined $opts{mindist} or $opts{mindist} = 0;
3197 defined $opts{other}
3198 or return $self->_set_error("No 'other' parameter supplied");
3199 defined $opts{other}{IMG}
3200 or return $self->_set_error("No image data in 'other' image");
3203 or return $self->_set_error("No image data");
3205 my $result = Imager->new;
3206 $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
3208 or return $self->_set_error($self->_error_as_msg());
3213 # destructive border - image is shrunk by one pixel all around
3216 my ($self,%opts)=@_;
3217 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
3218 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
3222 # Get the width of an image
3226 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3227 return (i_img_info($self->{IMG}))[0];
3230 # Get the height of an image
3234 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3235 return (i_img_info($self->{IMG}))[1];
3238 # Get number of channels in an image
3242 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3243 return i_img_getchannels($self->{IMG});
3250 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3251 return i_img_getmask($self->{IMG});
3259 if (!defined($self->{IMG})) {
3260 $self->{ERRSTR} = 'image is empty';
3263 unless (defined $opts{mask}) {
3264 $self->_set_error("mask parameter required");
3267 i_img_setmask( $self->{IMG} , $opts{mask} );
3272 # Get number of colors in an image
3276 my %opts=('maxcolors'=>2**30,@_);
3277 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
3278 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
3279 return ($rc==-1? undef : $rc);
3282 # draw string to an image
3286 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
3288 my %input=('x'=>0, 'y'=>0, @_);
3289 defined($input{string}) or $input{string} = $input{text};
3291 unless(defined $input{string}) {
3292 $self->{ERRSTR}="missing required parameter 'string'";
3296 unless($input{font}) {
3297 $self->{ERRSTR}="missing required parameter 'font'";
3301 unless ($input{font}->draw(image=>$self, %input)) {
3313 unless ($self->{IMG}) {
3314 $self->{ERRSTR}='empty input image';
3323 my %input=('x'=>0, 'y'=>0, @_);
3324 $input{string}||=$input{text};
3326 unless(exists $input{string}) {
3327 $self->_set_error("missing required parameter 'string'");
3331 unless($input{font}) {
3332 $self->_set_error("missing required parameter 'font'");
3337 unless (@result = $input{font}->align(image=>$img, %input)) {
3341 return wantarray ? @result : $result[0];
3344 my @file_limit_names = qw/width height bytes/;
3346 sub set_file_limits {
3353 @values{@file_limit_names} = (0) x @file_limit_names;
3356 @values{@file_limit_names} = i_get_image_file_limits();
3359 for my $key (keys %values) {
3360 defined $opts{$key} and $values{$key} = $opts{$key};
3363 i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
3366 sub get_file_limits {
3367 i_get_image_file_limits();
3370 # Shortcuts that can be exported
3372 sub newcolor { Imager::Color->new(@_); }
3373 sub newfont { Imager::Font->new(@_); }
3375 *NC=*newcolour=*newcolor;
3382 #### Utility routines
3385 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
3389 my ($self, $msg) = @_;
3392 $self->{ERRSTR} = $msg;
3400 # Default guess for the type of an image from extension
3402 sub def_guess_type {
3405 $ext=($name =~ m/\.([^\.]+)$/)[0];
3406 return 'tiff' if ($ext =~ m/^tiff?$/);
3407 return 'jpeg' if ($ext =~ m/^jpe?g$/);
3408 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
3409 return 'png' if ($ext eq "png");
3410 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
3411 return 'tga' if ($ext eq "tga");
3412 return 'rgb' if ($ext eq "rgb");
3413 return 'gif' if ($ext eq "gif");
3414 return 'raw' if ($ext eq "raw");
3415 return lc $ext; # best guess
3419 # get the minimum of a list
3423 for(@_) { if ($_<$mx) { $mx=$_; }}
3427 # get the maximum of a list
3431 for(@_) { if ($_>$mx) { $mx=$_; }}
3435 # string stuff for iptc headers
3439 $str = substr($str,3);
3440 $str =~ s/[\n\r]//g;
3447 # A little hack to parse iptc headers.
3452 my($caption,$photogr,$headln,$credit);
3454 my $str=$self->{IPTCRAW};
3459 @ar=split(/8BIM/,$str);
3464 @sar=split(/\034\002/);
3465 foreach $item (@sar) {
3466 if ($item =~ m/^x/) {
3467 $caption = _clean($item);
3470 if ($item =~ m/^P/) {
3471 $photogr = _clean($item);
3474 if ($item =~ m/^i/) {
3475 $headln = _clean($item);
3478 if ($item =~ m/^n/) {
3479 $credit = _clean($item);
3485 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
3492 or die "Only C language supported";
3494 require Imager::ExtUtils;
3495 return Imager::ExtUtils->inline_config;
3500 # Below is the stub of documentation for your module. You better edit it!
3504 Imager - Perl extension for Generating 24 bit Images
3514 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
3519 my $img = Imager->new();
3520 # see Imager::Files for information on the read() method
3521 $img->read(file=>$file) or die $img->errstr();
3523 $file =~ s/\.[^.]*$//;
3525 # Create smaller version
3526 # documented in Imager::Transformations
3527 my $thumb = $img->scale(scalefactor=>.3);
3529 # Autostretch individual channels
3530 $thumb->filter(type=>'autolevels');
3532 # try to save in one of these formats
3535 for $format ( qw( png gif jpg tiff ppm ) ) {
3536 # Check if given format is supported
3537 if ($Imager::formats{$format}) {
3538 $file.="_low.$format";
3539 print "Storing image as: $file\n";
3540 # documented in Imager::Files
3541 $thumb->write(file=>$file) or
3549 Imager is a module for creating and altering images. It can read and
3550 write various image formats, draw primitive shapes like lines,and
3551 polygons, blend multiple images together in various ways, scale, crop,
3552 render text and more.
3554 =head2 Overview of documentation
3560 Imager - This document - Synopsis, Example, Table of Contents and
3565 L<Imager::Tutorial> - a brief introduction to Imager.
3569 L<Imager::Cookbook> - how to do various things with Imager.
3573 L<Imager::ImageTypes> - Basics of constructing image objects with
3574 C<new()>: Direct type/virtual images, RGB(A)/paletted images,
3575 8/16/double bits/channel, color maps, channel masks, image tags, color
3576 quantization. Also discusses basic image information methods.
3580 L<Imager::Files> - IO interaction, reading/writing images, format
3585 L<Imager::Draw> - Drawing Primitives, lines, boxes, circles, arcs,
3590 L<Imager::Color> - Color specification.
3594 L<Imager::Fill> - Fill pattern specification.
3598 L<Imager::Font> - General font rendering, bounding boxes and font
3603 L<Imager::Transformations> - Copying, scaling, cropping, flipping,
3604 blending, pasting, convert and map.
3608 L<Imager::Engines> - Programmable transformations through
3609 C<transform()>, C<transform2()> and C<matrix_transform()>.
3613 L<Imager::Filters> - Filters, sharpen, blur, noise, convolve etc. and
3618 L<Imager::Expr> - Expressions for evaluation engine used by
3623 L<Imager::Matrix2d> - Helper class for affine transformations.
3627 L<Imager::Fountain> - Helper for making gradient profiles.
3631 L<Imager::API> - using Imager's C API
3635 L<Imager::APIRef> - API function reference
3639 L<Imager::Inline> - using Imager's C API from Inline::C
3643 L<Imager::ExtUtils> - tools to get access to Imager's C API.
3647 =head2 Basic Overview
3649 An Image object is created with C<$img = Imager-E<gt>new()>.
3652 $img=Imager->new(); # create empty image
3653 $img->read(file=>'lena.png',type=>'png') or # read image from file
3654 die $img->errstr(); # give an explanation
3655 # if something failed
3657 or if you want to create an empty image:
3659 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
3661 This example creates a completely black image of width 400 and height
3664 =head1 ERROR HANDLING
3666 In general a method will return false when it fails, if it does use the errstr() method to find out why:
3672 Returns the last error message in that context.
3674 If the last error you received was from calling an object method, such
3675 as read, call errstr() as an object method to find out why:
3677 my $image = Imager->new;
3678 $image->read(file => 'somefile.gif')
3679 or die $image->errstr;
3681 If it was a class method then call errstr() as a class method:
3683 my @imgs = Imager->read_multi(file => 'somefile.gif')
3684 or die Imager->errstr;
3686 Note that in some cases object methods are implemented in terms of
3687 class methods so a failing object method may set both.
3691 The C<Imager-E<gt>new> method is described in detail in
3692 L<Imager::ImageTypes>.
3696 Where to find information on methods for Imager class objects.
3698 addcolors() - L<Imager::ImageTypes/addcolors>
3700 addtag() - L<Imager::ImageTypes/addtag> - add image tags
3702 align_string() - L<Imager::Draw/align_string>
3704 arc() - L<Imager::Draw/arc>
3706 bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
3709 box() - L<Imager::Draw/box>
3711 circle() - L<Imager::Draw/circle>
3713 colorcount() - L<Imager::Draw/colorcount>
3715 convert() - L<Imager::Transformations/"Color transformations"> -
3716 transform the color space
3718 copy() - L<Imager::Transformations/copy>
3720 crop() - L<Imager::Transformations/crop> - extract part of an image
3722 def_guess_type() - L<Imager::Files/def_guess_type>
3724 deltag() - L<Imager::ImageTypes/deltag> - delete image tags
3726 difference() - L<Imager::Filters/"Image Difference">
3728 errstr() - L<"Basic Overview">
3730 filter() - L<Imager::Filters>
3732 findcolor() - L<Imager::ImageTypes/findcolor> - search the image palette, if it
3735 flip() - L<Imager::Transformations/flip>
3737 flood_fill() - L<Imager::Draw/flood_fill>
3739 getchannels() - L<Imager::ImageTypes/getchannels>
3741 getcolorcount() - L<Imager::ImageTypes/getcolorcount>
3743 getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
3744 palette, if it has one
3746 get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3748 getheight() - L<Imager::ImageTypes/getwidth>
3750 getmask() - L<Imager::ImageTypes/getmask>
3752 getpixel() - L<Imager::Draw/getpixel>
3754 getsamples() - L<Imager::Draw/getsamples>
3756 getscanline() - L<Imager::Draw/getscanline>
3758 getwidth() - L<Imager::ImageTypes/getwidth>
3760 img_set() - L<Imager::ImageTypes/img_set>
3762 init() - L<Imager::ImageTypes/init>
3764 line() - L<Imager::Draw/line>
3766 load_plugin() - L<Imager::Filters/load_plugin>
3768 map() - L<Imager::Transformations/"Color Mappings"> - remap color
3771 masked() - L<Imager::ImageTypes/masked> - make a masked image
3773 matrix_transform() - L<Imager::Engines/matrix_transform>
3775 maxcolors() - L<Imager::ImageTypes/maxcolors>
3777 NC() - L<Imager::Handy/NC>
3779 new() - L<Imager::ImageTypes/new>
3781 newcolor() - L<Imager::Handy/newcolor>
3783 newcolour() - L<Imager::Handy/newcolour>
3785 newfont() - L<Imager::Handy/newfont>
3787 NF() - L<Imager::Handy/NF>
3789 open() - L<Imager::Files> - an alias for read()
3791 parseiptc() - L<Imager::Files/parseiptc> - parse IPTC data from a JPEG
3794 paste() - L<Imager::Transformations/paste> - draw an image onto an image
3796 polygon() - L<Imager::Draw/polygon>
3798 polyline() - L<Imager::Draw/polyline>
3800 read() - L<Imager::Files> - read a single image from an image file
3802 read_multi() - L<Imager::Files> - read multiple images from an image
3805 register_filter() - L<Imager::Filters/register_filter>
3807 register_reader() - L<Imager::Filters/register_reader>
3809 register_writer() - L<Imager::Filters/register_writer>
3811 rotate() - L<Imager::Transformations/rotate>
3813 rubthrough() - L<Imager::Transformations/rubthrough> - draw an image onto an
3814 image and use the alpha channel
3816 scale() - L<Imager::Transformations/scale>
3818 scaleX() - L<Imager::Transformations/scaleX>
3820 scaleY() - L<Imager::Transformations/scaleY>
3822 setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
3825 set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3827 setmask() - L<Imager::ImageTypes/setmask>
3829 setpixel() - L<Imager::Draw/setpixel>
3831 setscanline() - L<Imager::Draw/setscanline>
3833 settag() - L<Imager::ImageTypes/settag>
3835 string() - L<Imager::Draw/string> - draw text on an image
3837 tags() - L<Imager::ImageTypes/tags> - fetch image tags
3839 to_paletted() - L<Imager::ImageTypes/to_paletted>
3841 to_rgb16() - L<Imager::ImageTypes/to_rgb16>
3843 to_rgb8() - L<Imager::ImageTypes/to_rgb8>
3845 transform() - L<Imager::Engines/"transform">
3847 transform2() - L<Imager::Engines/"transform2">
3849 type() - L<Imager::ImageTypes/type> - type of image (direct vs paletted)
3851 unload_plugin() - L<Imager::Filters/unload_plugin>
3853 virtual() - L<Imager::ImageTypes/virtual> - whether the image has it's own
3856 write() - L<Imager::Files> - write an image to a file
3858 write_multi() - L<Imager::Files> - write multiple image to an image
3861 =head1 CONCEPT INDEX
3863 animated GIF - L<Imager::File/"Writing an animated GIF">
3865 aspect ratio - L<Imager::ImageTypes/i_xres>,
3866 L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
3868 blend - alpha blending one image onto another
3869 L<Imager::Transformations/rubthrough>
3871 blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
3873 boxes, drawing - L<Imager::Draw/box>
3875 changes between image - L<Imager::Filter/"Image Difference">
3877 color - L<Imager::Color>
3879 color names - L<Imager::Color>, L<Imager::Color::Table>
3881 combine modes - L<Imager::Fill/combine>
3883 compare images - L<Imager::Filter/"Image Difference">
3885 contrast - L<Imager::Filter/contrast>, L<Imager::Filter/autolevels>
3887 convolution - L<Imager::Filter/conv>
3889 cropping - L<Imager::Transformations/crop>
3891 C<diff> images - L<Imager::Filter/"Image Difference">
3893 dpi - L<Imager::ImageTypes/i_xres>,
3894 L<Imager::Cookbook/"Image spatial resolution">
3896 drawing boxes - L<Imager::Draw/box>
3898 drawing lines - L<Imager::Draw/line>
3900 drawing text - L<Imager::Draw/string>, L<Imager::Draw/align_string>
3902 error message - L<"Basic Overview">
3904 files, font - L<Imager::Font>
3906 files, image - L<Imager::Files>
3908 filling, types of fill - L<Imager::Fill>
3910 filling, boxes - L<Imager::Draw/box>
3912 filling, flood fill - L<Imager::Draw/flood_fill>
3914 flood fill - L<Imager::Draw/flood_fill>
3916 fonts - L<Imager::Font>
3918 fonts, drawing with - L<Imager::Draw/string>,
3919 L<Imager::Draw/align_string>, L<Imager::Font::Wrap>
3921 fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3923 fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
3925 fountain fill - L<Imager::Fill/"Fountain fills">,
3926 L<Imager::Filters/fountain>, L<Imager::Fountain>,
3927 L<Imager::Filters/gradgen>
3929 GIF files - L<Imager::Files/"GIF">
3931 GIF files, animated - L<Imager::File/"Writing an animated GIF">
3933 gradient fill - L<Imager::Fill/"Fountain fills">,
3934 L<Imager::Filters/fountain>, L<Imager::Fountain>,
3935 L<Imager::Filters/gradgen>
3937 guassian blur - L<Imager::Filter/guassian>
3939 hatch fills - L<Imager::Fill/"Hatched fills">
3941 invert image - L<Imager::Filter/hardinvert>
3943 JPEG - L<Imager::Files/"JPEG">
3945 limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
3947 lines, drawing - L<Imager::Draw/line>
3949 matrix - L<Imager::Matrix2d>,
3950 L<Imager::Transformations/"Matrix Transformations">,
3951 L<Imager::Font/transform>
3953 metadata, image - L<Imager::ImageTypes/"Tags">
3955 mosaic - L<Imager::Filter/mosaic>
3957 noise, filter - L<Imager::Filter/noise>
3959 noise, rendered - L<Imager::Filter/turbnoise>,
3960 L<Imager::Filter/radnoise>
3962 paste - L<Imager::Transformations/paste>,
3963 L<Imager::Transformations/rubthrough>
3965 pseudo-color image - L<Imager::ImageTypes/to_paletted>,
3966 L<Imager::ImageTypes/new>
3968 posterize - L<Imager::Filter/postlevels>
3970 png files - L<Imager::Files>, L<Imager::Files/"PNG">
3972 pnm - L<Imager::Files/"PNM (Portable aNy Map)">
3974 rectangles, drawing - L<Imager::Draw/box>
3976 resizing an image - L<Imager::Transformations/scale>,
3977 L<Imager::Transformations/crop>
3979 saving an image - L<Imager::Files>
3981 scaling - L<Imager::Transformations/scale>
3983 sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
3985 size, image - L<Imager::ImageTypes/getwidth>,
3986 L<Imager::ImageTypes/getheight>
3988 size, text - L<Imager::Font/bounding_box>
3990 tags, image metadata - L<Imager::ImageTypes/"Tags">
3992 text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
3993 L<Imager::Font::Wrap>
3995 text, wrapping text in an area - L<Imager::Font::Wrap>
3997 text, measuring - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3999 tiles, color - L<Imager::Filter/mosaic>
4001 unsharp mask - L<Imager::Filter/unsharpmask>
4003 watermark - L<Imager::Filter/watermark>
4005 writing an image to a file - L<Imager::Files>
4009 The best place to get help with Imager is the mailing list.
4011 To subscribe send a message with C<subscribe> in the body to:
4013 imager-devel+request@molar.is
4019 L<http://www.molar.is/en/lists/imager-devel/>
4023 where you can also find the mailing list archive.
4025 You can report bugs by pointing your browser at:
4029 L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager>
4033 Please remember to include the versions of Imager, perl, supporting
4034 libraries, and any relevant code. If you have specific images that
4035 cause the problems, please include those too.
4037 If you don't want to publish your email address on a mailing list you
4038 can use CPAN::Forum:
4040 http://www.cpanforum.com/dist/Imager
4042 You will need to register to post.
4044 =head1 CONTRIBUTING TO IMAGER
4050 If you like or dislike Imager, you can add a public review of Imager
4053 http://cpanratings.perl.org/dist/Imager
4055 This requires a Bitcard Account (http://www.bitcard.org).
4057 You can also send email to the maintainer below.
4059 If you send me a bug report via email, it will be copied to RT.
4063 I accept patches, preferably against the main branch in subversion.
4064 You should include an explanation of the reason for why the patch is
4067 Your patch should include regression tests where possible, otherwise
4068 it will be delayed until I get a chance to write them.
4072 Tony Cook <tony@imager.perl.org> is the current maintainer for Imager.
4074 Arnar M. Hrafnkelsson is the original author of Imager.
4076 Many others have contributed to Imager, please see the README for a
4081 L<perl>(1), L<Imager::ImageTypes>(3), L<Imager::Files>(3),
4082 L<Imager::Draw>(3), L<Imager::Color>(3), L<Imager::Fill>(3),
4083 L<Imager::Font>(3), L<Imager::Transformations>(3),
4084 L<Imager::Engines>(3), L<Imager::Filters>(3), L<Imager::Expr>(3),
4085 L<Imager::Matrix2d>(3), L<Imager::Fountain>(3)
4087 L<http://imager.perl.org/>
4089 L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
4091 Other perl imaging modules include:
4093 L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).