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
151 @ISA = qw(Exporter DynaLoader);
152 bootstrap Imager $VERSION;
156 i_init_fonts(); # Initialize font engines
157 Imager::Font::__init();
158 for(i_list_formats()) { $formats{$_}++; }
160 if ($formats{'t1'}) {
164 if (!$formats{'t1'} and !$formats{'tt'}
165 && !$formats{'ft2'} && !$formats{'w32'}) {
166 $fontstate='no font support';
169 %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]);
173 # the members of the subhashes under %filters are:
174 # callseq - a list of the parameters to the underlying filter in the
175 # order they are passed
176 # callsub - a code ref that takes a named parameter list and calls the
178 # defaults - a hash of default values
179 # names - defines names for value of given parameters so if the names
180 # field is foo=> { bar=>1 }, and the user supplies "bar" as the
181 # foo parameter, the filter will receive 1 for the foo
184 callseq => ['image','intensity'],
185 callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); }
189 callseq => ['image', 'amount', 'subtype'],
190 defaults => { amount=>3,subtype=>0 },
191 callsub => sub { my %hsh=@_; i_noise($hsh{image},$hsh{amount},$hsh{subtype}); }
194 $filters{hardinvert} ={
195 callseq => ['image'],
197 callsub => sub { my %hsh=@_; i_hardinvert($hsh{image}); }
200 $filters{autolevels} ={
201 callseq => ['image','lsat','usat','skew'],
202 defaults => { lsat=>0.1,usat=>0.1,skew=>0.0 },
203 callsub => sub { my %hsh=@_; i_autolevels($hsh{image},$hsh{lsat},$hsh{usat},$hsh{skew}); }
206 $filters{turbnoise} ={
207 callseq => ['image'],
208 defaults => { xo=>0.0,yo=>0.0,scale=>10.0 },
209 callsub => sub { my %hsh=@_; i_turbnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{scale}); }
212 $filters{radnoise} ={
213 callseq => ['image'],
214 defaults => { xo=>100,yo=>100,ascale=>17.0,rscale=>0.02 },
215 callsub => sub { my %hsh=@_; i_radnoise($hsh{image},$hsh{xo},$hsh{yo},$hsh{rscale},$hsh{ascale}); }
219 callseq => ['image', 'coef'],
221 callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}); }
225 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
227 callsub => sub { my %hsh=@_; i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, $hsh{colors}, $hsh{dist}); }
230 $filters{nearest_color} ={
231 callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
233 callsub => sub { my %hsh=@_; i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, $hsh{colors}, $hsh{dist}); }
235 $filters{gaussian} = {
236 callseq => [ 'image', 'stddev' ],
238 callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); },
242 callseq => [ qw(image size) ],
243 defaults => { size => 20 },
244 callsub => sub { my %hsh = @_; i_mosaic($hsh{image}, $hsh{size}) },
248 callseq => [ qw(image bump elevation lightx lighty st) ],
249 defaults => { elevation=>0, st=> 2 },
252 i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation},
253 $hsh{lightx}, $hsh{lighty}, $hsh{st});
256 $filters{bumpmap_complex} =
258 callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ],
269 Ia => Imager::Color->new(rgb=>[0,0,0]),
270 Il => Imager::Color->new(rgb=>[255,255,255]),
271 Is => Imager::Color->new(rgb=>[255,255,255]),
275 i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel},
276 $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz},
277 $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il},
281 $filters{postlevels} =
283 callseq => [ qw(image levels) ],
284 defaults => { levels => 10 },
285 callsub => sub { my %hsh = @_; i_postlevels($hsh{image}, $hsh{levels}); },
287 $filters{watermark} =
289 callseq => [ qw(image wmark tx ty pixdiff) ],
290 defaults => { pixdiff=>10, tx=>0, ty=>0 },
294 i_watermark($hsh{image}, $hsh{wmark}{IMG}, $hsh{tx}, $hsh{ty},
300 callseq => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ],
302 ftype => { linear => 0,
308 repeat => { none => 0,
323 multiply => 2, mult => 2,
326 subtract => 5, 'sub' => 5,
336 defaults => { ftype => 0, repeat => 0, combine => 0,
337 super_sample => 0, ssample_param => 4,
340 Imager::Color->new(0,0,0),
341 Imager::Color->new(255, 255, 255),
349 i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
350 $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
351 $hsh{ssample_param}, $hsh{segments});
354 $filters{unsharpmask} =
356 callseq => [ qw(image stddev scale) ],
357 defaults => { stddev=>2.0, scale=>1.0 },
361 i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
365 $FORMATGUESS=\&def_guess_type;
375 # NOTE: this might be moved to an import override later on
379 # (look through @_ for special tags, process, and remove them);
381 # print Dumper($pack);
386 my %parms=(loglevel=>1,@_);
388 init_log($parms{'log'},$parms{'loglevel'});
390 if (exists $parms{'warn_obsolete'}) {
391 $warn_obsolete = $parms{'warn_obsolete'};
394 # if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
395 # if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
403 print "shutdown code\n";
404 # for(keys %instances) { $instances{$_}->DESTROY(); }
405 malloc_state(); # how do decide if this should be used? -- store something from the import
406 print "Imager exiting\n";
410 # Load a filter plugin
415 my ($DSO_handle,$str)=DSO_open($filename);
416 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
417 my %funcs=DSO_funclist($DSO_handle);
418 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
420 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
422 $DSOs{$filename}=[$DSO_handle,\%funcs];
425 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
426 $DEBUG && print "eval string:\n",$evstr,"\n";
438 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
439 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
440 for(keys %{$funcref}) {
442 $DEBUG && print "unloading: $_\n";
444 my $rc=DSO_close($DSO_handle);
445 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
449 # take the results of i_error() and make a message out of it
451 return join(": ", map $_->[0], i_errors());
454 # this function tries to DWIM for color parameters
455 # color objects are used as is
456 # simple scalars are simply treated as single parameters to Imager::Color->new
457 # hashrefs are treated as named argument lists to Imager::Color->new
458 # arrayrefs are treated as list arguments to Imager::Color->new iff any
460 # other arrayrefs are treated as list arguments to Imager::Color::Float
464 # perl 5.6.0 seems to do weird things to $arg if we don't make an
465 # explicitly stringified copy
466 # I vaguely remember a bug on this on p5p, but couldn't find it
467 # through bugs.perl.org (I had trouble getting it to find any bugs)
468 my $copy = $arg . "";
472 if (UNIVERSAL::isa($arg, "Imager::Color")
473 || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
477 if ($copy =~ /^HASH\(/) {
478 $result = Imager::Color->new(%$arg);
480 elsif ($copy =~ /^ARRAY\(/) {
481 if (grep $_ > 1, @$arg) {
482 $result = Imager::Color->new(@$arg);
485 $result = Imager::Color::Float->new(@$arg);
489 $Imager::ERRSTR = "Not a color";
494 # assume Imager::Color::new knows how to handle it
495 $result = Imager::Color->new($arg);
503 # Methods to be called on objects.
506 # Create a new Imager object takes very few parameters.
507 # usually you call this method and then call open from
508 # the resulting object
515 $self->{IMG}=undef; # Just to indicate what exists
516 $self->{ERRSTR}=undef; #
517 $self->{DEBUG}=$DEBUG;
518 $self->{DEBUG} && print "Initialized Imager\n";
519 if ($hsh{xsize} && $hsh{ysize}) { $self->img_set(%hsh); }
523 # Copy an entire image with no changes
524 # - if an image has magic the copy of it will not be magical
528 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
530 my $newcopy=Imager->new();
531 $newcopy->{IMG}=i_img_new();
532 i_copy($newcopy->{IMG},$self->{IMG});
540 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
541 my %input=(left=>0, top=>0, @_);
542 unless($input{img}) {
543 $self->{ERRSTR}="no source image";
546 $input{left}=0 if $input{left} <= 0;
547 $input{top}=0 if $input{top} <= 0;
549 my($r,$b)=i_img_info($src->{IMG});
551 i_copyto($self->{IMG}, $src->{IMG},
552 0,0, $r, $b, $input{left}, $input{top});
553 return $self; # What should go here??
556 # Crop an image - i.e. return a new image that is smaller
560 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
561 my %hsh=(left=>0,right=>0,top=>0,bottom=>0,@_);
563 my ($w,$h,$l,$r,$b,$t)=($self->getwidth(),$self->getheight(),
564 @hsh{qw(left right bottom top)});
565 $l=0 if not defined $l;
566 $t=0 if not defined $t;
568 $r||=$l+delete $hsh{'width'} if defined $l and exists $hsh{'width'};
569 $b||=$t+delete $hsh{'height'} if defined $t and exists $hsh{'height'};
570 $l||=$r-delete $hsh{'width'} if defined $r and exists $hsh{'width'};
571 $t||=$b-delete $hsh{'height'} if defined $b and exists $hsh{'height'};
573 $r=$self->getwidth if not defined $r;
574 $b=$self->getheight if not defined $b;
576 ($l,$r)=($r,$l) if $l>$r;
577 ($t,$b)=($b,$t) if $t>$b;
580 $l=int(0.5+($w-$hsh{'width'})/2);
585 if ($hsh{'height'}) {
586 $b=int(0.5+($h-$hsh{'height'})/2);
587 $t=$h+$hsh{'height'};
589 $hsh{'height'}=$b-$t;
592 # print "l=$l, r=$r, h=$hsh{'width'}\n";
593 # print "t=$t, b=$b, w=$hsh{'height'}\n";
595 my $dst=Imager->new(xsize=>$hsh{'width'}, ysize=>$hsh{'height'}, channels=>$self->getchannels());
597 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
601 # Sets an image to a certain size and channel number
602 # if there was previously data in the image it is discarded
607 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
609 if (defined($self->{IMG})) {
610 # let IIM_DESTROY destroy it, it's possible this image is
611 # referenced from a virtual image (like masked)
612 #i_img_destroy($self->{IMG});
616 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
617 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
618 $hsh{maxcolors} || 256);
620 elsif ($hsh{bits} eq 'double') {
621 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
623 elsif ($hsh{bits} == 16) {
624 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
627 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
632 # created a masked version of the current image
636 $self or return undef;
637 my %opts = (left => 0,
639 right => $self->getwidth,
640 bottom => $self->getheight,
642 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
644 my $result = Imager->new;
645 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
646 $opts{top}, $opts{right} - $opts{left},
647 $opts{bottom} - $opts{top});
648 # keep references to the mask and base images so they don't
650 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
655 # convert an RGB image into a paletted image
659 if (@_ != 1 && !ref $_[0]) {
666 my $result = Imager->new;
667 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
669 #print "Type ", i_img_type($result->{IMG}), "\n";
671 $result->{IMG} or undef $result;
676 # convert a paletted (or any image) to an 8-bit/channel RGB images
682 $result = Imager->new;
683 $result->{IMG} = i_img_to_rgb($self->{IMG})
692 my %opts = (colors=>[], @_);
694 @{$opts{colors}} or return undef;
696 $self->{IMG} and i_addcolors($self->{IMG}, @{$opts{colors}});
701 my %opts = (start=>0, colors=>[], @_);
702 @{$opts{colors}} or return undef;
704 $self->{IMG} and i_setcolors($self->{IMG}, $opts{start}, @{$opts{colors}});
710 if (!exists $opts{start} && !exists $opts{count}) {
713 $opts{count} = $self->colorcount;
715 elsif (!exists $opts{count}) {
718 elsif (!exists $opts{start}) {
723 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
727 i_colorcount($_[0]{IMG});
731 i_maxcolors($_[0]{IMG});
737 $opts{color} or return undef;
739 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
744 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
745 if ($bits && $bits == length(pack("d", 1)) * 8) {
754 return i_img_type($self->{IMG}) ? "paletted" : "direct";
760 $self->{IMG} and i_img_virtual($self->{IMG});
764 my ($self, %opts) = @_;
766 $self->{IMG} or return;
768 if (defined $opts{name}) {
772 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
773 push @result, (i_tags_get($self->{IMG}, $found))[1];
776 return wantarray ? @result : $result[0];
778 elsif (defined $opts{code}) {
782 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
783 push @result, (i_tags_get($self->{IMG}, $found))[1];
790 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
793 return i_tags_count($self->{IMG});
802 return -1 unless $self->{IMG};
804 if (defined $opts{value}) {
805 if ($opts{value} =~ /^\d+$/) {
807 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
810 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
813 elsif (defined $opts{data}) {
814 # force addition as a string
815 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
818 $self->{ERRSTR} = "No value supplied";
822 elsif ($opts{code}) {
823 if (defined $opts{value}) {
824 if ($opts{value} =~ /^\d+$/) {
826 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
829 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
832 elsif (defined $opts{data}) {
833 # force addition as a string
834 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
837 $self->{ERRSTR} = "No value supplied";
850 return 0 unless $self->{IMG};
852 if (defined $opts{'index'}) {
853 return i_tags_delete($self->{IMG}, $opts{'index'});
855 elsif (defined $opts{name}) {
856 return i_tags_delbyname($self->{IMG}, $opts{name});
858 elsif (defined $opts{code}) {
859 return i_tags_delbycode($self->{IMG}, $opts{code});
862 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
868 my ($self, %opts) = @_;
871 $self->deltag(name=>$opts{name});
872 return $self->addtag(name=>$opts{name}, value=>$opts{value});
874 elsif (defined $opts{code}) {
875 $self->deltag(code=>$opts{code});
876 return $self->addtag(code=>$opts{code}, value=>$opts{value});
883 my @needseekcb = qw/tiff/;
884 my %needseekcb = map { $_, $_ } @needseekcb;
888 my ($self, $input, $type) = @_;
891 return io_new_fd($input->{fd});
893 elsif ($input->{fh}) {
894 my $fd = fileno($input->{fh});
896 $self->_set_error("Handle in fh option not opened");
899 return io_new_fd($fd);
901 elsif ($input->{file}) {
902 my $file = IO::File->new($input->{file}, "r");
904 $self->_set_error("Could not open $input->{file}: $!");
908 return (io_new_fd(fileno($file)), $file);
910 elsif ($input->{data}) {
911 return io_new_buffer($input->{data});
913 elsif ($input->{callback} || $input->{readcb}) {
914 if ($needseekcb{$type} && !$input->{seekcb}) {
915 $self->_set_error("Format $type needs a seekcb parameter");
917 if ($input->{maxbuffer}) {
918 return io_new_cb($input->{writecb},
919 $input->{callback} || $input->{readcb},
920 $input->{seekcb}, $input->{closecb},
921 $input->{maxbuffer});
924 return io_new_cb($input->{writecb},
925 $input->{callback} || $input->{readcb},
926 $input->{seekcb}, $input->{closecb});
930 $self->_set_error("file/fd/fh/data/callback parameter missing");
936 my ($self, $input, $type) = @_;
939 return io_new_fd($input->{fd});
941 elsif ($input->{fh}) {
942 my $fd = fileno($input->{fh});
944 $self->_set_error("Handle in fh option not opened");
947 return io_new_fd($fd);
949 elsif ($input->{file}) {
950 my $fh = new IO::File($input->{file},"w+");
952 $self->_set_error("Could not open file $input->{file}: $!");
956 return (io_new_fd(fileno($fh)), $fh);
958 elsif ($input->{data}) {
959 return io_new_bufchain();
961 elsif ($input->{callback} || $input->{writecb}) {
962 if ($input->{maxbuffer}) {
963 return io_new_cb($input->{callback} || $input->{writecb},
965 $input->{seekcb}, $input->{closecb},
966 $input->{maxbuffer});
969 return io_new_cb($input->{callback} || $input->{writecb},
971 $input->{seekcb}, $input->{closecb});
975 $self->_set_error("file/fd/fh/data/callback parameter missing");
980 # Read an image from file
986 if (defined($self->{IMG})) {
987 # let IIM_DESTROY do the destruction, since the image may be
988 # referenced from elsewhere
989 #i_img_destroy($self->{IMG});
993 # FIXME: Find the format here if not specified
994 # yes the code isn't here yet - next week maybe?
995 # Next week? Are you high or something? That comment
996 # has been there for half a year dude.
997 # Look, i just work here, ok?
999 if (!$input{'type'} and $input{file}) {
1000 $input{'type'}=$FORMATGUESS->($input{file});
1002 unless ($input{'type'}) {
1003 $self->_set_error('type parameter missing and not possible to guess from extension');
1006 if (!$formats{$input{'type'}}) {
1007 $self->{ERRSTR}='format not supported'; return undef;
1010 my %iolready=(jpeg=>1, png=>1, tiff=>1, pnm=>1, raw=>1, bmp=>1, tga=>1, rgb=>1, gif=>1);
1012 if ($iolready{$input{'type'}}) {
1014 my ($IO, $fh) = $self->_get_reader_io(\%input, $input{'type'})
1017 if ( $input{'type'} eq 'jpeg' ) {
1018 ($self->{IMG},$self->{IPTCRAW})=i_readjpeg_wiol( $IO );
1019 if ( !defined($self->{IMG}) ) {
1020 $self->{ERRSTR}='unable to read jpeg image'; return undef;
1022 $self->{DEBUG} && print "loading a jpeg file\n";
1026 if ( $input{'type'} eq 'tiff' ) {
1027 $self->{IMG}=i_readtiff_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1028 if ( !defined($self->{IMG}) ) {
1029 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1031 $self->{DEBUG} && print "loading a tiff file\n";
1035 if ( $input{'type'} eq 'pnm' ) {
1036 $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1037 if ( !defined($self->{IMG}) ) {
1038 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); return undef;
1040 $self->{DEBUG} && print "loading a pnm file\n";
1044 if ( $input{'type'} eq 'png' ) {
1045 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1046 if ( !defined($self->{IMG}) ) {
1047 $self->{ERRSTR}='unable to read png image';
1050 $self->{DEBUG} && print "loading a png file\n";
1053 if ( $input{'type'} eq 'bmp' ) {
1054 $self->{IMG}=i_readbmp_wiol( $IO );
1055 if ( !defined($self->{IMG}) ) {
1056 $self->{ERRSTR}=$self->_error_as_msg();
1059 $self->{DEBUG} && print "loading a bmp file\n";
1062 if ( $input{'type'} eq 'gif' ) {
1063 if ($input{colors} && !ref($input{colors})) {
1064 # must be a reference to a scalar that accepts the colour map
1065 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1068 if ($input{colors}) {
1070 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1072 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1076 $self->{IMG} =i_readgif_wiol( $IO );
1078 if ( !defined($self->{IMG}) ) {
1079 $self->{ERRSTR}=$self->_error_as_msg();
1082 $self->{DEBUG} && print "loading a gif file\n";
1085 if ( $input{'type'} eq 'tga' ) {
1086 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1087 if ( !defined($self->{IMG}) ) {
1088 $self->{ERRSTR}=$self->_error_as_msg();
1091 $self->{DEBUG} && print "loading a tga file\n";
1094 if ( $input{'type'} eq 'rgb' ) {
1095 $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1096 if ( !defined($self->{IMG}) ) {
1097 $self->{ERRSTR}=$self->_error_as_msg();
1100 $self->{DEBUG} && print "loading a tga file\n";
1104 if ( $input{'type'} eq 'raw' ) {
1105 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1107 if ( !($params{xsize} && $params{ysize}) ) {
1108 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1112 $self->{IMG} = i_readraw_wiol( $IO,
1115 $params{datachannels},
1116 $params{storechannels},
1117 $params{interleave});
1118 if ( !defined($self->{IMG}) ) {
1119 $self->{ERRSTR}='unable to read raw image';
1122 $self->{DEBUG} && print "loading a raw file\n";
1127 # Old code for reference while changing the new stuff
1129 if (!$input{'type'} and $input{file}) {
1130 $input{'type'}=$FORMATGUESS->($input{file});
1133 if (!$input{'type'}) {
1134 $self->{ERRSTR}='type parameter missing and not possible to guess from extension'; return undef;
1137 if (!$formats{$input{'type'}}) {
1138 $self->{ERRSTR}='format not supported';
1144 $fh = new IO::File($input{file},"r");
1146 $self->{ERRSTR}='Could not open file';
1150 $fd = $fh->fileno();
1157 if ( $input{'type'} eq 'gif' ) {
1159 if ($input{colors} && !ref($input{colors})) {
1160 # must be a reference to a scalar that accepts the colour map
1161 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1164 if (exists $input{data}) {
1165 if ($input{colors}) {
1166 ($self->{IMG}, $colors) = i_readgif_scalar($input{data});
1168 $self->{IMG}=i_readgif_scalar($input{data});
1171 if ($input{colors}) {
1172 ($self->{IMG}, $colors) = i_readgif( $fd );
1174 $self->{IMG} = i_readgif( $fd )
1178 # we may or may not change i_readgif to return blessed objects...
1179 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1181 if ( !defined($self->{IMG}) ) {
1182 $self->{ERRSTR}= 'reading GIF:'._error_as_msg();
1185 $self->{DEBUG} && print "loading a gif file\n";
1191 sub _fix_gif_positions {
1192 my ($opts, $opt, $msg, @imgs) = @_;
1194 my $positions = $opts->{'gif_positions'};
1196 for my $pos (@$positions) {
1197 my ($x, $y) = @$pos;
1198 my $img = $imgs[$index++];
1199 $img->settag(gif_left=>$x);
1200 $img->settag(gif_top=>$y) if defined $y;
1202 $$msg .= "replaced with the gif_left and gif_top tags";
1207 gif_each_palette=>'gif_local_map',
1208 interlace => 'gif_interlace',
1209 gif_delays => 'gif_delay',
1210 gif_positions => \&_fix_gif_positions,
1211 gif_loop_count => 'gif_loop',
1215 my ($self, $opts, $prefix, @imgs) = @_;
1217 for my $opt (keys %$opts) {
1219 if ($obsolete_opts{$opt}) {
1220 my $new = $obsolete_opts{$opt};
1221 my $msg = "Obsolete option $opt ";
1223 $new->($opts, $opt, \$msg, @imgs);
1226 $msg .= "replaced with the $new tag ";
1229 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1230 warn $msg if $warn_obsolete && $^W;
1232 next unless $tagname =~ /^\Q$prefix/;
1233 my $value = $opts->{$opt};
1235 if (UNIVERSAL::isa($value, "Imager::Color")) {
1236 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1237 for my $img (@imgs) {
1238 $img->settag(name=>$tagname, value=>$tag);
1241 elsif (ref($value) eq 'ARRAY') {
1242 for my $i (0..$#$value) {
1243 my $val = $value->[$i];
1245 if (UNIVERSAL::isa($val, "Imager::Color")) {
1246 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1248 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1251 $self->_set_error("Unknown reference type " . ref($value) .
1252 " supplied in array for $opt");
1258 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1263 $self->_set_error("Unknown reference type " . ref($value) .
1264 " supplied for $opt");
1269 # set it as a tag for every image
1270 for my $img (@imgs) {
1271 $img->settag(name=>$tagname, value=>$value);
1279 # Write an image to file
1282 my %input=(jpegquality=>75,
1292 $self->_set_opts(\%input, "i_", $self)
1295 my %iolready=( tiff=>1, raw=>1, png=>1, pnm=>1, bmp=>1, jpeg=>1, tga=>1,
1296 gif=>1 ); # this will be SO MUCH BETTER once they are all in there
1298 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1300 if (!$input{'type'} and $input{file}) {
1301 $input{'type'}=$FORMATGUESS->($input{file});
1303 if (!$input{'type'}) {
1304 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1308 if (!$formats{$input{'type'}}) { $self->{ERRSTR}='format not supported'; return undef; }
1310 my ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1313 # this conditional is probably obsolete
1314 if ($iolready{$input{'type'}}) {
1316 if ($input{'type'} eq 'tiff') {
1317 $self->_set_opts(\%input, "tiff_", $self)
1319 $self->_set_opts(\%input, "exif_", $self)
1322 if (defined $input{class} && $input{class} eq 'fax') {
1323 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1324 $self->{ERRSTR}='Could not write to buffer';
1328 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1329 $self->{ERRSTR}='Could not write to buffer';
1333 } elsif ( $input{'type'} eq 'pnm' ) {
1334 $self->_set_opts(\%input, "pnm_", $self)
1336 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1337 $self->{ERRSTR}='unable to write pnm image';
1340 $self->{DEBUG} && print "writing a pnm file\n";
1341 } elsif ( $input{'type'} eq 'raw' ) {
1342 $self->_set_opts(\%input, "raw_", $self)
1344 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1345 $self->{ERRSTR}='unable to write raw image';
1348 $self->{DEBUG} && print "writing a raw file\n";
1349 } elsif ( $input{'type'} eq 'png' ) {
1350 $self->_set_opts(\%input, "png_", $self)
1352 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1353 $self->{ERRSTR}='unable to write png image';
1356 $self->{DEBUG} && print "writing a png file\n";
1357 } elsif ( $input{'type'} eq 'jpeg' ) {
1358 $self->_set_opts(\%input, "jpeg_", $self)
1360 $self->_set_opts(\%input, "exif_", $self)
1362 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1363 $self->{ERRSTR} = $self->_error_as_msg();
1366 $self->{DEBUG} && print "writing a jpeg file\n";
1367 } elsif ( $input{'type'} eq 'bmp' ) {
1368 $self->_set_opts(\%input, "bmp_", $self)
1370 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1371 $self->{ERRSTR}='unable to write bmp image';
1374 $self->{DEBUG} && print "writing a bmp file\n";
1375 } elsif ( $input{'type'} eq 'tga' ) {
1376 $self->_set_opts(\%input, "tga_", $self)
1379 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1380 $self->{ERRSTR}=$self->_error_as_msg();
1383 $self->{DEBUG} && print "writing a tga file\n";
1384 } elsif ( $input{'type'} eq 'gif' ) {
1385 $self->_set_opts(\%input, "gif_", $self)
1387 # compatibility with the old interfaces
1388 if ($input{gifquant} eq 'lm') {
1389 $input{make_colors} = 'addi';
1390 $input{translate} = 'perturb';
1391 $input{perturb} = $input{lmdither};
1392 } elsif ($input{gifquant} eq 'gen') {
1393 # just pass options through
1395 $input{make_colors} = 'webmap'; # ignored
1396 $input{translate} = 'giflib';
1398 $rc = i_writegif_wiol($IO, \%input, $self->{IMG});
1401 if (exists $input{'data'}) {
1402 my $data = io_slurp($IO);
1404 $self->{ERRSTR}='Could not slurp from buffer';
1407 ${$input{data}} = $data;
1416 my ($class, $opts, @images) = @_;
1418 if (!$opts->{'type'} && $opts->{'file'}) {
1419 $opts->{'type'} = $FORMATGUESS->($opts->{'file'});
1421 unless ($opts->{'type'}) {
1422 $class->_set_error('type parameter missing and not possible to guess from extension');
1425 # translate to ImgRaw
1426 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1427 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1430 $class->_set_opts($opts, "i_", @images)
1432 my @work = map $_->{IMG}, @images;
1433 my ($IO, $file) = $class->_get_writer_io($opts, $opts->{'type'})
1435 if ($opts->{'type'} eq 'gif') {
1436 $class->_set_opts($opts, "gif_", @images)
1438 my $gif_delays = $opts->{gif_delays};
1439 local $opts->{gif_delays} = $gif_delays;
1440 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1441 # assume the caller wants the same delay for each frame
1442 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1444 my $res = i_writegif_wiol($IO, $opts, @work);
1445 $res or $class->_set_error($class->_error_as_msg());
1448 elsif ($opts->{'type'} eq 'tiff') {
1449 $class->_set_opts($opts, "tiff_", @images)
1451 $class->_set_opts($opts, "exif_", @images)
1454 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1455 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1456 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1459 $res = i_writetiff_multi_wiol($IO, @work);
1461 $res or $class->_set_error($class->_error_as_msg());
1465 $ERRSTR = "Sorry, write_multi doesn't support $opts->{'type'} yet";
1470 # read multiple images from a file
1472 my ($class, %opts) = @_;
1474 if ($opts{file} && !exists $opts{'type'}) {
1476 my $type = $FORMATGUESS->($opts{file});
1477 $opts{'type'} = $type;
1479 unless ($opts{'type'}) {
1480 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1484 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1486 if ($opts{'type'} eq 'gif') {
1488 @imgs = i_readgif_multi_wiol($IO);
1491 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1495 $ERRSTR = _error_as_msg();
1499 elsif ($opts{'type'} eq 'tiff') {
1500 my @imgs = i_readtiff_multi_wiol($IO, -1);
1503 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1507 $ERRSTR = _error_as_msg();
1512 $ERRSTR = "Cannot read multiple images from $opts{'type'} files";
1516 # Destroy an Imager object
1520 # delete $instances{$self};
1521 if (defined($self->{IMG})) {
1522 # the following is now handled by the XS DESTROY method for
1523 # Imager::ImgRaw object
1524 # Re-enabling this will break virtual images
1525 # tested for in t/t020masked.t
1526 # i_img_destroy($self->{IMG});
1527 undef($self->{IMG});
1529 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1533 # Perform an inplace filter of an image
1534 # that is the image will be overwritten with the data
1540 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1542 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1544 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1545 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1548 if ($filters{$input{'type'}}{names}) {
1549 my $names = $filters{$input{'type'}}{names};
1550 for my $name (keys %$names) {
1551 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1552 $input{$name} = $names->{$name}{$input{$name}};
1556 if (defined($filters{$input{'type'}}{defaults})) {
1557 %hsh=('image',$self->{IMG},%{$filters{$input{'type'}}{defaults}},%input);
1559 %hsh=('image',$self->{IMG},%input);
1562 my @cs=@{$filters{$input{'type'}}{callseq}};
1565 if (!defined($hsh{$_})) {
1566 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1570 &{$filters{$input{'type'}}{callsub}}(%hsh);
1574 $self->{DEBUG} && print "callseq is: @cs\n";
1575 $self->{DEBUG} && print "matching callseq is: @b\n";
1580 # Scale an image to requested size and return the scaled version
1584 my %opts=(scalefactor=>0.5,'type'=>'max',qtype=>'normal',@_);
1585 my $img = Imager->new();
1586 my $tmp = Imager->new();
1588 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1590 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
1591 my ($xpix,$ypix)=( $opts{xpixels}/$self->getwidth() , $opts{ypixels}/$self->getheight() );
1592 if ($opts{'type'} eq 'min') { $opts{scalefactor}=min($xpix,$ypix); }
1593 if ($opts{'type'} eq 'max') { $opts{scalefactor}=max($xpix,$ypix); }
1594 } elsif ($opts{xpixels}) { $opts{scalefactor}=$opts{xpixels}/$self->getwidth(); }
1595 elsif ($opts{ypixels}) { $opts{scalefactor}=$opts{ypixels}/$self->getheight(); }
1597 if ($opts{qtype} eq 'normal') {
1598 $tmp->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
1599 if ( !defined($tmp->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1600 $img->{IMG}=i_scaleaxis($tmp->{IMG},$opts{scalefactor},1);
1601 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1604 if ($opts{'qtype'} eq 'preview') {
1605 $img->{IMG}=i_scale_nn($self->{IMG},$opts{'scalefactor'},$opts{'scalefactor'});
1606 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1609 $self->{ERRSTR}='scale: invalid value for qtype'; return undef;
1612 # Scales only along the X axis
1616 my %opts=(scalefactor=>0.5,@_);
1618 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1620 my $img = Imager->new();
1622 if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getwidth(); }
1624 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1625 $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
1627 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1631 # Scales only along the Y axis
1635 my %opts=(scalefactor=>0.5,@_);
1637 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1639 my $img = Imager->new();
1641 if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getheight(); }
1643 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1644 $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},1);
1646 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1651 # Transform returns a spatial transformation of the input image
1652 # this moves pixels to a new location in the returned image.
1653 # NOTE - should make a utility function to check transforms for
1658 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1660 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
1662 # print Dumper(\%opts);
1665 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
1667 eval ("use Affix::Infix2Postfix;");
1670 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
1673 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
1674 {op=>'-',trans=>'Sub'},
1675 {op=>'*',trans=>'Mult'},
1676 {op=>'/',trans=>'Div'},
1677 {op=>'-','type'=>'unary',trans=>'u-'},
1679 {op=>'func','type'=>'unary'}],
1680 'grouping'=>[qw( \( \) )],
1681 'func'=>[qw( sin cos )],
1686 @xt=$I2P->translate($opts{'xexpr'});
1687 @yt=$I2P->translate($opts{'yexpr'});
1689 $numre=$I2P->{'numre'};
1692 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
1693 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
1694 @{$opts{'parm'}}=@pt;
1697 # print Dumper(\%opts);
1699 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
1700 $self->{ERRSTR}='transform: no xopcodes given.';
1704 @op=@{$opts{'xopcodes'}};
1706 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
1707 $self->{ERRSTR}="transform: illegal opcode '$_'.";
1710 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
1716 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
1717 $self->{ERRSTR}='transform: no yopcodes given.';
1721 @op=@{$opts{'yopcodes'}};
1723 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
1724 $self->{ERRSTR}="transform: illegal opcode '$_'.";
1727 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
1732 if ( !exists $opts{'parm'}) {
1733 $self->{ERRSTR}='transform: no parameter arg given.';
1737 # print Dumper(\@ropx);
1738 # print Dumper(\@ropy);
1739 # print Dumper(\@ropy);
1741 my $img = Imager->new();
1742 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
1743 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
1749 my ($opts, @imgs) = @_;
1751 require "Imager/Expr.pm";
1753 $opts->{variables} = [ qw(x y) ];
1754 my ($width, $height) = @{$opts}{qw(width height)};
1756 $width ||= $imgs[0]->getwidth();
1757 $height ||= $imgs[0]->getheight();
1759 for my $img (@imgs) {
1760 $opts->{constants}{"w$img_num"} = $img->getwidth();
1761 $opts->{constants}{"h$img_num"} = $img->getheight();
1762 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
1763 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
1768 $opts->{constants}{w} = $width;
1769 $opts->{constants}{cx} = $width/2;
1772 $Imager::ERRSTR = "No width supplied";
1776 $opts->{constants}{h} = $height;
1777 $opts->{constants}{cy} = $height/2;
1780 $Imager::ERRSTR = "No height supplied";
1783 my $code = Imager::Expr->new($opts);
1785 $Imager::ERRSTR = Imager::Expr::error();
1789 my $img = Imager->new();
1790 $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, $code->code(),
1791 $code->nregs(), $code->cregs(),
1792 [ map { $_->{IMG} } @imgs ]);
1793 if (!defined $img->{IMG}) {
1794 $Imager::ERRSTR = Imager->_error_as_msg();
1803 my %opts=(tx=>0,ty=>0,@_);
1805 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1806 unless ($opts{src} && $opts{src}->{IMG}) { $self->{ERRSTR}='empty input image for source'; return undef; }
1808 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx},$opts{ty})) {
1809 $self->{ERRSTR} = $self->_error_as_msg();
1819 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
1821 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
1822 $dir = $xlate{$opts{'dir'}};
1823 return $self if i_flipxy($self->{IMG}, $dir);
1830 if (defined $opts{right}) {
1831 my $degrees = $opts{right};
1833 $degrees += 360 * int(((-$degrees)+360)/360);
1835 $degrees = $degrees % 360;
1836 if ($degrees == 0) {
1837 return $self->copy();
1839 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
1840 my $result = Imager->new();
1841 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
1845 $self->{ERRSTR} = $self->_error_as_msg();
1850 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
1854 elsif (defined $opts{radians} || defined $opts{degrees}) {
1855 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
1857 my $result = Imager->new;
1858 if ($result->{IMG} = i_rotate_exact($self->{IMG}, $amount)) {
1862 $self->{ERRSTR} = $self->_error_as_msg();
1867 $self->{ERRSTR} = "Only the 'right' parameter is available";
1872 sub matrix_transform {
1876 if ($opts{matrix}) {
1877 my $xsize = $opts{xsize} || $self->getwidth;
1878 my $ysize = $opts{ysize} || $self->getheight;
1880 my $result = Imager->new;
1881 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
1888 $self->{ERRSTR} = "matrix parameter required";
1894 *yatf = \&matrix_transform;
1896 # These two are supported for legacy code only
1899 return Imager::Color->new(@_);
1903 return Imager::Color::set(@_);
1906 # Draws a box between the specified corner points.
1909 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1910 my $dflcl=i_color_new(255,255,255,255);
1911 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
1913 if (exists $opts{'box'}) {
1914 $opts{'xmin'} = min($opts{'box'}->[0],$opts{'box'}->[2]);
1915 $opts{'xmax'} = max($opts{'box'}->[0],$opts{'box'}->[2]);
1916 $opts{'ymin'} = min($opts{'box'}->[1],$opts{'box'}->[3]);
1917 $opts{'ymax'} = max($opts{'box'}->[1],$opts{'box'}->[3]);
1920 if ($opts{filled}) {
1921 my $color = _color($opts{'color'});
1923 $self->{ERRSTR} = $Imager::ERRSTR;
1926 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
1927 $opts{ymax}, $color);
1929 elsif ($opts{fill}) {
1930 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
1931 # assume it's a hash ref
1932 require 'Imager/Fill.pm';
1933 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
1934 $self->{ERRSTR} = $Imager::ERRSTR;
1938 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
1939 $opts{ymax},$opts{fill}{fill});
1942 my $color = _color($opts{'color'});
1944 $self->{ERRSTR} = $Imager::ERRSTR;
1947 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
1953 # Draws an arc - this routine SUCKS and is buggy - it sometimes doesn't work when the arc is a convex polygon
1957 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1958 my $dflcl=i_color_new(255,255,255,255);
1959 my %opts=(color=>$dflcl,
1960 'r'=>min($self->getwidth(),$self->getheight())/3,
1961 'x'=>$self->getwidth()/2,
1962 'y'=>$self->getheight()/2,
1963 'd1'=>0, 'd2'=>361, @_);
1965 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
1966 # assume it's a hash ref
1967 require 'Imager/Fill.pm';
1968 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
1969 $self->{ERRSTR} = $Imager::ERRSTR;
1973 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
1974 $opts{'d2'}, $opts{fill}{fill});
1977 my $color = _color($opts{'color'});
1979 $self->{ERRSTR} = $Imager::ERRSTR;
1982 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
1983 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
1987 if ($opts{'d1'} <= $opts{'d2'}) {
1988 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
1989 $opts{'d1'}, $opts{'d2'}, $color);
1992 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
1993 $opts{'d1'}, 361, $color);
1994 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
1995 0, $opts{'d2'}, $color);
2003 # Draws a line from one point to (but not including) the destination point
2007 my $dflcl=i_color_new(0,0,0,0);
2008 my %opts=(color=>$dflcl,@_);
2009 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2011 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2012 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2014 my $color = _color($opts{'color'});
2016 $self->{ERRSTR} = $Imager::ERRSTR;
2019 $opts{antialias} = $opts{aa} if defined $opts{aa};
2020 if ($opts{antialias}) {
2021 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2024 i_draw($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2030 # Draws a line between an ordered set of points - It more or less just transforms this
2031 # into a list of lines.
2035 my ($pt,$ls,@points);
2036 my $dflcl=i_color_new(0,0,0,0);
2037 my %opts=(color=>$dflcl,@_);
2039 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2041 if (exists($opts{points})) { @points=@{$opts{points}}; }
2042 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2043 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2046 # print Dumper(\@points);
2048 my $color = _color($opts{'color'});
2050 $self->{ERRSTR} = $Imager::ERRSTR;
2053 $opts{antialias} = $opts{aa} if defined $opts{aa};
2054 if ($opts{antialias}) {
2057 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color);
2064 i_draw($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color);
2074 my ($pt,$ls,@points);
2075 my $dflcl = i_color_new(0,0,0,0);
2076 my %opts = (color=>$dflcl, @_);
2078 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2080 if (exists($opts{points})) {
2081 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2082 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2085 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2086 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2089 if ($opts{'fill'}) {
2090 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2091 # assume it's a hash ref
2092 require 'Imager/Fill.pm';
2093 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2094 $self->{ERRSTR} = $Imager::ERRSTR;
2098 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2099 $opts{'fill'}{'fill'});
2102 my $color = _color($opts{'color'});
2104 $self->{ERRSTR} = $Imager::ERRSTR;
2107 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2114 # this the multipoint bezier curve
2115 # this is here more for testing that actual usage since
2116 # this is not a good algorithm. Usually the curve would be
2117 # broken into smaller segments and each done individually.
2121 my ($pt,$ls,@points);
2122 my $dflcl=i_color_new(0,0,0,0);
2123 my %opts=(color=>$dflcl,@_);
2125 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2127 if (exists $opts{points}) {
2128 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2129 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2132 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2133 $self->{ERRSTR}='Missing or invalid points.';
2137 my $color = _color($opts{'color'});
2139 $self->{ERRSTR} = $Imager::ERRSTR;
2142 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2148 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2150 unless (exists $opts{'x'} && exists $opts{'y'}) {
2151 $self->{ERRSTR} = "missing seed x and y parameters";
2156 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2157 # assume it's a hash ref
2158 require 'Imager/Fill.pm';
2159 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2160 $self->{ERRSTR} = $Imager::ERRSTR;
2164 i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2167 my $color = _color($opts{'color'});
2169 $self->{ERRSTR} = $Imager::ERRSTR;
2172 i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2181 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2183 unless (exists $opts{'x'} && exists $opts{'y'}) {
2184 $self->{ERRSTR} = 'missing x and y parameters';
2190 my $color = _color($opts{color})
2192 if (ref $x && ref $y) {
2193 unless (@$x == @$y) {
2194 $self->{ERRSTR} = 'length of x and y mistmatch';
2197 if ($color->isa('Imager::Color')) {
2198 for my $i (0..$#{$opts{'x'}}) {
2199 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color);
2203 for my $i (0..$#{$opts{'x'}}) {
2204 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color);
2209 if ($color->isa('Imager::Color')) {
2210 i_ppix($self->{IMG}, $x, $y, $color);
2213 i_ppixf($self->{IMG}, $x, $y, $color);
2223 my %opts = ( type=>'8bit', @_);
2225 unless (exists $opts{'x'} && exists $opts{'y'}) {
2226 $self->{ERRSTR} = 'missing x and y parameters';
2232 if (ref $x && ref $y) {
2233 unless (@$x == @$y) {
2234 $self->{ERRSTR} = 'length of x and y mismatch';
2238 if ($opts{type} eq '8bit') {
2239 for my $i (0..$#{$opts{'x'}}) {
2240 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2244 for my $i (0..$#{$opts{'x'}}) {
2245 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2248 return wantarray ? @result : \@result;
2251 if ($opts{type} eq '8bit') {
2252 return i_get_pixel($self->{IMG}, $x, $y);
2255 return i_gpixf($self->{IMG}, $x, $y);
2262 # make an identity matrix of the given size
2266 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
2267 for my $c (0 .. ($size-1)) {
2268 $matrix->[$c][$c] = 1;
2273 # general function to convert an image
2275 my ($self, %opts) = @_;
2278 # the user can either specify a matrix or preset
2279 # the matrix overrides the preset
2280 if (!exists($opts{matrix})) {
2281 unless (exists($opts{preset})) {
2282 $self->{ERRSTR} = "convert() needs a matrix or preset";
2286 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
2287 # convert to greyscale, keeping the alpha channel if any
2288 if ($self->getchannels == 3) {
2289 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
2291 elsif ($self->getchannels == 4) {
2292 # preserve the alpha channel
2293 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
2298 $matrix = _identity($self->getchannels);
2301 elsif ($opts{preset} eq 'noalpha') {
2302 # strip the alpha channel
2303 if ($self->getchannels == 2 or $self->getchannels == 4) {
2304 $matrix = _identity($self->getchannels);
2305 pop(@$matrix); # lose the alpha entry
2308 $matrix = _identity($self->getchannels);
2311 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
2313 $matrix = [ [ 1 ] ];
2315 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
2316 $matrix = [ [ 0, 1 ] ];
2318 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
2319 $matrix = [ [ 0, 0, 1 ] ];
2321 elsif ($opts{preset} eq 'alpha') {
2322 if ($self->getchannels == 2 or $self->getchannels == 4) {
2323 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
2326 # the alpha is just 1 <shrug>
2327 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
2330 elsif ($opts{preset} eq 'rgb') {
2331 if ($self->getchannels == 1) {
2332 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
2334 elsif ($self->getchannels == 2) {
2335 # preserve the alpha channel
2336 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
2339 $matrix = _identity($self->getchannels);
2342 elsif ($opts{preset} eq 'addalpha') {
2343 if ($self->getchannels == 1) {
2344 $matrix = _identity(2);
2346 elsif ($self->getchannels == 3) {
2347 $matrix = _identity(4);
2350 $matrix = _identity($self->getchannels);
2354 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
2360 $matrix = $opts{matrix};
2363 my $new = Imager->new();
2364 $new->{IMG} = i_img_new();
2365 unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
2366 # most likely a bad matrix
2367 $self->{ERRSTR} = _error_as_msg();
2374 # general function to map an image through lookup tables
2377 my ($self, %opts) = @_;
2378 my @chlist = qw( red green blue alpha );
2380 if (!exists($opts{'maps'})) {
2381 # make maps from channel maps
2383 for $chnum (0..$#chlist) {
2384 if (exists $opts{$chlist[$chnum]}) {
2385 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
2386 } elsif (exists $opts{'all'}) {
2387 $opts{'maps'}[$chnum] = $opts{'all'};
2391 if ($opts{'maps'} and $self->{IMG}) {
2392 i_map($self->{IMG}, $opts{'maps'} );
2397 # destructive border - image is shrunk by one pixel all around
2400 my ($self,%opts)=@_;
2401 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
2402 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
2406 # Get the width of an image
2410 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2411 return (i_img_info($self->{IMG}))[0];
2414 # Get the height of an image
2418 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2419 return (i_img_info($self->{IMG}))[1];
2422 # Get number of channels in an image
2426 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2427 return i_img_getchannels($self->{IMG});
2434 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2435 return i_img_getmask($self->{IMG});
2443 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2444 i_img_setmask( $self->{IMG} , $opts{mask} );
2447 # Get number of colors in an image
2451 my %opts=('maxcolors'=>2**30,@_);
2452 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
2453 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
2454 return ($rc==-1? undef : $rc);
2457 # draw string to an image
2461 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2463 my %input=('x'=>0, 'y'=>0, @_);
2464 $input{string}||=$input{text};
2466 unless(exists $input{string}) {
2467 $self->{ERRSTR}="missing required parameter 'string'";
2471 unless($input{font}) {
2472 $self->{ERRSTR}="missing required parameter 'font'";
2476 unless ($input{font}->draw(image=>$self, %input)) {
2477 $self->{ERRSTR} = $self->_error_as_msg();
2484 # Shortcuts that can be exported
2486 sub newcolor { Imager::Color->new(@_); }
2487 sub newfont { Imager::Font->new(@_); }
2489 *NC=*newcolour=*newcolor;
2496 #### Utility routines
2499 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
2503 my ($self, $msg) = @_;
2506 $self->{ERRSTR} = $msg;
2513 # Default guess for the type of an image from extension
2515 sub def_guess_type {
2518 $ext=($name =~ m/\.([^\.]+)$/)[0];
2519 return 'tiff' if ($ext =~ m/^tiff?$/);
2520 return 'jpeg' if ($ext =~ m/^jpe?g$/);
2521 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
2522 return 'png' if ($ext eq "png");
2523 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
2524 return 'tga' if ($ext eq "tga");
2525 return 'rgb' if ($ext eq "rgb");
2526 return 'gif' if ($ext eq "gif");
2527 return 'raw' if ($ext eq "raw");
2531 # get the minimum of a list
2535 for(@_) { if ($_<$mx) { $mx=$_; }}
2539 # get the maximum of a list
2543 for(@_) { if ($_>$mx) { $mx=$_; }}
2547 # string stuff for iptc headers
2551 $str = substr($str,3);
2552 $str =~ s/[\n\r]//g;
2559 # A little hack to parse iptc headers.
2564 my($caption,$photogr,$headln,$credit);
2566 my $str=$self->{IPTCRAW};
2570 @ar=split(/8BIM/,$str);
2575 @sar=split(/\034\002/);
2576 foreach $item (@sar) {
2577 if ($item =~ m/^x/) {
2578 $caption=&clean($item);
2581 if ($item =~ m/^P/) {
2582 $photogr=&clean($item);
2585 if ($item =~ m/^i/) {
2586 $headln=&clean($item);
2589 if ($item =~ m/^n/) {
2590 $credit=&clean($item);
2596 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
2599 # Autoload methods go after =cut, and are processed by the autosplit program.
2603 # Below is the stub of documentation for your module. You better edit it!
2607 Imager - Perl extension for Generating 24 bit Images
2617 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
2622 my $img = Imager->new();
2623 $img->open(file=>$file) or die $img->errstr();
2625 $file =~ s/\.[^.]*$//;
2627 # Create smaller version
2628 my $thumb = $img->scale(scalefactor=>.3);
2630 # Autostretch individual channels
2631 $thumb->filter(type=>'autolevels');
2633 # try to save in one of these formats
2636 for $format ( qw( png gif jpg tiff ppm ) ) {
2637 # Check if given format is supported
2638 if ($Imager::formats{$format}) {
2639 $file.="_low.$format";
2640 print "Storing image as: $file\n";
2641 $thumb->write(file=>$file) or
2648 # Logo Generator Example
2654 Imager is a module for creating and altering images. It can read and
2655 write various image formats, draw primitive shapes like lines,and
2656 polygons, blend multiple images together in various ways, scale, crop,
2657 render text and more.
2659 =head2 Overview of documentation
2665 This document - Synopsis Example, Table of Contents and Overview.
2667 =item Imager::ImageTypes
2669 Direct type/virtual images, RGB(A)/paletted images, 8/16/double
2670 bits/channel, color maps, channel masks, image tags, color
2675 IO interaction, reading/writing images, format specific tags.
2679 Drawing Primitives, lines, boxes, circles, arcs, flood fill.
2683 Color specification.
2687 Fill pattern specification.
2691 General font rendering, bounding boxes and font metrics.
2693 =item Imager::Transformations
2695 Copying, scaling, cropping, flipping, blending, pasting, convert and
2698 =item Imager::Engines
2700 Programmable transformations through C<transform()>, C<transform2()>
2701 and C<matrix_transform()>.
2703 =item Imager::Filters
2705 Filters, sharpen, blur, noise, convolve etc. and filter plugins.
2709 Expressions for evaluation engine used by transform2().
2711 =item Imager::Matrix2d
2713 Helper class for affine transformations.
2715 =item Imager::Fountain
2717 Helper for making gradient profiles.
2723 =head2 Basic Overview
2725 An Image object is created with C<$img = Imager-E<gt>new()> Should
2726 this fail for some reason an explanation can be found in
2727 C<$Imager::ERRSTR> usually error messages are stored in
2728 C<$img-E<gt>{ERRSTR}>, but since no object is created this is the only
2729 way to give back errors. C<$Imager::ERRSTR> is also used to report
2730 all errors not directly associated with an image object. Examples:
2732 $img=Imager->new(); # This is an empty image (size is 0 by 0)
2733 $img->open(file=>'lena.png',type=>'png'); # initializes from file
2735 or if you want to create an empty image:
2737 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
2739 This example creates a completely black image of width 400 and height
2744 You can ask for help, report bugs or express your undying love for
2745 Imager on the Imager-devel mailing list.
2747 To subscribe send a message with C<subscribe> in the body to:
2749 imager-devel+request@molar.is
2753 http://www.molar.is/en/lists/imager-devel/
2755 where you can also find the mailing list archive.
2757 If you're into IRC, you can typically find the developers in #Imager
2758 on irc.rhizomatic.net. As with any IRC channel, the participants
2759 could be occupied or asleep, so please be patient.
2763 Bugs are listed individually for relevant pod pages.
2767 Arnar M. Hrafnkelsson (addi@umich.edu) and Tony Cook
2768 (tony@imager.perl.org) See the README for a complete list.
2772 perl(1), Imager::Color(3), Imager::Font(3), Imager::Matrix2d(3),
2774 Affix::Infix2Postfix(3), Parse::RecDescent(3)
2775 http://www.eecs.umich.edu/~addi/perl/Imager/