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;
155 # library keys that are image file formats
156 my %file_formats = map { $_ => 1 } qw/tiff pnm gif png jpeg raw bmp tga/;
164 XSLoader::load(Imager => $VERSION);
168 push @ISA, 'DynaLoader';
169 bootstrap Imager $VERSION;
174 i_init_fonts(); # Initialize font engines
175 Imager::Font::__init();
176 for(i_list_formats()) { $formats{$_}++; }
178 if ($formats{'t1'}) {
182 if (!$formats{'t1'} and !$formats{'tt'}
183 && !$formats{'ft2'} && !$formats{'w32'}) {
184 $fontstate='no font support';
187 %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]);
191 # the members of the subhashes under %filters are:
192 # callseq - a list of the parameters to the underlying filter in the
193 # order they are passed
194 # callsub - a code ref that takes a named parameter list and calls the
196 # defaults - a hash of default values
197 # names - defines names for value of given parameters so if the names
198 # field is foo=> { bar=>1 }, and the user supplies "bar" as the
199 # foo parameter, the filter will receive 1 for the foo
202 callseq => ['image','intensity'],
203 callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); }
207 callseq => ['image', 'amount', 'subtype'],
208 defaults => { amount=>3,subtype=>0 },
209 callsub => sub { my %hsh=@_; i_noise($hsh{image},$hsh{amount},$hsh{subtype}); }
212 $filters{hardinvert} ={
213 callseq => ['image'],
215 callsub => sub { my %hsh=@_; i_hardinvert($hsh{image}); }
218 $filters{autolevels} ={
219 callseq => ['image','lsat','usat','skew'],
220 defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 },
221 callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); }
224 $filters{turbnoise} ={
225 callseq => ['image'],
226 defaults => { xo=>0.0,yo=>0.0,scale=>10.0 },
227 callsub => sub { my %hsh=@_; i_turbnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{scale}); }
230 $filters{radnoise} ={
231 callseq => ['image'],
232 defaults => { xo=>100,yo=>100,ascale=>17.0,rscale=>0.02 },
233 callsub => sub { my %hsh=@_; i_radnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{rscale},$hsh{ascale}); }
237 callseq => ['image', 'coef'],
239 callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}); }
244 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
245 defaults => { dist => 0 },
249 my @colors = @{$hsh{colors}};
252 i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist});
256 $filters{nearest_color} =
258 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
263 # make sure the segments are specified with colors
265 for my $color (@{$hsh{colors}}) {
266 my $new_color = _color($color)
267 or die $Imager::ERRSTR."\n";
268 push @colors, $new_color;
271 i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors,
273 or die Imager->_error_as_msg() . "\n";
276 $filters{gaussian} = {
277 callseq => [ 'image', 'stddev' ],
279 callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); },
283 callseq => [ qw(image size) ],
284 defaults => { size => 20 },
285 callsub => sub { my %hsh = @_; i_mosaic($hsh{image}, $hsh{size}) },
289 callseq => [ qw(image bump elevation lightx lighty st) ],
290 defaults => { elevation=>0, st=> 2 },
293 i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation},
294 $hsh{lightx}, $hsh{lighty}, $hsh{st});
297 $filters{bumpmap_complex} =
299 callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ],
310 Ia => Imager::Color->new(rgb=>[0,0,0]),
311 Il => Imager::Color->new(rgb=>[255,255,255]),
312 Is => Imager::Color->new(rgb=>[255,255,255]),
316 i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel},
317 $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz},
318 $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il},
322 $filters{postlevels} =
324 callseq => [ qw(image levels) ],
325 defaults => { levels => 10 },
326 callsub => sub { my %hsh = @_; i_postlevels($hsh{image}, $hsh{levels}); },
328 $filters{watermark} =
330 callseq => [ qw(image wmark tx ty pixdiff) ],
331 defaults => { pixdiff=>10, tx=>0, ty=>0 },
335 i_watermark($hsh{image}, $hsh{wmark}{IMG}, $hsh{tx}, $hsh{ty},
341 callseq => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ],
343 ftype => { linear => 0,
349 repeat => { none => 0,
364 multiply => 2, mult => 2,
367 subtract => 5, 'sub' => 5,
377 defaults => { ftype => 0, repeat => 0, combine => 0,
378 super_sample => 0, ssample_param => 4,
381 Imager::Color->new(0,0,0),
382 Imager::Color->new(255, 255, 255),
391 # make sure the segments are specified with colors
393 for my $segment (@{$hsh{segments}}) {
394 my @new_segment = @$segment;
396 $_ = _color($_) or die $Imager::ERRSTR."\n" for @new_segment[3,4];
397 push @segments, \@new_segment;
400 i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
401 $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
402 $hsh{ssample_param}, \@segments)
403 or die Imager->_error_as_msg() . "\n";
406 $filters{unsharpmask} =
408 callseq => [ qw(image stddev scale) ],
409 defaults => { stddev=>2.0, scale=>1.0 },
413 i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
417 $FORMATGUESS=\&def_guess_type;
427 # NOTE: this might be moved to an import override later on
431 # (look through @_ for special tags, process, and remove them);
433 # print Dumper($pack);
438 i_init_log($_[0],$_[1]);
439 i_log_entry("Imager $VERSION starting\n", 1);
444 my %parms=(loglevel=>1,@_);
446 init_log($parms{'log'},$parms{'loglevel'});
449 if (exists $parms{'warn_obsolete'}) {
450 $warn_obsolete = $parms{'warn_obsolete'};
453 # if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
454 # if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
458 if (exists $parms{'t1log'}) {
459 i_init_fonts($parms{'t1log'});
465 print "shutdown code\n";
466 # for(keys %instances) { $instances{$_}->DESTROY(); }
467 malloc_state(); # how do decide if this should be used? -- store something from the import
468 print "Imager exiting\n";
472 # Load a filter plugin
477 my ($DSO_handle,$str)=DSO_open($filename);
478 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
479 my %funcs=DSO_funclist($DSO_handle);
480 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
482 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
484 $DSOs{$filename}=[$DSO_handle,\%funcs];
487 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
488 $DEBUG && print "eval string:\n",$evstr,"\n";
500 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
501 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
502 for(keys %{$funcref}) {
504 $DEBUG && print "unloading: $_\n";
506 my $rc=DSO_close($DSO_handle);
507 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
511 # take the results of i_error() and make a message out of it
513 return join(": ", map $_->[0], i_errors());
516 # this function tries to DWIM for color parameters
517 # color objects are used as is
518 # simple scalars are simply treated as single parameters to Imager::Color->new
519 # hashrefs are treated as named argument lists to Imager::Color->new
520 # arrayrefs are treated as list arguments to Imager::Color->new iff any
522 # other arrayrefs are treated as list arguments to Imager::Color::Float
526 # perl 5.6.0 seems to do weird things to $arg if we don't make an
527 # explicitly stringified copy
528 # I vaguely remember a bug on this on p5p, but couldn't find it
529 # through bugs.perl.org (I had trouble getting it to find any bugs)
530 my $copy = $arg . "";
534 if (UNIVERSAL::isa($arg, "Imager::Color")
535 || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
539 if ($copy =~ /^HASH\(/) {
540 $result = Imager::Color->new(%$arg);
542 elsif ($copy =~ /^ARRAY\(/) {
543 $result = Imager::Color->new(@$arg);
546 $Imager::ERRSTR = "Not a color";
551 # assume Imager::Color::new knows how to handle it
552 $result = Imager::Color->new($arg);
561 $self->{IMG} and return 1;
563 $self->_set_error('empty input image');
569 # Methods to be called on objects.
572 # Create a new Imager object takes very few parameters.
573 # usually you call this method and then call open from
574 # the resulting object
581 $self->{IMG}=undef; # Just to indicate what exists
582 $self->{ERRSTR}=undef; #
583 $self->{DEBUG}=$DEBUG;
584 $self->{DEBUG} && print "Initialized Imager\n";
585 if (defined $hsh{xsize} && defined $hsh{ysize}) {
586 unless ($self->img_set(%hsh)) {
587 $Imager::ERRSTR = $self->{ERRSTR};
594 # Copy an entire image with no changes
595 # - if an image has magic the copy of it will not be magical
599 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
601 unless (defined wantarray) {
603 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
607 my $newcopy=Imager->new();
608 $newcopy->{IMG} = i_copy($self->{IMG});
617 unless ($self->{IMG}) {
618 $self->_set_error('empty input image');
621 my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_);
622 my $src = $input{img} || $input{src};
624 $self->_set_error("no source image");
627 $input{left}=0 if $input{left} <= 0;
628 $input{top}=0 if $input{top} <= 0;
630 my($r,$b)=i_img_info($src->{IMG});
631 my ($src_left, $src_top) = @input{qw/src_minx src_miny/};
632 my ($src_right, $src_bottom);
633 if ($input{src_coords}) {
634 ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}}
637 if (defined $input{src_maxx}) {
638 $src_right = $input{src_maxx};
640 elsif (defined $input{width}) {
641 if ($input{width} <= 0) {
642 $self->_set_error("paste: width must me positive");
645 $src_right = $src_left + $input{width};
650 if (defined $input{src_maxy}) {
651 $src_bottom = $input{src_maxy};
653 elsif (defined $input{height}) {
654 if ($input{height} < 0) {
655 $self->_set_error("paste: height must be positive");
658 $src_bottom = $src_top + $input{height};
665 $src_right > $r and $src_right = $r;
666 $src_bottom > $b and $src_bottom = $b;
668 if ($src_right <= $src_left
669 || $src_bottom < $src_top) {
670 $self->_set_error("nothing to paste");
674 i_copyto($self->{IMG}, $src->{IMG},
675 $src_left, $src_top, $src_right, $src_bottom,
676 $input{left}, $input{top});
678 return $self; # What should go here??
681 # Crop an image - i.e. return a new image that is smaller
685 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
687 unless (defined wantarray) {
689 warn "crop() called in void context - crop() returns the cropped image at $caller[1] line $caller[2]\n";
695 my ($w, $h, $l, $r, $b, $t) =
696 @hsh{qw(width height left right bottom top)};
698 # work through the various possibilities
703 elsif (!defined $r) {
704 $r = $self->getwidth;
716 $l = int(0.5+($self->getwidth()-$w)/2);
721 $r = $self->getwidth;
727 elsif (!defined $b) {
728 $b = $self->getheight;
740 $t=int(0.5+($self->getheight()-$h)/2);
745 $b = $self->getheight;
748 ($l,$r)=($r,$l) if $l>$r;
749 ($t,$b)=($b,$t) if $t>$b;
752 $r > $self->getwidth and $r = $self->getwidth;
754 $b > $self->getheight and $b = $self->getheight;
756 if ($l == $r || $t == $b) {
757 $self->_set_error("resulting image would have no content");
760 if( $r < $l or $b < $t ) {
761 $self->_set_error("attempting to crop outside of the image");
764 my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t);
766 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
771 my ($self, %opts) = @_;
773 $self->{IMG} or return $self->_set_error("Not a valid image");
775 my $x = $opts{xsize} || $self->getwidth;
776 my $y = $opts{ysize} || $self->getheight;
777 my $channels = $opts{channels} || $self->getchannels;
779 my $out = Imager->new;
780 if ($channels == $self->getchannels) {
781 $out->{IMG} = i_sametype($self->{IMG}, $x, $y);
784 $out->{IMG} = i_sametype_chans($self->{IMG}, $x, $y, $channels);
786 unless ($out->{IMG}) {
787 $self->{ERRSTR} = $self->_error_as_msg;
794 # Sets an image to a certain size and channel number
795 # if there was previously data in the image it is discarded
800 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
802 if (defined($self->{IMG})) {
803 # let IIM_DESTROY destroy it, it's possible this image is
804 # referenced from a virtual image (like masked)
805 #i_img_destroy($self->{IMG});
809 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
810 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
811 $hsh{maxcolors} || 256);
813 elsif ($hsh{bits} eq 'double') {
814 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
816 elsif ($hsh{bits} == 16) {
817 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
820 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
824 unless ($self->{IMG}) {
825 $self->{ERRSTR} = Imager->_error_as_msg();
832 # created a masked version of the current image
836 $self or return undef;
837 my %opts = (left => 0,
839 right => $self->getwidth,
840 bottom => $self->getheight,
842 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
844 my $result = Imager->new;
845 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
846 $opts{top}, $opts{right} - $opts{left},
847 $opts{bottom} - $opts{top});
848 # keep references to the mask and base images so they don't
850 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
855 # convert an RGB image into a paletted image
859 if (@_ != 1 && !ref $_[0]) {
866 unless (defined wantarray) {
868 warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n";
872 my $result = Imager->new;
873 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
875 #print "Type ", i_img_type($result->{IMG}), "\n";
877 if ($result->{IMG}) {
881 $self->{ERRSTR} = $self->_error_as_msg;
886 # convert a paletted (or any image) to an 8-bit/channel RGB images
891 unless (defined wantarray) {
893 warn "to_rgb8() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
898 $result = Imager->new;
899 $result->{IMG} = i_img_to_rgb($self->{IMG})
906 # convert a paletted (or any image) to an 8-bit/channel RGB images
911 unless (defined wantarray) {
913 warn "to_rgb16() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
918 $result = Imager->new;
919 $result->{IMG} = i_img_to_rgb16($self->{IMG})
928 my %opts = (colors=>[], @_);
930 unless ($self->{IMG}) {
931 $self->_set_error("empty input image");
935 my @colors = @{$opts{colors}}
938 for my $color (@colors) {
939 $color = _color($color);
941 $self->_set_error($Imager::ERRSTR);
946 return i_addcolors($self->{IMG}, @colors);
951 my %opts = (start=>0, colors=>[], @_);
953 unless ($self->{IMG}) {
954 $self->_set_error("empty input image");
958 my @colors = @{$opts{colors}}
961 for my $color (@colors) {
962 $color = _color($color);
964 $self->_set_error($Imager::ERRSTR);
969 return i_setcolors($self->{IMG}, $opts{start}, @colors);
975 if (!exists $opts{start} && !exists $opts{count}) {
978 $opts{count} = $self->colorcount;
980 elsif (!exists $opts{count}) {
983 elsif (!exists $opts{start}) {
988 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
992 i_colorcount($_[0]{IMG});
996 i_maxcolors($_[0]{IMG});
1002 $opts{color} or return undef;
1004 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
1009 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
1010 if ($bits && $bits == length(pack("d", 1)) * 8) {
1019 return i_img_type($self->{IMG}) ? "paletted" : "direct";
1025 $self->{IMG} and i_img_virtual($self->{IMG});
1029 my ($self, %opts) = @_;
1031 $self->{IMG} or return;
1033 if (defined $opts{name}) {
1037 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
1038 push @result, (i_tags_get($self->{IMG}, $found))[1];
1041 return wantarray ? @result : $result[0];
1043 elsif (defined $opts{code}) {
1047 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
1048 push @result, (i_tags_get($self->{IMG}, $found))[1];
1055 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
1058 return i_tags_count($self->{IMG});
1067 return -1 unless $self->{IMG};
1069 if (defined $opts{value}) {
1070 if ($opts{value} =~ /^\d+$/) {
1072 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
1075 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
1078 elsif (defined $opts{data}) {
1079 # force addition as a string
1080 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
1083 $self->{ERRSTR} = "No value supplied";
1087 elsif ($opts{code}) {
1088 if (defined $opts{value}) {
1089 if ($opts{value} =~ /^\d+$/) {
1091 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
1094 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
1097 elsif (defined $opts{data}) {
1098 # force addition as a string
1099 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
1102 $self->{ERRSTR} = "No value supplied";
1115 return 0 unless $self->{IMG};
1117 if (defined $opts{'index'}) {
1118 return i_tags_delete($self->{IMG}, $opts{'index'});
1120 elsif (defined $opts{name}) {
1121 return i_tags_delbyname($self->{IMG}, $opts{name});
1123 elsif (defined $opts{code}) {
1124 return i_tags_delbycode($self->{IMG}, $opts{code});
1127 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
1133 my ($self, %opts) = @_;
1136 $self->deltag(name=>$opts{name});
1137 return $self->addtag(name=>$opts{name}, value=>$opts{value});
1139 elsif (defined $opts{code}) {
1140 $self->deltag(code=>$opts{code});
1141 return $self->addtag(code=>$opts{code}, value=>$opts{value});
1149 sub _get_reader_io {
1150 my ($self, $input) = @_;
1153 return $input->{io}, undef;
1155 elsif ($input->{fd}) {
1156 return io_new_fd($input->{fd});
1158 elsif ($input->{fh}) {
1159 my $fd = fileno($input->{fh});
1161 $self->_set_error("Handle in fh option not opened");
1164 return io_new_fd($fd);
1166 elsif ($input->{file}) {
1167 my $file = IO::File->new($input->{file}, "r");
1169 $self->_set_error("Could not open $input->{file}: $!");
1173 return (io_new_fd(fileno($file)), $file);
1175 elsif ($input->{data}) {
1176 return io_new_buffer($input->{data});
1178 elsif ($input->{callback} || $input->{readcb}) {
1179 if (!$input->{seekcb}) {
1180 $self->_set_error("Need a seekcb parameter");
1182 if ($input->{maxbuffer}) {
1183 return io_new_cb($input->{writecb},
1184 $input->{callback} || $input->{readcb},
1185 $input->{seekcb}, $input->{closecb},
1186 $input->{maxbuffer});
1189 return io_new_cb($input->{writecb},
1190 $input->{callback} || $input->{readcb},
1191 $input->{seekcb}, $input->{closecb});
1195 $self->_set_error("file/fd/fh/data/callback parameter missing");
1200 sub _get_writer_io {
1201 my ($self, $input, $type) = @_;
1204 return $input->{io};
1206 elsif ($input->{fd}) {
1207 return io_new_fd($input->{fd});
1209 elsif ($input->{fh}) {
1210 my $fd = fileno($input->{fh});
1212 $self->_set_error("Handle in fh option not opened");
1216 my $oldfh = select($input->{fh});
1217 # flush anything that's buffered, and make sure anything else is flushed
1220 return io_new_fd($fd);
1222 elsif ($input->{file}) {
1223 my $fh = new IO::File($input->{file},"w+");
1225 $self->_set_error("Could not open file $input->{file}: $!");
1228 binmode($fh) or die;
1229 return (io_new_fd(fileno($fh)), $fh);
1231 elsif ($input->{data}) {
1232 return io_new_bufchain();
1234 elsif ($input->{callback} || $input->{writecb}) {
1235 if ($input->{maxbuffer}) {
1236 return io_new_cb($input->{callback} || $input->{writecb},
1238 $input->{seekcb}, $input->{closecb},
1239 $input->{maxbuffer});
1242 return io_new_cb($input->{callback} || $input->{writecb},
1244 $input->{seekcb}, $input->{closecb});
1248 $self->_set_error("file/fd/fh/data/callback parameter missing");
1253 # Read an image from file
1259 if (defined($self->{IMG})) {
1260 # let IIM_DESTROY do the destruction, since the image may be
1261 # referenced from elsewhere
1262 #i_img_destroy($self->{IMG});
1263 undef($self->{IMG});
1266 my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
1268 unless ($input{'type'}) {
1269 $input{'type'} = i_test_format_probe($IO, -1);
1272 unless ($input{'type'}) {
1273 $self->_set_error('type parameter missing and not possible to guess from extension');
1277 _reader_autoload($input{type});
1279 if ($readers{$input{type}} && $readers{$input{type}}{single}) {
1280 return $readers{$input{type}}{single}->($self, $IO, %input);
1283 unless ($formats{$input{'type'}}) {
1284 my $read_types = join ', ', sort Imager->read_types();
1285 $self->_set_error("format '$input{'type'}' not supported - formats $read_types available for reading");
1290 if ( $input{'type'} eq 'jpeg' ) {
1291 ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
1292 if ( !defined($self->{IMG}) ) {
1293 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1295 $self->{DEBUG} && print "loading a jpeg file\n";
1299 my $allow_incomplete = $input{allow_incomplete};
1300 defined $allow_incomplete or $allow_incomplete = 0;
1302 if ( $input{'type'} eq 'tiff' ) {
1303 my $page = $input{'page'};
1304 defined $page or $page = 0;
1305 $self->{IMG}=i_readtiff_wiol( $IO, $allow_incomplete, $page );
1306 if ( !defined($self->{IMG}) ) {
1307 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1309 $self->{DEBUG} && print "loading a tiff file\n";
1313 if ( $input{'type'} eq 'pnm' ) {
1314 $self->{IMG}=i_readpnm_wiol( $IO, $allow_incomplete );
1315 if ( !defined($self->{IMG}) ) {
1316 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg();
1319 $self->{DEBUG} && print "loading a pnm file\n";
1323 if ( $input{'type'} eq 'png' ) {
1324 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1325 if ( !defined($self->{IMG}) ) {
1326 $self->{ERRSTR} = $self->_error_as_msg();
1329 $self->{DEBUG} && print "loading a png file\n";
1332 if ( $input{'type'} eq 'bmp' ) {
1333 $self->{IMG}=i_readbmp_wiol( $IO, $allow_incomplete );
1334 if ( !defined($self->{IMG}) ) {
1335 $self->{ERRSTR}=$self->_error_as_msg();
1338 $self->{DEBUG} && print "loading a bmp file\n";
1341 if ( $input{'type'} eq 'gif' ) {
1342 if ($input{colors} && !ref($input{colors})) {
1343 # must be a reference to a scalar that accepts the colour map
1344 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1347 if ($input{'gif_consolidate'}) {
1348 if ($input{colors}) {
1350 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1352 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1356 $self->{IMG} =i_readgif_wiol( $IO );
1360 my $page = $input{'page'};
1361 defined $page or $page = 0;
1362 $self->{IMG} = i_readgif_single_wiol( $IO, $page );
1363 if ($self->{IMG} && $input{colors}) {
1364 ${ $input{colors} } =
1365 [ i_getcolors($self->{IMG}, 0, i_colorcount($self->{IMG})) ];
1369 if ( !defined($self->{IMG}) ) {
1370 $self->{ERRSTR}=$self->_error_as_msg();
1373 $self->{DEBUG} && print "loading a gif file\n";
1376 if ( $input{'type'} eq 'tga' ) {
1377 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1378 if ( !defined($self->{IMG}) ) {
1379 $self->{ERRSTR}=$self->_error_as_msg();
1382 $self->{DEBUG} && print "loading a tga file\n";
1385 if ( $input{'type'} eq 'raw' ) {
1386 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1388 if ( !($params{xsize} && $params{ysize}) ) {
1389 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1393 $self->{IMG} = i_readraw_wiol( $IO,
1396 $params{datachannels},
1397 $params{storechannels},
1398 $params{interleave});
1399 if ( !defined($self->{IMG}) ) {
1400 $self->{ERRSTR}=$self->_error_as_msg();
1403 $self->{DEBUG} && print "loading a raw file\n";
1409 sub register_reader {
1410 my ($class, %opts) = @_;
1413 or die "register_reader called with no type parameter\n";
1415 my $type = $opts{type};
1417 defined $opts{single} || defined $opts{multiple}
1418 or die "register_reader called with no single or multiple parameter\n";
1420 $readers{$type} = { };
1421 if ($opts{single}) {
1422 $readers{$type}{single} = $opts{single};
1424 if ($opts{multiple}) {
1425 $readers{$type}{multiple} = $opts{multiple};
1431 sub register_writer {
1432 my ($class, %opts) = @_;
1435 or die "register_writer called with no type parameter\n";
1437 my $type = $opts{type};
1439 defined $opts{single} || defined $opts{multiple}
1440 or die "register_writer called with no single or multiple parameter\n";
1442 $writers{$type} = { };
1443 if ($opts{single}) {
1444 $writers{$type}{single} = $opts{single};
1446 if ($opts{multiple}) {
1447 $writers{$type}{multiple} = $opts{multiple};
1458 grep($file_formats{$_}, keys %formats),
1459 qw(ico sgi), # formats not handled directly, but supplied with Imager
1470 grep($file_formats{$_}, keys %formats),
1471 qw(ico sgi), # formats not handled directly, but supplied with Imager
1477 # probes for an Imager::File::whatever module
1478 sub _reader_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 reader specific module
1494 my $file = "Imager/File/\U$type\EReader.pm";
1495 unless ($attempted_to_load{$file}) {
1497 ++$attempted_to_load{$file};
1505 # probes for an Imager::File::whatever module
1506 sub _writer_autoload {
1509 return if $formats{$type} || $readers{$type};
1511 return unless $type =~ /^\w+$/;
1513 my $file = "Imager/File/\U$type\E.pm";
1515 unless ($attempted_to_load{$file}) {
1517 ++$attempted_to_load{$file};
1521 # try to get a writer specific module
1522 my $file = "Imager/File/\U$type\EWriter.pm";
1523 unless ($attempted_to_load{$file}) {
1525 ++$attempted_to_load{$file};
1533 sub _fix_gif_positions {
1534 my ($opts, $opt, $msg, @imgs) = @_;
1536 my $positions = $opts->{'gif_positions'};
1538 for my $pos (@$positions) {
1539 my ($x, $y) = @$pos;
1540 my $img = $imgs[$index++];
1541 $img->settag(name=>'gif_left', value=>$x);
1542 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1544 $$msg .= "replaced with the gif_left and gif_top tags";
1549 gif_each_palette=>'gif_local_map',
1550 interlace => 'gif_interlace',
1551 gif_delays => 'gif_delay',
1552 gif_positions => \&_fix_gif_positions,
1553 gif_loop_count => 'gif_loop',
1557 my ($self, $opts, $prefix, @imgs) = @_;
1559 for my $opt (keys %$opts) {
1561 if ($obsolete_opts{$opt}) {
1562 my $new = $obsolete_opts{$opt};
1563 my $msg = "Obsolete option $opt ";
1565 $new->($opts, $opt, \$msg, @imgs);
1568 $msg .= "replaced with the $new tag ";
1571 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1572 warn $msg if $warn_obsolete && $^W;
1574 next unless $tagname =~ /^\Q$prefix/;
1575 my $value = $opts->{$opt};
1577 if (UNIVERSAL::isa($value, "Imager::Color")) {
1578 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1579 for my $img (@imgs) {
1580 $img->settag(name=>$tagname, value=>$tag);
1583 elsif (ref($value) eq 'ARRAY') {
1584 for my $i (0..$#$value) {
1585 my $val = $value->[$i];
1587 if (UNIVERSAL::isa($val, "Imager::Color")) {
1588 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1590 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1593 $self->_set_error("Unknown reference type " . ref($value) .
1594 " supplied in array for $opt");
1600 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1605 $self->_set_error("Unknown reference type " . ref($value) .
1606 " supplied for $opt");
1611 # set it as a tag for every image
1612 for my $img (@imgs) {
1613 $img->settag(name=>$tagname, value=>$value);
1621 # Write an image to file
1624 my %input=(jpegquality=>75,
1634 $self->_set_opts(\%input, "i_", $self)
1637 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1639 if (!$input{'type'} and $input{file}) {
1640 $input{'type'}=$FORMATGUESS->($input{file});
1642 if (!$input{'type'}) {
1643 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1647 _writer_autoload($input{type});
1650 if ($writers{$input{type}} && $writers{$input{type}}{single}) {
1651 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1654 $writers{$input{type}}{single}->($self, $IO, %input)
1658 if (!$formats{$input{'type'}}) {
1659 my $write_types = join ', ', sort Imager->write_types();
1660 $self->_set_error("format '$input{'type'}' not supported - formats $write_types available for writing");
1664 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1667 if ($input{'type'} eq 'tiff') {
1668 $self->_set_opts(\%input, "tiff_", $self)
1670 $self->_set_opts(\%input, "exif_", $self)
1673 if (defined $input{class} && $input{class} eq 'fax') {
1674 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1675 $self->{ERRSTR} = $self->_error_as_msg();
1679 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1680 $self->{ERRSTR} = $self->_error_as_msg();
1684 } elsif ( $input{'type'} eq 'pnm' ) {
1685 $self->_set_opts(\%input, "pnm_", $self)
1687 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1688 $self->{ERRSTR} = $self->_error_as_msg();
1691 $self->{DEBUG} && print "writing a pnm file\n";
1692 } elsif ( $input{'type'} eq 'raw' ) {
1693 $self->_set_opts(\%input, "raw_", $self)
1695 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1696 $self->{ERRSTR} = $self->_error_as_msg();
1699 $self->{DEBUG} && print "writing a raw file\n";
1700 } elsif ( $input{'type'} eq 'png' ) {
1701 $self->_set_opts(\%input, "png_", $self)
1703 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1704 $self->{ERRSTR}='unable to write png image';
1707 $self->{DEBUG} && print "writing a png file\n";
1708 } elsif ( $input{'type'} eq 'jpeg' ) {
1709 $self->_set_opts(\%input, "jpeg_", $self)
1711 $self->_set_opts(\%input, "exif_", $self)
1713 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1714 $self->{ERRSTR} = $self->_error_as_msg();
1717 $self->{DEBUG} && print "writing a jpeg file\n";
1718 } elsif ( $input{'type'} eq 'bmp' ) {
1719 $self->_set_opts(\%input, "bmp_", $self)
1721 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1722 $self->{ERRSTR} = $self->_error_as_msg;
1725 $self->{DEBUG} && print "writing a bmp file\n";
1726 } elsif ( $input{'type'} eq 'tga' ) {
1727 $self->_set_opts(\%input, "tga_", $self)
1730 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1731 $self->{ERRSTR}=$self->_error_as_msg();
1734 $self->{DEBUG} && print "writing a tga file\n";
1735 } elsif ( $input{'type'} eq 'gif' ) {
1736 $self->_set_opts(\%input, "gif_", $self)
1738 # compatibility with the old interfaces
1739 if ($input{gifquant} eq 'lm') {
1740 $input{make_colors} = 'addi';
1741 $input{translate} = 'perturb';
1742 $input{perturb} = $input{lmdither};
1743 } elsif ($input{gifquant} eq 'gen') {
1744 # just pass options through
1746 $input{make_colors} = 'webmap'; # ignored
1747 $input{translate} = 'giflib';
1749 if (!i_writegif_wiol($IO, \%input, $self->{IMG})) {
1750 $self->{ERRSTR} = $self->_error_as_msg;
1756 if (exists $input{'data'}) {
1757 my $data = io_slurp($IO);
1759 $self->{ERRSTR}='Could not slurp from buffer';
1762 ${$input{data}} = $data;
1768 my ($class, $opts, @images) = @_;
1770 my $type = $opts->{type};
1772 if (!$type && $opts->{'file'}) {
1773 $type = $FORMATGUESS->($opts->{'file'});
1776 $class->_set_error('type parameter missing and not possible to guess from extension');
1779 # translate to ImgRaw
1780 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1781 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1784 $class->_set_opts($opts, "i_", @images)
1786 my @work = map $_->{IMG}, @images;
1788 _writer_autoload($type);
1791 if ($writers{$type} && $writers{$type}{multiple}) {
1792 ($IO, $file) = $class->_get_writer_io($opts, $type)
1795 $writers{$type}{multiple}->($class, $IO, $opts, @images)
1799 if (!$formats{$type}) {
1800 my $write_types = join ', ', sort Imager->write_types();
1801 $class->_set_error("format '$type' not supported - formats $write_types available for writing");
1805 ($IO, $file) = $class->_get_writer_io($opts, $type)
1808 if ($type eq 'gif') {
1809 $class->_set_opts($opts, "gif_", @images)
1811 my $gif_delays = $opts->{gif_delays};
1812 local $opts->{gif_delays} = $gif_delays;
1813 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1814 # assume the caller wants the same delay for each frame
1815 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1817 unless (i_writegif_wiol($IO, $opts, @work)) {
1818 $class->_set_error($class->_error_as_msg());
1822 elsif ($type eq 'tiff') {
1823 $class->_set_opts($opts, "tiff_", @images)
1825 $class->_set_opts($opts, "exif_", @images)
1828 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1829 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1830 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1833 $res = i_writetiff_multi_wiol($IO, @work);
1836 $class->_set_error($class->_error_as_msg());
1842 unless ($images[0]->write(%$opts, io => $IO, type => $type)) {
1847 $ERRSTR = "Sorry, write_multi doesn't support $type yet";
1853 if (exists $opts->{'data'}) {
1854 my $data = io_slurp($IO);
1856 Imager->_set_error('Could not slurp from buffer');
1859 ${$opts->{data}} = $data;
1864 # read multiple images from a file
1866 my ($class, %opts) = @_;
1868 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1871 my $type = $opts{'type'};
1873 $type = i_test_format_probe($IO, -1);
1876 if ($opts{file} && !$type) {
1878 $type = $FORMATGUESS->($opts{file});
1882 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1886 _reader_autoload($type);
1888 if ($readers{$type} && $readers{$type}{multiple}) {
1889 return $readers{$type}{multiple}->($IO, %opts);
1892 if ($type eq 'gif') {
1894 @imgs = i_readgif_multi_wiol($IO);
1897 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1901 $ERRSTR = _error_as_msg();
1905 elsif ($type eq 'tiff') {
1906 my @imgs = i_readtiff_multi_wiol($IO, -1);
1909 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1913 $ERRSTR = _error_as_msg();
1918 my $img = Imager->new;
1919 if ($img->read(%opts, io => $IO, type => $type)) {
1922 Imager->_set_error($img->errstr);
1928 # Destroy an Imager object
1932 # delete $instances{$self};
1933 if (defined($self->{IMG})) {
1934 # the following is now handled by the XS DESTROY method for
1935 # Imager::ImgRaw object
1936 # Re-enabling this will break virtual images
1937 # tested for in t/t020masked.t
1938 # i_img_destroy($self->{IMG});
1939 undef($self->{IMG});
1941 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1945 # Perform an inplace filter of an image
1946 # that is the image will be overwritten with the data
1952 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1954 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1956 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1957 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1960 if ($filters{$input{'type'}}{names}) {
1961 my $names = $filters{$input{'type'}}{names};
1962 for my $name (keys %$names) {
1963 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1964 $input{$name} = $names->{$name}{$input{$name}};
1968 if (defined($filters{$input{'type'}}{defaults})) {
1969 %hsh=( image => $self->{IMG},
1971 %{$filters{$input{'type'}}{defaults}},
1974 %hsh=( image => $self->{IMG},
1979 my @cs=@{$filters{$input{'type'}}{callseq}};
1982 if (!defined($hsh{$_})) {
1983 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1988 local $SIG{__DIE__}; # we don't want this processed by confess, etc
1989 &{$filters{$input{'type'}}{callsub}}(%hsh);
1992 chomp($self->{ERRSTR} = $@);
1998 $self->{DEBUG} && print "callseq is: @cs\n";
1999 $self->{DEBUG} && print "matching callseq is: @b\n";
2004 sub register_filter {
2006 my %hsh = ( defaults => {}, @_ );
2009 or die "register_filter() with no type\n";
2010 defined $hsh{callsub}
2011 or die "register_filter() with no callsub\n";
2012 defined $hsh{callseq}
2013 or die "register_filter() with no callseq\n";
2015 exists $filters{$hsh{type}}
2018 $filters{$hsh{type}} = \%hsh;
2023 # Scale an image to requested size and return the scaled version
2027 my %opts=('type'=>'max',qtype=>'normal',@_);
2028 my $img = Imager->new();
2029 my $tmp = Imager->new();
2030 my ($x_scale, $y_scale);
2032 unless (defined wantarray) {
2033 my @caller = caller;
2034 warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
2038 unless ($self->{IMG}) {
2039 $self->_set_error('empty input image');
2043 if ($opts{'xscalefactor'} && $opts{'yscalefactor'}) {
2044 $x_scale = $opts{'xscalefactor'};
2045 $y_scale = $opts{'yscalefactor'};
2047 elsif ($opts{'xscalefactor'}) {
2048 $x_scale = $opts{'xscalefactor'};
2049 $y_scale = $opts{'scalefactor'} || $x_scale;
2051 elsif ($opts{'yscalefactor'}) {
2052 $y_scale = $opts{'yscalefactor'};
2053 $x_scale = $opts{'scalefactor'} || $y_scale;
2056 $x_scale = $y_scale = $opts{'scalefactor'} || 0.5;
2059 # work out the scaling
2060 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
2061 my ($xpix, $ypix)=( $opts{xpixels} / $self->getwidth() ,
2062 $opts{ypixels} / $self->getheight() );
2063 if ($opts{'type'} eq 'min') {
2064 $x_scale = $y_scale = _min($xpix,$ypix);
2066 elsif ($opts{'type'} eq 'max') {
2067 $x_scale = $y_scale = _max($xpix,$ypix);
2069 elsif ($opts{'type'} eq 'nonprop' || $opts{'type'} eq 'non-proportional') {
2074 $self->_set_error('invalid value for type parameter');
2077 } elsif ($opts{xpixels}) {
2078 $x_scale = $y_scale = $opts{xpixels} / $self->getwidth();
2080 elsif ($opts{ypixels}) {
2081 $x_scale = $y_scale = $opts{ypixels}/$self->getheight();
2083 elsif ($opts{constrain} && ref $opts{constrain}
2084 && $opts{constrain}->can('constrain')) {
2085 # we've been passed an Image::Math::Constrain object or something
2086 # that looks like one
2088 (undef, undef, $scalefactor)
2089 = $opts{constrain}->constrain($self->getwidth, $self->getheight);
2090 unless ($scalefactor) {
2091 $self->_set_error('constrain method failed on constrain parameter');
2094 $x_scale = $y_scale = $scalefactor;
2097 if ($opts{qtype} eq 'normal') {
2098 $tmp->{IMG} = i_scaleaxis($self->{IMG}, $x_scale, 0);
2099 if ( !defined($tmp->{IMG}) ) {
2100 $self->{ERRSTR} = 'unable to scale image';
2103 $img->{IMG}=i_scaleaxis($tmp->{IMG}, $y_scale, 1);
2104 if ( !defined($img->{IMG}) ) {
2105 $self->{ERRSTR}='unable to scale image';
2111 elsif ($opts{'qtype'} eq 'preview') {
2112 $img->{IMG} = i_scale_nn($self->{IMG}, $x_scale, $y_scale);
2113 if ( !defined($img->{IMG}) ) {
2114 $self->{ERRSTR}='unable to scale image';
2119 elsif ($opts{'qtype'} eq 'mixing') {
2120 my $new_width = int(0.5 + $self->getwidth * $x_scale);
2121 my $new_height = int(0.5 + $self->getheight * $y_scale);
2122 $new_width >= 1 or $new_width = 1;
2123 $new_height >= 1 or $new_height = 1;
2124 $img->{IMG} = i_scale_mixing($self->{IMG}, $new_width, $new_height);
2125 unless ($img->{IMG}) {
2126 $self->_set_error(Imager->_error_as_meg);
2132 $self->_set_error('invalid value for qtype parameter');
2137 # Scales only along the X axis
2141 my %opts = ( scalefactor=>0.5, @_ );
2143 unless (defined wantarray) {
2144 my @caller = caller;
2145 warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
2149 unless ($self->{IMG}) {
2150 $self->{ERRSTR} = 'empty input image';
2154 my $img = Imager->new();
2156 my $scalefactor = $opts{scalefactor};
2158 if ($opts{pixels}) {
2159 $scalefactor = $opts{pixels} / $self->getwidth();
2162 unless ($self->{IMG}) {
2163 $self->{ERRSTR}='empty input image';
2167 $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
2169 if ( !defined($img->{IMG}) ) {
2170 $self->{ERRSTR} = 'unable to scale image';
2177 # Scales only along the Y axis
2181 my %opts = ( scalefactor => 0.5, @_ );
2183 unless (defined wantarray) {
2184 my @caller = caller;
2185 warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
2189 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2191 my $img = Imager->new();
2193 my $scalefactor = $opts{scalefactor};
2195 if ($opts{pixels}) {
2196 $scalefactor = $opts{pixels} / $self->getheight();
2199 unless ($self->{IMG}) {
2200 $self->{ERRSTR} = 'empty input image';
2203 $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
2205 if ( !defined($img->{IMG}) ) {
2206 $self->{ERRSTR} = 'unable to scale image';
2213 # Transform returns a spatial transformation of the input image
2214 # this moves pixels to a new location in the returned image.
2215 # NOTE - should make a utility function to check transforms for
2220 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2222 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
2224 # print Dumper(\%opts);
2227 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
2229 eval ("use Affix::Infix2Postfix;");
2232 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
2235 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
2236 {op=>'-',trans=>'Sub'},
2237 {op=>'*',trans=>'Mult'},
2238 {op=>'/',trans=>'Div'},
2239 {op=>'-','type'=>'unary',trans=>'u-'},
2241 {op=>'func','type'=>'unary'}],
2242 'grouping'=>[qw( \( \) )],
2243 'func'=>[qw( sin cos )],
2248 @xt=$I2P->translate($opts{'xexpr'});
2249 @yt=$I2P->translate($opts{'yexpr'});
2251 $numre=$I2P->{'numre'};
2254 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
2255 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
2256 @{$opts{'parm'}}=@pt;
2259 # print Dumper(\%opts);
2261 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
2262 $self->{ERRSTR}='transform: no xopcodes given.';
2266 @op=@{$opts{'xopcodes'}};
2268 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2269 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2272 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2278 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
2279 $self->{ERRSTR}='transform: no yopcodes given.';
2283 @op=@{$opts{'yopcodes'}};
2285 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2286 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2289 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2294 if ( !exists $opts{'parm'}) {
2295 $self->{ERRSTR}='transform: no parameter arg given.';
2299 # print Dumper(\@ropx);
2300 # print Dumper(\@ropy);
2301 # print Dumper(\@ropy);
2303 my $img = Imager->new();
2304 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
2305 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
2311 my ($opts, @imgs) = @_;
2313 require "Imager/Expr.pm";
2315 $opts->{variables} = [ qw(x y) ];
2316 my ($width, $height) = @{$opts}{qw(width height)};
2318 $width ||= $imgs[0]->getwidth();
2319 $height ||= $imgs[0]->getheight();
2321 for my $img (@imgs) {
2322 $opts->{constants}{"w$img_num"} = $img->getwidth();
2323 $opts->{constants}{"h$img_num"} = $img->getheight();
2324 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
2325 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
2330 $opts->{constants}{w} = $width;
2331 $opts->{constants}{cx} = $width/2;
2334 $Imager::ERRSTR = "No width supplied";
2338 $opts->{constants}{h} = $height;
2339 $opts->{constants}{cy} = $height/2;
2342 $Imager::ERRSTR = "No height supplied";
2345 my $code = Imager::Expr->new($opts);
2347 $Imager::ERRSTR = Imager::Expr::error();
2350 my $channels = $opts->{channels} || 3;
2351 unless ($channels >= 1 && $channels <= 4) {
2352 return Imager->_set_error("channels must be an integer between 1 and 4");
2355 my $img = Imager->new();
2356 $img->{IMG} = i_transform2($opts->{width}, $opts->{height},
2357 $channels, $code->code(),
2358 $code->nregs(), $code->cregs(),
2359 [ map { $_->{IMG} } @imgs ]);
2360 if (!defined $img->{IMG}) {
2361 $Imager::ERRSTR = Imager->_error_as_msg();
2370 my %opts=(tx => 0,ty => 0, @_);
2372 unless ($self->{IMG}) {
2373 $self->{ERRSTR}='empty input image';
2376 unless ($opts{src} && $opts{src}->{IMG}) {
2377 $self->{ERRSTR}='empty input image for src';
2381 %opts = (src_minx => 0,
2383 src_maxx => $opts{src}->getwidth(),
2384 src_maxy => $opts{src}->getheight(),
2387 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
2388 $opts{src_minx}, $opts{src_miny},
2389 $opts{src_maxx}, $opts{src_maxy})) {
2390 $self->_set_error($self->_error_as_msg());
2400 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
2402 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
2403 $dir = $xlate{$opts{'dir'}};
2404 return $self if i_flipxy($self->{IMG}, $dir);
2412 unless (defined wantarray) {
2413 my @caller = caller;
2414 warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
2418 if (defined $opts{right}) {
2419 my $degrees = $opts{right};
2421 $degrees += 360 * int(((-$degrees)+360)/360);
2423 $degrees = $degrees % 360;
2424 if ($degrees == 0) {
2425 return $self->copy();
2427 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
2428 my $result = Imager->new();
2429 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
2433 $self->{ERRSTR} = $self->_error_as_msg();
2438 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
2442 elsif (defined $opts{radians} || defined $opts{degrees}) {
2443 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
2445 my $back = $opts{back};
2446 my $result = Imager->new;
2448 $back = _color($back);
2450 $self->_set_error(Imager->errstr);
2454 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
2457 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
2459 if ($result->{IMG}) {
2463 $self->{ERRSTR} = $self->_error_as_msg();
2468 $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available";
2473 sub matrix_transform {
2477 unless (defined wantarray) {
2478 my @caller = caller;
2479 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
2483 if ($opts{matrix}) {
2484 my $xsize = $opts{xsize} || $self->getwidth;
2485 my $ysize = $opts{ysize} || $self->getheight;
2487 my $result = Imager->new;
2489 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2490 $opts{matrix}, $opts{back})
2494 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2502 $self->{ERRSTR} = "matrix parameter required";
2508 *yatf = \&matrix_transform;
2510 # These two are supported for legacy code only
2513 return Imager::Color->new(@_);
2517 return Imager::Color::set(@_);
2520 # Draws a box between the specified corner points.
2523 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2524 my $dflcl=i_color_new(255,255,255,255);
2525 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
2527 if (exists $opts{'box'}) {
2528 $opts{'xmin'} = _min($opts{'box'}->[0],$opts{'box'}->[2]);
2529 $opts{'xmax'} = _max($opts{'box'}->[0],$opts{'box'}->[2]);
2530 $opts{'ymin'} = _min($opts{'box'}->[1],$opts{'box'}->[3]);
2531 $opts{'ymax'} = _max($opts{'box'}->[1],$opts{'box'}->[3]);
2534 if ($opts{filled}) {
2535 my $color = _color($opts{'color'});
2537 $self->{ERRSTR} = $Imager::ERRSTR;
2540 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2541 $opts{ymax}, $color);
2543 elsif ($opts{fill}) {
2544 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2545 # assume it's a hash ref
2546 require 'Imager/Fill.pm';
2547 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2548 $self->{ERRSTR} = $Imager::ERRSTR;
2552 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2553 $opts{ymax},$opts{fill}{fill});
2556 my $color = _color($opts{'color'});
2558 $self->{ERRSTR} = $Imager::ERRSTR;
2561 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
2569 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2570 my $dflcl=i_color_new(255,255,255,255);
2571 my %opts=(color=>$dflcl,
2572 'r'=>_min($self->getwidth(),$self->getheight())/3,
2573 'x'=>$self->getwidth()/2,
2574 'y'=>$self->getheight()/2,
2575 'd1'=>0, 'd2'=>361, @_);
2578 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2579 # assume it's a hash ref
2580 require 'Imager/Fill.pm';
2581 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2582 $self->{ERRSTR} = $Imager::ERRSTR;
2586 i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2587 $opts{'d2'}, $opts{fill}{fill});
2590 my $color = _color($opts{'color'});
2592 $self->{ERRSTR} = $Imager::ERRSTR;
2595 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
2596 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
2600 i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2601 $opts{'d1'}, $opts{'d2'}, $color);
2607 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2608 # assume it's a hash ref
2609 require 'Imager/Fill.pm';
2610 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2611 $self->{ERRSTR} = $Imager::ERRSTR;
2615 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2616 $opts{'d2'}, $opts{fill}{fill});
2619 my $color = _color($opts{'color'});
2621 $self->{ERRSTR} = $Imager::ERRSTR;
2624 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2625 $opts{'d1'}, $opts{'d2'}, $color);
2632 # Draws a line from one point to the other
2633 # the endpoint is set if the endp parameter is set which it is by default.
2634 # to turn of the endpoint being set use endp=>0 when calling line.
2638 my $dflcl=i_color_new(0,0,0,0);
2639 my %opts=(color=>$dflcl,
2642 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2644 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2645 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2647 my $color = _color($opts{'color'});
2649 $self->{ERRSTR} = $Imager::ERRSTR;
2653 $opts{antialias} = $opts{aa} if defined $opts{aa};
2654 if ($opts{antialias}) {
2655 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2656 $color, $opts{endp});
2658 i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2659 $color, $opts{endp});
2664 # Draws a line between an ordered set of points - It more or less just transforms this
2665 # into a list of lines.
2669 my ($pt,$ls,@points);
2670 my $dflcl=i_color_new(0,0,0,0);
2671 my %opts=(color=>$dflcl,@_);
2673 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2675 if (exists($opts{points})) { @points=@{$opts{points}}; }
2676 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2677 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2680 # print Dumper(\@points);
2682 my $color = _color($opts{'color'});
2684 $self->{ERRSTR} = $Imager::ERRSTR;
2687 $opts{antialias} = $opts{aa} if defined $opts{aa};
2688 if ($opts{antialias}) {
2691 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1);
2698 i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1);
2708 my ($pt,$ls,@points);
2709 my $dflcl = i_color_new(0,0,0,0);
2710 my %opts = (color=>$dflcl, @_);
2712 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2714 if (exists($opts{points})) {
2715 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2716 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2719 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2720 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2723 if ($opts{'fill'}) {
2724 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2725 # assume it's a hash ref
2726 require 'Imager/Fill.pm';
2727 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2728 $self->{ERRSTR} = $Imager::ERRSTR;
2732 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2733 $opts{'fill'}{'fill'});
2736 my $color = _color($opts{'color'});
2738 $self->{ERRSTR} = $Imager::ERRSTR;
2741 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2748 # this the multipoint bezier curve
2749 # this is here more for testing that actual usage since
2750 # this is not a good algorithm. Usually the curve would be
2751 # broken into smaller segments and each done individually.
2755 my ($pt,$ls,@points);
2756 my $dflcl=i_color_new(0,0,0,0);
2757 my %opts=(color=>$dflcl,@_);
2759 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2761 if (exists $opts{points}) {
2762 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2763 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2766 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2767 $self->{ERRSTR}='Missing or invalid points.';
2771 my $color = _color($opts{'color'});
2773 $self->{ERRSTR} = $Imager::ERRSTR;
2776 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2782 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2785 unless (exists $opts{'x'} && exists $opts{'y'}) {
2786 $self->{ERRSTR} = "missing seed x and y parameters";
2790 if ($opts{border}) {
2791 my $border = _color($opts{border});
2793 $self->_set_error($Imager::ERRSTR);
2797 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2798 # assume it's a hash ref
2799 require Imager::Fill;
2800 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2801 $self->{ERRSTR} = $Imager::ERRSTR;
2805 $rc = i_flood_cfill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2806 $opts{fill}{fill}, $border);
2809 my $color = _color($opts{'color'});
2811 $self->{ERRSTR} = $Imager::ERRSTR;
2814 $rc = i_flood_fill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2821 $self->{ERRSTR} = $self->_error_as_msg();
2827 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2828 # assume it's a hash ref
2829 require 'Imager/Fill.pm';
2830 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2831 $self->{ERRSTR} = $Imager::ERRSTR;
2835 $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2838 my $color = _color($opts{'color'});
2840 $self->{ERRSTR} = $Imager::ERRSTR;
2843 $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2849 $self->{ERRSTR} = $self->_error_as_msg();
2858 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2860 unless (exists $opts{'x'} && exists $opts{'y'}) {
2861 $self->{ERRSTR} = 'missing x and y parameters';
2867 my $color = _color($opts{color})
2869 if (ref $x && ref $y) {
2870 unless (@$x == @$y) {
2871 $self->{ERRSTR} = 'length of x and y mismatch';
2875 if ($color->isa('Imager::Color')) {
2876 for my $i (0..$#{$opts{'x'}}) {
2877 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color)
2882 for my $i (0..$#{$opts{'x'}}) {
2883 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color)
2891 if ($color->isa('Imager::Color')) {
2892 i_ppix($self->{IMG}, $x, $y, $color)
2896 i_ppixf($self->{IMG}, $x, $y, $color)
2907 my %opts = ( "type"=>'8bit', @_);
2909 unless (exists $opts{'x'} && exists $opts{'y'}) {
2910 $self->{ERRSTR} = 'missing x and y parameters';
2916 if (ref $x && ref $y) {
2917 unless (@$x == @$y) {
2918 $self->{ERRSTR} = 'length of x and y mismatch';
2922 if ($opts{"type"} eq '8bit') {
2923 for my $i (0..$#{$opts{'x'}}) {
2924 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2928 for my $i (0..$#{$opts{'x'}}) {
2929 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2932 return wantarray ? @result : \@result;
2935 if ($opts{"type"} eq '8bit') {
2936 return i_get_pixel($self->{IMG}, $x, $y);
2939 return i_gpixf($self->{IMG}, $x, $y);
2948 my %opts = ( type => '8bit', x=>0, @_);
2950 $self->_valid_image or return;
2952 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2954 unless (defined $opts{'y'}) {
2955 $self->_set_error("missing y parameter");
2959 if ($opts{type} eq '8bit') {
2960 return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2963 elsif ($opts{type} eq 'float') {
2964 return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2967 elsif ($opts{type} eq 'index') {
2968 unless (i_img_type($self->{IMG})) {
2969 $self->_set_error("type => index only valid on paletted images");
2972 return i_gpal($self->{IMG}, $opts{x}, $opts{x} + $opts{width},
2976 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2983 my %opts = ( x=>0, @_);
2985 $self->_valid_image or return;
2987 unless (defined $opts{'y'}) {
2988 $self->_set_error("missing y parameter");
2993 if (ref $opts{pixels} && @{$opts{pixels}}) {
2994 # try to guess the type
2995 if ($opts{pixels}[0]->isa('Imager::Color')) {
2996 $opts{type} = '8bit';
2998 elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
2999 $opts{type} = 'float';
3002 $self->_set_error("missing type parameter and could not guess from pixels");
3008 $opts{type} = '8bit';
3012 if ($opts{type} eq '8bit') {
3013 if (ref $opts{pixels}) {
3014 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3017 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3020 elsif ($opts{type} eq 'float') {
3021 if (ref $opts{pixels}) {
3022 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3025 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3028 elsif ($opts{type} eq 'index') {
3029 if (ref $opts{pixels}) {
3030 return i_ppal($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3033 return i_ppal_p($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3037 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3044 my %opts = ( type => '8bit', x=>0, @_);
3046 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
3048 unless (defined $opts{'y'}) {
3049 $self->_set_error("missing y parameter");
3053 unless ($opts{channels}) {
3054 $opts{channels} = [ 0 .. $self->getchannels()-1 ];
3057 if ($opts{type} eq '8bit') {
3058 return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3059 $opts{y}, @{$opts{channels}});
3061 elsif ($opts{type} eq 'float') {
3062 return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3063 $opts{y}, @{$opts{channels}});
3066 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3071 # make an identity matrix of the given size
3075 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
3076 for my $c (0 .. ($size-1)) {
3077 $matrix->[$c][$c] = 1;
3082 # general function to convert an image
3084 my ($self, %opts) = @_;
3087 unless (defined wantarray) {
3088 my @caller = caller;
3089 warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
3093 # the user can either specify a matrix or preset
3094 # the matrix overrides the preset
3095 if (!exists($opts{matrix})) {
3096 unless (exists($opts{preset})) {
3097 $self->{ERRSTR} = "convert() needs a matrix or preset";
3101 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
3102 # convert to greyscale, keeping the alpha channel if any
3103 if ($self->getchannels == 3) {
3104 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
3106 elsif ($self->getchannels == 4) {
3107 # preserve the alpha channel
3108 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
3113 $matrix = _identity($self->getchannels);
3116 elsif ($opts{preset} eq 'noalpha') {
3117 # strip the alpha channel
3118 if ($self->getchannels == 2 or $self->getchannels == 4) {
3119 $matrix = _identity($self->getchannels);
3120 pop(@$matrix); # lose the alpha entry
3123 $matrix = _identity($self->getchannels);
3126 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
3128 $matrix = [ [ 1 ] ];
3130 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
3131 $matrix = [ [ 0, 1 ] ];
3133 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
3134 $matrix = [ [ 0, 0, 1 ] ];
3136 elsif ($opts{preset} eq 'alpha') {
3137 if ($self->getchannels == 2 or $self->getchannels == 4) {
3138 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
3141 # the alpha is just 1 <shrug>
3142 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
3145 elsif ($opts{preset} eq 'rgb') {
3146 if ($self->getchannels == 1) {
3147 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
3149 elsif ($self->getchannels == 2) {
3150 # preserve the alpha channel
3151 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
3154 $matrix = _identity($self->getchannels);
3157 elsif ($opts{preset} eq 'addalpha') {
3158 if ($self->getchannels == 1) {
3159 $matrix = _identity(2);
3161 elsif ($self->getchannels == 3) {
3162 $matrix = _identity(4);
3165 $matrix = _identity($self->getchannels);
3169 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
3175 $matrix = $opts{matrix};
3178 my $new = Imager->new;
3179 $new->{IMG} = i_convert($self->{IMG}, $matrix);
3180 unless ($new->{IMG}) {
3181 # most likely a bad matrix
3182 $self->{ERRSTR} = _error_as_msg();
3189 # general function to map an image through lookup tables
3192 my ($self, %opts) = @_;
3193 my @chlist = qw( red green blue alpha );
3195 if (!exists($opts{'maps'})) {
3196 # make maps from channel maps
3198 for $chnum (0..$#chlist) {
3199 if (exists $opts{$chlist[$chnum]}) {
3200 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
3201 } elsif (exists $opts{'all'}) {
3202 $opts{'maps'}[$chnum] = $opts{'all'};
3206 if ($opts{'maps'} and $self->{IMG}) {
3207 i_map($self->{IMG}, $opts{'maps'} );
3213 my ($self, %opts) = @_;
3215 defined $opts{mindist} or $opts{mindist} = 0;
3217 defined $opts{other}
3218 or return $self->_set_error("No 'other' parameter supplied");
3219 defined $opts{other}{IMG}
3220 or return $self->_set_error("No image data in 'other' image");
3223 or return $self->_set_error("No image data");
3225 my $result = Imager->new;
3226 $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
3228 or return $self->_set_error($self->_error_as_msg());
3233 # destructive border - image is shrunk by one pixel all around
3236 my ($self,%opts)=@_;
3237 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
3238 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
3242 # Get the width of an image
3246 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3247 return (i_img_info($self->{IMG}))[0];
3250 # Get the height of an image
3254 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3255 return (i_img_info($self->{IMG}))[1];
3258 # Get number of channels in an image
3262 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3263 return i_img_getchannels($self->{IMG});
3270 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3271 return i_img_getmask($self->{IMG});
3279 if (!defined($self->{IMG})) {
3280 $self->{ERRSTR} = 'image is empty';
3283 unless (defined $opts{mask}) {
3284 $self->_set_error("mask parameter required");
3287 i_img_setmask( $self->{IMG} , $opts{mask} );
3292 # Get number of colors in an image
3296 my %opts=('maxcolors'=>2**30,@_);
3297 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
3298 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
3299 return ($rc==-1? undef : $rc);
3302 # Returns a reference to a hash. The keys are colour named (packed) and the
3303 # values are the number of pixels in this colour.
3304 sub getcolorusagehash {
3307 my %opts = ( maxcolors => 2**30, @_ );
3308 my $max_colors = $opts{maxcolors};
3309 unless (defined $max_colors && $max_colors > 0) {
3310 $self->_set_error('maxcolors must be a positive integer');
3314 unless (defined $self->{IMG}) {
3315 $self->_set_error('empty input image');
3319 my $channels= $self->getchannels;
3320 # We don't want to look at the alpha channel, because some gifs using it
3321 # doesn't define it for every colour (but only for some)
3322 $channels -= 1 if $channels == 2 or $channels == 4;
3324 my $height = $self->getheight;
3325 for my $y (0 .. $height - 1) {
3326 my $colors = $self->getsamples('y' => $y, channels => [ 0 .. $channels - 1 ]);
3327 while (length $colors) {
3328 $color_use{ substr($colors, 0, $channels, '') }++;
3330 keys %color_use > $max_colors
3336 # This will return a ordered array of the colour usage. Kind of the sorted
3337 # version of the values of the hash returned by getcolorusagehash.
3338 # You might want to add safety checks and change the names, etc...
3342 my %opts = ( maxcolors => 2**30, @_ );
3343 my $max_colors = $opts{maxcolors};
3344 unless (defined $max_colors && $max_colors > 0) {
3345 $self->_set_error('maxcolors must be a positive integer');
3349 unless (defined $self->{IMG}) {
3350 $self->_set_error('empty input image');
3354 return i_get_anonymous_color_histo($self->{IMG}, $max_colors);
3357 # draw string to an image
3361 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
3363 my %input=('x'=>0, 'y'=>0, @_);
3364 defined($input{string}) or $input{string} = $input{text};
3366 unless(defined $input{string}) {
3367 $self->{ERRSTR}="missing required parameter 'string'";
3371 unless($input{font}) {
3372 $self->{ERRSTR}="missing required parameter 'font'";
3376 unless ($input{font}->draw(image=>$self, %input)) {
3388 unless ($self->{IMG}) {
3389 $self->{ERRSTR}='empty input image';
3398 my %input=('x'=>0, 'y'=>0, @_);
3399 $input{string}||=$input{text};
3401 unless(exists $input{string}) {
3402 $self->_set_error("missing required parameter 'string'");
3406 unless($input{font}) {
3407 $self->_set_error("missing required parameter 'font'");
3412 unless (@result = $input{font}->align(image=>$img, %input)) {
3416 return wantarray ? @result : $result[0];
3419 my @file_limit_names = qw/width height bytes/;
3421 sub set_file_limits {
3428 @values{@file_limit_names} = (0) x @file_limit_names;
3431 @values{@file_limit_names} = i_get_image_file_limits();
3434 for my $key (keys %values) {
3435 defined $opts{$key} and $values{$key} = $opts{$key};
3438 i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
3441 sub get_file_limits {
3442 i_get_image_file_limits();
3445 # Shortcuts that can be exported
3447 sub newcolor { Imager::Color->new(@_); }
3448 sub newfont { Imager::Font->new(@_); }
3450 *NC=*newcolour=*newcolor;
3457 #### Utility routines
3460 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
3464 my ($self, $msg) = @_;
3467 $self->{ERRSTR} = $msg;
3475 # Default guess for the type of an image from extension
3477 sub def_guess_type {
3480 $ext=($name =~ m/\.([^\.]+)$/)[0];
3481 return 'tiff' if ($ext =~ m/^tiff?$/);
3482 return 'jpeg' if ($ext =~ m/^jpe?g$/);
3483 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
3484 return 'png' if ($ext eq "png");
3485 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
3486 return 'tga' if ($ext eq "tga");
3487 return 'sgi' if ($ext eq "rgb" || $ext eq "bw" || $ext eq "sgi" || $ext eq "rgba");
3488 return 'gif' if ($ext eq "gif");
3489 return 'raw' if ($ext eq "raw");
3490 return lc $ext; # best guess
3494 # get the minimum of a list
3498 for(@_) { if ($_<$mx) { $mx=$_; }}
3502 # get the maximum of a list
3506 for(@_) { if ($_>$mx) { $mx=$_; }}
3510 # string stuff for iptc headers
3514 $str = substr($str,3);
3515 $str =~ s/[\n\r]//g;
3522 # A little hack to parse iptc headers.
3527 my($caption,$photogr,$headln,$credit);
3529 my $str=$self->{IPTCRAW};
3534 @ar=split(/8BIM/,$str);
3539 @sar=split(/\034\002/);
3540 foreach $item (@sar) {
3541 if ($item =~ m/^x/) {
3542 $caption = _clean($item);
3545 if ($item =~ m/^P/) {
3546 $photogr = _clean($item);
3549 if ($item =~ m/^i/) {
3550 $headln = _clean($item);
3553 if ($item =~ m/^n/) {
3554 $credit = _clean($item);
3560 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
3567 or die "Only C language supported";
3569 require Imager::ExtUtils;
3570 return Imager::ExtUtils->inline_config;
3575 # Below is the stub of documentation for your module. You better edit it!
3579 Imager - Perl extension for Generating 24 bit Images
3589 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
3594 my $img = Imager->new();
3595 # see Imager::Files for information on the read() method
3596 $img->read(file=>$file) or die $img->errstr();
3598 $file =~ s/\.[^.]*$//;
3600 # Create smaller version
3601 # documented in Imager::Transformations
3602 my $thumb = $img->scale(scalefactor=>.3);
3604 # Autostretch individual channels
3605 $thumb->filter(type=>'autolevels');
3607 # try to save in one of these formats
3610 for $format ( qw( png gif jpg tiff ppm ) ) {
3611 # Check if given format is supported
3612 if ($Imager::formats{$format}) {
3613 $file.="_low.$format";
3614 print "Storing image as: $file\n";
3615 # documented in Imager::Files
3616 $thumb->write(file=>$file) or
3624 Imager is a module for creating and altering images. It can read and
3625 write various image formats, draw primitive shapes like lines,and
3626 polygons, blend multiple images together in various ways, scale, crop,
3627 render text and more.
3629 =head2 Overview of documentation
3635 Imager - This document - Synopsis, Example, Table of Contents and
3640 L<Imager::Tutorial> - a brief introduction to Imager.
3644 L<Imager::Cookbook> - how to do various things with Imager.
3648 L<Imager::ImageTypes> - Basics of constructing image objects with
3649 C<new()>: Direct type/virtual images, RGB(A)/paletted images,
3650 8/16/double bits/channel, color maps, channel masks, image tags, color
3651 quantization. Also discusses basic image information methods.
3655 L<Imager::Files> - IO interaction, reading/writing images, format
3660 L<Imager::Draw> - Drawing Primitives, lines, boxes, circles, arcs,
3665 L<Imager::Color> - Color specification.
3669 L<Imager::Fill> - Fill pattern specification.
3673 L<Imager::Font> - General font rendering, bounding boxes and font
3678 L<Imager::Transformations> - Copying, scaling, cropping, flipping,
3679 blending, pasting, convert and map.
3683 L<Imager::Engines> - Programmable transformations through
3684 C<transform()>, C<transform2()> and C<matrix_transform()>.
3688 L<Imager::Filters> - Filters, sharpen, blur, noise, convolve etc. and
3693 L<Imager::Expr> - Expressions for evaluation engine used by
3698 L<Imager::Matrix2d> - Helper class for affine transformations.
3702 L<Imager::Fountain> - Helper for making gradient profiles.
3706 L<Imager::API> - using Imager's C API
3710 L<Imager::APIRef> - API function reference
3714 L<Imager::Inline> - using Imager's C API from Inline::C
3718 L<Imager::ExtUtils> - tools to get access to Imager's C API.
3722 =head2 Basic Overview
3724 An Image object is created with C<$img = Imager-E<gt>new()>.
3727 $img=Imager->new(); # create empty image
3728 $img->read(file=>'lena.png',type=>'png') or # read image from file
3729 die $img->errstr(); # give an explanation
3730 # if something failed
3732 or if you want to create an empty image:
3734 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
3736 This example creates a completely black image of width 400 and height
3739 =head1 ERROR HANDLING
3741 In general a method will return false when it fails, if it does use the errstr() method to find out why:
3747 Returns the last error message in that context.
3749 If the last error you received was from calling an object method, such
3750 as read, call errstr() as an object method to find out why:
3752 my $image = Imager->new;
3753 $image->read(file => 'somefile.gif')
3754 or die $image->errstr;
3756 If it was a class method then call errstr() as a class method:
3758 my @imgs = Imager->read_multi(file => 'somefile.gif')
3759 or die Imager->errstr;
3761 Note that in some cases object methods are implemented in terms of
3762 class methods so a failing object method may set both.
3766 The C<Imager-E<gt>new> method is described in detail in
3767 L<Imager::ImageTypes>.
3771 Where to find information on methods for Imager class objects.
3773 addcolors() - L<Imager::ImageTypes/addcolors>
3775 addtag() - L<Imager::ImageTypes/addtag> - add image tags
3777 align_string() - L<Imager::Draw/align_string>
3779 arc() - L<Imager::Draw/arc>
3781 bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
3784 box() - L<Imager::Draw/box>
3786 circle() - L<Imager::Draw/circle>
3788 colorcount() - L<Imager::Draw/colorcount>
3790 convert() - L<Imager::Transformations/"Color transformations"> -
3791 transform the color space
3793 copy() - L<Imager::Transformations/copy>
3795 crop() - L<Imager::Transformations/crop> - extract part of an image
3797 def_guess_type() - L<Imager::Files/def_guess_type>
3799 deltag() - L<Imager::ImageTypes/deltag> - delete image tags
3801 difference() - L<Imager::Filters/"Image Difference">
3803 errstr() - L<"Basic Overview">
3805 filter() - L<Imager::Filters>
3807 findcolor() - L<Imager::ImageTypes/findcolor> - search the image palette, if it
3810 flip() - L<Imager::Transformations/flip>
3812 flood_fill() - L<Imager::Draw/flood_fill>
3814 getchannels() - L<Imager::ImageTypes/getchannels>
3816 getcolorcount() - L<Imager::ImageTypes/getcolorcount>
3818 getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
3819 palette, if it has one
3821 getcolorusage() - L<Imager::ImageTypes/getcolorusage>
3823 getcolorusagehash() - L<Imager::ImageTypes/getcolorusagehash>
3825 get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3827 getheight() - L<Imager::ImageTypes/getwidth>
3829 getmask() - L<Imager::ImageTypes/getmask>
3831 getpixel() - L<Imager::Draw/getpixel>
3833 getsamples() - L<Imager::Draw/getsamples>
3835 getscanline() - L<Imager::Draw/getscanline>
3837 getwidth() - L<Imager::ImageTypes/getwidth>
3839 img_set() - L<Imager::ImageTypes/img_set>
3841 init() - L<Imager::ImageTypes/init>
3843 line() - L<Imager::Draw/line>
3845 load_plugin() - L<Imager::Filters/load_plugin>
3847 map() - L<Imager::Transformations/"Color Mappings"> - remap color
3850 masked() - L<Imager::ImageTypes/masked> - make a masked image
3852 matrix_transform() - L<Imager::Engines/matrix_transform>
3854 maxcolors() - L<Imager::ImageTypes/maxcolors>
3856 NC() - L<Imager::Handy/NC>
3858 new() - L<Imager::ImageTypes/new>
3860 newcolor() - L<Imager::Handy/newcolor>
3862 newcolour() - L<Imager::Handy/newcolour>
3864 newfont() - L<Imager::Handy/newfont>
3866 NF() - L<Imager::Handy/NF>
3868 open() - L<Imager::Files> - an alias for read()
3870 parseiptc() - L<Imager::Files/parseiptc> - parse IPTC data from a JPEG
3873 paste() - L<Imager::Transformations/paste> - draw an image onto an image
3875 polygon() - L<Imager::Draw/polygon>
3877 polyline() - L<Imager::Draw/polyline>
3879 read() - L<Imager::Files> - read a single image from an image file
3881 read_multi() - L<Imager::Files> - read multiple images from an image
3884 read_types() - L<Imager::Files/read_types> - list image types Imager
3887 register_filter() - L<Imager::Filters/register_filter>
3889 register_reader() - L<Imager::Filters/register_reader>
3891 register_writer() - L<Imager::Filters/register_writer>
3893 rotate() - L<Imager::Transformations/rotate>
3895 rubthrough() - L<Imager::Transformations/rubthrough> - draw an image onto an
3896 image and use the alpha channel
3898 scale() - L<Imager::Transformations/scale>
3900 scaleX() - L<Imager::Transformations/scaleX>
3902 scaleY() - L<Imager::Transformations/scaleY>
3904 setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
3907 set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3909 setmask() - L<Imager::ImageTypes/setmask>
3911 setpixel() - L<Imager::Draw/setpixel>
3913 setscanline() - L<Imager::Draw/setscanline>
3915 settag() - L<Imager::ImageTypes/settag>
3917 string() - L<Imager::Draw/string> - draw text on an image
3919 tags() - L<Imager::ImageTypes/tags> - fetch image tags
3921 to_paletted() - L<Imager::ImageTypes/to_paletted>
3923 to_rgb16() - L<Imager::ImageTypes/to_rgb16>
3925 to_rgb8() - L<Imager::ImageTypes/to_rgb8>
3927 transform() - L<Imager::Engines/"transform">
3929 transform2() - L<Imager::Engines/"transform2">
3931 type() - L<Imager::ImageTypes/type> - type of image (direct vs paletted)
3933 unload_plugin() - L<Imager::Filters/unload_plugin>
3935 virtual() - L<Imager::ImageTypes/virtual> - whether the image has it's own
3938 write() - L<Imager::Files> - write an image to a file
3940 write_multi() - L<Imager::Files> - write multiple image to an image
3943 write_types() - L<Imager::Files/read_types> - list image types Imager
3946 =head1 CONCEPT INDEX
3948 animated GIF - L<Imager::Files/"Writing an animated GIF">
3950 aspect ratio - L<Imager::ImageTypes/i_xres>,
3951 L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
3953 blend - alpha blending one image onto another
3954 L<Imager::Transformations/rubthrough>
3956 blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
3958 boxes, drawing - L<Imager::Draw/box>
3960 changes between image - L<Imager::Filter/"Image Difference">
3962 color - L<Imager::Color>
3964 color names - L<Imager::Color>, L<Imager::Color::Table>
3966 combine modes - L<Imager::Fill/combine>
3968 compare images - L<Imager::Filter/"Image Difference">
3970 contrast - L<Imager::Filter/contrast>, L<Imager::Filter/autolevels>
3972 convolution - L<Imager::Filter/conv>
3974 cropping - L<Imager::Transformations/crop>
3976 CUR files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
3978 C<diff> images - L<Imager::Filter/"Image Difference">
3980 dpi - L<Imager::ImageTypes/i_xres>,
3981 L<Imager::Cookbook/"Image spatial resolution">
3983 drawing boxes - L<Imager::Draw/box>
3985 drawing lines - L<Imager::Draw/line>
3987 drawing text - L<Imager::Draw/string>, L<Imager::Draw/align_string>
3989 error message - L<"Basic Overview">
3991 files, font - L<Imager::Font>
3993 files, image - L<Imager::Files>
3995 filling, types of fill - L<Imager::Fill>
3997 filling, boxes - L<Imager::Draw/box>
3999 filling, flood fill - L<Imager::Draw/flood_fill>
4001 flood fill - L<Imager::Draw/flood_fill>
4003 fonts - L<Imager::Font>
4005 fonts, drawing with - L<Imager::Draw/string>,
4006 L<Imager::Draw/align_string>, L<Imager::Font::Wrap>
4008 fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
4010 fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
4012 fountain fill - L<Imager::Fill/"Fountain fills">,
4013 L<Imager::Filters/fountain>, L<Imager::Fountain>,
4014 L<Imager::Filters/gradgen>
4016 GIF files - L<Imager::Files/"GIF">
4018 GIF files, animated - L<Imager::File/"Writing an animated GIF">
4020 gradient fill - L<Imager::Fill/"Fountain fills">,
4021 L<Imager::Filters/fountain>, L<Imager::Fountain>,
4022 L<Imager::Filters/gradgen>
4024 grayscale, convert image to - L<Imager::Transformations/convert>
4026 guassian blur - L<Imager::Filter/guassian>
4028 hatch fills - L<Imager::Fill/"Hatched fills">
4030 ICO files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
4032 invert image - L<Imager::Filter/hardinvert>
4034 JPEG - L<Imager::Files/"JPEG">
4036 limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
4038 lines, drawing - L<Imager::Draw/line>
4040 matrix - L<Imager::Matrix2d>,
4041 L<Imager::Transformations/"Matrix Transformations">,
4042 L<Imager::Font/transform>
4044 metadata, image - L<Imager::ImageTypes/"Tags">
4046 mosaic - L<Imager::Filter/mosaic>
4048 noise, filter - L<Imager::Filter/noise>
4050 noise, rendered - L<Imager::Filter/turbnoise>,
4051 L<Imager::Filter/radnoise>
4053 paste - L<Imager::Transformations/paste>,
4054 L<Imager::Transformations/rubthrough>
4056 pseudo-color image - L<Imager::ImageTypes/to_paletted>,
4057 L<Imager::ImageTypes/new>
4059 posterize - L<Imager::Filter/postlevels>
4061 png files - L<Imager::Files>, L<Imager::Files/"PNG">
4063 pnm - L<Imager::Files/"PNM (Portable aNy Map)">
4065 rectangles, drawing - L<Imager::Draw/box>
4067 resizing an image - L<Imager::Transformations/scale>,
4068 L<Imager::Transformations/crop>
4070 RGB (SGI) files - L<Imager::Files/"SGI (RGB, BW)">
4072 saving an image - L<Imager::Files>
4074 scaling - L<Imager::Transformations/scale>
4076 SGI files - L<Imager::Files/"SGI (RGB, BW)">
4078 sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
4080 size, image - L<Imager::ImageTypes/getwidth>,
4081 L<Imager::ImageTypes/getheight>
4083 size, text - L<Imager::Font/bounding_box>
4085 tags, image metadata - L<Imager::ImageTypes/"Tags">
4087 text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
4088 L<Imager::Font::Wrap>
4090 text, wrapping text in an area - L<Imager::Font::Wrap>
4092 text, measuring - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
4094 tiles, color - L<Imager::Filter/mosaic>
4096 unsharp mask - L<Imager::Filter/unsharpmask>
4098 watermark - L<Imager::Filter/watermark>
4100 writing an image to a file - L<Imager::Files>
4104 The best place to get help with Imager is the mailing list.
4106 To subscribe send a message with C<subscribe> in the body to:
4108 imager-devel+request@molar.is
4114 L<http://www.molar.is/en/lists/imager-devel/>
4118 where you can also find the mailing list archive.
4120 You can report bugs by pointing your browser at:
4124 L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager>
4128 or by sending an email to:
4132 bug-Imager@rt.cpan.org
4136 Please remember to include the versions of Imager, perl, supporting
4137 libraries, and any relevant code. If you have specific images that
4138 cause the problems, please include those too.
4140 If you don't want to publish your email address on a mailing list you
4141 can use CPAN::Forum:
4143 http://www.cpanforum.com/dist/Imager
4145 You will need to register to post.
4147 =head1 CONTRIBUTING TO IMAGER
4153 If you like or dislike Imager, you can add a public review of Imager
4156 http://cpanratings.perl.org/dist/Imager
4158 This requires a Bitcard Account (http://www.bitcard.org).
4160 You can also send email to the maintainer below.
4162 If you send me a bug report via email, it will be copied to RT.
4166 I accept patches, preferably against the main branch in subversion.
4167 You should include an explanation of the reason for why the patch is
4170 Your patch should include regression tests where possible, otherwise
4171 it will be delayed until I get a chance to write them.
4175 Tony Cook <tony@imager.perl.org> is the current maintainer for Imager.
4177 Arnar M. Hrafnkelsson is the original author of Imager.
4179 Many others have contributed to Imager, please see the README for a
4184 L<perl>(1), L<Imager::ImageTypes>(3), L<Imager::Files>(3),
4185 L<Imager::Draw>(3), L<Imager::Color>(3), L<Imager::Fill>(3),
4186 L<Imager::Font>(3), L<Imager::Transformations>(3),
4187 L<Imager::Engines>(3), L<Imager::Filters>(3), L<Imager::Expr>(3),
4188 L<Imager::Matrix2d>(3), L<Imager::Fountain>(3)
4190 L<http://imager.perl.org/>
4192 L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
4194 Other perl imaging modules include:
4196 L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).