4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %formats $DEBUG %filters %DSOs $ERRSTR $fontstate %OPCODES $I2P $FORMATGUESS $warn_obsolete);
82 i_writetiff_wiol_faxable
146 # registered file readers
149 # registered file writers
152 # modules we attempted to autoload
153 my %attempted_to_load;
161 XSLoader::load(Imager => $VERSION);
165 push @ISA, 'DynaLoader';
166 bootstrap Imager $VERSION;
171 i_init_fonts(); # Initialize font engines
172 Imager::Font::__init();
173 for(i_list_formats()) { $formats{$_}++; }
175 if ($formats{'t1'}) {
179 if (!$formats{'t1'} and !$formats{'tt'}
180 && !$formats{'ft2'} && !$formats{'w32'}) {
181 $fontstate='no font support';
184 %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]);
188 # the members of the subhashes under %filters are:
189 # callseq - a list of the parameters to the underlying filter in the
190 # order they are passed
191 # callsub - a code ref that takes a named parameter list and calls the
193 # defaults - a hash of default values
194 # names - defines names for value of given parameters so if the names
195 # field is foo=> { bar=>1 }, and the user supplies "bar" as the
196 # foo parameter, the filter will receive 1 for the foo
199 callseq => ['image','intensity'],
200 callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); }
204 callseq => ['image', 'amount', 'subtype'],
205 defaults => { amount=>3,subtype=>0 },
206 callsub => sub { my %hsh=@_; i_noise($hsh{image},$hsh{amount},$hsh{subtype}); }
209 $filters{hardinvert} ={
210 callseq => ['image'],
212 callsub => sub { my %hsh=@_; i_hardinvert($hsh{image}); }
215 $filters{autolevels} ={
216 callseq => ['image','lsat','usat','skew'],
217 defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 },
218 callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); }
221 $filters{turbnoise} ={
222 callseq => ['image'],
223 defaults => { xo=>0.0,yo=>0.0,scale=>10.0 },
224 callsub => sub { my %hsh=@_; i_turbnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{scale}); }
227 $filters{radnoise} ={
228 callseq => ['image'],
229 defaults => { xo=>100,yo=>100,ascale=>17.0,rscale=>0.02 },
230 callsub => sub { my %hsh=@_; i_radnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{rscale},$hsh{ascale}); }
234 callseq => ['image', 'coef'],
236 callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}); }
241 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
242 defaults => { dist => 0 },
246 my @colors = @{$hsh{colors}};
249 i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist});
253 $filters{nearest_color} =
255 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
260 # make sure the segments are specified with colors
262 for my $color (@{$hsh{colors}}) {
263 my $new_color = _color($color)
264 or die $Imager::ERRSTR."\n";
265 push @colors, $new_color;
268 i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors,
270 or die Imager->_error_as_msg() . "\n";
273 $filters{gaussian} = {
274 callseq => [ 'image', 'stddev' ],
276 callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); },
280 callseq => [ qw(image size) ],
281 defaults => { size => 20 },
282 callsub => sub { my %hsh = @_; i_mosaic($hsh{image}, $hsh{size}) },
286 callseq => [ qw(image bump elevation lightx lighty st) ],
287 defaults => { elevation=>0, st=> 2 },
290 i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation},
291 $hsh{lightx}, $hsh{lighty}, $hsh{st});
294 $filters{bumpmap_complex} =
296 callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ],
307 Ia => Imager::Color->new(rgb=>[0,0,0]),
308 Il => Imager::Color->new(rgb=>[255,255,255]),
309 Is => Imager::Color->new(rgb=>[255,255,255]),
313 i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel},
314 $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz},
315 $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il},
319 $filters{postlevels} =
321 callseq => [ qw(image levels) ],
322 defaults => { levels => 10 },
323 callsub => sub { my %hsh = @_; i_postlevels($hsh{image}, $hsh{levels}); },
325 $filters{watermark} =
327 callseq => [ qw(image wmark tx ty pixdiff) ],
328 defaults => { pixdiff=>10, tx=>0, ty=>0 },
332 i_watermark($hsh{image}, $hsh{wmark}{IMG}, $hsh{tx}, $hsh{ty},
338 callseq => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ],
340 ftype => { linear => 0,
346 repeat => { none => 0,
361 multiply => 2, mult => 2,
364 subtract => 5, 'sub' => 5,
374 defaults => { ftype => 0, repeat => 0, combine => 0,
375 super_sample => 0, ssample_param => 4,
378 Imager::Color->new(0,0,0),
379 Imager::Color->new(255, 255, 255),
388 # make sure the segments are specified with colors
390 for my $segment (@{$hsh{segments}}) {
391 my @new_segment = @$segment;
393 $_ = _color($_) or die $Imager::ERRSTR."\n" for @new_segment[3,4];
394 push @segments, \@new_segment;
397 i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
398 $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
399 $hsh{ssample_param}, \@segments)
400 or die Imager->_error_as_msg() . "\n";
403 $filters{unsharpmask} =
405 callseq => [ qw(image stddev scale) ],
406 defaults => { stddev=>2.0, scale=>1.0 },
410 i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
414 $FORMATGUESS=\&def_guess_type;
424 # NOTE: this might be moved to an import override later on
428 # (look through @_ for special tags, process, and remove them);
430 # print Dumper($pack);
435 i_init_log($_[0],$_[1]);
436 i_log_entry("Imager $VERSION starting\n", 1);
441 my %parms=(loglevel=>1,@_);
443 init_log($parms{'log'},$parms{'loglevel'});
446 if (exists $parms{'warn_obsolete'}) {
447 $warn_obsolete = $parms{'warn_obsolete'};
450 # if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
451 # if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
455 if (exists $parms{'t1log'}) {
456 i_init_fonts($parms{'t1log'});
462 print "shutdown code\n";
463 # for(keys %instances) { $instances{$_}->DESTROY(); }
464 malloc_state(); # how do decide if this should be used? -- store something from the import
465 print "Imager exiting\n";
469 # Load a filter plugin
474 my ($DSO_handle,$str)=DSO_open($filename);
475 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
476 my %funcs=DSO_funclist($DSO_handle);
477 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
479 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
481 $DSOs{$filename}=[$DSO_handle,\%funcs];
484 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
485 $DEBUG && print "eval string:\n",$evstr,"\n";
497 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
498 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
499 for(keys %{$funcref}) {
501 $DEBUG && print "unloading: $_\n";
503 my $rc=DSO_close($DSO_handle);
504 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
508 # take the results of i_error() and make a message out of it
510 return join(": ", map $_->[0], i_errors());
513 # this function tries to DWIM for color parameters
514 # color objects are used as is
515 # simple scalars are simply treated as single parameters to Imager::Color->new
516 # hashrefs are treated as named argument lists to Imager::Color->new
517 # arrayrefs are treated as list arguments to Imager::Color->new iff any
519 # other arrayrefs are treated as list arguments to Imager::Color::Float
523 # perl 5.6.0 seems to do weird things to $arg if we don't make an
524 # explicitly stringified copy
525 # I vaguely remember a bug on this on p5p, but couldn't find it
526 # through bugs.perl.org (I had trouble getting it to find any bugs)
527 my $copy = $arg . "";
531 if (UNIVERSAL::isa($arg, "Imager::Color")
532 || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
536 if ($copy =~ /^HASH\(/) {
537 $result = Imager::Color->new(%$arg);
539 elsif ($copy =~ /^ARRAY\(/) {
540 $result = Imager::Color->new(@$arg);
543 $Imager::ERRSTR = "Not a color";
548 # assume Imager::Color::new knows how to handle it
549 $result = Imager::Color->new($arg);
558 $self->{IMG} and return 1;
560 $self->_set_error('empty input image');
566 # Methods to be called on objects.
569 # Create a new Imager object takes very few parameters.
570 # usually you call this method and then call open from
571 # the resulting object
578 $self->{IMG}=undef; # Just to indicate what exists
579 $self->{ERRSTR}=undef; #
580 $self->{DEBUG}=$DEBUG;
581 $self->{DEBUG} && print "Initialized Imager\n";
582 if (defined $hsh{xsize} && defined $hsh{ysize}) {
583 unless ($self->img_set(%hsh)) {
584 $Imager::ERRSTR = $self->{ERRSTR};
591 # Copy an entire image with no changes
592 # - if an image has magic the copy of it will not be magical
596 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
598 unless (defined wantarray) {
600 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
604 my $newcopy=Imager->new();
605 $newcopy->{IMG} = i_copy($self->{IMG});
614 unless ($self->{IMG}) {
615 $self->_set_error('empty input image');
618 my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_);
619 my $src = $input{img} || $input{src};
621 $self->_set_error("no source image");
624 $input{left}=0 if $input{left} <= 0;
625 $input{top}=0 if $input{top} <= 0;
627 my($r,$b)=i_img_info($src->{IMG});
628 my ($src_left, $src_top) = @input{qw/src_minx src_miny/};
629 my ($src_right, $src_bottom);
630 if ($input{src_coords}) {
631 ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}}
634 if (defined $input{src_maxx}) {
635 $src_right = $input{src_maxx};
637 elsif (defined $input{width}) {
638 if ($input{width} <= 0) {
639 $self->_set_error("paste: width must me positive");
642 $src_right = $src_left + $input{width};
647 if (defined $input{src_maxy}) {
648 $src_bottom = $input{src_maxy};
650 elsif (defined $input{height}) {
651 if ($input{height} < 0) {
652 $self->_set_error("paste: height must be positive");
655 $src_bottom = $src_top + $input{height};
662 $src_right > $r and $src_right = $r;
663 $src_bottom > $b and $src_bottom = $b;
665 if ($src_right <= $src_left
666 || $src_bottom < $src_top) {
667 $self->_set_error("nothing to paste");
671 i_copyto($self->{IMG}, $src->{IMG},
672 $src_left, $src_top, $src_right, $src_bottom,
673 $input{left}, $input{top});
675 return $self; # What should go here??
678 # Crop an image - i.e. return a new image that is smaller
682 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
684 unless (defined wantarray) {
686 warn "crop() called in void context - crop() returns the cropped image at $caller[1] line $caller[2]\n";
692 my ($w, $h, $l, $r, $b, $t) =
693 @hsh{qw(width height left right bottom top)};
695 # work through the various possibilities
700 elsif (!defined $r) {
701 $r = $self->getwidth;
713 $l = int(0.5+($self->getwidth()-$w)/2);
718 $r = $self->getwidth;
724 elsif (!defined $b) {
725 $b = $self->getheight;
737 $t=int(0.5+($self->getheight()-$h)/2);
742 $b = $self->getheight;
745 ($l,$r)=($r,$l) if $l>$r;
746 ($t,$b)=($b,$t) if $t>$b;
749 $r > $self->getwidth and $r = $self->getwidth;
751 $b > $self->getheight and $b = $self->getheight;
753 if ($l == $r || $t == $b) {
754 $self->_set_error("resulting image would have no content");
758 my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t);
760 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
765 my ($self, %opts) = @_;
767 $self->{IMG} or return $self->_set_error("Not a valid image");
769 my $x = $opts{xsize} || $self->getwidth;
770 my $y = $opts{ysize} || $self->getheight;
771 my $channels = $opts{channels} || $self->getchannels;
773 my $out = Imager->new;
774 if ($channels == $self->getchannels) {
775 $out->{IMG} = i_sametype($self->{IMG}, $x, $y);
778 $out->{IMG} = i_sametype_chans($self->{IMG}, $x, $y, $channels);
780 unless ($out->{IMG}) {
781 $self->{ERRSTR} = $self->_error_as_msg;
788 # Sets an image to a certain size and channel number
789 # if there was previously data in the image it is discarded
794 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
796 if (defined($self->{IMG})) {
797 # let IIM_DESTROY destroy it, it's possible this image is
798 # referenced from a virtual image (like masked)
799 #i_img_destroy($self->{IMG});
803 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
804 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
805 $hsh{maxcolors} || 256);
807 elsif ($hsh{bits} eq 'double') {
808 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
810 elsif ($hsh{bits} == 16) {
811 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
814 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
818 unless ($self->{IMG}) {
819 $self->{ERRSTR} = Imager->_error_as_msg();
826 # created a masked version of the current image
830 $self or return undef;
831 my %opts = (left => 0,
833 right => $self->getwidth,
834 bottom => $self->getheight,
836 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
838 my $result = Imager->new;
839 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
840 $opts{top}, $opts{right} - $opts{left},
841 $opts{bottom} - $opts{top});
842 # keep references to the mask and base images so they don't
844 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
849 # convert an RGB image into a paletted image
853 if (@_ != 1 && !ref $_[0]) {
860 unless (defined wantarray) {
862 warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n";
866 my $result = Imager->new;
867 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
869 #print "Type ", i_img_type($result->{IMG}), "\n";
871 if ($result->{IMG}) {
875 $self->{ERRSTR} = $self->_error_as_msg;
880 # convert a paletted (or any image) to an 8-bit/channel RGB images
885 unless (defined wantarray) {
887 warn "to_rgb8() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
892 $result = Imager->new;
893 $result->{IMG} = i_img_to_rgb($self->{IMG})
902 my %opts = (colors=>[], @_);
904 unless ($self->{IMG}) {
905 $self->_set_error("empty input image");
909 my @colors = @{$opts{colors}}
912 for my $color (@colors) {
913 $color = _color($color);
915 $self->_set_error($Imager::ERRSTR);
920 return i_addcolors($self->{IMG}, @colors);
925 my %opts = (start=>0, colors=>[], @_);
927 unless ($self->{IMG}) {
928 $self->_set_error("empty input image");
932 my @colors = @{$opts{colors}}
935 for my $color (@colors) {
936 $color = _color($color);
938 $self->_set_error($Imager::ERRSTR);
943 return i_setcolors($self->{IMG}, $opts{start}, @colors);
949 if (!exists $opts{start} && !exists $opts{count}) {
952 $opts{count} = $self->colorcount;
954 elsif (!exists $opts{count}) {
957 elsif (!exists $opts{start}) {
962 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
966 i_colorcount($_[0]{IMG});
970 i_maxcolors($_[0]{IMG});
976 $opts{color} or return undef;
978 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
983 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
984 if ($bits && $bits == length(pack("d", 1)) * 8) {
993 return i_img_type($self->{IMG}) ? "paletted" : "direct";
999 $self->{IMG} and i_img_virtual($self->{IMG});
1003 my ($self, %opts) = @_;
1005 $self->{IMG} or return;
1007 if (defined $opts{name}) {
1011 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
1012 push @result, (i_tags_get($self->{IMG}, $found))[1];
1015 return wantarray ? @result : $result[0];
1017 elsif (defined $opts{code}) {
1021 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
1022 push @result, (i_tags_get($self->{IMG}, $found))[1];
1029 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
1032 return i_tags_count($self->{IMG});
1041 return -1 unless $self->{IMG};
1043 if (defined $opts{value}) {
1044 if ($opts{value} =~ /^\d+$/) {
1046 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
1049 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
1052 elsif (defined $opts{data}) {
1053 # force addition as a string
1054 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
1057 $self->{ERRSTR} = "No value supplied";
1061 elsif ($opts{code}) {
1062 if (defined $opts{value}) {
1063 if ($opts{value} =~ /^\d+$/) {
1065 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
1068 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
1071 elsif (defined $opts{data}) {
1072 # force addition as a string
1073 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
1076 $self->{ERRSTR} = "No value supplied";
1089 return 0 unless $self->{IMG};
1091 if (defined $opts{'index'}) {
1092 return i_tags_delete($self->{IMG}, $opts{'index'});
1094 elsif (defined $opts{name}) {
1095 return i_tags_delbyname($self->{IMG}, $opts{name});
1097 elsif (defined $opts{code}) {
1098 return i_tags_delbycode($self->{IMG}, $opts{code});
1101 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
1107 my ($self, %opts) = @_;
1110 $self->deltag(name=>$opts{name});
1111 return $self->addtag(name=>$opts{name}, value=>$opts{value});
1113 elsif (defined $opts{code}) {
1114 $self->deltag(code=>$opts{code});
1115 return $self->addtag(code=>$opts{code}, value=>$opts{value});
1123 sub _get_reader_io {
1124 my ($self, $input) = @_;
1127 return $input->{io}, undef;
1129 elsif ($input->{fd}) {
1130 return io_new_fd($input->{fd});
1132 elsif ($input->{fh}) {
1133 my $fd = fileno($input->{fh});
1135 $self->_set_error("Handle in fh option not opened");
1138 return io_new_fd($fd);
1140 elsif ($input->{file}) {
1141 my $file = IO::File->new($input->{file}, "r");
1143 $self->_set_error("Could not open $input->{file}: $!");
1147 return (io_new_fd(fileno($file)), $file);
1149 elsif ($input->{data}) {
1150 return io_new_buffer($input->{data});
1152 elsif ($input->{callback} || $input->{readcb}) {
1153 if (!$input->{seekcb}) {
1154 $self->_set_error("Need a seekcb parameter");
1156 if ($input->{maxbuffer}) {
1157 return io_new_cb($input->{writecb},
1158 $input->{callback} || $input->{readcb},
1159 $input->{seekcb}, $input->{closecb},
1160 $input->{maxbuffer});
1163 return io_new_cb($input->{writecb},
1164 $input->{callback} || $input->{readcb},
1165 $input->{seekcb}, $input->{closecb});
1169 $self->_set_error("file/fd/fh/data/callback parameter missing");
1174 sub _get_writer_io {
1175 my ($self, $input, $type) = @_;
1178 return io_new_fd($input->{fd});
1180 elsif ($input->{fh}) {
1181 my $fd = fileno($input->{fh});
1183 $self->_set_error("Handle in fh option not opened");
1187 my $oldfh = select($input->{fh});
1188 # flush anything that's buffered, and make sure anything else is flushed
1191 return io_new_fd($fd);
1193 elsif ($input->{file}) {
1194 my $fh = new IO::File($input->{file},"w+");
1196 $self->_set_error("Could not open file $input->{file}: $!");
1199 binmode($fh) or die;
1200 return (io_new_fd(fileno($fh)), $fh);
1202 elsif ($input->{data}) {
1203 return io_new_bufchain();
1205 elsif ($input->{callback} || $input->{writecb}) {
1206 if ($input->{maxbuffer}) {
1207 return io_new_cb($input->{callback} || $input->{writecb},
1209 $input->{seekcb}, $input->{closecb},
1210 $input->{maxbuffer});
1213 return io_new_cb($input->{callback} || $input->{writecb},
1215 $input->{seekcb}, $input->{closecb});
1219 $self->_set_error("file/fd/fh/data/callback parameter missing");
1224 # Read an image from file
1230 if (defined($self->{IMG})) {
1231 # let IIM_DESTROY do the destruction, since the image may be
1232 # referenced from elsewhere
1233 #i_img_destroy($self->{IMG});
1234 undef($self->{IMG});
1237 my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
1239 unless ($input{'type'}) {
1240 $input{'type'} = i_test_format_probe($IO, -1);
1243 unless ($input{'type'}) {
1244 $self->_set_error('type parameter missing and not possible to guess from extension');
1248 _reader_autoload($input{type});
1250 if ($readers{$input{type}} && $readers{$input{type}}{single}) {
1251 return $readers{$input{type}}{single}->($self, $IO, %input);
1254 unless ($formats{$input{'type'}}) {
1255 $self->_set_error("format '$input{'type'}' not supported");
1260 if ( $input{'type'} eq 'jpeg' ) {
1261 ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
1262 if ( !defined($self->{IMG}) ) {
1263 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1265 $self->{DEBUG} && print "loading a jpeg file\n";
1269 if ( $input{'type'} eq 'tiff' ) {
1270 my $page = $input{'page'};
1271 defined $page or $page = 0;
1272 # Fixme, check if that length parameter is ever needed
1273 $self->{IMG}=i_readtiff_wiol( $IO, -1, $page );
1274 if ( !defined($self->{IMG}) ) {
1275 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1277 $self->{DEBUG} && print "loading a tiff file\n";
1281 if ( $input{'type'} eq 'pnm' ) {
1282 $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1283 if ( !defined($self->{IMG}) ) {
1284 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg();
1287 $self->{DEBUG} && print "loading a pnm file\n";
1291 if ( $input{'type'} eq 'png' ) {
1292 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1293 if ( !defined($self->{IMG}) ) {
1294 $self->{ERRSTR} = $self->_error_as_msg();
1297 $self->{DEBUG} && print "loading a png file\n";
1300 if ( $input{'type'} eq 'bmp' ) {
1301 $self->{IMG}=i_readbmp_wiol( $IO );
1302 if ( !defined($self->{IMG}) ) {
1303 $self->{ERRSTR}=$self->_error_as_msg();
1306 $self->{DEBUG} && print "loading a bmp file\n";
1309 if ( $input{'type'} eq 'gif' ) {
1310 if ($input{colors} && !ref($input{colors})) {
1311 # must be a reference to a scalar that accepts the colour map
1312 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1315 if ($input{'gif_consolidate'}) {
1316 if ($input{colors}) {
1318 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1320 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1324 $self->{IMG} =i_readgif_wiol( $IO );
1328 my $page = $input{'page'};
1329 defined $page or $page = 0;
1330 $self->{IMG} = i_readgif_single_wiol( $IO, $page );
1331 if ($input{colors}) {
1332 ${ $input{colors} } =
1333 [ i_getcolors($self->{IMG}, 0, i_colorcount($self->{IMG})) ];
1337 if ( !defined($self->{IMG}) ) {
1338 $self->{ERRSTR}=$self->_error_as_msg();
1341 $self->{DEBUG} && print "loading a gif file\n";
1344 if ( $input{'type'} eq 'tga' ) {
1345 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1346 if ( !defined($self->{IMG}) ) {
1347 $self->{ERRSTR}=$self->_error_as_msg();
1350 $self->{DEBUG} && print "loading a tga file\n";
1353 if ( $input{'type'} eq 'rgb' ) {
1354 $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1355 if ( !defined($self->{IMG}) ) {
1356 $self->{ERRSTR}=$self->_error_as_msg();
1359 $self->{DEBUG} && print "loading a tga file\n";
1363 if ( $input{'type'} eq 'raw' ) {
1364 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1366 if ( !($params{xsize} && $params{ysize}) ) {
1367 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1371 $self->{IMG} = i_readraw_wiol( $IO,
1374 $params{datachannels},
1375 $params{storechannels},
1376 $params{interleave});
1377 if ( !defined($self->{IMG}) ) {
1378 $self->{ERRSTR}=$self->_error_as_msg();
1381 $self->{DEBUG} && print "loading a raw file\n";
1387 sub register_reader {
1388 my ($class, %opts) = @_;
1391 or die "register_reader called with no type parameter\n";
1393 my $type = $opts{type};
1395 defined $opts{single} || defined $opts{multiple}
1396 or die "register_reader called with no single or multiple parameter\n";
1398 $readers{$type} = { };
1399 if ($opts{single}) {
1400 $readers{$type}{single} = $opts{single};
1402 if ($opts{multiple}) {
1403 $readers{$type}{multiple} = $opts{multiple};
1409 sub register_writer {
1410 my ($class, %opts) = @_;
1413 or die "register_writer called with no type parameter\n";
1415 my $type = $opts{type};
1417 defined $opts{single} || defined $opts{multiple}
1418 or die "register_writer called with no single or multiple parameter\n";
1420 $writers{$type} = { };
1421 if ($opts{single}) {
1422 $writers{$type}{single} = $opts{single};
1424 if ($opts{multiple}) {
1425 $writers{$type}{multiple} = $opts{multiple};
1431 # probes for an Imager::File::whatever module
1432 sub _reader_autoload {
1435 return if $formats{$type} || $readers{$type};
1437 return unless $type =~ /^\w+$/;
1439 my $file = "Imager/File/\U$type\E.pm";
1441 unless ($attempted_to_load{$file}) {
1443 ++$attempted_to_load{$file};
1447 # try to get a reader specific module
1448 my $file = "Imager/File/\U$type\EReader.pm";
1449 unless ($attempted_to_load{$file}) {
1451 ++$attempted_to_load{$file};
1459 # probes for an Imager::File::whatever module
1460 sub _writer_autoload {
1463 return if $formats{$type} || $readers{$type};
1465 return unless $type =~ /^\w+$/;
1467 my $file = "Imager/File/\U$type\E.pm";
1469 unless ($attempted_to_load{$file}) {
1471 ++$attempted_to_load{$file};
1475 # try to get a writer specific module
1476 my $file = "Imager/File/\U$type\EWriter.pm";
1477 unless ($attempted_to_load{$file}) {
1479 ++$attempted_to_load{$file};
1487 sub _fix_gif_positions {
1488 my ($opts, $opt, $msg, @imgs) = @_;
1490 my $positions = $opts->{'gif_positions'};
1492 for my $pos (@$positions) {
1493 my ($x, $y) = @$pos;
1494 my $img = $imgs[$index++];
1495 $img->settag(name=>'gif_left', value=>$x);
1496 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1498 $$msg .= "replaced with the gif_left and gif_top tags";
1503 gif_each_palette=>'gif_local_map',
1504 interlace => 'gif_interlace',
1505 gif_delays => 'gif_delay',
1506 gif_positions => \&_fix_gif_positions,
1507 gif_loop_count => 'gif_loop',
1511 my ($self, $opts, $prefix, @imgs) = @_;
1513 for my $opt (keys %$opts) {
1515 if ($obsolete_opts{$opt}) {
1516 my $new = $obsolete_opts{$opt};
1517 my $msg = "Obsolete option $opt ";
1519 $new->($opts, $opt, \$msg, @imgs);
1522 $msg .= "replaced with the $new tag ";
1525 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1526 warn $msg if $warn_obsolete && $^W;
1528 next unless $tagname =~ /^\Q$prefix/;
1529 my $value = $opts->{$opt};
1531 if (UNIVERSAL::isa($value, "Imager::Color")) {
1532 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1533 for my $img (@imgs) {
1534 $img->settag(name=>$tagname, value=>$tag);
1537 elsif (ref($value) eq 'ARRAY') {
1538 for my $i (0..$#$value) {
1539 my $val = $value->[$i];
1541 if (UNIVERSAL::isa($val, "Imager::Color")) {
1542 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1544 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1547 $self->_set_error("Unknown reference type " . ref($value) .
1548 " supplied in array for $opt");
1554 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1559 $self->_set_error("Unknown reference type " . ref($value) .
1560 " supplied for $opt");
1565 # set it as a tag for every image
1566 for my $img (@imgs) {
1567 $img->settag(name=>$tagname, value=>$value);
1575 # Write an image to file
1578 my %input=(jpegquality=>75,
1588 $self->_set_opts(\%input, "i_", $self)
1591 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1593 if (!$input{'type'} and $input{file}) {
1594 $input{'type'}=$FORMATGUESS->($input{file});
1596 if (!$input{'type'}) {
1597 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1601 _writer_autoload($input{type});
1604 if ($writers{$input{type}} && $writers{$input{type}}{single}) {
1605 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1608 $writers{$input{type}}{single}->($self, $IO, %input)
1612 if (!$formats{$input{'type'}}) {
1613 $self->{ERRSTR}='format not supported';
1617 ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1620 if ($input{'type'} eq 'tiff') {
1621 $self->_set_opts(\%input, "tiff_", $self)
1623 $self->_set_opts(\%input, "exif_", $self)
1626 if (defined $input{class} && $input{class} eq 'fax') {
1627 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1628 $self->{ERRSTR} = $self->_error_as_msg();
1632 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1633 $self->{ERRSTR} = $self->_error_as_msg();
1637 } elsif ( $input{'type'} eq 'pnm' ) {
1638 $self->_set_opts(\%input, "pnm_", $self)
1640 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1641 $self->{ERRSTR} = $self->_error_as_msg();
1644 $self->{DEBUG} && print "writing a pnm file\n";
1645 } elsif ( $input{'type'} eq 'raw' ) {
1646 $self->_set_opts(\%input, "raw_", $self)
1648 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1649 $self->{ERRSTR} = $self->_error_as_msg();
1652 $self->{DEBUG} && print "writing a raw file\n";
1653 } elsif ( $input{'type'} eq 'png' ) {
1654 $self->_set_opts(\%input, "png_", $self)
1656 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1657 $self->{ERRSTR}='unable to write png image';
1660 $self->{DEBUG} && print "writing a png file\n";
1661 } elsif ( $input{'type'} eq 'jpeg' ) {
1662 $self->_set_opts(\%input, "jpeg_", $self)
1664 $self->_set_opts(\%input, "exif_", $self)
1666 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1667 $self->{ERRSTR} = $self->_error_as_msg();
1670 $self->{DEBUG} && print "writing a jpeg file\n";
1671 } elsif ( $input{'type'} eq 'bmp' ) {
1672 $self->_set_opts(\%input, "bmp_", $self)
1674 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1675 $self->{ERRSTR}='unable to write bmp image';
1678 $self->{DEBUG} && print "writing a bmp file\n";
1679 } elsif ( $input{'type'} eq 'tga' ) {
1680 $self->_set_opts(\%input, "tga_", $self)
1683 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1684 $self->{ERRSTR}=$self->_error_as_msg();
1687 $self->{DEBUG} && print "writing a tga file\n";
1688 } elsif ( $input{'type'} eq 'gif' ) {
1689 $self->_set_opts(\%input, "gif_", $self)
1691 # compatibility with the old interfaces
1692 if ($input{gifquant} eq 'lm') {
1693 $input{make_colors} = 'addi';
1694 $input{translate} = 'perturb';
1695 $input{perturb} = $input{lmdither};
1696 } elsif ($input{gifquant} eq 'gen') {
1697 # just pass options through
1699 $input{make_colors} = 'webmap'; # ignored
1700 $input{translate} = 'giflib';
1702 if (!i_writegif_wiol($IO, \%input, $self->{IMG})) {
1703 $self->{ERRSTR} = $self->_error_as_msg;
1709 if (exists $input{'data'}) {
1710 my $data = io_slurp($IO);
1712 $self->{ERRSTR}='Could not slurp from buffer';
1715 ${$input{data}} = $data;
1721 my ($class, $opts, @images) = @_;
1723 my $type = $opts->{type};
1725 if (!$type && $opts->{'file'}) {
1726 $type = $FORMATGUESS->($opts->{'file'});
1729 $class->_set_error('type parameter missing and not possible to guess from extension');
1732 # translate to ImgRaw
1733 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1734 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1737 $class->_set_opts($opts, "i_", @images)
1739 my @work = map $_->{IMG}, @images;
1741 _writer_autoload($type);
1744 if ($writers{$type} && $writers{$type}{multiple}) {
1745 ($IO, $file) = $class->_get_writer_io($opts, $type)
1748 $writers{$type}{multiple}->($class, $IO, $opts, @images)
1752 if (!$formats{$type}) {
1753 $class->_set_error("format $type not supported");
1757 ($IO, $file) = $class->_get_writer_io($opts, $type)
1760 if ($type eq 'gif') {
1761 $class->_set_opts($opts, "gif_", @images)
1763 my $gif_delays = $opts->{gif_delays};
1764 local $opts->{gif_delays} = $gif_delays;
1765 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1766 # assume the caller wants the same delay for each frame
1767 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1769 unless (i_writegif_wiol($IO, $opts, @work)) {
1770 $class->_set_error($class->_error_as_msg());
1774 elsif ($type eq 'tiff') {
1775 $class->_set_opts($opts, "tiff_", @images)
1777 $class->_set_opts($opts, "exif_", @images)
1780 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1781 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1782 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1785 $res = i_writetiff_multi_wiol($IO, @work);
1788 $class->_set_error($class->_error_as_msg());
1793 $ERRSTR = "Sorry, write_multi doesn't support $type yet";
1798 if (exists $opts->{'data'}) {
1799 my $data = io_slurp($IO);
1801 Imager->_set_error('Could not slurp from buffer');
1804 ${$opts->{data}} = $data;
1809 # read multiple images from a file
1811 my ($class, %opts) = @_;
1813 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1816 my $type = $opts{'type'};
1818 $type = i_test_format_probe($IO, -1);
1821 if ($opts{file} && !$type) {
1823 $type = $FORMATGUESS->($opts{file});
1827 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1831 _reader_autoload($type);
1833 if ($readers{$type} && $readers{$type}{multiple}) {
1834 return $readers{$type}{multiple}->($IO, %opts);
1837 if ($type eq 'gif') {
1839 @imgs = i_readgif_multi_wiol($IO);
1842 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1846 $ERRSTR = _error_as_msg();
1850 elsif ($type eq 'tiff') {
1851 my @imgs = i_readtiff_multi_wiol($IO, -1);
1854 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1858 $ERRSTR = _error_as_msg();
1863 $ERRSTR = "Cannot read multiple images from $type files";
1867 # Destroy an Imager object
1871 # delete $instances{$self};
1872 if (defined($self->{IMG})) {
1873 # the following is now handled by the XS DESTROY method for
1874 # Imager::ImgRaw object
1875 # Re-enabling this will break virtual images
1876 # tested for in t/t020masked.t
1877 # i_img_destroy($self->{IMG});
1878 undef($self->{IMG});
1880 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1884 # Perform an inplace filter of an image
1885 # that is the image will be overwritten with the data
1891 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1893 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1895 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1896 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1899 if ($filters{$input{'type'}}{names}) {
1900 my $names = $filters{$input{'type'}}{names};
1901 for my $name (keys %$names) {
1902 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1903 $input{$name} = $names->{$name}{$input{$name}};
1907 if (defined($filters{$input{'type'}}{defaults})) {
1908 %hsh=( image => $self->{IMG},
1910 %{$filters{$input{'type'}}{defaults}},
1913 %hsh=( image => $self->{IMG},
1918 my @cs=@{$filters{$input{'type'}}{callseq}};
1921 if (!defined($hsh{$_})) {
1922 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1927 local $SIG{__DIE__}; # we don't want this processed by confess, etc
1928 &{$filters{$input{'type'}}{callsub}}(%hsh);
1931 chomp($self->{ERRSTR} = $@);
1937 $self->{DEBUG} && print "callseq is: @cs\n";
1938 $self->{DEBUG} && print "matching callseq is: @b\n";
1943 sub register_filter {
1945 my %hsh = ( defaults => {}, @_ );
1948 or die "register_filter() with no type\n";
1949 defined $hsh{callsub}
1950 or die "register_filter() with no callsub\n";
1951 defined $hsh{callseq}
1952 or die "register_filter() with no callseq\n";
1954 exists $filters{$hsh{type}}
1957 $filters{$hsh{type}} = \%hsh;
1962 # Scale an image to requested size and return the scaled version
1966 my %opts=('type'=>'max',qtype=>'normal',@_);
1967 my $img = Imager->new();
1968 my $tmp = Imager->new();
1969 my ($x_scale, $y_scale);
1971 unless (defined wantarray) {
1972 my @caller = caller;
1973 warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
1977 unless ($self->{IMG}) {
1978 $self->_set_error('empty input image');
1982 if ($opts{'xscalefactor'} && $opts{'yscalefactor'}) {
1983 $x_scale = $opts{'xscalefactor'};
1984 $y_scale = $opts{'yscalefactor'};
1986 elsif ($opts{'xscalefactor'}) {
1987 $x_scale = $opts{'xscalefactor'};
1988 $y_scale = $opts{'scalefactor'} || $x_scale;
1990 elsif ($opts{'yscalefactor'}) {
1991 $y_scale = $opts{'yscalefactor'};
1992 $x_scale = $opts{'scalefactor'} || $y_scale;
1995 $x_scale = $y_scale = $opts{'scalefactor'} || 0.5;
1998 # work out the scaling
1999 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
2000 my ($xpix, $ypix)=( $opts{xpixels} / $self->getwidth() ,
2001 $opts{ypixels} / $self->getheight() );
2002 if ($opts{'type'} eq 'min') {
2003 $x_scale = $y_scale = _min($xpix,$ypix);
2005 elsif ($opts{'type'} eq 'max') {
2006 $x_scale = $y_scale = _max($xpix,$ypix);
2008 elsif ($opts{'type'} eq 'nonprop' || $opts{'type'} eq 'non-proportional') {
2013 $self->_set_error('invalid value for type parameter');
2016 } elsif ($opts{xpixels}) {
2017 $x_scale = $y_scale = $opts{xpixels} / $self->getwidth();
2019 elsif ($opts{ypixels}) {
2020 $x_scale = $y_scale = $opts{ypixels}/$self->getheight();
2022 elsif ($opts{constrain} && ref $opts{constrain}
2023 && $opts{constrain}->can('constrain')) {
2024 # we've been passed an Image::Math::Constrain object or something
2025 # that looks like one
2027 (undef, undef, $scalefactor)
2028 = $opts{constrain}->constrain($self->getwidth, $self->getheight);
2029 unless ($scalefactor) {
2030 $self->_set_error('constrain method failed on constrain parameter');
2033 $x_scale = $y_scale = $scalefactor;
2036 if ($opts{qtype} eq 'normal') {
2037 $tmp->{IMG} = i_scaleaxis($self->{IMG}, $x_scale, 0);
2038 if ( !defined($tmp->{IMG}) ) {
2039 $self->{ERRSTR} = 'unable to scale image';
2042 $img->{IMG}=i_scaleaxis($tmp->{IMG}, $y_scale, 1);
2043 if ( !defined($img->{IMG}) ) {
2044 $self->{ERRSTR}='unable to scale image';
2050 elsif ($opts{'qtype'} eq 'preview') {
2051 $img->{IMG} = i_scale_nn($self->{IMG}, $x_scale, $y_scale);
2052 if ( !defined($img->{IMG}) ) {
2053 $self->{ERRSTR}='unable to scale image';
2058 elsif ($opts{'qtype'} eq 'mixing') {
2059 my $new_width = int(0.5 + $self->getwidth * $x_scale);
2060 my $new_height = int(0.5 + $self->getheight * $y_scale);
2061 $new_width >= 1 or $new_width = 1;
2062 $new_height >= 1 or $new_height = 1;
2063 $img->{IMG} = i_scale_mixing($self->{IMG}, $new_width, $new_height);
2064 unless ($img->{IMG}) {
2065 $self->_set_error(Imager->_error_as_meg);
2071 $self->_set_error('invalid value for qtype parameter');
2076 # Scales only along the X axis
2080 my %opts = ( scalefactor=>0.5, @_ );
2082 unless (defined wantarray) {
2083 my @caller = caller;
2084 warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
2088 unless ($self->{IMG}) {
2089 $self->{ERRSTR} = 'empty input image';
2093 my $img = Imager->new();
2095 my $scalefactor = $opts{scalefactor};
2097 if ($opts{pixels}) {
2098 $scalefactor = $opts{pixels} / $self->getwidth();
2101 unless ($self->{IMG}) {
2102 $self->{ERRSTR}='empty input image';
2106 $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
2108 if ( !defined($img->{IMG}) ) {
2109 $self->{ERRSTR} = 'unable to scale image';
2116 # Scales only along the Y axis
2120 my %opts = ( scalefactor => 0.5, @_ );
2122 unless (defined wantarray) {
2123 my @caller = caller;
2124 warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
2128 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2130 my $img = Imager->new();
2132 my $scalefactor = $opts{scalefactor};
2134 if ($opts{pixels}) {
2135 $scalefactor = $opts{pixels} / $self->getheight();
2138 unless ($self->{IMG}) {
2139 $self->{ERRSTR} = 'empty input image';
2142 $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
2144 if ( !defined($img->{IMG}) ) {
2145 $self->{ERRSTR} = 'unable to scale image';
2152 # Transform returns a spatial transformation of the input image
2153 # this moves pixels to a new location in the returned image.
2154 # NOTE - should make a utility function to check transforms for
2159 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2161 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
2163 # print Dumper(\%opts);
2166 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
2168 eval ("use Affix::Infix2Postfix;");
2171 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
2174 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
2175 {op=>'-',trans=>'Sub'},
2176 {op=>'*',trans=>'Mult'},
2177 {op=>'/',trans=>'Div'},
2178 {op=>'-','type'=>'unary',trans=>'u-'},
2180 {op=>'func','type'=>'unary'}],
2181 'grouping'=>[qw( \( \) )],
2182 'func'=>[qw( sin cos )],
2187 @xt=$I2P->translate($opts{'xexpr'});
2188 @yt=$I2P->translate($opts{'yexpr'});
2190 $numre=$I2P->{'numre'};
2193 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
2194 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
2195 @{$opts{'parm'}}=@pt;
2198 # print Dumper(\%opts);
2200 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
2201 $self->{ERRSTR}='transform: no xopcodes given.';
2205 @op=@{$opts{'xopcodes'}};
2207 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2208 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2211 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2217 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
2218 $self->{ERRSTR}='transform: no yopcodes given.';
2222 @op=@{$opts{'yopcodes'}};
2224 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
2225 $self->{ERRSTR}="transform: illegal opcode '$_'.";
2228 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
2233 if ( !exists $opts{'parm'}) {
2234 $self->{ERRSTR}='transform: no parameter arg given.';
2238 # print Dumper(\@ropx);
2239 # print Dumper(\@ropy);
2240 # print Dumper(\@ropy);
2242 my $img = Imager->new();
2243 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
2244 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
2250 my ($opts, @imgs) = @_;
2252 require "Imager/Expr.pm";
2254 $opts->{variables} = [ qw(x y) ];
2255 my ($width, $height) = @{$opts}{qw(width height)};
2257 $width ||= $imgs[0]->getwidth();
2258 $height ||= $imgs[0]->getheight();
2260 for my $img (@imgs) {
2261 $opts->{constants}{"w$img_num"} = $img->getwidth();
2262 $opts->{constants}{"h$img_num"} = $img->getheight();
2263 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
2264 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
2269 $opts->{constants}{w} = $width;
2270 $opts->{constants}{cx} = $width/2;
2273 $Imager::ERRSTR = "No width supplied";
2277 $opts->{constants}{h} = $height;
2278 $opts->{constants}{cy} = $height/2;
2281 $Imager::ERRSTR = "No height supplied";
2284 my $code = Imager::Expr->new($opts);
2286 $Imager::ERRSTR = Imager::Expr::error();
2289 my $channels = $opts->{channels} || 3;
2290 unless ($channels >= 1 && $channels <= 4) {
2291 return Imager->_set_error("channels must be an integer between 1 and 4");
2294 my $img = Imager->new();
2295 $img->{IMG} = i_transform2($opts->{width}, $opts->{height},
2296 $channels, $code->code(),
2297 $code->nregs(), $code->cregs(),
2298 [ map { $_->{IMG} } @imgs ]);
2299 if (!defined $img->{IMG}) {
2300 $Imager::ERRSTR = Imager->_error_as_msg();
2309 my %opts=(tx => 0,ty => 0, @_);
2311 unless ($self->{IMG}) {
2312 $self->{ERRSTR}='empty input image';
2315 unless ($opts{src} && $opts{src}->{IMG}) {
2316 $self->{ERRSTR}='empty input image for src';
2320 %opts = (src_minx => 0,
2322 src_maxx => $opts{src}->getwidth(),
2323 src_maxy => $opts{src}->getheight(),
2326 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
2327 $opts{src_minx}, $opts{src_miny},
2328 $opts{src_maxx}, $opts{src_maxy})) {
2329 $self->_set_error($self->_error_as_msg());
2339 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
2341 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
2342 $dir = $xlate{$opts{'dir'}};
2343 return $self if i_flipxy($self->{IMG}, $dir);
2351 unless (defined wantarray) {
2352 my @caller = caller;
2353 warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
2357 if (defined $opts{right}) {
2358 my $degrees = $opts{right};
2360 $degrees += 360 * int(((-$degrees)+360)/360);
2362 $degrees = $degrees % 360;
2363 if ($degrees == 0) {
2364 return $self->copy();
2366 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
2367 my $result = Imager->new();
2368 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
2372 $self->{ERRSTR} = $self->_error_as_msg();
2377 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
2381 elsif (defined $opts{radians} || defined $opts{degrees}) {
2382 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
2384 my $back = $opts{back};
2385 my $result = Imager->new;
2387 $back = _color($back);
2389 $self->_set_error(Imager->errstr);
2393 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
2396 $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
2398 if ($result->{IMG}) {
2402 $self->{ERRSTR} = $self->_error_as_msg();
2407 $self->{ERRSTR} = "Only the 'right', 'radians' and 'degrees' parameters are available";
2412 sub matrix_transform {
2416 unless (defined wantarray) {
2417 my @caller = caller;
2418 warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
2422 if ($opts{matrix}) {
2423 my $xsize = $opts{xsize} || $self->getwidth;
2424 my $ysize = $opts{ysize} || $self->getheight;
2426 my $result = Imager->new;
2428 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2429 $opts{matrix}, $opts{back})
2433 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
2441 $self->{ERRSTR} = "matrix parameter required";
2447 *yatf = \&matrix_transform;
2449 # These two are supported for legacy code only
2452 return Imager::Color->new(@_);
2456 return Imager::Color::set(@_);
2459 # Draws a box between the specified corner points.
2462 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2463 my $dflcl=i_color_new(255,255,255,255);
2464 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
2466 if (exists $opts{'box'}) {
2467 $opts{'xmin'} = _min($opts{'box'}->[0],$opts{'box'}->[2]);
2468 $opts{'xmax'} = _max($opts{'box'}->[0],$opts{'box'}->[2]);
2469 $opts{'ymin'} = _min($opts{'box'}->[1],$opts{'box'}->[3]);
2470 $opts{'ymax'} = _max($opts{'box'}->[1],$opts{'box'}->[3]);
2473 if ($opts{filled}) {
2474 my $color = _color($opts{'color'});
2476 $self->{ERRSTR} = $Imager::ERRSTR;
2479 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2480 $opts{ymax}, $color);
2482 elsif ($opts{fill}) {
2483 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2484 # assume it's a hash ref
2485 require 'Imager/Fill.pm';
2486 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2487 $self->{ERRSTR} = $Imager::ERRSTR;
2491 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
2492 $opts{ymax},$opts{fill}{fill});
2495 my $color = _color($opts{'color'});
2497 $self->{ERRSTR} = $Imager::ERRSTR;
2500 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
2508 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2509 my $dflcl=i_color_new(255,255,255,255);
2510 my %opts=(color=>$dflcl,
2511 'r'=>_min($self->getwidth(),$self->getheight())/3,
2512 'x'=>$self->getwidth()/2,
2513 'y'=>$self->getheight()/2,
2514 'd1'=>0, 'd2'=>361, @_);
2517 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2518 # assume it's a hash ref
2519 require 'Imager/Fill.pm';
2520 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2521 $self->{ERRSTR} = $Imager::ERRSTR;
2525 i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2526 $opts{'d2'}, $opts{fill}{fill});
2529 my $color = _color($opts{'color'});
2531 $self->{ERRSTR} = $Imager::ERRSTR;
2534 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
2535 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
2539 i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2540 $opts{'d1'}, $opts{'d2'}, $color);
2546 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2547 # assume it's a hash ref
2548 require 'Imager/Fill.pm';
2549 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2550 $self->{ERRSTR} = $Imager::ERRSTR;
2554 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
2555 $opts{'d2'}, $opts{fill}{fill});
2558 my $color = _color($opts{'color'});
2560 $self->{ERRSTR} = $Imager::ERRSTR;
2563 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2564 $opts{'d1'}, $opts{'d2'}, $color);
2571 # Draws a line from one point to the other
2572 # the endpoint is set if the endp parameter is set which it is by default.
2573 # to turn of the endpoint being set use endp=>0 when calling line.
2577 my $dflcl=i_color_new(0,0,0,0);
2578 my %opts=(color=>$dflcl,
2581 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2583 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2584 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2586 my $color = _color($opts{'color'});
2588 $self->{ERRSTR} = $Imager::ERRSTR;
2592 $opts{antialias} = $opts{aa} if defined $opts{aa};
2593 if ($opts{antialias}) {
2594 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2595 $color, $opts{endp});
2597 i_line($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2598 $color, $opts{endp});
2603 # Draws a line between an ordered set of points - It more or less just transforms this
2604 # into a list of lines.
2608 my ($pt,$ls,@points);
2609 my $dflcl=i_color_new(0,0,0,0);
2610 my %opts=(color=>$dflcl,@_);
2612 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2614 if (exists($opts{points})) { @points=@{$opts{points}}; }
2615 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2616 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2619 # print Dumper(\@points);
2621 my $color = _color($opts{'color'});
2623 $self->{ERRSTR} = $Imager::ERRSTR;
2626 $opts{antialias} = $opts{aa} if defined $opts{aa};
2627 if ($opts{antialias}) {
2630 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color, 1);
2637 i_line($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color,1);
2647 my ($pt,$ls,@points);
2648 my $dflcl = i_color_new(0,0,0,0);
2649 my %opts = (color=>$dflcl, @_);
2651 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2653 if (exists($opts{points})) {
2654 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2655 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2658 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2659 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2662 if ($opts{'fill'}) {
2663 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2664 # assume it's a hash ref
2665 require 'Imager/Fill.pm';
2666 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2667 $self->{ERRSTR} = $Imager::ERRSTR;
2671 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2672 $opts{'fill'}{'fill'});
2675 my $color = _color($opts{'color'});
2677 $self->{ERRSTR} = $Imager::ERRSTR;
2680 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2687 # this the multipoint bezier curve
2688 # this is here more for testing that actual usage since
2689 # this is not a good algorithm. Usually the curve would be
2690 # broken into smaller segments and each done individually.
2694 my ($pt,$ls,@points);
2695 my $dflcl=i_color_new(0,0,0,0);
2696 my %opts=(color=>$dflcl,@_);
2698 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2700 if (exists $opts{points}) {
2701 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2702 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2705 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2706 $self->{ERRSTR}='Missing or invalid points.';
2710 my $color = _color($opts{'color'});
2712 $self->{ERRSTR} = $Imager::ERRSTR;
2715 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2721 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2724 unless (exists $opts{'x'} && exists $opts{'y'}) {
2725 $self->{ERRSTR} = "missing seed x and y parameters";
2729 if ($opts{border}) {
2730 my $border = _color($opts{border});
2732 $self->_set_error($Imager::ERRSTR);
2736 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2737 # assume it's a hash ref
2738 require Imager::Fill;
2739 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2740 $self->{ERRSTR} = $Imager::ERRSTR;
2744 $rc = i_flood_cfill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2745 $opts{fill}{fill}, $border);
2748 my $color = _color($opts{'color'});
2750 $self->{ERRSTR} = $Imager::ERRSTR;
2753 $rc = i_flood_fill_border($self->{IMG}, $opts{'x'}, $opts{'y'},
2760 $self->{ERRSTR} = $self->_error_as_msg();
2766 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2767 # assume it's a hash ref
2768 require 'Imager/Fill.pm';
2769 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2770 $self->{ERRSTR} = $Imager::ERRSTR;
2774 $rc = i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2777 my $color = _color($opts{'color'});
2779 $self->{ERRSTR} = $Imager::ERRSTR;
2782 $rc = i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2788 $self->{ERRSTR} = $self->_error_as_msg();
2797 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2799 unless (exists $opts{'x'} && exists $opts{'y'}) {
2800 $self->{ERRSTR} = 'missing x and y parameters';
2806 my $color = _color($opts{color})
2808 if (ref $x && ref $y) {
2809 unless (@$x == @$y) {
2810 $self->{ERRSTR} = 'length of x and y mismatch';
2813 if ($color->isa('Imager::Color')) {
2814 for my $i (0..$#{$opts{'x'}}) {
2815 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color);
2819 for my $i (0..$#{$opts{'x'}}) {
2820 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color);
2825 if ($color->isa('Imager::Color')) {
2826 i_ppix($self->{IMG}, $x, $y, $color);
2829 i_ppixf($self->{IMG}, $x, $y, $color);
2839 my %opts = ( "type"=>'8bit', @_);
2841 unless (exists $opts{'x'} && exists $opts{'y'}) {
2842 $self->{ERRSTR} = 'missing x and y parameters';
2848 if (ref $x && ref $y) {
2849 unless (@$x == @$y) {
2850 $self->{ERRSTR} = 'length of x and y mismatch';
2854 if ($opts{"type"} eq '8bit') {
2855 for my $i (0..$#{$opts{'x'}}) {
2856 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2860 for my $i (0..$#{$opts{'x'}}) {
2861 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2864 return wantarray ? @result : \@result;
2867 if ($opts{"type"} eq '8bit') {
2868 return i_get_pixel($self->{IMG}, $x, $y);
2871 return i_gpixf($self->{IMG}, $x, $y);
2880 my %opts = ( type => '8bit', x=>0, @_);
2882 $self->_valid_image or return;
2884 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2886 unless (defined $opts{'y'}) {
2887 $self->_set_error("missing y parameter");
2891 if ($opts{type} eq '8bit') {
2892 return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2895 elsif ($opts{type} eq 'float') {
2896 return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2899 elsif ($opts{type} eq 'index') {
2900 unless (i_img_type($self->{IMG})) {
2901 $self->_set_error("type => index only valid on paletted images");
2904 return i_gpal($self->{IMG}, $opts{x}, $opts{x} + $opts{width},
2908 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2915 my %opts = ( x=>0, @_);
2917 $self->_valid_image or return;
2919 unless (defined $opts{'y'}) {
2920 $self->_set_error("missing y parameter");
2925 if (ref $opts{pixels} && @{$opts{pixels}}) {
2926 # try to guess the type
2927 if ($opts{pixels}[0]->isa('Imager::Color')) {
2928 $opts{type} = '8bit';
2930 elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
2931 $opts{type} = 'float';
2934 $self->_set_error("missing type parameter and could not guess from pixels");
2940 $opts{type} = '8bit';
2944 if ($opts{type} eq '8bit') {
2945 if (ref $opts{pixels}) {
2946 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2949 return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2952 elsif ($opts{type} eq 'float') {
2953 if (ref $opts{pixels}) {
2954 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2957 return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2960 elsif ($opts{type} eq 'index') {
2961 if (ref $opts{pixels}) {
2962 return i_ppal($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
2965 return i_ppal_p($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
2969 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
2976 my %opts = ( type => '8bit', x=>0, @_);
2978 defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
2980 unless (defined $opts{'y'}) {
2981 $self->_set_error("missing y parameter");
2985 unless ($opts{channels}) {
2986 $opts{channels} = [ 0 .. $self->getchannels()-1 ];
2989 if ($opts{type} eq '8bit') {
2990 return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2991 $opts{y}, @{$opts{channels}});
2993 elsif ($opts{type} eq 'float') {
2994 return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
2995 $opts{y}, @{$opts{channels}});
2998 $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
3003 # make an identity matrix of the given size
3007 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
3008 for my $c (0 .. ($size-1)) {
3009 $matrix->[$c][$c] = 1;
3014 # general function to convert an image
3016 my ($self, %opts) = @_;
3019 unless (defined wantarray) {
3020 my @caller = caller;
3021 warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
3025 # the user can either specify a matrix or preset
3026 # the matrix overrides the preset
3027 if (!exists($opts{matrix})) {
3028 unless (exists($opts{preset})) {
3029 $self->{ERRSTR} = "convert() needs a matrix or preset";
3033 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
3034 # convert to greyscale, keeping the alpha channel if any
3035 if ($self->getchannels == 3) {
3036 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
3038 elsif ($self->getchannels == 4) {
3039 # preserve the alpha channel
3040 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
3045 $matrix = _identity($self->getchannels);
3048 elsif ($opts{preset} eq 'noalpha') {
3049 # strip the alpha channel
3050 if ($self->getchannels == 2 or $self->getchannels == 4) {
3051 $matrix = _identity($self->getchannels);
3052 pop(@$matrix); # lose the alpha entry
3055 $matrix = _identity($self->getchannels);
3058 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
3060 $matrix = [ [ 1 ] ];
3062 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
3063 $matrix = [ [ 0, 1 ] ];
3065 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
3066 $matrix = [ [ 0, 0, 1 ] ];
3068 elsif ($opts{preset} eq 'alpha') {
3069 if ($self->getchannels == 2 or $self->getchannels == 4) {
3070 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
3073 # the alpha is just 1 <shrug>
3074 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
3077 elsif ($opts{preset} eq 'rgb') {
3078 if ($self->getchannels == 1) {
3079 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
3081 elsif ($self->getchannels == 2) {
3082 # preserve the alpha channel
3083 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
3086 $matrix = _identity($self->getchannels);
3089 elsif ($opts{preset} eq 'addalpha') {
3090 if ($self->getchannels == 1) {
3091 $matrix = _identity(2);
3093 elsif ($self->getchannels == 3) {
3094 $matrix = _identity(4);
3097 $matrix = _identity($self->getchannels);
3101 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
3107 $matrix = $opts{matrix};
3110 my $new = Imager->new();
3111 $new->{IMG} = i_img_new();
3112 unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
3113 # most likely a bad matrix
3114 $self->{ERRSTR} = _error_as_msg();
3121 # general function to map an image through lookup tables
3124 my ($self, %opts) = @_;
3125 my @chlist = qw( red green blue alpha );
3127 if (!exists($opts{'maps'})) {
3128 # make maps from channel maps
3130 for $chnum (0..$#chlist) {
3131 if (exists $opts{$chlist[$chnum]}) {
3132 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
3133 } elsif (exists $opts{'all'}) {
3134 $opts{'maps'}[$chnum] = $opts{'all'};
3138 if ($opts{'maps'} and $self->{IMG}) {
3139 i_map($self->{IMG}, $opts{'maps'} );
3145 my ($self, %opts) = @_;
3147 defined $opts{mindist} or $opts{mindist} = 0;
3149 defined $opts{other}
3150 or return $self->_set_error("No 'other' parameter supplied");
3151 defined $opts{other}{IMG}
3152 or return $self->_set_error("No image data in 'other' image");
3155 or return $self->_set_error("No image data");
3157 my $result = Imager->new;
3158 $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
3160 or return $self->_set_error($self->_error_as_msg());
3165 # destructive border - image is shrunk by one pixel all around
3168 my ($self,%opts)=@_;
3169 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
3170 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
3174 # Get the width of an image
3178 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3179 return (i_img_info($self->{IMG}))[0];
3182 # Get the height of an image
3186 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3187 return (i_img_info($self->{IMG}))[1];
3190 # Get number of channels in an image
3194 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3195 return i_img_getchannels($self->{IMG});
3202 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
3203 return i_img_getmask($self->{IMG});
3211 if (!defined($self->{IMG})) {
3212 $self->{ERRSTR} = 'image is empty';
3215 unless (defined $opts{mask}) {
3216 $self->_set_error("mask parameter required");
3219 i_img_setmask( $self->{IMG} , $opts{mask} );
3224 # Get number of colors in an image
3228 my %opts=('maxcolors'=>2**30,@_);
3229 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
3230 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
3231 return ($rc==-1? undef : $rc);
3234 # draw string to an image
3238 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
3240 my %input=('x'=>0, 'y'=>0, @_);
3241 $input{string}||=$input{text};
3243 unless(defined $input{string}) {
3244 $self->{ERRSTR}="missing required parameter 'string'";
3248 unless($input{font}) {
3249 $self->{ERRSTR}="missing required parameter 'font'";
3253 unless ($input{font}->draw(image=>$self, %input)) {
3265 unless ($self->{IMG}) {
3266 $self->{ERRSTR}='empty input image';
3275 my %input=('x'=>0, 'y'=>0, @_);
3276 $input{string}||=$input{text};
3278 unless(exists $input{string}) {
3279 $self->_set_error("missing required parameter 'string'");
3283 unless($input{font}) {
3284 $self->_set_error("missing required parameter 'font'");
3289 unless (@result = $input{font}->align(image=>$img, %input)) {
3293 return wantarray ? @result : $result[0];
3296 my @file_limit_names = qw/width height bytes/;
3298 sub set_file_limits {
3305 @values{@file_limit_names} = (0) x @file_limit_names;
3308 @values{@file_limit_names} = i_get_image_file_limits();
3311 for my $key (keys %values) {
3312 defined $opts{$key} and $values{$key} = $opts{$key};
3315 i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
3318 sub get_file_limits {
3319 i_get_image_file_limits();
3322 # Shortcuts that can be exported
3324 sub newcolor { Imager::Color->new(@_); }
3325 sub newfont { Imager::Font->new(@_); }
3327 *NC=*newcolour=*newcolor;
3334 #### Utility routines
3337 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
3341 my ($self, $msg) = @_;
3344 $self->{ERRSTR} = $msg;
3352 # Default guess for the type of an image from extension
3354 sub def_guess_type {
3357 $ext=($name =~ m/\.([^\.]+)$/)[0];
3358 return 'tiff' if ($ext =~ m/^tiff?$/);
3359 return 'jpeg' if ($ext =~ m/^jpe?g$/);
3360 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
3361 return 'png' if ($ext eq "png");
3362 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
3363 return 'tga' if ($ext eq "tga");
3364 return 'rgb' if ($ext eq "rgb");
3365 return 'gif' if ($ext eq "gif");
3366 return 'raw' if ($ext eq "raw");
3367 return lc $ext; # best guess
3371 # get the minimum of a list
3375 for(@_) { if ($_<$mx) { $mx=$_; }}
3379 # get the maximum of a list
3383 for(@_) { if ($_>$mx) { $mx=$_; }}
3387 # string stuff for iptc headers
3391 $str = substr($str,3);
3392 $str =~ s/[\n\r]//g;
3399 # A little hack to parse iptc headers.
3404 my($caption,$photogr,$headln,$credit);
3406 my $str=$self->{IPTCRAW};
3411 @ar=split(/8BIM/,$str);
3416 @sar=split(/\034\002/);
3417 foreach $item (@sar) {
3418 if ($item =~ m/^x/) {
3419 $caption = _clean($item);
3422 if ($item =~ m/^P/) {
3423 $photogr = _clean($item);
3426 if ($item =~ m/^i/) {
3427 $headln = _clean($item);
3430 if ($item =~ m/^n/) {
3431 $credit = _clean($item);
3437 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
3444 or die "Only C language supported";
3446 require Imager::ExtUtils;
3447 return Imager::ExtUtils->inline_config;
3452 # Below is the stub of documentation for your module. You better edit it!
3456 Imager - Perl extension for Generating 24 bit Images
3466 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
3471 my $img = Imager->new();
3472 # see Imager::Files for information on the read() method
3473 $img->read(file=>$file) or die $img->errstr();
3475 $file =~ s/\.[^.]*$//;
3477 # Create smaller version
3478 # documented in Imager::Transformations
3479 my $thumb = $img->scale(scalefactor=>.3);
3481 # Autostretch individual channels
3482 $thumb->filter(type=>'autolevels');
3484 # try to save in one of these formats
3487 for $format ( qw( png gif jpg tiff ppm ) ) {
3488 # Check if given format is supported
3489 if ($Imager::formats{$format}) {
3490 $file.="_low.$format";
3491 print "Storing image as: $file\n";
3492 # documented in Imager::Files
3493 $thumb->write(file=>$file) or
3501 Imager is a module for creating and altering images. It can read and
3502 write various image formats, draw primitive shapes like lines,and
3503 polygons, blend multiple images together in various ways, scale, crop,
3504 render text and more.
3506 =head2 Overview of documentation
3512 Imager - This document - Synopsis, Example, Table of Contents and
3517 L<Imager::Tutorial> - a brief introduction to Imager.
3521 L<Imager::Cookbook> - how to do various things with Imager.
3525 L<Imager::ImageTypes> - Basics of constructing image objects with
3526 C<new()>: Direct type/virtual images, RGB(A)/paletted images,
3527 8/16/double bits/channel, color maps, channel masks, image tags, color
3528 quantization. Also discusses basic image information methods.
3532 L<Imager::Files> - IO interaction, reading/writing images, format
3537 L<Imager::Draw> - Drawing Primitives, lines, boxes, circles, arcs,
3542 L<Imager::Color> - Color specification.
3546 L<Imager::Fill> - Fill pattern specification.
3550 L<Imager::Font> - General font rendering, bounding boxes and font
3555 L<Imager::Transformations> - Copying, scaling, cropping, flipping,
3556 blending, pasting, convert and map.
3560 L<Imager::Engines> - Programmable transformations through
3561 C<transform()>, C<transform2()> and C<matrix_transform()>.
3565 L<Imager::Filters> - Filters, sharpen, blur, noise, convolve etc. and
3570 L<Imager::Expr> - Expressions for evaluation engine used by
3575 L<Imager::Matrix2d> - Helper class for affine transformations.
3579 L<Imager::Fountain> - Helper for making gradient profiles.
3583 L<Imager::API> - using Imager's C API
3587 L<Imager::APIRef> - API function reference
3591 L<Imager::Inline> - using Imager's C API from Inline::C
3595 L<Imager::ExtUtils> - tools to get access to Imager's C API.
3599 =head2 Basic Overview
3601 An Image object is created with C<$img = Imager-E<gt>new()>.
3604 $img=Imager->new(); # create empty image
3605 $img->read(file=>'lena.png',type=>'png') or # read image from file
3606 die $img->errstr(); # give an explanation
3607 # if something failed
3609 or if you want to create an empty image:
3611 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
3613 This example creates a completely black image of width 400 and height
3616 =head1 ERROR HANDLING
3618 In general a method will return false when it fails, if it does use the errstr() method to find out why:
3624 Returns the last error message in that context.
3626 If the last error you received was from calling an object method, such
3627 as read, call errstr() as an object method to find out why:
3629 my $image = Imager->new;
3630 $image->read(file => 'somefile.gif')
3631 or die $image->errstr;
3633 If it was a class method then call errstr() as a class method:
3635 my @imgs = Imager->read_multi(file => 'somefile.gif')
3636 or die Imager->errstr;
3638 Note that in some cases object methods are implemented in terms of
3639 class methods so a failing object method may set both.
3643 The C<Imager-E<gt>new> method is described in detail in
3644 L<Imager::ImageTypes>.
3648 Where to find information on methods for Imager class objects.
3650 addcolors() - L<Imager::ImageTypes/addcolors>
3652 addtag() - L<Imager::ImageTypes/addtag> - add image tags
3654 align_string() - L<Imager::Draw/align_string>
3656 arc() - L<Imager::Draw/arc>
3658 bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
3661 box() - L<Imager::Draw/box>
3663 circle() - L<Imager::Draw/circle>
3665 colorcount() - L<Imager::Draw/colorcount>
3667 convert() - L<Imager::Transformations/"Color transformations"> -
3668 transform the color space
3670 copy() - L<Imager::Transformations/copy>
3672 crop() - L<Imager::Transformations/crop> - extract part of an image
3674 def_guess_type() - L<Imager::Files/def_guess_type>
3676 deltag() - L<Imager::ImageTypes/deltag> - delete image tags
3678 difference() - L<Imager::Filters/"Image Difference">
3680 errstr() - L<"Basic Overview">
3682 filter() - L<Imager::Filters>
3684 findcolor() - L<Imager::ImageTypes/findcolor> - search the image palette, if it
3687 flip() - L<Imager::Transformations/flip>
3689 flood_fill() - L<Imager::Draw/flood_fill>
3691 getchannels() - L<Imager::ImageTypes/getchannels>
3693 getcolorcount() - L<Imager::ImageTypes/getcolorcount>
3695 getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
3696 palette, if it has one
3698 get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3700 getheight() - L<Imager::ImageTypes/getwidth>
3702 getmask() - L<Imager::ImageTypes/getmask>
3704 getpixel() - L<Imager::Draw/getpixel>
3706 getsamples() - L<Imager::Draw/getsamples>
3708 getscanline() - L<Imager::Draw/getscanline>
3710 getwidth() - L<Imager::ImageTypes/getwidth>
3712 img_set() - L<Imager::ImageTypes/img_set>
3714 init() - L<Imager::ImageTypes/init>
3716 line() - L<Imager::Draw/line>
3718 load_plugin() - L<Imager::Filters/load_plugin>
3720 map() - L<Imager::Transformations/"Color Mappings"> - remap color
3723 masked() - L<Imager::ImageTypes/masked> - make a masked image
3725 matrix_transform() - L<Imager::Engines/matrix_transform>
3727 maxcolors() - L<Imager::ImageTypes/maxcolors>
3729 NC() - L<Imager::Handy/NC>
3731 new() - L<Imager::ImageTypes/new>
3733 newcolor() - L<Imager::Handy/newcolor>
3735 newcolour() - L<Imager::Handy/newcolour>
3737 newfont() - L<Imager::Handy/newfont>
3739 NF() - L<Imager::Handy/NF>
3741 open() - L<Imager::Files> - an alias for read()
3743 parseiptc() - L<Imager::Files/parseiptc> - parse IPTC data from a JPEG
3746 paste() - L<Imager::Transformations/paste> - draw an image onto an image
3748 polygon() - L<Imager::Draw/polygon>
3750 polyline() - L<Imager::Draw/polyline>
3752 read() - L<Imager::Files> - read a single image from an image file
3754 read_multi() - L<Imager::Files> - read multiple images from an image
3757 register_filter() - L<Imager::Filters/register_filter>
3759 register_reader() - L<Imager::Filters/register_reader>
3761 register_writer() - L<Imager::Filters/register_writer>
3763 rotate() - L<Imager::Transformations/rotate>
3765 rubthrough() - L<Imager::Transformations/rubthrough> - draw an image onto an
3766 image and use the alpha channel
3768 scale() - L<Imager::Transformations/scale>
3770 scaleX() - L<Imager::Transformations/scaleX>
3772 scaleY() - L<Imager::Transformations/scaleY>
3774 setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
3777 set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
3779 setmask() - L<Imager::ImageTypes/setmask>
3781 setpixel() - L<Imager::Draw/setpixel>
3783 setscanline() - L<Imager::Draw/setscanline>
3785 settag() - L<Imager::ImageTypes/settag>
3787 string() - L<Imager::Draw/string> - draw text on an image
3789 tags() - L<Imager::ImageTypes/tags> - fetch image tags
3791 to_paletted() - L<Imager::ImageTypes/to_paletted>
3793 to_rgb8() - L<Imager::ImageTypes/to_rgb8>
3795 transform() - L<Imager::Engines/"transform">
3797 transform2() - L<Imager::Engines/"transform2">
3799 type() - L<Imager::ImageTypes/type> - type of image (direct vs paletted)
3801 unload_plugin() - L<Imager::Filters/unload_plugin>
3803 virtual() - L<Imager::ImageTypes/virtual> - whether the image has it's own
3806 write() - L<Imager::Files> - write an image to a file
3808 write_multi() - L<Imager::Files> - write multiple image to an image
3811 =head1 CONCEPT INDEX
3813 animated GIF - L<Imager::File/"Writing an animated GIF">
3815 aspect ratio - L<Imager::ImageTypes/i_xres>,
3816 L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
3818 blend - alpha blending one image onto another
3819 L<Imager::Transformations/rubthrough>
3821 blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
3823 boxes, drawing - L<Imager::Draw/box>
3825 changes between image - L<Imager::Filter/"Image Difference">
3827 color - L<Imager::Color>
3829 color names - L<Imager::Color>, L<Imager::Color::Table>
3831 combine modes - L<Imager::Fill/combine>
3833 compare images - L<Imager::Filter/"Image Difference">
3835 contrast - L<Imager::Filter/contrast>, L<Imager::Filter/autolevels>
3837 convolution - L<Imager::Filter/conv>
3839 cropping - L<Imager::Transformations/crop>
3841 C<diff> images - L<Imager::Filter/"Image Difference">
3843 dpi - L<Imager::ImageTypes/i_xres>,
3844 L<Imager::Cookbook/"Image spatial resolution">
3846 drawing boxes - L<Imager::Draw/box>
3848 drawing lines - L<Imager::Draw/line>
3850 drawing text - L<Imager::Draw/string>, L<Imager::Draw/align_string>
3852 error message - L<"Basic Overview">
3854 files, font - L<Imager::Font>
3856 files, image - L<Imager::Files>
3858 filling, types of fill - L<Imager::Fill>
3860 filling, boxes - L<Imager::Draw/box>
3862 filling, flood fill - L<Imager::Draw/flood_fill>
3864 flood fill - L<Imager::Draw/flood_fill>
3866 fonts - L<Imager::Font>
3868 fonts, drawing with - L<Imager::Draw/string>,
3869 L<Imager::Draw/align_string>, L<Imager::Font::Wrap>
3871 fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3873 fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
3875 fountain fill - L<Imager::Fill/"Fountain fills">,
3876 L<Imager::Filters/fountain>, L<Imager::Fountain>,
3877 L<Imager::Filters/gradgen>
3879 GIF files - L<Imager::Files/"GIF">
3881 GIF files, animated - L<Imager::File/"Writing an animated GIF">
3883 gradient fill - L<Imager::Fill/"Fountain fills">,
3884 L<Imager::Filters/fountain>, L<Imager::Fountain>,
3885 L<Imager::Filters/gradgen>
3887 guassian blur - L<Imager::Filter/guassian>
3889 hatch fills - L<Imager::Fill/"Hatched fills">
3891 invert image - L<Imager::Filter/hardinvert>
3893 JPEG - L<Imager::Files/"JPEG">
3895 limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
3897 lines, drawing - L<Imager::Draw/line>
3899 matrix - L<Imager::Matrix2d>,
3900 L<Imager::Transformations/"Matrix Transformations">,
3901 L<Imager::Font/transform>
3903 metadata, image - L<Imager::ImageTypes/"Tags">
3905 mosaic - L<Imager::Filter/mosaic>
3907 noise, filter - L<Imager::Filter/noise>
3909 noise, rendered - L<Imager::Filter/turbnoise>,
3910 L<Imager::Filter/radnoise>
3912 paste - L<Imager::Transformations/paste>,
3913 L<Imager::Transformations/rubthrough>
3915 pseudo-color image - L<Imager::ImageTypes/to_paletted>,
3916 L<Imager::ImageTypes/new>
3918 posterize - L<Imager::Filter/postlevels>
3920 png files - L<Imager::Files>, L<Imager::Files/"PNG">
3922 pnm - L<Imager::Files/"PNM (Portable aNy Map)">
3924 rectangles, drawing - L<Imager::Draw/box>
3926 resizing an image - L<Imager::Transformations/scale>,
3927 L<Imager::Transformations/crop>
3929 saving an image - L<Imager::Files>
3931 scaling - L<Imager::Transformations/scale>
3933 sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
3935 size, image - L<Imager::ImageTypes/getwidth>,
3936 L<Imager::ImageTypes/getheight>
3938 size, text - L<Imager::Font/bounding_box>
3940 tags, image metadata - L<Imager::ImageTypes/"Tags">
3942 text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
3943 L<Imager::Font::Wrap>
3945 text, wrapping text in an area - L<Imager::Font::Wrap>
3947 text, measuring - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
3949 tiles, color - L<Imager::Filter/mosaic>
3951 unsharp mask - L<Imager::Filter/unsharpmask>
3953 watermark - L<Imager::Filter/watermark>
3955 writing an image to a file - L<Imager::Files>
3959 The best place to get help with Imager is the mailing list.
3961 To subscribe send a message with C<subscribe> in the body to:
3963 imager-devel+request@molar.is
3969 L<http://www.molar.is/en/lists/imager-devel/>
3973 where you can also find the mailing list archive.
3975 You can report bugs by pointing your browser at:
3979 L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager>
3983 Please remember to include the versions of Imager, perl, supporting
3984 libraries, and any relevant code. If you have specific images that
3985 cause the problems, please include those too.
3989 Bugs are listed individually for relevant pod pages.
3993 Arnar M. Hrafnkelsson and Tony Cook (tony@imager.perl.org) among
3994 others. See the README for a complete list.
3998 L<perl>(1), L<Imager::ImageTypes>(3), L<Imager::Files>(3),
3999 L<Imager::Draw>(3), L<Imager::Color>(3), L<Imager::Fill>(3),
4000 L<Imager::Font>(3), L<Imager::Transformations>(3),
4001 L<Imager::Engines>(3), L<Imager::Filters>(3), L<Imager::Expr>(3),
4002 L<Imager::Matrix2d>(3), L<Imager::Fountain>(3)
4004 L<http://imager.perl.org/>
4006 L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
4008 Other perl imaging modules include:
4010 L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).