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 ($self->{IMG} && $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 'raw' ) {
1382 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1384 if ( !($params{xsize} && $params{ysize}) ) {
1385 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1389 $self->{IMG} = i_readraw_wiol( $IO,
1392 $params{datachannels},
1393 $params{storechannels},
1394 $params{interleave});
1395 if ( !defined($self->{IMG}) ) {
1396 $self->{ERRSTR}=$self->_error_as_msg();
1399 $self->{DEBUG} && print "loading a raw file\n";
1405 sub register_reader {
1406 my ($class, %opts) = @_;
1409 or die "register_reader called with no type parameter\n";
1411 my $type = $opts{type};
1413 defined $opts{single} || defined $opts{multiple}
1414 or die "register_reader called with no single or multiple parameter\n";
1416 $readers{$type} = { };
1417 if ($opts{single}) {
1418 $readers{$type}{single} = $opts{single};
1420 if ($opts{multiple}) {
1421 $readers{$type}{multiple} = $opts{multiple};
1427 sub register_writer {
1428 my ($class, %opts) = @_;
1431 or die "register_writer called with no type parameter\n";
1433 my $type = $opts{type};
1435 defined $opts{single} || defined $opts{multiple}
1436 or die "register_writer called with no single or multiple parameter\n";
1438 $writers{$type} = { };
1439 if ($opts{single}) {
1440 $writers{$type}{single} = $opts{single};
1442 if ($opts{multiple}) {
1443 $writers{$type}{multiple} = $opts{multiple};
1449 # probes for an Imager::File::whatever module
1450 sub _reader_autoload {
1453 return if $formats{$type} || $readers{$type};
1455 return unless $type =~ /^\w+$/;
1457 my $file = "Imager/File/\U$type\E.pm";
1459 unless ($attempted_to_load{$file}) {
1461 ++$attempted_to_load{$file};
1465 # try to get a reader specific module
1466 my $file = "Imager/File/\U$type\EReader.pm";
1467 unless ($attempted_to_load{$file}) {
1469 ++$attempted_to_load{$file};
1477 # probes for an Imager::File::whatever module
1478 sub _writer_autoload {
1481 return if $formats{$type} || $readers{$type};
1483 return unless $type =~ /^\w+$/;
1485 my $file = "Imager/File/\U$type\E.pm";
1487 unless ($attempted_to_load{$file}) {
1489 ++$attempted_to_load{$file};
1493 # try to get a writer specific module
1494 my $file = "Imager/File/\U$type\EWriter.pm";
1495 unless ($attempted_to_load{$file}) {
1497 ++$attempted_to_load{$file};
1505 sub _fix_gif_positions {
1506 my ($opts, $opt, $msg, @imgs) = @_;
1508 my $positions = $opts->{'gif_positions'};
1510 for my $pos (@$positions) {
1511 my ($x, $y) = @$pos;
1512 my $img = $imgs[$index++];
1513 $img->settag(name=>'gif_left', value=>$x);
1514 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1516 $$msg .= "replaced with the gif_left and gif_top tags";
1521 gif_each_palette=>'gif_local_map',
1522 interlace => 'gif_interlace',
1523 gif_delays => 'gif_delay',
1524 gif_positions => \&_fix_gif_positions,
1525 gif_loop_count => 'gif_loop',
1529 my ($self, $opts, $prefix, @imgs) = @_;
1531 for my $opt (keys %$opts) {
1533 if ($obsolete_opts{$opt}) {
1534 my $new = $obsolete_opts{$opt};
1535 my $msg = "Obsolete option $opt ";
1537 $new->($opts, $opt, \$msg, @imgs);
1540 $msg .= "replaced with the $new tag ";
1543 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1544 warn $msg if $warn_obsolete && $^W;
1546 next unless $tagname =~ /^\Q$prefix/;
1547 my $value = $opts->{$opt};
1549 if (UNIVERSAL::isa($value, "Imager::Color")) {
1550 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1551 for my $img (@imgs) {
1552 $img->settag(name=>$tagname, value=>$tag);
1555 elsif (ref($value) eq 'ARRAY') {
1556 for my $i (0..$#$value) {
1557 my $val = $value->[$i];
1559 if (UNIVERSAL::isa($val, "Imager::Color")) {
1560 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1562 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1565 $self->_set_error("Unknown reference type " . ref($value) .
1566 " supplied in array for $opt");
1572 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1577 $self->_set_error("Unknown reference type " . ref($value) .
1578 " supplied for $opt");
1583 # set it as a tag for every image
1584 for my $img (@imgs) {
1585 $img->settag(name=>$tagname, value=>$value);
1593 # Write an image to file
1596 my %input=(jpegquality=>75,
1606 $self->_set_opts(\%input, "i_", $self)
1609 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1611 if (!$input{'type'} and $input{file}) {
1612 $input{'type'}=$FORMATGUESS->($input{file});
1614 if (!$input{'type'}) {
1615 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1619 _writer_autoload($input{type});
1622 if ($writers{$input{type}} && $writers{$input{type}}{single}) {
1623 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1626 $writers{$input{type}}{single}->($self, $IO, %input)
1630 if (!$formats{$input{'type'}}) {
1631 $self->{ERRSTR}='format not supported';
1635 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1638 if ($input{'type'} eq 'tiff') {
1639 $self->_set_opts(\%input, "tiff_", $self)
1641 $self->_set_opts(\%input, "exif_", $self)
1644 if (defined $input{class} && $input{class} eq 'fax') {
1645 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1646 $self->{ERRSTR} = $self->_error_as_msg();
1650 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1651 $self->{ERRSTR} = $self->_error_as_msg();
1655 } elsif ( $input{'type'} eq 'pnm' ) {
1656 $self->_set_opts(\%input, "pnm_", $self)
1658 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1659 $self->{ERRSTR} = $self->_error_as_msg();
1662 $self->{DEBUG} && print "writing a pnm file\n";
1663 } elsif ( $input{'type'} eq 'raw' ) {
1664 $self->_set_opts(\%input, "raw_", $self)
1666 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1667 $self->{ERRSTR} = $self->_error_as_msg();
1670 $self->{DEBUG} && print "writing a raw file\n";
1671 } elsif ( $input{'type'} eq 'png' ) {
1672 $self->_set_opts(\%input, "png_", $self)
1674 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1675 $self->{ERRSTR}='unable to write png image';
1678 $self->{DEBUG} && print "writing a png file\n";
1679 } elsif ( $input{'type'} eq 'jpeg' ) {
1680 $self->_set_opts(\%input, "jpeg_", $self)
1682 $self->_set_opts(\%input, "exif_", $self)
1684 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1685 $self->{ERRSTR} = $self->_error_as_msg();
1688 $self->{DEBUG} && print "writing a jpeg file\n";
1689 } elsif ( $input{'type'} eq 'bmp' ) {
1690 $self->_set_opts(\%input, "bmp_", $self)
1692 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1693 $self->{ERRSTR} = $self->_error_as_msg;
1696 $self->{DEBUG} && print "writing a bmp file\n";
1697 } elsif ( $input{'type'} eq 'tga' ) {
1698 $self->_set_opts(\%input, "tga_", $self)
1701 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1702 $self->{ERRSTR}=$self->_error_as_msg();
1705 $self->{DEBUG} && print "writing a tga file\n";
1706 } elsif ( $input{'type'} eq 'gif' ) {
1707 $self->_set_opts(\%input, "gif_", $self)
1709 # compatibility with the old interfaces
1710 if ($input{gifquant} eq 'lm') {
1711 $input{make_colors} = 'addi';
1712 $input{translate} = 'perturb';
1713 $input{perturb} = $input{lmdither};
1714 } elsif ($input{gifquant} eq 'gen') {
1715 # just pass options through
1717 $input{make_colors} = 'webmap'; # ignored
1718 $input{translate} = 'giflib';
1720 if (!i_writegif_wiol($IO, \%input, $self->{IMG})) {
1721 $self->{ERRSTR} = $self->_error_as_msg;
1727 if (exists $input{'data'}) {
1728 my $data = io_slurp($IO);
1730 $self->{ERRSTR}='Could not slurp from buffer';
1733 ${$input{data}} = $data;
1739 my ($class, $opts, @images) = @_;
1741 my $type = $opts->{type};
1743 if (!$type && $opts->{'file'}) {
1744 $type = $FORMATGUESS->($opts->{'file'});
1747 $class->_set_error('type parameter missing and not possible to guess from extension');
1750 # translate to ImgRaw
1751 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1752 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1755 $class->_set_opts($opts, "i_", @images)
1757 my @work = map $_->{IMG}, @images;
1759 _writer_autoload($type);
1762 if ($writers{$type} && $writers{$type}{multiple}) {
1763 ($IO, $file) = $class->_get_writer_io($opts, $type)
1766 $writers{$type}{multiple}->($class, $IO, $opts, @images)
1770 if (!$formats{$type}) {
1771 $class->_set_error("format $type not supported");
1775 ($IO, $file) = $class->_get_writer_io($opts, $type)
1778 if ($type eq 'gif') {
1779 $class->_set_opts($opts, "gif_", @images)
1781 my $gif_delays = $opts->{gif_delays};
1782 local $opts->{gif_delays} = $gif_delays;
1783 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1784 # assume the caller wants the same delay for each frame
1785 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1787 unless (i_writegif_wiol($IO, $opts, @work)) {
1788 $class->_set_error($class->_error_as_msg());
1792 elsif ($type eq 'tiff') {
1793 $class->_set_opts($opts, "tiff_", @images)
1795 $class->_set_opts($opts, "exif_", @images)
1798 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1799 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1800 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1803 $res = i_writetiff_multi_wiol($IO, @work);
1806 $class->_set_error($class->_error_as_msg());
1812 unless ($images[0]->write(%$opts, io => $IO, type => $type)) {
1817 $ERRSTR = "Sorry, write_multi doesn't support $type yet";
1823 if (exists $opts->{'data'}) {
1824 my $data = io_slurp($IO);
1826 Imager->_set_error('Could not slurp from buffer');
1829 ${$opts->{data}} = $data;
1834 # read multiple images from a file
1836 my ($class, %opts) = @_;
1838 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1841 my $type = $opts{'type'};
1843 $type = i_test_format_probe($IO, -1);
1846 if ($opts{file} && !$type) {
1848 $type = $FORMATGUESS->($opts{file});
1852 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1856 _reader_autoload($type);
1858 if ($readers{$type} && $readers{$type}{multiple}) {
1859 return $readers{$type}{multiple}->($IO, %opts);
1862 if ($type eq 'gif') {
1864 @imgs = i_readgif_multi_wiol($IO);
1867 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1871 $ERRSTR = _error_as_msg();
1875 elsif ($type eq 'tiff') {
1876 my @imgs = i_readtiff_multi_wiol($IO, -1);
1879 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1883 $ERRSTR = _error_as_msg();
1888 my $img = Imager->new;
1889 if ($img->read(%opts, io => $IO, type => $type)) {
1894 $ERRSTR = "Cannot read multiple images from $type files";
1898 # Destroy an Imager object
1902 # delete $instances{$self};
1903 if (defined($self->{IMG})) {
1904 # the following is now handled by the XS DESTROY method for
1905 # Imager::ImgRaw object
1906 # Re-enabling this will break virtual images
1907 # tested for in t/t020masked.t
1908 # i_img_destroy($self->{IMG});
1909 undef($self->{IMG});
1911 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1915 # Perform an inplace filter of an image
1916 # that is the image will be overwritten with the data
1922 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1924 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1926 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1927 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1930 if ($filters{$input{'type'}}{names}) {
1931 my $names = $filters{$input{'type'}}{names};
1932 for my $name (keys %$names) {
1933 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1934 $input{$name} = $names->{$name}{$input{$name}};
1938 if (defined($filters{$input{'type'}}{defaults})) {
1939 %hsh=( image => $self->{IMG},
1941 %{$filters{$input{'type'}}{defaults}},
1944 %hsh=( image => $self->{IMG},
1949 my @cs=@{$filters{$input{'type'}}{callseq}};
1952 if (!defined($hsh{$_})) {
1953 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1958 local $SIG{__DIE__}; # we don't want this processed by confess, etc
1959 &{$filters{$input{'type'}}{callsub}}(%hsh);
1962 chomp($self->{ERRSTR} = $@);
1968 $self->{DEBUG} && print "callseq is: @cs\n";
1969 $self->{DEBUG} && print "matching callseq is: @b\n";
1974 sub register_filter {
1976 my %hsh = ( defaults => {}, @_ );
1979 or die "register_filter() with no type\n";
1980 defined $hsh{callsub}
1981 or die "register_filter() with no callsub\n";
1982 defined $hsh{callseq}
1983 or die "register_filter() with no callseq\n";
1985 exists $filters{$hsh{type}}
1988 $filters{$hsh{type}} = \%hsh;
1993 # Scale an image to requested size and return the scaled version
1997 my %opts=('type'=>'max',qtype=>'normal',@_);
1998 my $img = Imager->new();
1999 my $tmp = Imager->new();
2000 my ($x_scale, $y_scale);
2002 unless (defined wantarray) {
2003 my @caller = caller;
2004 warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
2008 unless ($self->{IMG}) {
2009 $self->_set_error('empty input image');
2013 if ($opts{'xscalefactor'} && $opts{'yscalefactor'}) {
2014 $x_scale = $opts{'xscalefactor'};
2015 $y_scale = $opts{'yscalefactor'};
2017 elsif ($opts{'xscalefactor'}) {
2018 $x_scale = $opts{'xscalefactor'};
2019 $y_scale = $opts{'scalefactor'} || $x_scale;
2021 elsif ($opts{'yscalefactor'}) {
2022 $y_scale = $opts{'yscalefactor'};
2023 $x_scale = $opts{'scalefactor'} || $y_scale;
2026 $x_scale = $y_scale = $opts{'scalefactor'} || 0.5;
2029 # work out the scaling
2030 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
2031 my ($xpix, $ypix)=( $opts{xpixels} / $self->getwidth() ,
2032 $opts{ypixels} / $self->getheight() );
2033 if ($opts{'type'} eq 'min') {
2034 $x_scale = $y_scale = _min($xpix,$ypix);
2036 elsif ($opts{'type'} eq 'max') {
2037 $x_scale = $y_scale = _max($xpix,$ypix);
2039 elsif ($opts{'type'} eq 'nonprop' || $opts{'type'} eq 'non-proportional') {
2044 $self->_set_error('invalid value for type parameter');
2047 } elsif ($opts{xpixels}) {
2048 $x_scale = $y_scale = $opts{xpixels} / $self->getwidth();
2050 elsif ($opts{ypixels}) {
2051 $x_scale = $y_scale = $opts{ypixels}/$self->getheight();
2053 elsif ($opts{constrain} && ref $opts{constrain}
2054 && $opts{constrain}->can('constrain')) {
2055 # we've been passed an Image::Math::Constrain object or something
2056 # that looks like one
2058 (undef, undef, $scalefactor)
2059 = $opts{constrain}->constrain($self->getwidth, $self->getheight);
2060 unless ($scalefactor) {
2061 $self->_set_error('constrain method failed on constrain parameter');
2064 $x_scale = $y_scale = $scalefactor;
2067 if ($opts{qtype} eq 'normal') {
2068 $tmp->{IMG} = i_scaleaxis($self->{IMG}, $x_scale, 0);
2069 if ( !defined($tmp->{IMG}) ) {
2070 $self->{ERRSTR} = 'unable to scale image';
2073 $img->{IMG}=i_scaleaxis($tmp->{IMG}, $y_scale, 1);
2074 if ( !defined($img->{IMG}) ) {
2075 $self->{ERRSTR}='unable to scale image';
2081 elsif ($opts{'qtype'} eq 'preview') {
2082 $img->{IMG} = i_scale_nn($self->{IMG}, $x_scale, $y_scale);
2083 if ( !defined($img->{IMG}) ) {
2084 $self->{ERRSTR}='unable to scale image';
2089 elsif ($opts{'qtype'} eq 'mixing') {
2090 my $new_width = int(0.5 + $self->getwidth * $x_scale);
2091 my $new_height = int(0.5 + $self->getheight * $y_scale);
2092 $new_width >= 1 or $new_width = 1;
2093 $new_height >= 1 or $new_height = 1;
2094 $img->{IMG} = i_scale_mixing($self->{IMG}, $new_width, $new_height);
2095 unless ($img->{IMG}) {
2096 $self->_set_error(Imager->_error_as_meg);
2102 $self->_set_error('invalid value for qtype parameter');
2107 # Scales only along the X axis
2111 my %opts = ( scalefactor=>0.5, @_ );
2113 unless (defined wantarray) {
2114 my @caller = caller;
2115 warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
2119 unless ($self->{IMG}) {
2120 $self->{ERRSTR} = 'empty input image';
2124 my $img = Imager->new();
2126 my $scalefactor = $opts{scalefactor};
2128 if ($opts{pixels}) {
2129 $scalefactor = $opts{pixels} / $self->getwidth();
2132 unless ($self->{IMG}) {
2133 $self->{ERRSTR}='empty input image';
2137 $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
2139 if ( !defined($img->{IMG}) ) {
2140 $self->{ERRSTR} = 'unable to scale image';
2147 # Scales only along the Y axis
2151 my %opts = ( scalefactor => 0.5, @_ );
2153 unless (defined wantarray) {
2154 my @caller = caller;
2155 warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
2159 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2161 my $img = Imager->new();
2163 my $scalefactor = $opts{scalefactor};
2165 if ($opts{pixels}) {
2166 $scalefactor = $opts{pixels} / $self->getheight();
2169 unless ($self->{IMG}) {
2170 $self->{ERRSTR} = 'empty input image';
2173 $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
2175 if ( !defined($img->{IMG}) ) {
2176 $self->{ERRSTR} = 'unable to scale image';
2183 # Transform returns a spatial transformation of the input image
2184 # this moves pixels to a new location in the returned image.
2185 # NOTE - should make a utility function to check transforms for
2190 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2192 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
2194 # print Dumper(\%opts);
2197 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
2199 eval ("use Affix::Infix2Postfix;");
2202 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
2205 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
2206 {op=>'-',trans=>'Sub'},
2207 {op=>'*',trans=>'Mult'},
2208 {op=>'/',trans=>'Div'},
2209 {op=>'-','type'=>'unary',trans=>'u-'},
2211 {op=>'func','type'=>'unary'}],
2212 'grouping'=>[qw( \( \) )],
2213 'func'=>[qw( sin cos )],
2218 @xt=$I2P->translate($opts{'xexpr'});
2219 @yt=$I2P->translate($opts{'yexpr'});
2221 $numre=$I2P->{'numre'};
2224 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
2225 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
2226 @{$opts{'parm'}}=@pt;
2229 # print Dumper(\%opts);
2231 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
2232 $self->{ERRSTR}='transform: no xopcodes given.';
2236 @op=@{$opts{'xopcodes'}};
2238 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2239 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2242 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2248 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
2249 $self->{ERRSTR}='transform: no yopcodes given.';
2253 @op=@{$opts{'yopcodes'}};
2255 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2256 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2259 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2264 if ( !exists $opts{'parm'}) {
2265 $self->{ERRSTR}='transform: no parameter arg given.';
2269 # print Dumper(\@ropx);
2270 # print Dumper(\@ropy);
2271 # print Dumper(\@ropy);
2273 my $img = Imager->new();
2274 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
2275 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
2281 my ($opts, @imgs) = @_;
2283 require "Imager/Expr.pm";
2285 $opts->{variables} = [ qw(x y) ];
2286 my ($width, $height) = @{$opts}{qw(width height)};
2288 $width ||= $imgs[0]->getwidth();
2289 $height ||= $imgs[0]->getheight();
2291 for my $img (@imgs) {
2292 $opts->{constants}{"w$img_num"} = $img->getwidth();
2293 $opts->{constants}{"h$img_num"} = $img->getheight();
2294 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
2295 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
2300 $opts->{constants}{w} = $width;
2301 $opts->{constants}{cx} = $width/2;
2304 $Imager::ERRSTR = "No width supplied";
2308 $opts->{constants}{h} = $height;
2309 $opts->{constants}{cy} = $height/2;
2312 $Imager::ERRSTR = "No height supplied";
2315 my $code = Imager::Expr->new($opts);
2317 $Imager::ERRSTR = Imager::Expr::error();
2320 my $channels = $opts->{channels} || 3;
2321 unless ($channels >= 1 && $channels <= 4) {
2322 return Imager->_set_error("channels must be an integer between 1 and 4");
2325 my $img = Imager->new();
2326 $img->{IMG} = i_transform2($opts->{width}, $opts->{height},
2327 $channels, $code->code(),
2328 $code->nregs(), $code->cregs(),
2329 [ map { $_->{IMG} } @imgs ]);
2330 if (!defined $img->{IMG}) {
2331 $Imager::ERRSTR = Imager->_error_as_msg();
2340 my %opts=(tx => 0,ty => 0, @_);
2342 unless ($self->{IMG}) {
2343 $self->{ERRSTR}='empty input image';
2346 unless ($opts{src} && $opts{src}->{IMG}) {
2347 $self->{ERRSTR}='empty input image for src';
2351 %opts = (src_minx => 0,
2353 src_maxx => $opts{src}->getwidth(),
2354 src_maxy => $opts{src}->getheight(),
2357 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
2358 $opts{src_minx}, $opts{src_miny},
2359 $opts{src_maxx}, $opts{src_maxy})) {
2360 $self->_set_error($self->_error_as_msg());
2370 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
2372 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
2373 $dir = $xlate{$opts{'dir'}};
2374 return $self if i_flipxy($self->{IMG}, $dir);
2382 unless (defined wantarray) {
2383 my @caller = caller;
2384 warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
2388 if (defined $opts{right}) {
2389 my $degrees = $opts{right};
2391 $degrees += 360 * int(((-$degrees)+360)/360);
2393 $degrees = $degrees % 360;
2394 if ($degrees == 0) {
2395 return $self->copy();
2397 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
2398 my $result = Imager->new();
2399 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
2403 $self->{ERRSTR} = $self->_error_as_msg();
2408 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
2412 elsif (defined $opts{radians} || defined $opts{degrees}) {
2413 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
2415 my $back = $opts{back};
2416 my $result = Imager->new;
2418 $back = _color($back);
2420 $self->_set_error(Imager->errstr);
2424 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
2427 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
2429 if ($result->{IMG}) {
2433 $self->{ERRSTR} = $self->_error_as_msg();
2438 $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available";
2443 sub matrix_transform {
2447 unless (defined wantarray) {
2448 my @caller = caller;
2449 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
2453 if ($opts{matrix}) {
2454 my $xsize = $opts{xsize} || $self->getwidth;
2455 my $ysize = $opts{ysize} || $self->getheight;
2457 my $result = Imager->new;
2459 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2460 $opts{matrix}, $opts{back})
2464 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2472 $self->{ERRSTR} = "matrix parameter required";
2478 *yatf = \&matrix_transform;
2480 # These two are supported for legacy code only
2483 return Imager::Color->new(@_);
2487 return Imager::Color::set(@_);
2490 # Draws a box between the specified corner points.
2493 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2494 my $dflcl=i_color_new(255,255,255,255);
2495 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
2497 if (exists $opts{'box'}) {
2498 $opts{'xmin'} = _min($opts{'box'}->[0],$opts{'box'}->[2]);
2499 $opts{'xmax'} = _max($opts{'box'}->[0],$opts{'box'}->[2]);
2500 $opts{'ymin'} = _min($opts{'box'}->[1],$opts{'box'}->[3]);
2501 $opts{'ymax'} = _max($opts{'box'}->[1],$opts{'box'}->[3]);
2504 if ($opts{filled}) {
2505 my $color = _color($opts{'color'});
2507 $self->{ERRSTR} = $Imager::ERRSTR;
2510 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2511 $opts{ymax}, $color);
2513 elsif ($opts{fill}) {
2514 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2515 # assume it's a hash ref
2516 require 'Imager/Fill.pm';
2517 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2518 $self->{ERRSTR} = $Imager::ERRSTR;
2522 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2523 $opts{ymax},$opts{fill}{fill});
2526 my $color = _color($opts{'color'});
2528 $self->{ERRSTR} = $Imager::ERRSTR;
2531 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
2539 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2540 my $dflcl=i_color_new(255,255,255,255);
2541 my %opts=(color=>$dflcl,
2542 'r'=>_min($self->getwidth(),$self->getheight())/3,
2543 'x'=>$self->getwidth()/2,
2544 'y'=>$self->getheight()/2,
2545 'd1'=>0, 'd2'=>361, @_);
2548 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2549 # assume it's a hash ref
2550 require 'Imager/Fill.pm';
2551 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2552 $self->{ERRSTR} = $Imager::ERRSTR;
2556 i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2557 $opts{'d2'}, $opts{fill}{fill});
2560 my $color = _color($opts{'color'});
2562 $self->{ERRSTR} = $Imager::ERRSTR;
2565 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
2566 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
2570 i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2571 $opts{'d1'}, $opts{'d2'}, $color);
2577 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2578 # assume it's a hash ref
2579 require 'Imager/Fill.pm';
2580 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2581 $self->{ERRSTR} = $Imager::ERRSTR;
2585 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2586 $opts{'d2'}, $opts{fill}{fill});
2589 my $color = _color($opts{'color'});
2591 $self->{ERRSTR} = $Imager::ERRSTR;
2594 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2595 $opts{'d1'}, $opts{'d2'}, $color);
2602 # Draws a line from one point to the other
2603 # the endpoint is set if the endp parameter is set which it is by default.
2604 # to turn of the endpoint being set use endp=>0 when calling line.
2608 my $dflcl=i_color_new(0,0,0,0);
2609 my %opts=(color=>$dflcl,
2612 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2614 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2615 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2617 my $color = _color($opts{'color'});
2619 $self->{ERRSTR} = $Imager::ERRSTR;
2623 $opts{antialias} = $opts{aa} if defined $opts{aa};
2624 if ($opts{antialias}) {
2625 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2626 $color, $opts{endp});
2628 i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2629 $color, $opts{endp});
2634 # Draws a line between an ordered set of points - It more or less just transforms this
2635 # into a list of lines.
2639 my ($pt,$ls,@points);
2640 my $dflcl=i_color_new(0,0,0,0);
2641 my %opts=(color=>$dflcl,@_);
2643 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2645 if (exists($opts{points})) { @points=@{$opts{points}}; }
2646 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2647 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2650 # print Dumper(\@points);
2652 my $color = _color($opts{'color'});
2654 $self->{ERRSTR} = $Imager::ERRSTR;
2657 $opts{antialias} = $opts{aa} if defined $opts{aa};
2658 if ($opts{antialias}) {
2661 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1);
2668 i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1);
2678 my ($pt,$ls,@points);
2679 my $dflcl = i_color_new(0,0,0,0);
2680 my %opts = (color=>$dflcl, @_);
2682 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2684 if (exists($opts{points})) {
2685 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2686 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2689 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2690 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2693 if ($opts{'fill'}) {
2694 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2695 # assume it's a hash ref
2696 require 'Imager/Fill.pm';
2697 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2698 $self->{ERRSTR} = $Imager::ERRSTR;
2702 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2703 $opts{'fill'}{'fill'});
2706 my $color = _color($opts{'color'});
2708 $self->{ERRSTR} = $Imager::ERRSTR;
2711 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2718 # this the multipoint bezier curve
2719 # this is here more for testing that actual usage since
2720 # this is not a good algorithm. Usually the curve would be
2721 # broken into smaller segments and each done individually.
2725 my ($pt,$ls,@points);
2726 my $dflcl=i_color_new(0,0,0,0);
2727 my %opts=(color=>$dflcl,@_);
2729 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2731 if (exists $opts{points}) {
2732 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2733 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2736 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2737 $self->{ERRSTR}='Missing or invalid points.';
2741 my $color = _color($opts{'color'});
2743 $self->{ERRSTR} = $Imager::ERRSTR;
2746 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2752 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2755 unless (exists $opts{'x'} && exists $opts{'y'}) {
2756 $self->{ERRSTR} = "missing seed x and y parameters";
2760 if ($opts{border}) {
2761 my $border = _color($opts{border});
2763 $self->_set_error($Imager::ERRSTR);
2767 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2768 # assume it's a hash ref
2769 require Imager::Fill;
2770 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2771 $self->{ERRSTR} = $Imager::ERRSTR;
2775 $rc = i_flood_cfill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2776 $opts{fill}{fill}, $border);
2779 my $color = _color($opts{'color'});
2781 $self->{ERRSTR} = $Imager::ERRSTR;
2784 $rc = i_flood_fill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2791 $self->{ERRSTR} = $self->_error_as_msg();
2797 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2798 # assume it's a hash ref
2799 require 'Imager/Fill.pm';
2800 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2801 $self->{ERRSTR} = $Imager::ERRSTR;
2805 $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2808 my $color = _color($opts{'color'});
2810 $self->{ERRSTR} = $Imager::ERRSTR;
2813 $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2819 $self->{ERRSTR} = $self->_error_as_msg();
2828 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2830 unless (exists $opts{'x'} && exists $opts{'y'}) {
2831 $self->{ERRSTR} = 'missing x and y parameters';
2837 my $color = _color($opts{color})
2839 if (ref $x && ref $y) {
2840 unless (@$x == @$y) {
2841 $self->{ERRSTR} = 'length of x and y mismatch';
2845 if ($color->isa('Imager::Color')) {
2846 for my $i (0..$#{$opts{'x'}}) {
2847 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color)
2852 for my $i (0..$#{$opts{'x'}}) {
2853 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color)
2861 if ($color->isa('Imager::Color')) {
2862 i_ppix($self->{IMG}, $x, $y, $color)
2866 i_ppixf($self->{IMG}, $x, $y, $color)
2877 my %opts = ( "type"=>'8bit', @_);
2879 unless (exists $opts{'x'} && exists $opts{'y'}) {
2880 $self->{ERRSTR} = 'missing x and y parameters';
2886 if (ref $x && ref $y) {
2887 unless (@$x == @$y) {
2888 $self->{ERRSTR} = 'length of x and y mismatch';
2892 if ($opts{"type"} eq '8bit') {
2893 for my $i (0..$#{$opts{'x'}}) {
2894 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2898 for my $i (0..$#{$opts{'x'}}) {
2899 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2902 return wantarray ? @result : \@result;
2905 if ($opts{"type"} eq '8bit') {
2906 return i_get_pixel($self->{IMG}, $x, $y);
2909 return i_gpixf($self->{IMG}, $x, $y);
2918 my %opts = ( type => '8bit', x=>0, @_);
2920 $self->_valid_image or return;
2922 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2924 unless (defined $opts{'y'}) {
2925 $self->_set_error("missing y parameter");
2929 if ($opts{type} eq '8bit') {
2930 return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2933 elsif ($opts{type} eq 'float') {
2934 return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2937 elsif ($opts{type} eq 'index') {
2938 unless (i_img_type($self->{IMG})) {
2939 $self->_set_error("type => index only valid on paletted images");
2942 return i_gpal($self->{IMG}, $opts{x}, $opts{x} + $opts{width},
2946 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2953 my %opts = ( x=>0, @_);
2955 $self->_valid_image or return;
2957 unless (defined $opts{'y'}) {
2958 $self->_set_error("missing y parameter");
2963 if (ref $opts{pixels} && @{$opts{pixels}}) {
2964 # try to guess the type
2965 if ($opts{pixels}[0]->isa('Imager::Color')) {
2966 $opts{type} = '8bit';
2968 elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
2969 $opts{type} = 'float';
2972 $self->_set_error("missing type parameter and could not guess from pixels");
2978 $opts{type} = '8bit';
2982 if ($opts{type} eq '8bit') {
2983 if (ref $opts{pixels}) {
2984 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2987 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2990 elsif ($opts{type} eq 'float') {
2991 if (ref $opts{pixels}) {
2992 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2995 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2998 elsif ($opts{type} eq 'index') {
2999 if (ref $opts{pixels}) {
3000 return i_ppal($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3003 return i_ppal_p($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3007 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3014 my %opts = ( type => '8bit', x=>0, @_);
3016 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
3018 unless (defined $opts{'y'}) {
3019 $self->_set_error("missing y parameter");
3023 unless ($opts{channels}) {
3024 $opts{channels} = [ 0 .. $self->getchannels()-1 ];
3027 if ($opts{type} eq '8bit') {
3028 return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3029 $opts{y}, @{$opts{channels}});
3031 elsif ($opts{type} eq 'float') {
3032 return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3033 $opts{y}, @{$opts{channels}});
3036 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3041 # make an identity matrix of the given size
3045 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
3046 for my $c (0 .. ($size-1)) {
3047 $matrix->[$c][$c] = 1;
3052 # general function to convert an image
3054 my ($self, %opts) = @_;
3057 unless (defined wantarray) {
3058 my @caller = caller;
3059 warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
3063 # the user can either specify a matrix or preset
3064 # the matrix overrides the preset
3065 if (!exists($opts{matrix})) {
3066 unless (exists($opts{preset})) {
3067 $self->{ERRSTR} = "convert() needs a matrix or preset";
3071 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
3072 # convert to greyscale, keeping the alpha channel if any
3073 if ($self->getchannels == 3) {
3074 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
3076 elsif ($self->getchannels == 4) {
3077 # preserve the alpha channel
3078 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
3083 $matrix = _identity($self->getchannels);
3086 elsif ($opts{preset} eq 'noalpha') {
3087 # strip the alpha channel
3088 if ($self->getchannels == 2 or $self->getchannels == 4) {
3089 $matrix = _identity($self->getchannels);
3090 pop(@$matrix); # lose the alpha entry
3093 $matrix = _identity($self->getchannels);
3096 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
3098 $matrix = [ [ 1 ] ];
3100 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
3101 $matrix = [ [ 0, 1 ] ];
3103 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
3104 $matrix = [ [ 0, 0, 1 ] ];
3106 elsif ($opts{preset} eq 'alpha') {
3107 if ($self->getchannels == 2 or $self->getchannels == 4) {
3108 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
3111 # the alpha is just 1 <shrug>
3112 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
3115 elsif ($opts{preset} eq 'rgb') {
3116 if ($self->getchannels == 1) {
3117 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
3119 elsif ($self->getchannels == 2) {
3120 # preserve the alpha channel
3121 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
3124 $matrix = _identity($self->getchannels);
3127 elsif ($opts{preset} eq 'addalpha') {
3128 if ($self->getchannels == 1) {
3129 $matrix = _identity(2);
3131 elsif ($self->getchannels == 3) {
3132 $matrix = _identity(4);
3135 $matrix = _identity($self->getchannels);
3139 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
3145 $matrix = $opts{matrix};
3148 my $new = Imager->new;
3149 $new->{IMG} = i_convert($self->{IMG}, $matrix);
3150 unless ($new->{IMG}) {
3151 # most likely a bad matrix
3152 $self->{ERRSTR} = _error_as_msg();
3159 # general function to map an image through lookup tables
3162 my ($self, %opts) = @_;
3163 my @chlist = qw( red green blue alpha );
3165 if (!exists($opts{'maps'})) {
3166 # make maps from channel maps
3168 for $chnum (0..$#chlist) {
3169 if (exists $opts{$chlist[$chnum]}) {
3170 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
3171 } elsif (exists $opts{'all'}) {
3172 $opts{'maps'}[$chnum] = $opts{'all'};
3176 if ($opts{'maps'} and $self->{IMG}) {
3177 i_map($self->{IMG}, $opts{'maps'} );
3183 my ($self, %opts) = @_;
3185 defined $opts{mindist} or $opts{mindist} = 0;
3187 defined $opts{other}
3188 or return $self->_set_error("No 'other' parameter supplied");
3189 defined $opts{other}{IMG}
3190 or return $self->_set_error("No image data in 'other' image");
3193 or return $self->_set_error("No image data");
3195 my $result = Imager->new;
3196 $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
3198 or return $self->_set_error($self->_error_as_msg());
3203 # destructive border - image is shrunk by one pixel all around
3206 my ($self,%opts)=@_;
3207 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
3208 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
3212 # Get the width of an image
3216 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3217 return (i_img_info($self->{IMG}))[0];
3220 # Get the height of an image
3224 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3225 return (i_img_info($self->{IMG}))[1];
3228 # Get number of channels in an image
3232 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3233 return i_img_getchannels($self->{IMG});
3240 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3241 return i_img_getmask($self->{IMG});
3249 if (!defined($self->{IMG})) {
3250 $self->{ERRSTR} = 'image is empty';
3253 unless (defined $opts{mask}) {
3254 $self->_set_error("mask parameter required");
3257 i_img_setmask( $self->{IMG} , $opts{mask} );
3262 # Get number of colors in an image
3266 my %opts=('maxcolors'=>2**30,@_);
3267 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
3268 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
3269 return ($rc==-1? undef : $rc);
3272 # draw string to an image
3276 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
3278 my %input=('x'=>0, 'y'=>0, @_);
3279 defined($input{string}) or $input{string} = $input{text};
3281 unless(defined $input{string}) {
3282 $self->{ERRSTR}="missing required parameter 'string'";
3286 unless($input{font}) {
3287 $self->{ERRSTR}="missing required parameter 'font'";
3291 unless ($input{font}->draw(image=>$self, %input)) {
3303 unless ($self->{IMG}) {
3304 $self->{ERRSTR}='empty input image';
3313 my %input=('x'=>0, 'y'=>0, @_);
3314 $input{string}||=$input{text};
3316 unless(exists $input{string}) {
3317 $self->_set_error("missing required parameter 'string'");
3321 unless($input{font}) {
3322 $self->_set_error("missing required parameter 'font'");
3327 unless (@result = $input{font}->align(image=>$img, %input)) {
3331 return wantarray ? @result : $result[0];
3334 my @file_limit_names = qw/width height bytes/;
3336 sub set_file_limits {
3343 @values{@file_limit_names} = (0) x @file_limit_names;
3346 @values{@file_limit_names} = i_get_image_file_limits();
3349 for my $key (keys %values) {
3350 defined $opts{$key} and $values{$key} = $opts{$key};
3353 i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
3356 sub get_file_limits {
3357 i_get_image_file_limits();
3360 # Shortcuts that can be exported
3362 sub newcolor { Imager::Color->new(@_); }
3363 sub newfont { Imager::Font->new(@_); }
3365 *NC=*newcolour=*newcolor;
3372 #### Utility routines
3375 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
3379 my ($self, $msg) = @_;
3382 $self->{ERRSTR} = $msg;
3390 # Default guess for the type of an image from extension
3392 sub def_guess_type {
3395 $ext=($name =~ m/\.([^\.]+)$/)[0];
3396 return 'tiff' if ($ext =~ m/^tiff?$/);
3397 return 'jpeg' if ($ext =~ m/^jpe?g$/);
3398 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
3399 return 'png' if ($ext eq "png");
3400 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
3401 return 'tga' if ($ext eq "tga");
3402 return 'sgi' if ($ext eq "rgb" || $ext eq "bw" || $ext eq "sgi" || $ext eq "rgba");
3403 return 'gif' if ($ext eq "gif");
3404 return 'raw' if ($ext eq "raw");
3405 return lc $ext; # best guess
3409 # get the minimum of a list
3413 for(@_) { if ($_<$mx) { $mx=$_; }}
3417 # get the maximum of a list
3421 for(@_) { if ($_>$mx) { $mx=$_; }}
3425 # string stuff for iptc headers
3429 $str = substr($str,3);
3430 $str =~ s/[\n\r]//g;
3437 # A little hack to parse iptc headers.
3442 my($caption,$photogr,$headln,$credit);
3444 my $str=$self->{IPTCRAW};
3449 @ar=split(/8BIM/,$str);
3454 @sar=split(/\034\002/);
3455 foreach $item (@sar) {
3456 if ($item =~ m/^x/) {
3457 $caption = _clean($item);
3460 if ($item =~ m/^P/) {
3461 $photogr = _clean($item);
3464 if ($item =~ m/^i/) {
3465 $headln = _clean($item);
3468 if ($item =~ m/^n/) {
3469 $credit = _clean($item);
3475 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
3482 or die "Only C language supported";
3484 require Imager::ExtUtils;
3485 return Imager::ExtUtils->inline_config;
3490 # Below is the stub of documentation for your module. You better edit it!
3494 Imager - Perl extension for Generating 24 bit Images
3504 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
3509 my $img = Imager->new();
3510 # see Imager::Files for information on the read() method
3511 $img->read(file=>$file) or die $img->errstr();
3513 $file =~ s/\.[^.]*$//;
3515 # Create smaller version
3516 # documented in Imager::Transformations
3517 my $thumb = $img->scale(scalefactor=>.3);
3519 # Autostretch individual channels
3520 $thumb->filter(type=>'autolevels');
3522 # try to save in one of these formats
3525 for $format ( qw( png gif jpg tiff ppm ) ) {
3526 # Check if given format is supported
3527 if ($Imager::formats{$format}) {
3528 $file.="_low.$format";
3529 print "Storing image as: $file\n";
3530 # documented in Imager::Files
3531 $thumb->write(file=>$file) or
3539 Imager is a module for creating and altering images. It can read and
3540 write various image formats, draw primitive shapes like lines,and
3541 polygons, blend multiple images together in various ways, scale, crop,
3542 render text and more.
3544 =head2 Overview of documentation
3550 Imager - This document - Synopsis, Example, Table of Contents and
3555 L<Imager::Tutorial> - a brief introduction to Imager.
3559 L<Imager::Cookbook> - how to do various things with Imager.
3563 L<Imager::ImageTypes> - Basics of constructing image objects with
3564 C<new()>: Direct type/virtual images, RGB(A)/paletted images,
3565 8/16/double bits/channel, color maps, channel masks, image tags, color
3566 quantization. Also discusses basic image information methods.
3570 L<Imager::Files> - IO interaction, reading/writing images, format
3575 L<Imager::Draw> - Drawing Primitives, lines, boxes, circles, arcs,
3580 L<Imager::Color> - Color specification.
3584 L<Imager::Fill> - Fill pattern specification.
3588 L<Imager::Font> - General font rendering, bounding boxes and font
3593 L<Imager::Transformations> - Copying, scaling, cropping, flipping,
3594 blending, pasting, convert and map.
3598 L<Imager::Engines> - Programmable transformations through
3599 C<transform()>, C<transform2()> and C<matrix_transform()>.
3603 L<Imager::Filters> - Filters, sharpen, blur, noise, convolve etc. and
3608 L<Imager::Expr> - Expressions for evaluation engine used by
3613 L<Imager::Matrix2d> - Helper class for affine transformations.
3617 L<Imager::Fountain> - Helper for making gradient profiles.
3621 L<Imager::API> - using Imager's C API
3625 L<Imager::APIRef> - API function reference
3629 L<Imager::Inline> - using Imager's C API from Inline::C
3633 L<Imager::ExtUtils> - tools to get access to Imager's C API.
3637 =head2 Basic Overview
3639 An Image object is created with C<$img = Imager-E<gt>new()>.
3642 $img=Imager->new(); # create empty image
3643 $img->read(file=>'lena.png',type=>'png') or # read image from file
3644 die $img->errstr(); # give an explanation
3645 # if something failed
3647 or if you want to create an empty image:
3649 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
3651 This example creates a completely black image of width 400 and height
3654 =head1 ERROR HANDLING
3656 In general a method will return false when it fails, if it does use the errstr() method to find out why:
3662 Returns the last error message in that context.
3664 If the last error you received was from calling an object method, such
3665 as read, call errstr() as an object method to find out why:
3667 my $image = Imager->new;
3668 $image->read(file => 'somefile.gif')
3669 or die $image->errstr;
3671 If it was a class method then call errstr() as a class method:
3673 my @imgs = Imager->read_multi(file => 'somefile.gif')
3674 or die Imager->errstr;
3676 Note that in some cases object methods are implemented in terms of
3677 class methods so a failing object method may set both.
3681 The C<Imager-E<gt>new> method is described in detail in
3682 L<Imager::ImageTypes>.
3686 Where to find information on methods for Imager class objects.
3688 addcolors() - L<Imager::ImageTypes/addcolors>
3690 addtag() - L<Imager::ImageTypes/addtag> - add image tags
3692 align_string() - L<Imager::Draw/align_string>
3694 arc() - L<Imager::Draw/arc>
3696 bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
3699 box() - L<Imager::Draw/box>
3701 circle() - L<Imager::Draw/circle>
3703 colorcount() - L<Imager::Draw/colorcount>
3705 convert() - L<Imager::Transformations/"Color transformations"> -
3706 transform the color space
3708 copy() - L<Imager::Transformations/copy>
3710 crop() - L<Imager::Transformations/crop> - extract part of an image
3712 def_guess_type() - L<Imager::Files/def_guess_type>
3714 deltag() - L<Imager::ImageTypes/deltag> - delete image tags
3716 difference() - L<Imager::Filters/"Image Difference">
3718 errstr() - L<"Basic Overview">
3720 filter() - L<Imager::Filters>
3722 findcolor() - L<Imager::ImageTypes/findcolor> - search the image palette, if it
3725 flip() - L<Imager::Transformations/flip>
3727 flood_fill() - L<Imager::Draw/flood_fill>
3729 getchannels() - L<Imager::ImageTypes/getchannels>
3731 getcolorcount() - L<Imager::ImageTypes/getcolorcount>
3733 getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
3734 palette, if it has one
3736 get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3738 getheight() - L<Imager::ImageTypes/getwidth>
3740 getmask() - L<Imager::ImageTypes/getmask>
3742 getpixel() - L<Imager::Draw/getpixel>
3744 getsamples() - L<Imager::Draw/getsamples>
3746 getscanline() - L<Imager::Draw/getscanline>
3748 getwidth() - L<Imager::ImageTypes/getwidth>
3750 img_set() - L<Imager::ImageTypes/img_set>
3752 init() - L<Imager::ImageTypes/init>
3754 line() - L<Imager::Draw/line>
3756 load_plugin() - L<Imager::Filters/load_plugin>
3758 map() - L<Imager::Transformations/"Color Mappings"> - remap color
3761 masked() - L<Imager::ImageTypes/masked> - make a masked image
3763 matrix_transform() - L<Imager::Engines/matrix_transform>
3765 maxcolors() - L<Imager::ImageTypes/maxcolors>
3767 NC() - L<Imager::Handy/NC>
3769 new() - L<Imager::ImageTypes/new>
3771 newcolor() - L<Imager::Handy/newcolor>
3773 newcolour() - L<Imager::Handy/newcolour>
3775 newfont() - L<Imager::Handy/newfont>
3777 NF() - L<Imager::Handy/NF>
3779 open() - L<Imager::Files> - an alias for read()
3781 parseiptc() - L<Imager::Files/parseiptc> - parse IPTC data from a JPEG
3784 paste() - L<Imager::Transformations/paste> - draw an image onto an image
3786 polygon() - L<Imager::Draw/polygon>
3788 polyline() - L<Imager::Draw/polyline>
3790 read() - L<Imager::Files> - read a single image from an image file
3792 read_multi() - L<Imager::Files> - read multiple images from an image
3795 register_filter() - L<Imager::Filters/register_filter>
3797 register_reader() - L<Imager::Filters/register_reader>
3799 register_writer() - L<Imager::Filters/register_writer>
3801 rotate() - L<Imager::Transformations/rotate>
3803 rubthrough() - L<Imager::Transformations/rubthrough> - draw an image onto an
3804 image and use the alpha channel
3806 scale() - L<Imager::Transformations/scale>
3808 scaleX() - L<Imager::Transformations/scaleX>
3810 scaleY() - L<Imager::Transformations/scaleY>
3812 setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
3815 set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3817 setmask() - L<Imager::ImageTypes/setmask>
3819 setpixel() - L<Imager::Draw/setpixel>
3821 setscanline() - L<Imager::Draw/setscanline>
3823 settag() - L<Imager::ImageTypes/settag>
3825 string() - L<Imager::Draw/string> - draw text on an image
3827 tags() - L<Imager::ImageTypes/tags> - fetch image tags
3829 to_paletted() - L<Imager::ImageTypes/to_paletted>
3831 to_rgb16() - L<Imager::ImageTypes/to_rgb16>
3833 to_rgb8() - L<Imager::ImageTypes/to_rgb8>
3835 transform() - L<Imager::Engines/"transform">
3837 transform2() - L<Imager::Engines/"transform2">
3839 type() - L<Imager::ImageTypes/type> - type of image (direct vs paletted)
3841 unload_plugin() - L<Imager::Filters/unload_plugin>
3843 virtual() - L<Imager::ImageTypes/virtual> - whether the image has it's own
3846 write() - L<Imager::Files> - write an image to a file
3848 write_multi() - L<Imager::Files> - write multiple image to an image
3851 =head1 CONCEPT INDEX
3853 animated GIF - L<Imager::File/"Writing an animated GIF">
3855 aspect ratio - L<Imager::ImageTypes/i_xres>,
3856 L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
3858 blend - alpha blending one image onto another
3859 L<Imager::Transformations/rubthrough>
3861 blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
3863 boxes, drawing - L<Imager::Draw/box>
3865 changes between image - L<Imager::Filter/"Image Difference">
3867 color - L<Imager::Color>
3869 color names - L<Imager::Color>, L<Imager::Color::Table>
3871 combine modes - L<Imager::Fill/combine>
3873 compare images - L<Imager::Filter/"Image Difference">
3875 contrast - L<Imager::Filter/contrast>, L<Imager::Filter/autolevels>
3877 convolution - L<Imager::Filter/conv>
3879 cropping - L<Imager::Transformations/crop>
3881 CUR files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
3883 C<diff> images - L<Imager::Filter/"Image Difference">
3885 dpi - L<Imager::ImageTypes/i_xres>,
3886 L<Imager::Cookbook/"Image spatial resolution">
3888 drawing boxes - L<Imager::Draw/box>
3890 drawing lines - L<Imager::Draw/line>
3892 drawing text - L<Imager::Draw/string>, L<Imager::Draw/align_string>
3894 error message - L<"Basic Overview">
3896 files, font - L<Imager::Font>
3898 files, image - L<Imager::Files>
3900 filling, types of fill - L<Imager::Fill>
3902 filling, boxes - L<Imager::Draw/box>
3904 filling, flood fill - L<Imager::Draw/flood_fill>
3906 flood fill - L<Imager::Draw/flood_fill>
3908 fonts - L<Imager::Font>
3910 fonts, drawing with - L<Imager::Draw/string>,
3911 L<Imager::Draw/align_string>, L<Imager::Font::Wrap>
3913 fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3915 fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
3917 fountain fill - L<Imager::Fill/"Fountain fills">,
3918 L<Imager::Filters/fountain>, L<Imager::Fountain>,
3919 L<Imager::Filters/gradgen>
3921 GIF files - L<Imager::Files/"GIF">
3923 GIF files, animated - L<Imager::File/"Writing an animated GIF">
3925 gradient fill - L<Imager::Fill/"Fountain fills">,
3926 L<Imager::Filters/fountain>, L<Imager::Fountain>,
3927 L<Imager::Filters/gradgen>
3929 guassian blur - L<Imager::Filter/guassian>
3931 hatch fills - L<Imager::Fill/"Hatched fills">
3933 ICO files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
3935 invert image - L<Imager::Filter/hardinvert>
3937 JPEG - L<Imager::Files/"JPEG">
3939 limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
3941 lines, drawing - L<Imager::Draw/line>
3943 matrix - L<Imager::Matrix2d>,
3944 L<Imager::Transformations/"Matrix Transformations">,
3945 L<Imager::Font/transform>
3947 metadata, image - L<Imager::ImageTypes/"Tags">
3949 mosaic - L<Imager::Filter/mosaic>
3951 noise, filter - L<Imager::Filter/noise>
3953 noise, rendered - L<Imager::Filter/turbnoise>,
3954 L<Imager::Filter/radnoise>
3956 paste - L<Imager::Transformations/paste>,
3957 L<Imager::Transformations/rubthrough>
3959 pseudo-color image - L<Imager::ImageTypes/to_paletted>,
3960 L<Imager::ImageTypes/new>
3962 posterize - L<Imager::Filter/postlevels>
3964 png files - L<Imager::Files>, L<Imager::Files/"PNG">
3966 pnm - L<Imager::Files/"PNM (Portable aNy Map)">
3968 rectangles, drawing - L<Imager::Draw/box>
3970 resizing an image - L<Imager::Transformations/scale>,
3971 L<Imager::Transformations/crop>
3973 RGB (SGI) files - L<Imager::Files/"SGI (RGB, BW)">
3975 saving an image - L<Imager::Files>
3977 scaling - L<Imager::Transformations/scale>
3979 SGI files - L<Imager::Files/"SGI (RGB, BW)">
3981 sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
3983 size, image - L<Imager::ImageTypes/getwidth>,
3984 L<Imager::ImageTypes/getheight>
3986 size, text - L<Imager::Font/bounding_box>
3988 tags, image metadata - L<Imager::ImageTypes/"Tags">
3990 text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
3991 L<Imager::Font::Wrap>
3993 text, wrapping text in an area - L<Imager::Font::Wrap>
3995 text, measuring - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3997 tiles, color - L<Imager::Filter/mosaic>
3999 unsharp mask - L<Imager::Filter/unsharpmask>
4001 watermark - L<Imager::Filter/watermark>
4003 writing an image to a file - L<Imager::Files>
4007 The best place to get help with Imager is the mailing list.
4009 To subscribe send a message with C<subscribe> in the body to:
4011 imager-devel+request@molar.is
4017 L<http://www.molar.is/en/lists/imager-devel/>
4021 where you can also find the mailing list archive.
4023 You can report bugs by pointing your browser at:
4027 L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager>
4031 Please remember to include the versions of Imager, perl, supporting
4032 libraries, and any relevant code. If you have specific images that
4033 cause the problems, please include those too.
4035 If you don't want to publish your email address on a mailing list you
4036 can use CPAN::Forum:
4038 http://www.cpanforum.com/dist/Imager
4040 You will need to register to post.
4042 =head1 CONTRIBUTING TO IMAGER
4048 If you like or dislike Imager, you can add a public review of Imager
4051 http://cpanratings.perl.org/dist/Imager
4053 This requires a Bitcard Account (http://www.bitcard.org).
4055 You can also send email to the maintainer below.
4057 If you send me a bug report via email, it will be copied to RT.
4061 I accept patches, preferably against the main branch in subversion.
4062 You should include an explanation of the reason for why the patch is
4065 Your patch should include regression tests where possible, otherwise
4066 it will be delayed until I get a chance to write them.
4070 Tony Cook <tony@imager.perl.org> is the current maintainer for Imager.
4072 Arnar M. Hrafnkelsson is the original author of Imager.
4074 Many others have contributed to Imager, please see the README for a
4079 L<perl>(1), L<Imager::ImageTypes>(3), L<Imager::Files>(3),
4080 L<Imager::Draw>(3), L<Imager::Color>(3), L<Imager::Fill>(3),
4081 L<Imager::Font>(3), L<Imager::Transformations>(3),
4082 L<Imager::Engines>(3), L<Imager::Filters>(3), L<Imager::Expr>(3),
4083 L<Imager::Matrix2d>(3), L<Imager::Fountain>(3)
4085 L<http://imager.perl.org/>
4087 L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
4089 Other perl imaging modules include:
4091 L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).