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
148 # registered file readers
151 # registered file writers
154 # modules we attempted to autoload
155 my %attempted_to_load;
157 # library keys that are image file formats
158 my %file_formats = map { $_ => 1 } qw/tiff pnm gif png jpeg raw bmp tga/;
166 XSLoader::load(Imager => $VERSION);
170 push @ISA, 'DynaLoader';
171 bootstrap Imager $VERSION;
176 i_init_fonts(); # Initialize font engines
177 Imager::Font::__init();
178 for(i_list_formats()) { $formats{$_}++; }
180 if ($formats{'t1'}) {
184 if (!$formats{'t1'} and !$formats{'tt'}
185 && !$formats{'ft2'} && !$formats{'w32'}) {
186 $fontstate='no font support';
189 %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]);
193 # the members of the subhashes under %filters are:
194 # callseq - a list of the parameters to the underlying filter in the
195 # order they are passed
196 # callsub - a code ref that takes a named parameter list and calls the
198 # defaults - a hash of default values
199 # names - defines names for value of given parameters so if the names
200 # field is foo=> { bar=>1 }, and the user supplies "bar" as the
201 # foo parameter, the filter will receive 1 for the foo
204 callseq => ['image','intensity'],
205 callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); }
209 callseq => ['image', 'amount', 'subtype'],
210 defaults => { amount=>3,subtype=>0 },
211 callsub => sub { my %hsh=@_; i_noise($hsh{image},$hsh{amount},$hsh{subtype}); }
214 $filters{hardinvert} ={
215 callseq => ['image'],
217 callsub => sub { my %hsh=@_; i_hardinvert($hsh{image}); }
220 $filters{autolevels} ={
221 callseq => ['image','lsat','usat','skew'],
222 defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 },
223 callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); }
226 $filters{turbnoise} ={
227 callseq => ['image'],
228 defaults => { xo=>0.0,yo=>0.0,scale=>10.0 },
229 callsub => sub { my %hsh=@_; i_turbnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{scale}); }
232 $filters{radnoise} ={
233 callseq => ['image'],
234 defaults => { xo=>100,yo=>100,ascale=>17.0,rscale=>0.02 },
235 callsub => sub { my %hsh=@_; i_radnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{rscale},$hsh{ascale}); }
239 callseq => ['image', 'coef'],
241 callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}); }
246 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
247 defaults => { dist => 0 },
251 my @colors = @{$hsh{colors}};
254 i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist});
258 $filters{nearest_color} =
260 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
265 # make sure the segments are specified with colors
267 for my $color (@{$hsh{colors}}) {
268 my $new_color = _color($color)
269 or die $Imager::ERRSTR."\n";
270 push @colors, $new_color;
273 i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors,
275 or die Imager->_error_as_msg() . "\n";
278 $filters{gaussian} = {
279 callseq => [ 'image', 'stddev' ],
281 callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); },
285 callseq => [ qw(image size) ],
286 defaults => { size => 20 },
287 callsub => sub { my %hsh = @_; i_mosaic($hsh{image}, $hsh{size}) },
291 callseq => [ qw(image bump elevation lightx lighty st) ],
292 defaults => { elevation=>0, st=> 2 },
295 i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation},
296 $hsh{lightx}, $hsh{lighty}, $hsh{st});
299 $filters{bumpmap_complex} =
301 callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ],
312 Ia => Imager::Color->new(rgb=>[0,0,0]),
313 Il => Imager::Color->new(rgb=>[255,255,255]),
314 Is => Imager::Color->new(rgb=>[255,255,255]),
318 i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel},
319 $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz},
320 $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il},
324 $filters{postlevels} =
326 callseq => [ qw(image levels) ],
327 defaults => { levels => 10 },
328 callsub => sub { my %hsh = @_; i_postlevels($hsh{image}, $hsh{levels}); },
330 $filters{watermark} =
332 callseq => [ qw(image wmark tx ty pixdiff) ],
333 defaults => { pixdiff=>10, tx=>0, ty=>0 },
337 i_watermark($hsh{image}, $hsh{wmark}{IMG}, $hsh{tx}, $hsh{ty},
343 callseq => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ],
345 ftype => { linear => 0,
351 repeat => { none => 0,
366 multiply => 2, mult => 2,
369 subtract => 5, 'sub' => 5,
379 defaults => { ftype => 0, repeat => 0, combine => 0,
380 super_sample => 0, ssample_param => 4,
383 Imager::Color->new(0,0,0),
384 Imager::Color->new(255, 255, 255),
393 # make sure the segments are specified with colors
395 for my $segment (@{$hsh{segments}}) {
396 my @new_segment = @$segment;
398 $_ = _color($_) or die $Imager::ERRSTR."\n" for @new_segment[3,4];
399 push @segments, \@new_segment;
402 i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
403 $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
404 $hsh{ssample_param}, \@segments)
405 or die Imager->_error_as_msg() . "\n";
408 $filters{unsharpmask} =
410 callseq => [ qw(image stddev scale) ],
411 defaults => { stddev=>2.0, scale=>1.0 },
415 i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
419 $FORMATGUESS=\&def_guess_type;
429 # NOTE: this might be moved to an import override later on
434 if ($_[$i] eq '-log-stderr') {
442 goto &Exporter::import;
446 i_init_log($_[0],$_[1]);
447 i_log_entry("Imager $VERSION starting\n", 1);
452 my %parms=(loglevel=>1,@_);
454 init_log($parms{'log'},$parms{'loglevel'});
457 if (exists $parms{'warn_obsolete'}) {
458 $warn_obsolete = $parms{'warn_obsolete'};
461 # if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
462 # if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
466 if (exists $parms{'t1log'}) {
467 i_init_fonts($parms{'t1log'});
473 print "shutdown code\n";
474 # for(keys %instances) { $instances{$_}->DESTROY(); }
475 malloc_state(); # how do decide if this should be used? -- store something from the import
476 print "Imager exiting\n";
480 # Load a filter plugin
485 my ($DSO_handle,$str)=DSO_open($filename);
486 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
487 my %funcs=DSO_funclist($DSO_handle);
488 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
490 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
492 $DSOs{$filename}=[$DSO_handle,\%funcs];
495 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
496 $DEBUG && print "eval string:\n",$evstr,"\n";
508 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
509 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
510 for(keys %{$funcref}) {
512 $DEBUG && print "unloading: $_\n";
514 my $rc=DSO_close($DSO_handle);
515 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
519 # take the results of i_error() and make a message out of it
521 return join(": ", map $_->[0], i_errors());
524 # this function tries to DWIM for color parameters
525 # color objects are used as is
526 # simple scalars are simply treated as single parameters to Imager::Color->new
527 # hashrefs are treated as named argument lists to Imager::Color->new
528 # arrayrefs are treated as list arguments to Imager::Color->new iff any
530 # other arrayrefs are treated as list arguments to Imager::Color::Float
534 # perl 5.6.0 seems to do weird things to $arg if we don't make an
535 # explicitly stringified copy
536 # I vaguely remember a bug on this on p5p, but couldn't find it
537 # through bugs.perl.org (I had trouble getting it to find any bugs)
538 my $copy = $arg . "";
542 if (UNIVERSAL::isa($arg, "Imager::Color")
543 || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
547 if ($copy =~ /^HASH\(/) {
548 $result = Imager::Color->new(%$arg);
550 elsif ($copy =~ /^ARRAY\(/) {
551 $result = Imager::Color->new(@$arg);
554 $Imager::ERRSTR = "Not a color";
559 # assume Imager::Color::new knows how to handle it
560 $result = Imager::Color->new($arg);
569 $self->{IMG} and return 1;
571 $self->_set_error('empty input image');
577 # Methods to be called on objects.
580 # Create a new Imager object takes very few parameters.
581 # usually you call this method and then call open from
582 # the resulting object
589 $self->{IMG}=undef; # Just to indicate what exists
590 $self->{ERRSTR}=undef; #
591 $self->{DEBUG}=$DEBUG;
592 $self->{DEBUG} && print "Initialized Imager\n";
593 if (defined $hsh{xsize} && defined $hsh{ysize}) {
594 unless ($self->img_set(%hsh)) {
595 $Imager::ERRSTR = $self->{ERRSTR};
602 # Copy an entire image with no changes
603 # - if an image has magic the copy of it will not be magical
607 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
609 unless (defined wantarray) {
611 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
615 my $newcopy=Imager->new();
616 $newcopy->{IMG} = i_copy($self->{IMG});
625 unless ($self->{IMG}) {
626 $self->_set_error('empty input image');
629 my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_);
630 my $src = $input{img} || $input{src};
632 $self->_set_error("no source image");
635 $input{left}=0 if $input{left} <= 0;
636 $input{top}=0 if $input{top} <= 0;
638 my($r,$b)=i_img_info($src->{IMG});
639 my ($src_left, $src_top) = @input{qw/src_minx src_miny/};
640 my ($src_right, $src_bottom);
641 if ($input{src_coords}) {
642 ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}}
645 if (defined $input{src_maxx}) {
646 $src_right = $input{src_maxx};
648 elsif (defined $input{width}) {
649 if ($input{width} <= 0) {
650 $self->_set_error("paste: width must me positive");
653 $src_right = $src_left + $input{width};
658 if (defined $input{src_maxy}) {
659 $src_bottom = $input{src_maxy};
661 elsif (defined $input{height}) {
662 if ($input{height} < 0) {
663 $self->_set_error("paste: height must be positive");
666 $src_bottom = $src_top + $input{height};
673 $src_right > $r and $src_right = $r;
674 $src_bottom > $b and $src_bottom = $b;
676 if ($src_right <= $src_left
677 || $src_bottom < $src_top) {
678 $self->_set_error("nothing to paste");
682 i_copyto($self->{IMG}, $src->{IMG},
683 $src_left, $src_top, $src_right, $src_bottom,
684 $input{left}, $input{top});
686 return $self; # What should go here??
689 # Crop an image - i.e. return a new image that is smaller
693 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
695 unless (defined wantarray) {
697 warn "crop() called in void context - crop() returns the cropped image at $caller[1] line $caller[2]\n";
703 my ($w, $h, $l, $r, $b, $t) =
704 @hsh{qw(width height left right bottom top)};
706 # work through the various possibilities
711 elsif (!defined $r) {
712 $r = $self->getwidth;
724 $l = int(0.5+($self->getwidth()-$w)/2);
729 $r = $self->getwidth;
735 elsif (!defined $b) {
736 $b = $self->getheight;
748 $t=int(0.5+($self->getheight()-$h)/2);
753 $b = $self->getheight;
756 ($l,$r)=($r,$l) if $l>$r;
757 ($t,$b)=($b,$t) if $t>$b;
760 $r > $self->getwidth and $r = $self->getwidth;
762 $b > $self->getheight and $b = $self->getheight;
764 if ($l == $r || $t == $b) {
765 $self->_set_error("resulting image would have no content");
768 if( $r < $l or $b < $t ) {
769 $self->_set_error("attempting to crop outside of the image");
772 my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t);
774 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
779 my ($self, %opts) = @_;
781 $self->{IMG} or return $self->_set_error("Not a valid image");
783 my $x = $opts{xsize} || $self->getwidth;
784 my $y = $opts{ysize} || $self->getheight;
785 my $channels = $opts{channels} || $self->getchannels;
787 my $out = Imager->new;
788 if ($channels == $self->getchannels) {
789 $out->{IMG} = i_sametype($self->{IMG}, $x, $y);
792 $out->{IMG} = i_sametype_chans($self->{IMG}, $x, $y, $channels);
794 unless ($out->{IMG}) {
795 $self->{ERRSTR} = $self->_error_as_msg;
802 # Sets an image to a certain size and channel number
803 # if there was previously data in the image it is discarded
808 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
810 if (defined($self->{IMG})) {
811 # let IIM_DESTROY destroy it, it's possible this image is
812 # referenced from a virtual image (like masked)
813 #i_img_destroy($self->{IMG});
817 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
818 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
819 $hsh{maxcolors} || 256);
821 elsif ($hsh{bits} eq 'double') {
822 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
824 elsif ($hsh{bits} == 16) {
825 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
828 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
832 unless ($self->{IMG}) {
833 $self->{ERRSTR} = Imager->_error_as_msg();
840 # created a masked version of the current image
844 $self or return undef;
845 my %opts = (left => 0,
847 right => $self->getwidth,
848 bottom => $self->getheight,
850 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
852 my $result = Imager->new;
853 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
854 $opts{top}, $opts{right} - $opts{left},
855 $opts{bottom} - $opts{top});
856 # keep references to the mask and base images so they don't
858 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
863 # convert an RGB image into a paletted image
867 if (@_ != 1 && !ref $_[0]) {
874 unless (defined wantarray) {
876 warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n";
880 my $result = Imager->new;
881 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
883 #print "Type ", i_img_type($result->{IMG}), "\n";
885 if ($result->{IMG}) {
889 $self->{ERRSTR} = $self->_error_as_msg;
894 # convert a paletted (or any image) to an 8-bit/channel RGB images
899 unless (defined wantarray) {
901 warn "to_rgb8() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
906 $result = Imager->new;
907 $result->{IMG} = i_img_to_rgb($self->{IMG})
914 # convert a paletted (or any image) to an 8-bit/channel RGB images
919 unless (defined wantarray) {
921 warn "to_rgb16() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
926 $result = Imager->new;
927 $result->{IMG} = i_img_to_rgb16($self->{IMG})
936 my %opts = (colors=>[], @_);
938 unless ($self->{IMG}) {
939 $self->_set_error("empty input image");
943 my @colors = @{$opts{colors}}
946 for my $color (@colors) {
947 $color = _color($color);
949 $self->_set_error($Imager::ERRSTR);
954 return i_addcolors($self->{IMG}, @colors);
959 my %opts = (start=>0, colors=>[], @_);
961 unless ($self->{IMG}) {
962 $self->_set_error("empty input image");
966 my @colors = @{$opts{colors}}
969 for my $color (@colors) {
970 $color = _color($color);
972 $self->_set_error($Imager::ERRSTR);
977 return i_setcolors($self->{IMG}, $opts{start}, @colors);
983 if (!exists $opts{start} && !exists $opts{count}) {
986 $opts{count} = $self->colorcount;
988 elsif (!exists $opts{count}) {
991 elsif (!exists $opts{start}) {
996 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
1000 i_colorcount($_[0]{IMG});
1004 i_maxcolors($_[0]{IMG});
1010 $opts{color} or return undef;
1012 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
1017 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
1018 if ($bits && $bits == length(pack("d", 1)) * 8) {
1027 return i_img_type($self->{IMG}) ? "paletted" : "direct";
1033 $self->{IMG} and i_img_virtual($self->{IMG});
1039 $self->{IMG} or return;
1041 return i_img_is_monochrome($self->{IMG});
1045 my ($self, %opts) = @_;
1047 $self->{IMG} or return;
1049 if (defined $opts{name}) {
1053 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
1054 push @result, (i_tags_get($self->{IMG}, $found))[1];
1057 return wantarray ? @result : $result[0];
1059 elsif (defined $opts{code}) {
1063 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
1064 push @result, (i_tags_get($self->{IMG}, $found))[1];
1071 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
1074 return i_tags_count($self->{IMG});
1083 return -1 unless $self->{IMG};
1085 if (defined $opts{value}) {
1086 if ($opts{value} =~ /^\d+$/) {
1088 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
1091 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
1094 elsif (defined $opts{data}) {
1095 # force addition as a string
1096 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
1099 $self->{ERRSTR} = "No value supplied";
1103 elsif ($opts{code}) {
1104 if (defined $opts{value}) {
1105 if ($opts{value} =~ /^\d+$/) {
1107 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
1110 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
1113 elsif (defined $opts{data}) {
1114 # force addition as a string
1115 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
1118 $self->{ERRSTR} = "No value supplied";
1131 return 0 unless $self->{IMG};
1133 if (defined $opts{'index'}) {
1134 return i_tags_delete($self->{IMG}, $opts{'index'});
1136 elsif (defined $opts{name}) {
1137 return i_tags_delbyname($self->{IMG}, $opts{name});
1139 elsif (defined $opts{code}) {
1140 return i_tags_delbycode($self->{IMG}, $opts{code});
1143 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
1149 my ($self, %opts) = @_;
1152 $self->deltag(name=>$opts{name});
1153 return $self->addtag(name=>$opts{name}, value=>$opts{value});
1155 elsif (defined $opts{code}) {
1156 $self->deltag(code=>$opts{code});
1157 return $self->addtag(code=>$opts{code}, value=>$opts{value});
1165 sub _get_reader_io {
1166 my ($self, $input) = @_;
1169 return $input->{io}, undef;
1171 elsif ($input->{fd}) {
1172 return io_new_fd($input->{fd});
1174 elsif ($input->{fh}) {
1175 my $fd = fileno($input->{fh});
1177 $self->_set_error("Handle in fh option not opened");
1180 return io_new_fd($fd);
1182 elsif ($input->{file}) {
1183 my $file = IO::File->new($input->{file}, "r");
1185 $self->_set_error("Could not open $input->{file}: $!");
1189 return (io_new_fd(fileno($file)), $file);
1191 elsif ($input->{data}) {
1192 return io_new_buffer($input->{data});
1194 elsif ($input->{callback} || $input->{readcb}) {
1195 if (!$input->{seekcb}) {
1196 $self->_set_error("Need a seekcb parameter");
1198 if ($input->{maxbuffer}) {
1199 return io_new_cb($input->{writecb},
1200 $input->{callback} || $input->{readcb},
1201 $input->{seekcb}, $input->{closecb},
1202 $input->{maxbuffer});
1205 return io_new_cb($input->{writecb},
1206 $input->{callback} || $input->{readcb},
1207 $input->{seekcb}, $input->{closecb});
1211 $self->_set_error("file/fd/fh/data/callback parameter missing");
1216 sub _get_writer_io {
1217 my ($self, $input, $type) = @_;
1220 return $input->{io};
1222 elsif ($input->{fd}) {
1223 return io_new_fd($input->{fd});
1225 elsif ($input->{fh}) {
1226 my $fd = fileno($input->{fh});
1228 $self->_set_error("Handle in fh option not opened");
1232 my $oldfh = select($input->{fh});
1233 # flush anything that's buffered, and make sure anything else is flushed
1236 return io_new_fd($fd);
1238 elsif ($input->{file}) {
1239 my $fh = new IO::File($input->{file},"w+");
1241 $self->_set_error("Could not open file $input->{file}: $!");
1244 binmode($fh) or die;
1245 return (io_new_fd(fileno($fh)), $fh);
1247 elsif ($input->{data}) {
1248 return io_new_bufchain();
1250 elsif ($input->{callback} || $input->{writecb}) {
1251 if ($input->{maxbuffer}) {
1252 return io_new_cb($input->{callback} || $input->{writecb},
1254 $input->{seekcb}, $input->{closecb},
1255 $input->{maxbuffer});
1258 return io_new_cb($input->{callback} || $input->{writecb},
1260 $input->{seekcb}, $input->{closecb});
1264 $self->_set_error("file/fd/fh/data/callback parameter missing");
1269 # Read an image from file
1275 if (defined($self->{IMG})) {
1276 # let IIM_DESTROY do the destruction, since the image may be
1277 # referenced from elsewhere
1278 #i_img_destroy($self->{IMG});
1279 undef($self->{IMG});
1282 my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
1284 unless ($input{'type'}) {
1285 $input{'type'} = i_test_format_probe($IO, -1);
1288 unless ($input{'type'}) {
1289 $self->_set_error('type parameter missing and not possible to guess from extension');
1293 _reader_autoload($input{type});
1295 if ($readers{$input{type}} && $readers{$input{type}}{single}) {
1296 return $readers{$input{type}}{single}->($self, $IO, %input);
1299 unless ($formats{$input{'type'}}) {
1300 my $read_types = join ', ', sort Imager->read_types();
1301 $self->_set_error("format '$input{'type'}' not supported - formats $read_types available for reading");
1306 if ( $input{'type'} eq 'jpeg' ) {
1307 ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
1308 if ( !defined($self->{IMG}) ) {
1309 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1311 $self->{DEBUG} && print "loading a jpeg file\n";
1315 my $allow_incomplete = $input{allow_incomplete};
1316 defined $allow_incomplete or $allow_incomplete = 0;
1318 if ( $input{'type'} eq 'tiff' ) {
1319 my $page = $input{'page'};
1320 defined $page or $page = 0;
1321 $self->{IMG}=i_readtiff_wiol( $IO, $allow_incomplete, $page );
1322 if ( !defined($self->{IMG}) ) {
1323 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1325 $self->{DEBUG} && print "loading a tiff file\n";
1329 if ( $input{'type'} eq 'pnm' ) {
1330 $self->{IMG}=i_readpnm_wiol( $IO, $allow_incomplete );
1331 if ( !defined($self->{IMG}) ) {
1332 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg();
1335 $self->{DEBUG} && print "loading a pnm file\n";
1339 if ( $input{'type'} eq 'png' ) {
1340 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1341 if ( !defined($self->{IMG}) ) {
1342 $self->{ERRSTR} = $self->_error_as_msg();
1345 $self->{DEBUG} && print "loading a png file\n";
1348 if ( $input{'type'} eq 'bmp' ) {
1349 $self->{IMG}=i_readbmp_wiol( $IO, $allow_incomplete );
1350 if ( !defined($self->{IMG}) ) {
1351 $self->{ERRSTR}=$self->_error_as_msg();
1354 $self->{DEBUG} && print "loading a bmp file\n";
1357 if ( $input{'type'} eq 'gif' ) {
1358 if ($input{colors} && !ref($input{colors})) {
1359 # must be a reference to a scalar that accepts the colour map
1360 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1363 if ($input{'gif_consolidate'}) {
1364 if ($input{colors}) {
1366 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1368 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1372 $self->{IMG} =i_readgif_wiol( $IO );
1376 my $page = $input{'page'};
1377 defined $page or $page = 0;
1378 $self->{IMG} = i_readgif_single_wiol( $IO, $page );
1379 if ($self->{IMG} && $input{colors}) {
1380 ${ $input{colors} } =
1381 [ i_getcolors($self->{IMG}, 0, i_colorcount($self->{IMG})) ];
1385 if ( !defined($self->{IMG}) ) {
1386 $self->{ERRSTR}=$self->_error_as_msg();
1389 $self->{DEBUG} && print "loading a gif file\n";
1392 if ( $input{'type'} eq 'tga' ) {
1393 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1394 if ( !defined($self->{IMG}) ) {
1395 $self->{ERRSTR}=$self->_error_as_msg();
1398 $self->{DEBUG} && print "loading a tga file\n";
1401 if ( $input{'type'} eq 'raw' ) {
1402 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1404 if ( !($params{xsize} && $params{ysize}) ) {
1405 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1409 $self->{IMG} = i_readraw_wiol( $IO,
1412 $params{datachannels},
1413 $params{storechannels},
1414 $params{interleave});
1415 if ( !defined($self->{IMG}) ) {
1416 $self->{ERRSTR}=$self->_error_as_msg();
1419 $self->{DEBUG} && print "loading a raw file\n";
1425 sub register_reader {
1426 my ($class, %opts) = @_;
1429 or die "register_reader called with no type parameter\n";
1431 my $type = $opts{type};
1433 defined $opts{single} || defined $opts{multiple}
1434 or die "register_reader called with no single or multiple parameter\n";
1436 $readers{$type} = { };
1437 if ($opts{single}) {
1438 $readers{$type}{single} = $opts{single};
1440 if ($opts{multiple}) {
1441 $readers{$type}{multiple} = $opts{multiple};
1447 sub register_writer {
1448 my ($class, %opts) = @_;
1451 or die "register_writer called with no type parameter\n";
1453 my $type = $opts{type};
1455 defined $opts{single} || defined $opts{multiple}
1456 or die "register_writer called with no single or multiple parameter\n";
1458 $writers{$type} = { };
1459 if ($opts{single}) {
1460 $writers{$type}{single} = $opts{single};
1462 if ($opts{multiple}) {
1463 $writers{$type}{multiple} = $opts{multiple};
1474 grep($file_formats{$_}, keys %formats),
1475 qw(ico sgi), # formats not handled directly, but supplied with Imager
1486 grep($file_formats{$_}, keys %formats),
1487 qw(ico sgi), # formats not handled directly, but supplied with Imager
1493 # probes for an Imager::File::whatever module
1494 sub _reader_autoload {
1497 return if $formats{$type} || $readers{$type};
1499 return unless $type =~ /^\w+$/;
1501 my $file = "Imager/File/\U$type\E.pm";
1503 unless ($attempted_to_load{$file}) {
1505 ++$attempted_to_load{$file};
1509 # try to get a reader specific module
1510 my $file = "Imager/File/\U$type\EReader.pm";
1511 unless ($attempted_to_load{$file}) {
1513 ++$attempted_to_load{$file};
1521 # probes for an Imager::File::whatever module
1522 sub _writer_autoload {
1525 return if $formats{$type} || $readers{$type};
1527 return unless $type =~ /^\w+$/;
1529 my $file = "Imager/File/\U$type\E.pm";
1531 unless ($attempted_to_load{$file}) {
1533 ++$attempted_to_load{$file};
1537 # try to get a writer specific module
1538 my $file = "Imager/File/\U$type\EWriter.pm";
1539 unless ($attempted_to_load{$file}) {
1541 ++$attempted_to_load{$file};
1549 sub _fix_gif_positions {
1550 my ($opts, $opt, $msg, @imgs) = @_;
1552 my $positions = $opts->{'gif_positions'};
1554 for my $pos (@$positions) {
1555 my ($x, $y) = @$pos;
1556 my $img = $imgs[$index++];
1557 $img->settag(name=>'gif_left', value=>$x);
1558 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1560 $$msg .= "replaced with the gif_left and gif_top tags";
1565 gif_each_palette=>'gif_local_map',
1566 interlace => 'gif_interlace',
1567 gif_delays => 'gif_delay',
1568 gif_positions => \&_fix_gif_positions,
1569 gif_loop_count => 'gif_loop',
1573 my ($self, $opts, $prefix, @imgs) = @_;
1575 for my $opt (keys %$opts) {
1577 if ($obsolete_opts{$opt}) {
1578 my $new = $obsolete_opts{$opt};
1579 my $msg = "Obsolete option $opt ";
1581 $new->($opts, $opt, \$msg, @imgs);
1584 $msg .= "replaced with the $new tag ";
1587 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1588 warn $msg if $warn_obsolete && $^W;
1590 next unless $tagname =~ /^\Q$prefix/;
1591 my $value = $opts->{$opt};
1593 if (UNIVERSAL::isa($value, "Imager::Color")) {
1594 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1595 for my $img (@imgs) {
1596 $img->settag(name=>$tagname, value=>$tag);
1599 elsif (ref($value) eq 'ARRAY') {
1600 for my $i (0..$#$value) {
1601 my $val = $value->[$i];
1603 if (UNIVERSAL::isa($val, "Imager::Color")) {
1604 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1606 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1609 $self->_set_error("Unknown reference type " . ref($value) .
1610 " supplied in array for $opt");
1616 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1621 $self->_set_error("Unknown reference type " . ref($value) .
1622 " supplied for $opt");
1627 # set it as a tag for every image
1628 for my $img (@imgs) {
1629 $img->settag(name=>$tagname, value=>$value);
1637 # Write an image to file
1640 my %input=(jpegquality=>75,
1650 $self->_set_opts(\%input, "i_", $self)
1653 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1655 if (!$input{'type'} and $input{file}) {
1656 $input{'type'}=$FORMATGUESS->($input{file});
1658 if (!$input{'type'}) {
1659 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1663 _writer_autoload($input{type});
1666 if ($writers{$input{type}} && $writers{$input{type}}{single}) {
1667 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1670 $writers{$input{type}}{single}->($self, $IO, %input)
1674 if (!$formats{$input{'type'}}) {
1675 my $write_types = join ', ', sort Imager->write_types();
1676 $self->_set_error("format '$input{'type'}' not supported - formats $write_types available for writing");
1680 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1683 if ($input{'type'} eq 'tiff') {
1684 $self->_set_opts(\%input, "tiff_", $self)
1686 $self->_set_opts(\%input, "exif_", $self)
1689 if (defined $input{class} && $input{class} eq 'fax') {
1690 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1691 $self->{ERRSTR} = $self->_error_as_msg();
1695 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1696 $self->{ERRSTR} = $self->_error_as_msg();
1700 } elsif ( $input{'type'} eq 'pnm' ) {
1701 $self->_set_opts(\%input, "pnm_", $self)
1703 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1704 $self->{ERRSTR} = $self->_error_as_msg();
1707 $self->{DEBUG} && print "writing a pnm file\n";
1708 } elsif ( $input{'type'} eq 'raw' ) {
1709 $self->_set_opts(\%input, "raw_", $self)
1711 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1712 $self->{ERRSTR} = $self->_error_as_msg();
1715 $self->{DEBUG} && print "writing a raw file\n";
1716 } elsif ( $input{'type'} eq 'png' ) {
1717 $self->_set_opts(\%input, "png_", $self)
1719 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1720 $self->{ERRSTR}='unable to write png image';
1723 $self->{DEBUG} && print "writing a png file\n";
1724 } elsif ( $input{'type'} eq 'jpeg' ) {
1725 $self->_set_opts(\%input, "jpeg_", $self)
1727 $self->_set_opts(\%input, "exif_", $self)
1729 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1730 $self->{ERRSTR} = $self->_error_as_msg();
1733 $self->{DEBUG} && print "writing a jpeg file\n";
1734 } elsif ( $input{'type'} eq 'bmp' ) {
1735 $self->_set_opts(\%input, "bmp_", $self)
1737 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1738 $self->{ERRSTR} = $self->_error_as_msg;
1741 $self->{DEBUG} && print "writing a bmp file\n";
1742 } elsif ( $input{'type'} eq 'tga' ) {
1743 $self->_set_opts(\%input, "tga_", $self)
1746 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1747 $self->{ERRSTR}=$self->_error_as_msg();
1750 $self->{DEBUG} && print "writing a tga file\n";
1751 } elsif ( $input{'type'} eq 'gif' ) {
1752 $self->_set_opts(\%input, "gif_", $self)
1754 # compatibility with the old interfaces
1755 if ($input{gifquant} eq 'lm') {
1756 $input{make_colors} = 'addi';
1757 $input{translate} = 'perturb';
1758 $input{perturb} = $input{lmdither};
1759 } elsif ($input{gifquant} eq 'gen') {
1760 # just pass options through
1762 $input{make_colors} = 'webmap'; # ignored
1763 $input{translate} = 'giflib';
1765 if (!i_writegif_wiol($IO, \%input, $self->{IMG})) {
1766 $self->{ERRSTR} = $self->_error_as_msg;
1772 if (exists $input{'data'}) {
1773 my $data = io_slurp($IO);
1775 $self->{ERRSTR}='Could not slurp from buffer';
1778 ${$input{data}} = $data;
1784 my ($class, $opts, @images) = @_;
1786 my $type = $opts->{type};
1788 if (!$type && $opts->{'file'}) {
1789 $type = $FORMATGUESS->($opts->{'file'});
1792 $class->_set_error('type parameter missing and not possible to guess from extension');
1795 # translate to ImgRaw
1796 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1797 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1800 $class->_set_opts($opts, "i_", @images)
1802 my @work = map $_->{IMG}, @images;
1804 _writer_autoload($type);
1807 if ($writers{$type} && $writers{$type}{multiple}) {
1808 ($IO, $file) = $class->_get_writer_io($opts, $type)
1811 $writers{$type}{multiple}->($class, $IO, $opts, @images)
1815 if (!$formats{$type}) {
1816 my $write_types = join ', ', sort Imager->write_types();
1817 $class->_set_error("format '$type' not supported - formats $write_types available for writing");
1821 ($IO, $file) = $class->_get_writer_io($opts, $type)
1824 if ($type eq 'gif') {
1825 $class->_set_opts($opts, "gif_", @images)
1827 my $gif_delays = $opts->{gif_delays};
1828 local $opts->{gif_delays} = $gif_delays;
1829 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1830 # assume the caller wants the same delay for each frame
1831 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1833 unless (i_writegif_wiol($IO, $opts, @work)) {
1834 $class->_set_error($class->_error_as_msg());
1838 elsif ($type eq 'tiff') {
1839 $class->_set_opts($opts, "tiff_", @images)
1841 $class->_set_opts($opts, "exif_", @images)
1844 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1845 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1846 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1849 $res = i_writetiff_multi_wiol($IO, @work);
1852 $class->_set_error($class->_error_as_msg());
1858 unless ($images[0]->write(%$opts, io => $IO, type => $type)) {
1863 $ERRSTR = "Sorry, write_multi doesn't support $type yet";
1869 if (exists $opts->{'data'}) {
1870 my $data = io_slurp($IO);
1872 Imager->_set_error('Could not slurp from buffer');
1875 ${$opts->{data}} = $data;
1880 # read multiple images from a file
1882 my ($class, %opts) = @_;
1884 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1887 my $type = $opts{'type'};
1889 $type = i_test_format_probe($IO, -1);
1892 if ($opts{file} && !$type) {
1894 $type = $FORMATGUESS->($opts{file});
1898 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1902 _reader_autoload($type);
1904 if ($readers{$type} && $readers{$type}{multiple}) {
1905 return $readers{$type}{multiple}->($IO, %opts);
1908 if ($type eq 'gif') {
1910 @imgs = i_readgif_multi_wiol($IO);
1913 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1917 $ERRSTR = _error_as_msg();
1921 elsif ($type eq 'tiff') {
1922 my @imgs = i_readtiff_multi_wiol($IO, -1);
1925 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1929 $ERRSTR = _error_as_msg();
1934 my $img = Imager->new;
1935 if ($img->read(%opts, io => $IO, type => $type)) {
1938 Imager->_set_error($img->errstr);
1944 # Destroy an Imager object
1948 # delete $instances{$self};
1949 if (defined($self->{IMG})) {
1950 # the following is now handled by the XS DESTROY method for
1951 # Imager::ImgRaw object
1952 # Re-enabling this will break virtual images
1953 # tested for in t/t020masked.t
1954 # i_img_destroy($self->{IMG});
1955 undef($self->{IMG});
1957 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1961 # Perform an inplace filter of an image
1962 # that is the image will be overwritten with the data
1968 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1970 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1972 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1973 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1976 if ($filters{$input{'type'}}{names}) {
1977 my $names = $filters{$input{'type'}}{names};
1978 for my $name (keys %$names) {
1979 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1980 $input{$name} = $names->{$name}{$input{$name}};
1984 if (defined($filters{$input{'type'}}{defaults})) {
1985 %hsh=( image => $self->{IMG},
1987 %{$filters{$input{'type'}}{defaults}},
1990 %hsh=( image => $self->{IMG},
1995 my @cs=@{$filters{$input{'type'}}{callseq}};
1998 if (!defined($hsh{$_})) {
1999 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
2004 local $SIG{__DIE__}; # we don't want this processed by confess, etc
2005 &{$filters{$input{'type'}}{callsub}}(%hsh);
2008 chomp($self->{ERRSTR} = $@);
2014 $self->{DEBUG} && print "callseq is: @cs\n";
2015 $self->{DEBUG} && print "matching callseq is: @b\n";
2020 sub register_filter {
2022 my %hsh = ( defaults => {}, @_ );
2025 or die "register_filter() with no type\n";
2026 defined $hsh{callsub}
2027 or die "register_filter() with no callsub\n";
2028 defined $hsh{callseq}
2029 or die "register_filter() with no callseq\n";
2031 exists $filters{$hsh{type}}
2034 $filters{$hsh{type}} = \%hsh;
2039 # Scale an image to requested size and return the scaled version
2043 my %opts=('type'=>'max',qtype=>'normal',@_);
2044 my $img = Imager->new();
2045 my $tmp = Imager->new();
2046 my ($x_scale, $y_scale);
2048 unless (defined wantarray) {
2049 my @caller = caller;
2050 warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
2054 unless ($self->{IMG}) {
2055 $self->_set_error('empty input image');
2059 if ($opts{'xscalefactor'} && $opts{'yscalefactor'}) {
2060 $x_scale = $opts{'xscalefactor'};
2061 $y_scale = $opts{'yscalefactor'};
2063 elsif ($opts{'xscalefactor'}) {
2064 $x_scale = $opts{'xscalefactor'};
2065 $y_scale = $opts{'scalefactor'} || $x_scale;
2067 elsif ($opts{'yscalefactor'}) {
2068 $y_scale = $opts{'yscalefactor'};
2069 $x_scale = $opts{'scalefactor'} || $y_scale;
2072 $x_scale = $y_scale = $opts{'scalefactor'} || 0.5;
2075 # work out the scaling
2076 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
2077 my ($xpix, $ypix)=( $opts{xpixels} / $self->getwidth() ,
2078 $opts{ypixels} / $self->getheight() );
2079 if ($opts{'type'} eq 'min') {
2080 $x_scale = $y_scale = _min($xpix,$ypix);
2082 elsif ($opts{'type'} eq 'max') {
2083 $x_scale = $y_scale = _max($xpix,$ypix);
2085 elsif ($opts{'type'} eq 'nonprop' || $opts{'type'} eq 'non-proportional') {
2090 $self->_set_error('invalid value for type parameter');
2093 } elsif ($opts{xpixels}) {
2094 $x_scale = $y_scale = $opts{xpixels} / $self->getwidth();
2096 elsif ($opts{ypixels}) {
2097 $x_scale = $y_scale = $opts{ypixels}/$self->getheight();
2099 elsif ($opts{constrain} && ref $opts{constrain}
2100 && $opts{constrain}->can('constrain')) {
2101 # we've been passed an Image::Math::Constrain object or something
2102 # that looks like one
2104 (undef, undef, $scalefactor)
2105 = $opts{constrain}->constrain($self->getwidth, $self->getheight);
2106 unless ($scalefactor) {
2107 $self->_set_error('constrain method failed on constrain parameter');
2110 $x_scale = $y_scale = $scalefactor;
2113 if ($opts{qtype} eq 'normal') {
2114 $tmp->{IMG} = i_scaleaxis($self->{IMG}, $x_scale, 0);
2115 if ( !defined($tmp->{IMG}) ) {
2116 $self->{ERRSTR} = 'unable to scale image';
2119 $img->{IMG}=i_scaleaxis($tmp->{IMG}, $y_scale, 1);
2120 if ( !defined($img->{IMG}) ) {
2121 $self->{ERRSTR}='unable to scale image';
2127 elsif ($opts{'qtype'} eq 'preview') {
2128 $img->{IMG} = i_scale_nn($self->{IMG}, $x_scale, $y_scale);
2129 if ( !defined($img->{IMG}) ) {
2130 $self->{ERRSTR}='unable to scale image';
2135 elsif ($opts{'qtype'} eq 'mixing') {
2136 my $new_width = int(0.5 + $self->getwidth * $x_scale);
2137 my $new_height = int(0.5 + $self->getheight * $y_scale);
2138 $new_width >= 1 or $new_width = 1;
2139 $new_height >= 1 or $new_height = 1;
2140 $img->{IMG} = i_scale_mixing($self->{IMG}, $new_width, $new_height);
2141 unless ($img->{IMG}) {
2142 $self->_set_error(Imager->_error_as_meg);
2148 $self->_set_error('invalid value for qtype parameter');
2153 # Scales only along the X axis
2157 my %opts = ( scalefactor=>0.5, @_ );
2159 unless (defined wantarray) {
2160 my @caller = caller;
2161 warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
2165 unless ($self->{IMG}) {
2166 $self->{ERRSTR} = 'empty input image';
2170 my $img = Imager->new();
2172 my $scalefactor = $opts{scalefactor};
2174 if ($opts{pixels}) {
2175 $scalefactor = $opts{pixels} / $self->getwidth();
2178 unless ($self->{IMG}) {
2179 $self->{ERRSTR}='empty input image';
2183 $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
2185 if ( !defined($img->{IMG}) ) {
2186 $self->{ERRSTR} = 'unable to scale image';
2193 # Scales only along the Y axis
2197 my %opts = ( scalefactor => 0.5, @_ );
2199 unless (defined wantarray) {
2200 my @caller = caller;
2201 warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
2205 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2207 my $img = Imager->new();
2209 my $scalefactor = $opts{scalefactor};
2211 if ($opts{pixels}) {
2212 $scalefactor = $opts{pixels} / $self->getheight();
2215 unless ($self->{IMG}) {
2216 $self->{ERRSTR} = 'empty input image';
2219 $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
2221 if ( !defined($img->{IMG}) ) {
2222 $self->{ERRSTR} = 'unable to scale image';
2229 # Transform returns a spatial transformation of the input image
2230 # this moves pixels to a new location in the returned image.
2231 # NOTE - should make a utility function to check transforms for
2236 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2238 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
2240 # print Dumper(\%opts);
2243 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
2245 eval ("use Affix::Infix2Postfix;");
2248 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
2251 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
2252 {op=>'-',trans=>'Sub'},
2253 {op=>'*',trans=>'Mult'},
2254 {op=>'/',trans=>'Div'},
2255 {op=>'-','type'=>'unary',trans=>'u-'},
2257 {op=>'func','type'=>'unary'}],
2258 'grouping'=>[qw( \( \) )],
2259 'func'=>[qw( sin cos )],
2264 @xt=$I2P->translate($opts{'xexpr'});
2265 @yt=$I2P->translate($opts{'yexpr'});
2267 $numre=$I2P->{'numre'};
2270 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
2271 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
2272 @{$opts{'parm'}}=@pt;
2275 # print Dumper(\%opts);
2277 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
2278 $self->{ERRSTR}='transform: no xopcodes given.';
2282 @op=@{$opts{'xopcodes'}};
2284 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2285 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2288 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2294 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
2295 $self->{ERRSTR}='transform: no yopcodes given.';
2299 @op=@{$opts{'yopcodes'}};
2301 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2302 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2305 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2310 if ( !exists $opts{'parm'}) {
2311 $self->{ERRSTR}='transform: no parameter arg given.';
2315 # print Dumper(\@ropx);
2316 # print Dumper(\@ropy);
2317 # print Dumper(\@ropy);
2319 my $img = Imager->new();
2320 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
2321 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
2327 my ($opts, @imgs) = @_;
2329 require "Imager/Expr.pm";
2331 $opts->{variables} = [ qw(x y) ];
2332 my ($width, $height) = @{$opts}{qw(width height)};
2334 $width ||= $imgs[0]->getwidth();
2335 $height ||= $imgs[0]->getheight();
2337 for my $img (@imgs) {
2338 $opts->{constants}{"w$img_num"} = $img->getwidth();
2339 $opts->{constants}{"h$img_num"} = $img->getheight();
2340 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
2341 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
2346 $opts->{constants}{w} = $width;
2347 $opts->{constants}{cx} = $width/2;
2350 $Imager::ERRSTR = "No width supplied";
2354 $opts->{constants}{h} = $height;
2355 $opts->{constants}{cy} = $height/2;
2358 $Imager::ERRSTR = "No height supplied";
2361 my $code = Imager::Expr->new($opts);
2363 $Imager::ERRSTR = Imager::Expr::error();
2366 my $channels = $opts->{channels} || 3;
2367 unless ($channels >= 1 && $channels <= 4) {
2368 return Imager->_set_error("channels must be an integer between 1 and 4");
2371 my $img = Imager->new();
2372 $img->{IMG} = i_transform2($opts->{width}, $opts->{height},
2373 $channels, $code->code(),
2374 $code->nregs(), $code->cregs(),
2375 [ map { $_->{IMG} } @imgs ]);
2376 if (!defined $img->{IMG}) {
2377 $Imager::ERRSTR = Imager->_error_as_msg();
2386 my %opts=(tx => 0,ty => 0, @_);
2388 unless ($self->{IMG}) {
2389 $self->{ERRSTR}='empty input image';
2392 unless ($opts{src} && $opts{src}->{IMG}) {
2393 $self->{ERRSTR}='empty input image for src';
2397 %opts = (src_minx => 0,
2399 src_maxx => $opts{src}->getwidth(),
2400 src_maxy => $opts{src}->getheight(),
2403 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
2404 $opts{src_minx}, $opts{src_miny},
2405 $opts{src_maxx}, $opts{src_maxy})) {
2406 $self->_set_error($self->_error_as_msg());
2416 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
2418 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
2419 $dir = $xlate{$opts{'dir'}};
2420 return $self if i_flipxy($self->{IMG}, $dir);
2428 unless (defined wantarray) {
2429 my @caller = caller;
2430 warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
2434 if (defined $opts{right}) {
2435 my $degrees = $opts{right};
2437 $degrees += 360 * int(((-$degrees)+360)/360);
2439 $degrees = $degrees % 360;
2440 if ($degrees == 0) {
2441 return $self->copy();
2443 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
2444 my $result = Imager->new();
2445 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
2449 $self->{ERRSTR} = $self->_error_as_msg();
2454 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
2458 elsif (defined $opts{radians} || defined $opts{degrees}) {
2459 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
2461 my $back = $opts{back};
2462 my $result = Imager->new;
2464 $back = _color($back);
2466 $self->_set_error(Imager->errstr);
2470 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
2473 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
2475 if ($result->{IMG}) {
2479 $self->{ERRSTR} = $self->_error_as_msg();
2484 $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available";
2489 sub matrix_transform {
2493 unless (defined wantarray) {
2494 my @caller = caller;
2495 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
2499 if ($opts{matrix}) {
2500 my $xsize = $opts{xsize} || $self->getwidth;
2501 my $ysize = $opts{ysize} || $self->getheight;
2503 my $result = Imager->new;
2505 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2506 $opts{matrix}, $opts{back})
2510 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2518 $self->{ERRSTR} = "matrix parameter required";
2524 *yatf = \&matrix_transform;
2526 # These two are supported for legacy code only
2529 return Imager::Color->new(@_);
2533 return Imager::Color::set(@_);
2536 # Draws a box between the specified corner points.
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,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
2543 if (exists $opts{'box'}) {
2544 $opts{'xmin'} = _min($opts{'box'}->[0],$opts{'box'}->[2]);
2545 $opts{'xmax'} = _max($opts{'box'}->[0],$opts{'box'}->[2]);
2546 $opts{'ymin'} = _min($opts{'box'}->[1],$opts{'box'}->[3]);
2547 $opts{'ymax'} = _max($opts{'box'}->[1],$opts{'box'}->[3]);
2550 if ($opts{filled}) {
2551 my $color = _color($opts{'color'});
2553 $self->{ERRSTR} = $Imager::ERRSTR;
2556 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2557 $opts{ymax}, $color);
2559 elsif ($opts{fill}) {
2560 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2561 # assume it's a hash ref
2562 require 'Imager/Fill.pm';
2563 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2564 $self->{ERRSTR} = $Imager::ERRSTR;
2568 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2569 $opts{ymax},$opts{fill}{fill});
2572 my $color = _color($opts{'color'});
2574 $self->{ERRSTR} = $Imager::ERRSTR;
2577 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
2585 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2586 my $dflcl=i_color_new(255,255,255,255);
2587 my %opts=(color=>$dflcl,
2588 'r'=>_min($self->getwidth(),$self->getheight())/3,
2589 'x'=>$self->getwidth()/2,
2590 'y'=>$self->getheight()/2,
2591 'd1'=>0, 'd2'=>361, @_);
2594 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2595 # assume it's a hash ref
2596 require 'Imager/Fill.pm';
2597 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2598 $self->{ERRSTR} = $Imager::ERRSTR;
2602 i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2603 $opts{'d2'}, $opts{fill}{fill});
2606 my $color = _color($opts{'color'});
2608 $self->{ERRSTR} = $Imager::ERRSTR;
2611 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
2612 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
2616 i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2617 $opts{'d1'}, $opts{'d2'}, $color);
2623 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2624 # assume it's a hash ref
2625 require 'Imager/Fill.pm';
2626 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2627 $self->{ERRSTR} = $Imager::ERRSTR;
2631 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2632 $opts{'d2'}, $opts{fill}{fill});
2635 my $color = _color($opts{'color'});
2637 $self->{ERRSTR} = $Imager::ERRSTR;
2640 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2641 $opts{'d1'}, $opts{'d2'}, $color);
2648 # Draws a line from one point to the other
2649 # the endpoint is set if the endp parameter is set which it is by default.
2650 # to turn of the endpoint being set use endp=>0 when calling line.
2654 my $dflcl=i_color_new(0,0,0,0);
2655 my %opts=(color=>$dflcl,
2658 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2660 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2661 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2663 my $color = _color($opts{'color'});
2665 $self->{ERRSTR} = $Imager::ERRSTR;
2669 $opts{antialias} = $opts{aa} if defined $opts{aa};
2670 if ($opts{antialias}) {
2671 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2672 $color, $opts{endp});
2674 i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2675 $color, $opts{endp});
2680 # Draws a line between an ordered set of points - It more or less just transforms this
2681 # into a list of lines.
2685 my ($pt,$ls,@points);
2686 my $dflcl=i_color_new(0,0,0,0);
2687 my %opts=(color=>$dflcl,@_);
2689 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2691 if (exists($opts{points})) { @points=@{$opts{points}}; }
2692 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2693 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2696 # print Dumper(\@points);
2698 my $color = _color($opts{'color'});
2700 $self->{ERRSTR} = $Imager::ERRSTR;
2703 $opts{antialias} = $opts{aa} if defined $opts{aa};
2704 if ($opts{antialias}) {
2707 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1);
2714 i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1);
2724 my ($pt,$ls,@points);
2725 my $dflcl = i_color_new(0,0,0,0);
2726 my %opts = (color=>$dflcl, @_);
2728 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2730 if (exists($opts{points})) {
2731 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2732 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2735 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2736 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2739 if ($opts{'fill'}) {
2740 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2741 # assume it's a hash ref
2742 require 'Imager/Fill.pm';
2743 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2744 $self->{ERRSTR} = $Imager::ERRSTR;
2748 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2749 $opts{'fill'}{'fill'});
2752 my $color = _color($opts{'color'});
2754 $self->{ERRSTR} = $Imager::ERRSTR;
2757 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2764 # this the multipoint bezier curve
2765 # this is here more for testing that actual usage since
2766 # this is not a good algorithm. Usually the curve would be
2767 # broken into smaller segments and each done individually.
2771 my ($pt,$ls,@points);
2772 my $dflcl=i_color_new(0,0,0,0);
2773 my %opts=(color=>$dflcl,@_);
2775 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2777 if (exists $opts{points}) {
2778 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2779 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2782 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2783 $self->{ERRSTR}='Missing or invalid points.';
2787 my $color = _color($opts{'color'});
2789 $self->{ERRSTR} = $Imager::ERRSTR;
2792 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2798 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2801 unless (exists $opts{'x'} && exists $opts{'y'}) {
2802 $self->{ERRSTR} = "missing seed x and y parameters";
2806 if ($opts{border}) {
2807 my $border = _color($opts{border});
2809 $self->_set_error($Imager::ERRSTR);
2813 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2814 # assume it's a hash ref
2815 require Imager::Fill;
2816 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2817 $self->{ERRSTR} = $Imager::ERRSTR;
2821 $rc = i_flood_cfill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2822 $opts{fill}{fill}, $border);
2825 my $color = _color($opts{'color'});
2827 $self->{ERRSTR} = $Imager::ERRSTR;
2830 $rc = i_flood_fill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2837 $self->{ERRSTR} = $self->_error_as_msg();
2843 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2844 # assume it's a hash ref
2845 require 'Imager/Fill.pm';
2846 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2847 $self->{ERRSTR} = $Imager::ERRSTR;
2851 $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2854 my $color = _color($opts{'color'});
2856 $self->{ERRSTR} = $Imager::ERRSTR;
2859 $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2865 $self->{ERRSTR} = $self->_error_as_msg();
2874 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2876 unless (exists $opts{'x'} && exists $opts{'y'}) {
2877 $self->{ERRSTR} = 'missing x and y parameters';
2883 my $color = _color($opts{color})
2885 if (ref $x && ref $y) {
2886 unless (@$x == @$y) {
2887 $self->{ERRSTR} = 'length of x and y mismatch';
2891 if ($color->isa('Imager::Color')) {
2892 for my $i (0..$#{$opts{'x'}}) {
2893 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color)
2898 for my $i (0..$#{$opts{'x'}}) {
2899 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color)
2907 if ($color->isa('Imager::Color')) {
2908 i_ppix($self->{IMG}, $x, $y, $color)
2912 i_ppixf($self->{IMG}, $x, $y, $color)
2923 my %opts = ( "type"=>'8bit', @_);
2925 unless (exists $opts{'x'} && exists $opts{'y'}) {
2926 $self->{ERRSTR} = 'missing x and y parameters';
2932 if (ref $x && ref $y) {
2933 unless (@$x == @$y) {
2934 $self->{ERRSTR} = 'length of x and y mismatch';
2938 if ($opts{"type"} eq '8bit') {
2939 for my $i (0..$#{$opts{'x'}}) {
2940 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2944 for my $i (0..$#{$opts{'x'}}) {
2945 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2948 return wantarray ? @result : \@result;
2951 if ($opts{"type"} eq '8bit') {
2952 return i_get_pixel($self->{IMG}, $x, $y);
2955 return i_gpixf($self->{IMG}, $x, $y);
2964 my %opts = ( type => '8bit', x=>0, @_);
2966 $self->_valid_image or return;
2968 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2970 unless (defined $opts{'y'}) {
2971 $self->_set_error("missing y parameter");
2975 if ($opts{type} eq '8bit') {
2976 return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2979 elsif ($opts{type} eq 'float') {
2980 return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2983 elsif ($opts{type} eq 'index') {
2984 unless (i_img_type($self->{IMG})) {
2985 $self->_set_error("type => index only valid on paletted images");
2988 return i_gpal($self->{IMG}, $opts{x}, $opts{x} + $opts{width},
2992 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2999 my %opts = ( x=>0, @_);
3001 $self->_valid_image or return;
3003 unless (defined $opts{'y'}) {
3004 $self->_set_error("missing y parameter");
3009 if (ref $opts{pixels} && @{$opts{pixels}}) {
3010 # try to guess the type
3011 if ($opts{pixels}[0]->isa('Imager::Color')) {
3012 $opts{type} = '8bit';
3014 elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
3015 $opts{type} = 'float';
3018 $self->_set_error("missing type parameter and could not guess from pixels");
3024 $opts{type} = '8bit';
3028 if ($opts{type} eq '8bit') {
3029 if (ref $opts{pixels}) {
3030 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3033 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3036 elsif ($opts{type} eq 'float') {
3037 if (ref $opts{pixels}) {
3038 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3041 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3044 elsif ($opts{type} eq 'index') {
3045 if (ref $opts{pixels}) {
3046 return i_ppal($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
3049 return i_ppal_p($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
3053 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3060 my %opts = ( type => '8bit', x=>0, offset => 0, @_);
3062 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
3064 unless (defined $opts{'y'}) {
3065 $self->_set_error("missing y parameter");
3069 unless ($opts{channels}) {
3070 $opts{channels} = [ 0 .. $self->getchannels()-1 ];
3073 if ($opts{target}) {
3074 my $target = $opts{target};
3075 my $offset = $opts{offset};
3076 if ($opts{type} eq '8bit') {
3077 my @samples = i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3078 $opts{y}, @{$opts{channels}})
3080 @{$target}{$offset .. $offset + @samples - 1} = @samples;
3081 return scalar(@samples);
3083 elsif ($opts{type} eq 'float') {
3084 my @samples = i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3085 $opts{y}, @{$opts{channels}});
3086 @{$target}{$offset .. $offset + @samples - 1} = @samples;
3087 return scalar(@samples);
3089 elsif ($opts{type} =~ /^(\d+)bit$/) {
3093 my $count = i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3094 $opts{y}, $bits, $target,
3095 $offset, @{$opts{channels}});
3096 unless (defined $count) {
3097 $self->_set_error(Imager->_error_as_msg);
3104 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3109 if ($opts{type} eq '8bit') {
3110 return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3111 $opts{y}, @{$opts{channels}});
3113 elsif ($opts{type} eq 'float') {
3114 return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3115 $opts{y}, @{$opts{channels}});
3117 elsif ($opts{type} =~ /^(\d+)bit$/) {
3121 i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
3122 $opts{y}, $bits, \@data, 0, @{$opts{channels}})
3127 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3135 my %opts = ( x => 0, offset => 0, @_ );
3137 unless ($self->{IMG}) {
3138 $self->_set_error('setsamples: empty input image');
3142 unless(defined $opts{data} && ref $opts{data}) {
3143 $self->_set_error('setsamples: data parameter missing or invalid');
3147 unless ($opts{channels}) {
3148 $opts{channels} = [ 0 .. $self->getchannels()-1 ];
3151 unless ($opts{type} && $opts{type} =~ /^(\d+)bit$/) {
3152 $self->_set_error('setsamples: type parameter missing or invalid');
3157 unless (defined $opts{width}) {
3158 $opts{width} = $self->getwidth() - $opts{x};
3161 my $count = i_psamp_bits($self->{IMG}, $opts{x}, $opts{y}, $bits,
3162 $opts{channels}, $opts{data}, $opts{offset},
3164 unless (defined $count) {
3165 $self->_set_error(Imager->_error_as_msg);
3172 # make an identity matrix of the given size
3176 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
3177 for my $c (0 .. ($size-1)) {
3178 $matrix->[$c][$c] = 1;
3183 # general function to convert an image
3185 my ($self, %opts) = @_;
3188 unless (defined wantarray) {
3189 my @caller = caller;
3190 warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
3194 # the user can either specify a matrix or preset
3195 # the matrix overrides the preset
3196 if (!exists($opts{matrix})) {
3197 unless (exists($opts{preset})) {
3198 $self->{ERRSTR} = "convert() needs a matrix or preset";
3202 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
3203 # convert to greyscale, keeping the alpha channel if any
3204 if ($self->getchannels == 3) {
3205 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
3207 elsif ($self->getchannels == 4) {
3208 # preserve the alpha channel
3209 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
3214 $matrix = _identity($self->getchannels);
3217 elsif ($opts{preset} eq 'noalpha') {
3218 # strip the alpha channel
3219 if ($self->getchannels == 2 or $self->getchannels == 4) {
3220 $matrix = _identity($self->getchannels);
3221 pop(@$matrix); # lose the alpha entry
3224 $matrix = _identity($self->getchannels);
3227 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
3229 $matrix = [ [ 1 ] ];
3231 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
3232 $matrix = [ [ 0, 1 ] ];
3234 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
3235 $matrix = [ [ 0, 0, 1 ] ];
3237 elsif ($opts{preset} eq 'alpha') {
3238 if ($self->getchannels == 2 or $self->getchannels == 4) {
3239 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
3242 # the alpha is just 1 <shrug>
3243 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
3246 elsif ($opts{preset} eq 'rgb') {
3247 if ($self->getchannels == 1) {
3248 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
3250 elsif ($self->getchannels == 2) {
3251 # preserve the alpha channel
3252 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
3255 $matrix = _identity($self->getchannels);
3258 elsif ($opts{preset} eq 'addalpha') {
3259 if ($self->getchannels == 1) {
3260 $matrix = _identity(2);
3262 elsif ($self->getchannels == 3) {
3263 $matrix = _identity(4);
3266 $matrix = _identity($self->getchannels);
3270 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
3276 $matrix = $opts{matrix};
3279 my $new = Imager->new;
3280 $new->{IMG} = i_convert($self->{IMG}, $matrix);
3281 unless ($new->{IMG}) {
3282 # most likely a bad matrix
3283 $self->{ERRSTR} = _error_as_msg();
3290 # general function to map an image through lookup tables
3293 my ($self, %opts) = @_;
3294 my @chlist = qw( red green blue alpha );
3296 if (!exists($opts{'maps'})) {
3297 # make maps from channel maps
3299 for $chnum (0..$#chlist) {
3300 if (exists $opts{$chlist[$chnum]}) {
3301 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
3302 } elsif (exists $opts{'all'}) {
3303 $opts{'maps'}[$chnum] = $opts{'all'};
3307 if ($opts{'maps'} and $self->{IMG}) {
3308 i_map($self->{IMG}, $opts{'maps'} );
3314 my ($self, %opts) = @_;
3316 defined $opts{mindist} or $opts{mindist} = 0;
3318 defined $opts{other}
3319 or return $self->_set_error("No 'other' parameter supplied");
3320 defined $opts{other}{IMG}
3321 or return $self->_set_error("No image data in 'other' image");
3324 or return $self->_set_error("No image data");
3326 my $result = Imager->new;
3327 $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
3329 or return $self->_set_error($self->_error_as_msg());
3334 # destructive border - image is shrunk by one pixel all around
3337 my ($self,%opts)=@_;
3338 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
3339 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
3343 # Get the width of an image
3347 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3348 return (i_img_info($self->{IMG}))[0];
3351 # Get the height of an image
3355 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3356 return (i_img_info($self->{IMG}))[1];
3359 # Get number of channels in an image
3363 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3364 return i_img_getchannels($self->{IMG});
3371 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3372 return i_img_getmask($self->{IMG});
3380 if (!defined($self->{IMG})) {
3381 $self->{ERRSTR} = 'image is empty';
3384 unless (defined $opts{mask}) {
3385 $self->_set_error("mask parameter required");
3388 i_img_setmask( $self->{IMG} , $opts{mask} );
3393 # Get number of colors in an image
3397 my %opts=('maxcolors'=>2**30,@_);
3398 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
3399 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
3400 return ($rc==-1? undef : $rc);
3403 # Returns a reference to a hash. The keys are colour named (packed) and the
3404 # values are the number of pixels in this colour.
3405 sub getcolorusagehash {
3408 my %opts = ( maxcolors => 2**30, @_ );
3409 my $max_colors = $opts{maxcolors};
3410 unless (defined $max_colors && $max_colors > 0) {
3411 $self->_set_error('maxcolors must be a positive integer');
3415 unless (defined $self->{IMG}) {
3416 $self->_set_error('empty input image');
3420 my $channels= $self->getchannels;
3421 # We don't want to look at the alpha channel, because some gifs using it
3422 # doesn't define it for every colour (but only for some)
3423 $channels -= 1 if $channels == 2 or $channels == 4;
3425 my $height = $self->getheight;
3426 for my $y (0 .. $height - 1) {
3427 my $colors = $self->getsamples('y' => $y, channels => [ 0 .. $channels - 1 ]);
3428 while (length $colors) {
3429 $color_use{ substr($colors, 0, $channels, '') }++;
3431 keys %color_use > $max_colors
3437 # This will return a ordered array of the colour usage. Kind of the sorted
3438 # version of the values of the hash returned by getcolorusagehash.
3439 # You might want to add safety checks and change the names, etc...
3443 my %opts = ( maxcolors => 2**30, @_ );
3444 my $max_colors = $opts{maxcolors};
3445 unless (defined $max_colors && $max_colors > 0) {
3446 $self->_set_error('maxcolors must be a positive integer');
3450 unless (defined $self->{IMG}) {
3451 $self->_set_error('empty input image');
3455 return i_get_anonymous_color_histo($self->{IMG}, $max_colors);
3458 # draw string to an image
3462 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
3464 my %input=('x'=>0, 'y'=>0, @_);
3465 defined($input{string}) or $input{string} = $input{text};
3467 unless(defined $input{string}) {
3468 $self->{ERRSTR}="missing required parameter 'string'";
3472 unless($input{font}) {
3473 $self->{ERRSTR}="missing required parameter 'font'";
3477 unless ($input{font}->draw(image=>$self, %input)) {
3489 unless ($self->{IMG}) {
3490 $self->{ERRSTR}='empty input image';
3499 my %input=('x'=>0, 'y'=>0, @_);
3500 $input{string}||=$input{text};
3502 unless(exists $input{string}) {
3503 $self->_set_error("missing required parameter 'string'");
3507 unless($input{font}) {
3508 $self->_set_error("missing required parameter 'font'");
3513 unless (@result = $input{font}->align(image=>$img, %input)) {
3517 return wantarray ? @result : $result[0];
3520 my @file_limit_names = qw/width height bytes/;
3522 sub set_file_limits {
3529 @values{@file_limit_names} = (0) x @file_limit_names;
3532 @values{@file_limit_names} = i_get_image_file_limits();
3535 for my $key (keys %values) {
3536 defined $opts{$key} and $values{$key} = $opts{$key};
3539 i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
3542 sub get_file_limits {
3543 i_get_image_file_limits();
3546 # Shortcuts that can be exported
3548 sub newcolor { Imager::Color->new(@_); }
3549 sub newfont { Imager::Font->new(@_); }
3550 sub NCF { Imager::Color::Float->new(@_) }
3552 *NC=*newcolour=*newcolor;
3559 #### Utility routines
3562 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
3566 my ($self, $msg) = @_;
3569 $self->{ERRSTR} = $msg;
3577 # Default guess for the type of an image from extension
3579 sub def_guess_type {
3582 $ext=($name =~ m/\.([^\.]+)$/)[0];
3583 return 'tiff' if ($ext =~ m/^tiff?$/);
3584 return 'jpeg' if ($ext =~ m/^jpe?g$/);
3585 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
3586 return 'png' if ($ext eq "png");
3587 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
3588 return 'tga' if ($ext eq "tga");
3589 return 'sgi' if ($ext eq "rgb" || $ext eq "bw" || $ext eq "sgi" || $ext eq "rgba");
3590 return 'gif' if ($ext eq "gif");
3591 return 'raw' if ($ext eq "raw");
3592 return lc $ext; # best guess
3596 # get the minimum of a list
3600 for(@_) { if ($_<$mx) { $mx=$_; }}
3604 # get the maximum of a list
3608 for(@_) { if ($_>$mx) { $mx=$_; }}
3612 # string stuff for iptc headers
3616 $str = substr($str,3);
3617 $str =~ s/[\n\r]//g;
3624 # A little hack to parse iptc headers.
3629 my($caption,$photogr,$headln,$credit);
3631 my $str=$self->{IPTCRAW};
3636 @ar=split(/8BIM/,$str);
3641 @sar=split(/\034\002/);
3642 foreach $item (@sar) {
3643 if ($item =~ m/^x/) {
3644 $caption = _clean($item);
3647 if ($item =~ m/^P/) {
3648 $photogr = _clean($item);
3651 if ($item =~ m/^i/) {
3652 $headln = _clean($item);
3655 if ($item =~ m/^n/) {
3656 $credit = _clean($item);
3662 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
3669 or die "Only C language supported";
3671 require Imager::ExtUtils;
3672 return Imager::ExtUtils->inline_config;
3677 # Below is the stub of documentation for your module. You better edit it!
3681 Imager - Perl extension for Generating 24 bit Images
3691 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
3696 my $img = Imager->new();
3697 # see Imager::Files for information on the read() method
3698 $img->read(file=>$file) or die $img->errstr();
3700 $file =~ s/\.[^.]*$//;
3702 # Create smaller version
3703 # documented in Imager::Transformations
3704 my $thumb = $img->scale(scalefactor=>.3);
3706 # Autostretch individual channels
3707 $thumb->filter(type=>'autolevels');
3709 # try to save in one of these formats
3712 for $format ( qw( png gif jpg tiff ppm ) ) {
3713 # Check if given format is supported
3714 if ($Imager::formats{$format}) {
3715 $file.="_low.$format";
3716 print "Storing image as: $file\n";
3717 # documented in Imager::Files
3718 $thumb->write(file=>$file) or
3726 Imager is a module for creating and altering images. It can read and
3727 write various image formats, draw primitive shapes like lines,and
3728 polygons, blend multiple images together in various ways, scale, crop,
3729 render text and more.
3731 =head2 Overview of documentation
3737 Imager - This document - Synopsis, Example, Table of Contents and
3742 L<Imager::Tutorial> - a brief introduction to Imager.
3746 L<Imager::Cookbook> - how to do various things with Imager.
3750 L<Imager::ImageTypes> - Basics of constructing image objects with
3751 C<new()>: Direct type/virtual images, RGB(A)/paletted images,
3752 8/16/double bits/channel, color maps, channel masks, image tags, color
3753 quantization. Also discusses basic image information methods.
3757 L<Imager::Files> - IO interaction, reading/writing images, format
3762 L<Imager::Draw> - Drawing Primitives, lines, boxes, circles, arcs,
3767 L<Imager::Color> - Color specification.
3771 L<Imager::Fill> - Fill pattern specification.
3775 L<Imager::Font> - General font rendering, bounding boxes and font
3780 L<Imager::Transformations> - Copying, scaling, cropping, flipping,
3781 blending, pasting, convert and map.
3785 L<Imager::Engines> - Programmable transformations through
3786 C<transform()>, C<transform2()> and C<matrix_transform()>.
3790 L<Imager::Filters> - Filters, sharpen, blur, noise, convolve etc. and
3795 L<Imager::Expr> - Expressions for evaluation engine used by
3800 L<Imager::Matrix2d> - Helper class for affine transformations.
3804 L<Imager::Fountain> - Helper for making gradient profiles.
3808 L<Imager::API> - using Imager's C API
3812 L<Imager::APIRef> - API function reference
3816 L<Imager::Inline> - using Imager's C API from Inline::C
3820 L<Imager::ExtUtils> - tools to get access to Imager's C API.
3824 =head2 Basic Overview
3826 An Image object is created with C<$img = Imager-E<gt>new()>.
3829 $img=Imager->new(); # create empty image
3830 $img->read(file=>'lena.png',type=>'png') or # read image from file
3831 die $img->errstr(); # give an explanation
3832 # if something failed
3834 or if you want to create an empty image:
3836 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
3838 This example creates a completely black image of width 400 and height
3841 =head1 ERROR HANDLING
3843 In general a method will return false when it fails, if it does use the errstr() method to find out why:
3849 Returns the last error message in that context.
3851 If the last error you received was from calling an object method, such
3852 as read, call errstr() as an object method to find out why:
3854 my $image = Imager->new;
3855 $image->read(file => 'somefile.gif')
3856 or die $image->errstr;
3858 If it was a class method then call errstr() as a class method:
3860 my @imgs = Imager->read_multi(file => 'somefile.gif')
3861 or die Imager->errstr;
3863 Note that in some cases object methods are implemented in terms of
3864 class methods so a failing object method may set both.
3868 The C<Imager-E<gt>new> method is described in detail in
3869 L<Imager::ImageTypes>.
3873 Where to find information on methods for Imager class objects.
3875 addcolors() - L<Imager::ImageTypes/addcolors>
3877 addtag() - L<Imager::ImageTypes/addtag> - add image tags
3879 align_string() - L<Imager::Draw/align_string>
3881 arc() - L<Imager::Draw/arc>
3883 bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
3886 box() - L<Imager::Draw/box>
3888 circle() - L<Imager::Draw/circle>
3890 colorcount() - L<Imager::Draw/colorcount>
3892 convert() - L<Imager::Transformations/"Color transformations"> -
3893 transform the color space
3895 copy() - L<Imager::Transformations/copy>
3897 crop() - L<Imager::Transformations/crop> - extract part of an image
3899 def_guess_type() - L<Imager::Files/def_guess_type>
3901 deltag() - L<Imager::ImageTypes/deltag> - delete image tags
3903 difference() - L<Imager::Filters/"Image Difference">
3905 errstr() - L<"Basic Overview">
3907 filter() - L<Imager::Filters>
3909 findcolor() - L<Imager::ImageTypes/findcolor> - search the image palette, if it
3912 flip() - L<Imager::Transformations/flip>
3914 flood_fill() - L<Imager::Draw/flood_fill>
3916 getchannels() - L<Imager::ImageTypes/getchannels>
3918 getcolorcount() - L<Imager::ImageTypes/getcolorcount>
3920 getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
3921 palette, if it has one
3923 getcolorusage() - L<Imager::ImageTypes/getcolorusage>
3925 getcolorusagehash() - L<Imager::ImageTypes/getcolorusagehash>
3927 get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3929 getheight() - L<Imager::ImageTypes/getwidth>
3931 getmask() - L<Imager::ImageTypes/getmask>
3933 getpixel() - L<Imager::Draw/getpixel>
3935 getsamples() - L<Imager::Draw/getsamples>
3937 getscanline() - L<Imager::Draw/getscanline>
3939 getwidth() - L<Imager::ImageTypes/getwidth>
3941 img_set() - L<Imager::ImageTypes/img_set>
3943 init() - L<Imager::ImageTypes/init>
3945 is_bilevel() - L<Imager::ImageTypes/is_bilevel>
3947 line() - L<Imager::Draw/line>
3949 load_plugin() - L<Imager::Filters/load_plugin>
3951 map() - L<Imager::Transformations/"Color Mappings"> - remap color
3954 masked() - L<Imager::ImageTypes/masked> - make a masked image
3956 matrix_transform() - L<Imager::Engines/matrix_transform>
3958 maxcolors() - L<Imager::ImageTypes/maxcolors>
3960 NC() - L<Imager::Handy/NC>
3962 NCF() - L<Imager::Handy/NCF>
3964 new() - L<Imager::ImageTypes/new>
3966 newcolor() - L<Imager::Handy/newcolor>
3968 newcolour() - L<Imager::Handy/newcolour>
3970 newfont() - L<Imager::Handy/newfont>
3972 NF() - L<Imager::Handy/NF>
3974 open() - L<Imager::Files> - an alias for read()
3976 parseiptc() - L<Imager::Files/parseiptc> - parse IPTC data from a JPEG
3979 paste() - L<Imager::Transformations/paste> - draw an image onto an image
3981 polygon() - L<Imager::Draw/polygon>
3983 polyline() - L<Imager::Draw/polyline>
3985 read() - L<Imager::Files> - read a single image from an image file
3987 read_multi() - L<Imager::Files> - read multiple images from an image
3990 read_types() - L<Imager::Files/read_types> - list image types Imager
3993 register_filter() - L<Imager::Filters/register_filter>
3995 register_reader() - L<Imager::Filters/register_reader>
3997 register_writer() - L<Imager::Filters/register_writer>
3999 rotate() - L<Imager::Transformations/rotate>
4001 rubthrough() - L<Imager::Transformations/rubthrough> - draw an image onto an
4002 image and use the alpha channel
4004 scale() - L<Imager::Transformations/scale>
4006 scaleX() - L<Imager::Transformations/scaleX>
4008 scaleY() - L<Imager::Transformations/scaleY>
4010 setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
4013 set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
4015 setmask() - L<Imager::ImageTypes/setmask>
4017 setpixel() - L<Imager::Draw/setpixel>
4019 setsamples() - L<Imager::Draw/setsamples>
4021 setscanline() - L<Imager::Draw/setscanline>
4023 settag() - L<Imager::ImageTypes/settag>
4025 string() - L<Imager::Draw/string> - draw text on an image
4027 tags() - L<Imager::ImageTypes/tags> - fetch image tags
4029 to_paletted() - L<Imager::ImageTypes/to_paletted>
4031 to_rgb16() - L<Imager::ImageTypes/to_rgb16>
4033 to_rgb8() - L<Imager::ImageTypes/to_rgb8>
4035 transform() - L<Imager::Engines/"transform">
4037 transform2() - L<Imager::Engines/"transform2">
4039 type() - L<Imager::ImageTypes/type> - type of image (direct vs paletted)
4041 unload_plugin() - L<Imager::Filters/unload_plugin>
4043 virtual() - L<Imager::ImageTypes/virtual> - whether the image has it's own
4046 write() - L<Imager::Files> - write an image to a file
4048 write_multi() - L<Imager::Files> - write multiple image to an image
4051 write_types() - L<Imager::Files/read_types> - list image types Imager
4054 =head1 CONCEPT INDEX
4056 animated GIF - L<Imager::Files/"Writing an animated GIF">
4058 aspect ratio - L<Imager::ImageTypes/i_xres>,
4059 L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
4061 blend - alpha blending one image onto another
4062 L<Imager::Transformations/rubthrough>
4064 blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
4066 boxes, drawing - L<Imager::Draw/box>
4068 changes between image - L<Imager::Filter/"Image Difference">
4070 color - L<Imager::Color>
4072 color names - L<Imager::Color>, L<Imager::Color::Table>
4074 combine modes - L<Imager::Fill/combine>
4076 compare images - L<Imager::Filter/"Image Difference">
4078 contrast - L<Imager::Filter/contrast>, L<Imager::Filter/autolevels>
4080 convolution - L<Imager::Filter/conv>
4082 cropping - L<Imager::Transformations/crop>
4084 CUR files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
4086 C<diff> images - L<Imager::Filter/"Image Difference">
4088 dpi - L<Imager::ImageTypes/i_xres>,
4089 L<Imager::Cookbook/"Image spatial resolution">
4091 drawing boxes - L<Imager::Draw/box>
4093 drawing lines - L<Imager::Draw/line>
4095 drawing text - L<Imager::Draw/string>, L<Imager::Draw/align_string>
4097 error message - L<"Basic Overview">
4099 files, font - L<Imager::Font>
4101 files, image - L<Imager::Files>
4103 filling, types of fill - L<Imager::Fill>
4105 filling, boxes - L<Imager::Draw/box>
4107 filling, flood fill - L<Imager::Draw/flood_fill>
4109 flood fill - L<Imager::Draw/flood_fill>
4111 fonts - L<Imager::Font>
4113 fonts, drawing with - L<Imager::Draw/string>,
4114 L<Imager::Draw/align_string>, L<Imager::Font::Wrap>
4116 fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
4118 fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
4120 fountain fill - L<Imager::Fill/"Fountain fills">,
4121 L<Imager::Filters/fountain>, L<Imager::Fountain>,
4122 L<Imager::Filters/gradgen>
4124 GIF files - L<Imager::Files/"GIF">
4126 GIF files, animated - L<Imager::File/"Writing an animated GIF">
4128 gradient fill - L<Imager::Fill/"Fountain fills">,
4129 L<Imager::Filters/fountain>, L<Imager::Fountain>,
4130 L<Imager::Filters/gradgen>
4132 grayscale, convert image to - L<Imager::Transformations/convert>
4134 guassian blur - L<Imager::Filter/guassian>
4136 hatch fills - L<Imager::Fill/"Hatched fills">
4138 ICO files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
4140 invert image - L<Imager::Filter/hardinvert>
4142 JPEG - L<Imager::Files/"JPEG">
4144 limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
4146 lines, drawing - L<Imager::Draw/line>
4148 matrix - L<Imager::Matrix2d>,
4149 L<Imager::Transformations/"Matrix Transformations">,
4150 L<Imager::Font/transform>
4152 metadata, image - L<Imager::ImageTypes/"Tags">
4154 mosaic - L<Imager::Filter/mosaic>
4156 noise, filter - L<Imager::Filter/noise>
4158 noise, rendered - L<Imager::Filter/turbnoise>,
4159 L<Imager::Filter/radnoise>
4161 paste - L<Imager::Transformations/paste>,
4162 L<Imager::Transformations/rubthrough>
4164 pseudo-color image - L<Imager::ImageTypes/to_paletted>,
4165 L<Imager::ImageTypes/new>
4167 posterize - L<Imager::Filter/postlevels>
4169 png files - L<Imager::Files>, L<Imager::Files/"PNG">
4171 pnm - L<Imager::Files/"PNM (Portable aNy Map)">
4173 rectangles, drawing - L<Imager::Draw/box>
4175 resizing an image - L<Imager::Transformations/scale>,
4176 L<Imager::Transformations/crop>
4178 RGB (SGI) files - L<Imager::Files/"SGI (RGB, BW)">
4180 saving an image - L<Imager::Files>
4182 scaling - L<Imager::Transformations/scale>
4184 SGI files - L<Imager::Files/"SGI (RGB, BW)">
4186 sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
4188 size, image - L<Imager::ImageTypes/getwidth>,
4189 L<Imager::ImageTypes/getheight>
4191 size, text - L<Imager::Font/bounding_box>
4193 tags, image metadata - L<Imager::ImageTypes/"Tags">
4195 text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
4196 L<Imager::Font::Wrap>
4198 text, wrapping text in an area - L<Imager::Font::Wrap>
4200 text, measuring - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
4202 tiles, color - L<Imager::Filter/mosaic>
4204 unsharp mask - L<Imager::Filter/unsharpmask>
4206 watermark - L<Imager::Filter/watermark>
4208 writing an image to a file - L<Imager::Files>
4212 The best place to get help with Imager is the mailing list.
4214 To subscribe send a message with C<subscribe> in the body to:
4216 imager-devel+request@molar.is
4222 L<http://www.molar.is/en/lists/imager-devel/>
4226 where you can also find the mailing list archive.
4228 You can report bugs by pointing your browser at:
4232 L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager>
4236 or by sending an email to:
4240 bug-Imager@rt.cpan.org
4244 Please remember to include the versions of Imager, perl, supporting
4245 libraries, and any relevant code. If you have specific images that
4246 cause the problems, please include those too.
4248 If you don't want to publish your email address on a mailing list you
4249 can use CPAN::Forum:
4251 http://www.cpanforum.com/dist/Imager
4253 You will need to register to post.
4255 =head1 CONTRIBUTING TO IMAGER
4261 If you like or dislike Imager, you can add a public review of Imager
4264 http://cpanratings.perl.org/dist/Imager
4266 This requires a Bitcard Account (http://www.bitcard.org).
4268 You can also send email to the maintainer below.
4270 If you send me a bug report via email, it will be copied to RT.
4274 I accept patches, preferably against the main branch in subversion.
4275 You should include an explanation of the reason for why the patch is
4278 Your patch should include regression tests where possible, otherwise
4279 it will be delayed until I get a chance to write them.
4283 Tony Cook <tony@imager.perl.org> is the current maintainer for Imager.
4285 Arnar M. Hrafnkelsson is the original author of Imager.
4287 Many others have contributed to Imager, please see the README for a
4292 L<perl>(1), L<Imager::ImageTypes>(3), L<Imager::Files>(3),
4293 L<Imager::Draw>(3), L<Imager::Color>(3), L<Imager::Fill>(3),
4294 L<Imager::Font>(3), L<Imager::Transformations>(3),
4295 L<Imager::Engines>(3), L<Imager::Filters>(3), L<Imager::Expr>(3),
4296 L<Imager::Matrix2d>(3), L<Imager::Fountain>(3)
4298 L<http://imager.perl.org/>
4300 L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
4302 Other perl imaging modules include:
4304 L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).