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");
948 my $oldfh = select($input->{fh});
949 # flush anything that's buffered, and make sure anything else is flushed
952 return io_new_fd($fd);
954 elsif ($input->{file}) {
955 my $fh = new IO::File($input->{file},"w+");
957 $self->_set_error("Could not open file $input->{file}: $!");
961 return (io_new_fd(fileno($fh)), $fh);
963 elsif ($input->{data}) {
964 return io_new_bufchain();
966 elsif ($input->{callback} || $input->{writecb}) {
967 if ($input->{maxbuffer}) {
968 return io_new_cb($input->{callback} || $input->{writecb},
970 $input->{seekcb}, $input->{closecb},
971 $input->{maxbuffer});
974 return io_new_cb($input->{callback} || $input->{writecb},
976 $input->{seekcb}, $input->{closecb});
980 $self->_set_error("file/fd/fh/data/callback parameter missing");
985 # Read an image from file
991 if (defined($self->{IMG})) {
992 # let IIM_DESTROY do the destruction, since the image may be
993 # referenced from elsewhere
994 #i_img_destroy($self->{IMG});
998 # FIXME: Find the format here if not specified
999 # yes the code isn't here yet - next week maybe?
1000 # Next week? Are you high or something? That comment
1001 # has been there for half a year dude.
1002 # Look, i just work here, ok?
1004 if (!$input{'type'} and $input{file}) {
1005 $input{'type'}=$FORMATGUESS->($input{file});
1007 unless ($input{'type'}) {
1008 $self->_set_error('type parameter missing and not possible to guess from extension');
1011 if (!$formats{$input{'type'}}) {
1012 $self->{ERRSTR}='format not supported'; return undef;
1015 my %iolready=(jpeg=>1, png=>1, tiff=>1, pnm=>1, raw=>1, bmp=>1, tga=>1, rgb=>1, gif=>1);
1017 if ($iolready{$input{'type'}}) {
1019 my ($IO, $fh) = $self->_get_reader_io(\%input, $input{'type'})
1022 if ( $input{'type'} eq 'jpeg' ) {
1023 ($self->{IMG},$self->{IPTCRAW})=i_readjpeg_wiol( $IO );
1024 if ( !defined($self->{IMG}) ) {
1025 $self->{ERRSTR}='unable to read jpeg image'; return undef;
1027 $self->{DEBUG} && print "loading a jpeg file\n";
1031 if ( $input{'type'} eq 'tiff' ) {
1032 $self->{IMG}=i_readtiff_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1033 if ( !defined($self->{IMG}) ) {
1034 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1036 $self->{DEBUG} && print "loading a tiff file\n";
1040 if ( $input{'type'} eq 'pnm' ) {
1041 $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1042 if ( !defined($self->{IMG}) ) {
1043 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); return undef;
1045 $self->{DEBUG} && print "loading a pnm file\n";
1049 if ( $input{'type'} eq 'png' ) {
1050 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1051 if ( !defined($self->{IMG}) ) {
1052 $self->{ERRSTR}='unable to read png image';
1055 $self->{DEBUG} && print "loading a png file\n";
1058 if ( $input{'type'} eq 'bmp' ) {
1059 $self->{IMG}=i_readbmp_wiol( $IO );
1060 if ( !defined($self->{IMG}) ) {
1061 $self->{ERRSTR}=$self->_error_as_msg();
1064 $self->{DEBUG} && print "loading a bmp file\n";
1067 if ( $input{'type'} eq 'gif' ) {
1068 if ($input{colors} && !ref($input{colors})) {
1069 # must be a reference to a scalar that accepts the colour map
1070 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1073 if ($input{colors}) {
1075 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1077 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1081 $self->{IMG} =i_readgif_wiol( $IO );
1083 if ( !defined($self->{IMG}) ) {
1084 $self->{ERRSTR}=$self->_error_as_msg();
1087 $self->{DEBUG} && print "loading a gif file\n";
1090 if ( $input{'type'} eq 'tga' ) {
1091 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1092 if ( !defined($self->{IMG}) ) {
1093 $self->{ERRSTR}=$self->_error_as_msg();
1096 $self->{DEBUG} && print "loading a tga file\n";
1099 if ( $input{'type'} eq 'rgb' ) {
1100 $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1101 if ( !defined($self->{IMG}) ) {
1102 $self->{ERRSTR}=$self->_error_as_msg();
1105 $self->{DEBUG} && print "loading a tga file\n";
1109 if ( $input{'type'} eq 'raw' ) {
1110 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1112 if ( !($params{xsize} && $params{ysize}) ) {
1113 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1117 $self->{IMG} = i_readraw_wiol( $IO,
1120 $params{datachannels},
1121 $params{storechannels},
1122 $params{interleave});
1123 if ( !defined($self->{IMG}) ) {
1124 $self->{ERRSTR}='unable to read raw image';
1127 $self->{DEBUG} && print "loading a raw file\n";
1132 # Old code for reference while changing the new stuff
1134 if (!$input{'type'} and $input{file}) {
1135 $input{'type'}=$FORMATGUESS->($input{file});
1138 if (!$input{'type'}) {
1139 $self->{ERRSTR}='type parameter missing and not possible to guess from extension'; return undef;
1142 if (!$formats{$input{'type'}}) {
1143 $self->{ERRSTR}='format not supported';
1149 $fh = new IO::File($input{file},"r");
1151 $self->{ERRSTR}='Could not open file';
1155 $fd = $fh->fileno();
1162 if ( $input{'type'} eq 'gif' ) {
1164 if ($input{colors} && !ref($input{colors})) {
1165 # must be a reference to a scalar that accepts the colour map
1166 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1169 if (exists $input{data}) {
1170 if ($input{colors}) {
1171 ($self->{IMG}, $colors) = i_readgif_scalar($input{data});
1173 $self->{IMG}=i_readgif_scalar($input{data});
1176 if ($input{colors}) {
1177 ($self->{IMG}, $colors) = i_readgif( $fd );
1179 $self->{IMG} = i_readgif( $fd )
1183 # we may or may not change i_readgif to return blessed objects...
1184 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1186 if ( !defined($self->{IMG}) ) {
1187 $self->{ERRSTR}= 'reading GIF:'._error_as_msg();
1190 $self->{DEBUG} && print "loading a gif file\n";
1196 sub _fix_gif_positions {
1197 my ($opts, $opt, $msg, @imgs) = @_;
1199 my $positions = $opts->{'gif_positions'};
1201 for my $pos (@$positions) {
1202 my ($x, $y) = @$pos;
1203 my $img = $imgs[$index++];
1204 $img->settag(name=>'gif_left', value=>$x);
1205 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1207 $$msg .= "replaced with the gif_left and gif_top tags";
1212 gif_each_palette=>'gif_local_map',
1213 interlace => 'gif_interlace',
1214 gif_delays => 'gif_delay',
1215 gif_positions => \&_fix_gif_positions,
1216 gif_loop_count => 'gif_loop',
1220 my ($self, $opts, $prefix, @imgs) = @_;
1222 for my $opt (keys %$opts) {
1224 if ($obsolete_opts{$opt}) {
1225 my $new = $obsolete_opts{$opt};
1226 my $msg = "Obsolete option $opt ";
1228 $new->($opts, $opt, \$msg, @imgs);
1231 $msg .= "replaced with the $new tag ";
1234 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1235 warn $msg if $warn_obsolete && $^W;
1237 next unless $tagname =~ /^\Q$prefix/;
1238 my $value = $opts->{$opt};
1240 if (UNIVERSAL::isa($value, "Imager::Color")) {
1241 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1242 for my $img (@imgs) {
1243 $img->settag(name=>$tagname, value=>$tag);
1246 elsif (ref($value) eq 'ARRAY') {
1247 for my $i (0..$#$value) {
1248 my $val = $value->[$i];
1250 if (UNIVERSAL::isa($val, "Imager::Color")) {
1251 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1253 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1256 $self->_set_error("Unknown reference type " . ref($value) .
1257 " supplied in array for $opt");
1263 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1268 $self->_set_error("Unknown reference type " . ref($value) .
1269 " supplied for $opt");
1274 # set it as a tag for every image
1275 for my $img (@imgs) {
1276 $img->settag(name=>$tagname, value=>$value);
1284 # Write an image to file
1287 my %input=(jpegquality=>75,
1297 $self->_set_opts(\%input, "i_", $self)
1300 my %iolready=( tiff=>1, raw=>1, png=>1, pnm=>1, bmp=>1, jpeg=>1, tga=>1,
1301 gif=>1 ); # this will be SO MUCH BETTER once they are all in there
1303 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1305 if (!$input{'type'} and $input{file}) {
1306 $input{'type'}=$FORMATGUESS->($input{file});
1308 if (!$input{'type'}) {
1309 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1313 if (!$formats{$input{'type'}}) { $self->{ERRSTR}='format not supported'; return undef; }
1315 my ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1318 # this conditional is probably obsolete
1319 if ($iolready{$input{'type'}}) {
1321 if ($input{'type'} eq 'tiff') {
1322 $self->_set_opts(\%input, "tiff_", $self)
1324 $self->_set_opts(\%input, "exif_", $self)
1327 if (defined $input{class} && $input{class} eq 'fax') {
1328 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1329 $self->{ERRSTR}='Could not write to buffer';
1333 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1334 $self->{ERRSTR}='Could not write to buffer';
1338 } elsif ( $input{'type'} eq 'pnm' ) {
1339 $self->_set_opts(\%input, "pnm_", $self)
1341 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1342 $self->{ERRSTR}='unable to write pnm image';
1345 $self->{DEBUG} && print "writing a pnm file\n";
1346 } elsif ( $input{'type'} eq 'raw' ) {
1347 $self->_set_opts(\%input, "raw_", $self)
1349 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1350 $self->{ERRSTR}='unable to write raw image';
1353 $self->{DEBUG} && print "writing a raw file\n";
1354 } elsif ( $input{'type'} eq 'png' ) {
1355 $self->_set_opts(\%input, "png_", $self)
1357 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1358 $self->{ERRSTR}='unable to write png image';
1361 $self->{DEBUG} && print "writing a png file\n";
1362 } elsif ( $input{'type'} eq 'jpeg' ) {
1363 $self->_set_opts(\%input, "jpeg_", $self)
1365 $self->_set_opts(\%input, "exif_", $self)
1367 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1368 $self->{ERRSTR} = $self->_error_as_msg();
1371 $self->{DEBUG} && print "writing a jpeg file\n";
1372 } elsif ( $input{'type'} eq 'bmp' ) {
1373 $self->_set_opts(\%input, "bmp_", $self)
1375 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1376 $self->{ERRSTR}='unable to write bmp image';
1379 $self->{DEBUG} && print "writing a bmp file\n";
1380 } elsif ( $input{'type'} eq 'tga' ) {
1381 $self->_set_opts(\%input, "tga_", $self)
1384 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1385 $self->{ERRSTR}=$self->_error_as_msg();
1388 $self->{DEBUG} && print "writing a tga file\n";
1389 } elsif ( $input{'type'} eq 'gif' ) {
1390 $self->_set_opts(\%input, "gif_", $self)
1392 # compatibility with the old interfaces
1393 if ($input{gifquant} eq 'lm') {
1394 $input{make_colors} = 'addi';
1395 $input{translate} = 'perturb';
1396 $input{perturb} = $input{lmdither};
1397 } elsif ($input{gifquant} eq 'gen') {
1398 # just pass options through
1400 $input{make_colors} = 'webmap'; # ignored
1401 $input{translate} = 'giflib';
1403 $rc = i_writegif_wiol($IO, \%input, $self->{IMG});
1406 if (exists $input{'data'}) {
1407 my $data = io_slurp($IO);
1409 $self->{ERRSTR}='Could not slurp from buffer';
1412 ${$input{data}} = $data;
1421 my ($class, $opts, @images) = @_;
1423 if (!$opts->{'type'} && $opts->{'file'}) {
1424 $opts->{'type'} = $FORMATGUESS->($opts->{'file'});
1426 unless ($opts->{'type'}) {
1427 $class->_set_error('type parameter missing and not possible to guess from extension');
1430 # translate to ImgRaw
1431 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1432 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1435 $class->_set_opts($opts, "i_", @images)
1437 my @work = map $_->{IMG}, @images;
1438 my ($IO, $file) = $class->_get_writer_io($opts, $opts->{'type'})
1440 if ($opts->{'type'} eq 'gif') {
1441 $class->_set_opts($opts, "gif_", @images)
1443 my $gif_delays = $opts->{gif_delays};
1444 local $opts->{gif_delays} = $gif_delays;
1445 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1446 # assume the caller wants the same delay for each frame
1447 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1449 my $res = i_writegif_wiol($IO, $opts, @work);
1450 $res or $class->_set_error($class->_error_as_msg());
1453 elsif ($opts->{'type'} eq 'tiff') {
1454 $class->_set_opts($opts, "tiff_", @images)
1456 $class->_set_opts($opts, "exif_", @images)
1459 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1460 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1461 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1464 $res = i_writetiff_multi_wiol($IO, @work);
1466 $res or $class->_set_error($class->_error_as_msg());
1470 $ERRSTR = "Sorry, write_multi doesn't support $opts->{'type'} yet";
1475 # read multiple images from a file
1477 my ($class, %opts) = @_;
1479 if ($opts{file} && !exists $opts{'type'}) {
1481 my $type = $FORMATGUESS->($opts{file});
1482 $opts{'type'} = $type;
1484 unless ($opts{'type'}) {
1485 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1489 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1491 if ($opts{'type'} eq 'gif') {
1493 @imgs = i_readgif_multi_wiol($IO);
1496 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1500 $ERRSTR = _error_as_msg();
1504 elsif ($opts{'type'} eq 'tiff') {
1505 my @imgs = i_readtiff_multi_wiol($IO, -1);
1508 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1512 $ERRSTR = _error_as_msg();
1517 $ERRSTR = "Cannot read multiple images from $opts{'type'} files";
1521 # Destroy an Imager object
1525 # delete $instances{$self};
1526 if (defined($self->{IMG})) {
1527 # the following is now handled by the XS DESTROY method for
1528 # Imager::ImgRaw object
1529 # Re-enabling this will break virtual images
1530 # tested for in t/t020masked.t
1531 # i_img_destroy($self->{IMG});
1532 undef($self->{IMG});
1534 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1538 # Perform an inplace filter of an image
1539 # that is the image will be overwritten with the data
1545 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1547 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1549 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1550 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1553 if ($filters{$input{'type'}}{names}) {
1554 my $names = $filters{$input{'type'}}{names};
1555 for my $name (keys %$names) {
1556 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1557 $input{$name} = $names->{$name}{$input{$name}};
1561 if (defined($filters{$input{'type'}}{defaults})) {
1562 %hsh=('image',$self->{IMG},%{$filters{$input{'type'}}{defaults}},%input);
1564 %hsh=('image',$self->{IMG},%input);
1567 my @cs=@{$filters{$input{'type'}}{callseq}};
1570 if (!defined($hsh{$_})) {
1571 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1575 &{$filters{$input{'type'}}{callsub}}(%hsh);
1579 $self->{DEBUG} && print "callseq is: @cs\n";
1580 $self->{DEBUG} && print "matching callseq is: @b\n";
1585 # Scale an image to requested size and return the scaled version
1589 my %opts=(scalefactor=>0.5,'type'=>'max',qtype=>'normal',@_);
1590 my $img = Imager->new();
1591 my $tmp = Imager->new();
1593 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1595 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
1596 my ($xpix,$ypix)=( $opts{xpixels}/$self->getwidth() , $opts{ypixels}/$self->getheight() );
1597 if ($opts{'type'} eq 'min') { $opts{scalefactor}=min($xpix,$ypix); }
1598 if ($opts{'type'} eq 'max') { $opts{scalefactor}=max($xpix,$ypix); }
1599 } elsif ($opts{xpixels}) { $opts{scalefactor}=$opts{xpixels}/$self->getwidth(); }
1600 elsif ($opts{ypixels}) { $opts{scalefactor}=$opts{ypixels}/$self->getheight(); }
1602 if ($opts{qtype} eq 'normal') {
1603 $tmp->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
1604 if ( !defined($tmp->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1605 $img->{IMG}=i_scaleaxis($tmp->{IMG},$opts{scalefactor},1);
1606 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1609 if ($opts{'qtype'} eq 'preview') {
1610 $img->{IMG}=i_scale_nn($self->{IMG},$opts{'scalefactor'},$opts{'scalefactor'});
1611 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1614 $self->{ERRSTR}='scale: invalid value for qtype'; return undef;
1617 # Scales only along the X axis
1621 my %opts=(scalefactor=>0.5,@_);
1623 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1625 my $img = Imager->new();
1627 if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getwidth(); }
1629 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1630 $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
1632 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1636 # Scales only along the Y axis
1640 my %opts=(scalefactor=>0.5,@_);
1642 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1644 my $img = Imager->new();
1646 if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getheight(); }
1648 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1649 $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},1);
1651 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1656 # Transform returns a spatial transformation of the input image
1657 # this moves pixels to a new location in the returned image.
1658 # NOTE - should make a utility function to check transforms for
1663 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1665 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
1667 # print Dumper(\%opts);
1670 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
1672 eval ("use Affix::Infix2Postfix;");
1675 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
1678 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
1679 {op=>'-',trans=>'Sub'},
1680 {op=>'*',trans=>'Mult'},
1681 {op=>'/',trans=>'Div'},
1682 {op=>'-','type'=>'unary',trans=>'u-'},
1684 {op=>'func','type'=>'unary'}],
1685 'grouping'=>[qw( \( \) )],
1686 'func'=>[qw( sin cos )],
1691 @xt=$I2P->translate($opts{'xexpr'});
1692 @yt=$I2P->translate($opts{'yexpr'});
1694 $numre=$I2P->{'numre'};
1697 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
1698 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
1699 @{$opts{'parm'}}=@pt;
1702 # print Dumper(\%opts);
1704 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
1705 $self->{ERRSTR}='transform: no xopcodes given.';
1709 @op=@{$opts{'xopcodes'}};
1711 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
1712 $self->{ERRSTR}="transform: illegal opcode '$_'.";
1715 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
1721 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
1722 $self->{ERRSTR}='transform: no yopcodes given.';
1726 @op=@{$opts{'yopcodes'}};
1728 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
1729 $self->{ERRSTR}="transform: illegal opcode '$_'.";
1732 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
1737 if ( !exists $opts{'parm'}) {
1738 $self->{ERRSTR}='transform: no parameter arg given.';
1742 # print Dumper(\@ropx);
1743 # print Dumper(\@ropy);
1744 # print Dumper(\@ropy);
1746 my $img = Imager->new();
1747 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
1748 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
1754 my ($opts, @imgs) = @_;
1756 require "Imager/Expr.pm";
1758 $opts->{variables} = [ qw(x y) ];
1759 my ($width, $height) = @{$opts}{qw(width height)};
1761 $width ||= $imgs[0]->getwidth();
1762 $height ||= $imgs[0]->getheight();
1764 for my $img (@imgs) {
1765 $opts->{constants}{"w$img_num"} = $img->getwidth();
1766 $opts->{constants}{"h$img_num"} = $img->getheight();
1767 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
1768 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
1773 $opts->{constants}{w} = $width;
1774 $opts->{constants}{cx} = $width/2;
1777 $Imager::ERRSTR = "No width supplied";
1781 $opts->{constants}{h} = $height;
1782 $opts->{constants}{cy} = $height/2;
1785 $Imager::ERRSTR = "No height supplied";
1788 my $code = Imager::Expr->new($opts);
1790 $Imager::ERRSTR = Imager::Expr::error();
1794 my $img = Imager->new();
1795 $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, $code->code(),
1796 $code->nregs(), $code->cregs(),
1797 [ map { $_->{IMG} } @imgs ]);
1798 if (!defined $img->{IMG}) {
1799 $Imager::ERRSTR = Imager->_error_as_msg();
1808 my %opts=(tx=>0,ty=>0,@_);
1810 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1811 unless ($opts{src} && $opts{src}->{IMG}) { $self->{ERRSTR}='empty input image for source'; return undef; }
1813 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx},$opts{ty})) {
1814 $self->{ERRSTR} = $self->_error_as_msg();
1824 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
1826 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
1827 $dir = $xlate{$opts{'dir'}};
1828 return $self if i_flipxy($self->{IMG}, $dir);
1835 if (defined $opts{right}) {
1836 my $degrees = $opts{right};
1838 $degrees += 360 * int(((-$degrees)+360)/360);
1840 $degrees = $degrees % 360;
1841 if ($degrees == 0) {
1842 return $self->copy();
1844 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
1845 my $result = Imager->new();
1846 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
1850 $self->{ERRSTR} = $self->_error_as_msg();
1855 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
1859 elsif (defined $opts{radians} || defined $opts{degrees}) {
1860 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
1862 my $result = Imager->new;
1863 if ($result->{IMG} = i_rotate_exact($self->{IMG}, $amount)) {
1867 $self->{ERRSTR} = $self->_error_as_msg();
1872 $self->{ERRSTR} = "Only the 'right' parameter is available";
1877 sub matrix_transform {
1881 if ($opts{matrix}) {
1882 my $xsize = $opts{xsize} || $self->getwidth;
1883 my $ysize = $opts{ysize} || $self->getheight;
1885 my $result = Imager->new;
1886 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
1893 $self->{ERRSTR} = "matrix parameter required";
1899 *yatf = \&matrix_transform;
1901 # These two are supported for legacy code only
1904 return Imager::Color->new(@_);
1908 return Imager::Color::set(@_);
1911 # Draws a box between the specified corner points.
1914 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1915 my $dflcl=i_color_new(255,255,255,255);
1916 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
1918 if (exists $opts{'box'}) {
1919 $opts{'xmin'} = min($opts{'box'}->[0],$opts{'box'}->[2]);
1920 $opts{'xmax'} = max($opts{'box'}->[0],$opts{'box'}->[2]);
1921 $opts{'ymin'} = min($opts{'box'}->[1],$opts{'box'}->[3]);
1922 $opts{'ymax'} = max($opts{'box'}->[1],$opts{'box'}->[3]);
1925 if ($opts{filled}) {
1926 my $color = _color($opts{'color'});
1928 $self->{ERRSTR} = $Imager::ERRSTR;
1931 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
1932 $opts{ymax}, $color);
1934 elsif ($opts{fill}) {
1935 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
1936 # assume it's a hash ref
1937 require 'Imager/Fill.pm';
1938 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
1939 $self->{ERRSTR} = $Imager::ERRSTR;
1943 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
1944 $opts{ymax},$opts{fill}{fill});
1947 my $color = _color($opts{'color'});
1949 $self->{ERRSTR} = $Imager::ERRSTR;
1952 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
1958 # Draws an arc - this routine SUCKS and is buggy - it sometimes doesn't work when the arc is a convex polygon
1962 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1963 my $dflcl=i_color_new(255,255,255,255);
1964 my %opts=(color=>$dflcl,
1965 'r'=>min($self->getwidth(),$self->getheight())/3,
1966 'x'=>$self->getwidth()/2,
1967 'y'=>$self->getheight()/2,
1968 'd1'=>0, 'd2'=>361, @_);
1970 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
1971 # assume it's a hash ref
1972 require 'Imager/Fill.pm';
1973 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
1974 $self->{ERRSTR} = $Imager::ERRSTR;
1978 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
1979 $opts{'d2'}, $opts{fill}{fill});
1982 my $color = _color($opts{'color'});
1984 $self->{ERRSTR} = $Imager::ERRSTR;
1987 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
1988 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
1992 if ($opts{'d1'} <= $opts{'d2'}) {
1993 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
1994 $opts{'d1'}, $opts{'d2'}, $color);
1997 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
1998 $opts{'d1'}, 361, $color);
1999 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2000 0, $opts{'d2'}, $color);
2008 # Draws a line from one point to (but not including) the destination point
2012 my $dflcl=i_color_new(0,0,0,0);
2013 my %opts=(color=>$dflcl,@_);
2014 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2016 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2017 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2019 my $color = _color($opts{'color'});
2021 $self->{ERRSTR} = $Imager::ERRSTR;
2024 $opts{antialias} = $opts{aa} if defined $opts{aa};
2025 if ($opts{antialias}) {
2026 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2029 i_draw($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2035 # Draws a line between an ordered set of points - It more or less just transforms this
2036 # into a list of lines.
2040 my ($pt,$ls,@points);
2041 my $dflcl=i_color_new(0,0,0,0);
2042 my %opts=(color=>$dflcl,@_);
2044 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2046 if (exists($opts{points})) { @points=@{$opts{points}}; }
2047 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2048 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2051 # print Dumper(\@points);
2053 my $color = _color($opts{'color'});
2055 $self->{ERRSTR} = $Imager::ERRSTR;
2058 $opts{antialias} = $opts{aa} if defined $opts{aa};
2059 if ($opts{antialias}) {
2062 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color);
2069 i_draw($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color);
2079 my ($pt,$ls,@points);
2080 my $dflcl = i_color_new(0,0,0,0);
2081 my %opts = (color=>$dflcl, @_);
2083 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2085 if (exists($opts{points})) {
2086 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2087 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2090 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2091 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2094 if ($opts{'fill'}) {
2095 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2096 # assume it's a hash ref
2097 require 'Imager/Fill.pm';
2098 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2099 $self->{ERRSTR} = $Imager::ERRSTR;
2103 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2104 $opts{'fill'}{'fill'});
2107 my $color = _color($opts{'color'});
2109 $self->{ERRSTR} = $Imager::ERRSTR;
2112 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2119 # this the multipoint bezier curve
2120 # this is here more for testing that actual usage since
2121 # this is not a good algorithm. Usually the curve would be
2122 # broken into smaller segments and each done individually.
2126 my ($pt,$ls,@points);
2127 my $dflcl=i_color_new(0,0,0,0);
2128 my %opts=(color=>$dflcl,@_);
2130 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2132 if (exists $opts{points}) {
2133 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2134 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2137 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2138 $self->{ERRSTR}='Missing or invalid points.';
2142 my $color = _color($opts{'color'});
2144 $self->{ERRSTR} = $Imager::ERRSTR;
2147 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2153 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2155 unless (exists $opts{'x'} && exists $opts{'y'}) {
2156 $self->{ERRSTR} = "missing seed x and y parameters";
2161 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2162 # assume it's a hash ref
2163 require 'Imager/Fill.pm';
2164 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2165 $self->{ERRSTR} = $Imager::ERRSTR;
2169 i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2172 my $color = _color($opts{'color'});
2174 $self->{ERRSTR} = $Imager::ERRSTR;
2177 i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2186 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2188 unless (exists $opts{'x'} && exists $opts{'y'}) {
2189 $self->{ERRSTR} = 'missing x and y parameters';
2195 my $color = _color($opts{color})
2197 if (ref $x && ref $y) {
2198 unless (@$x == @$y) {
2199 $self->{ERRSTR} = 'length of x and y mismatch';
2202 if ($color->isa('Imager::Color')) {
2203 for my $i (0..$#{$opts{'x'}}) {
2204 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color);
2208 for my $i (0..$#{$opts{'x'}}) {
2209 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color);
2214 if ($color->isa('Imager::Color')) {
2215 i_ppix($self->{IMG}, $x, $y, $color);
2218 i_ppixf($self->{IMG}, $x, $y, $color);
2228 my %opts = ( type=>'8bit', @_);
2230 unless (exists $opts{'x'} && exists $opts{'y'}) {
2231 $self->{ERRSTR} = 'missing x and y parameters';
2237 if (ref $x && ref $y) {
2238 unless (@$x == @$y) {
2239 $self->{ERRSTR} = 'length of x and y mismatch';
2243 if ($opts{type} eq '8bit') {
2244 for my $i (0..$#{$opts{'x'}}) {
2245 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2249 for my $i (0..$#{$opts{'x'}}) {
2250 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2253 return wantarray ? @result : \@result;
2256 if ($opts{type} eq '8bit') {
2257 return i_get_pixel($self->{IMG}, $x, $y);
2260 return i_gpixf($self->{IMG}, $x, $y);
2267 # make an identity matrix of the given size
2271 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
2272 for my $c (0 .. ($size-1)) {
2273 $matrix->[$c][$c] = 1;
2278 # general function to convert an image
2280 my ($self, %opts) = @_;
2283 # the user can either specify a matrix or preset
2284 # the matrix overrides the preset
2285 if (!exists($opts{matrix})) {
2286 unless (exists($opts{preset})) {
2287 $self->{ERRSTR} = "convert() needs a matrix or preset";
2291 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
2292 # convert to greyscale, keeping the alpha channel if any
2293 if ($self->getchannels == 3) {
2294 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
2296 elsif ($self->getchannels == 4) {
2297 # preserve the alpha channel
2298 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
2303 $matrix = _identity($self->getchannels);
2306 elsif ($opts{preset} eq 'noalpha') {
2307 # strip the alpha channel
2308 if ($self->getchannels == 2 or $self->getchannels == 4) {
2309 $matrix = _identity($self->getchannels);
2310 pop(@$matrix); # lose the alpha entry
2313 $matrix = _identity($self->getchannels);
2316 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
2318 $matrix = [ [ 1 ] ];
2320 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
2321 $matrix = [ [ 0, 1 ] ];
2323 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
2324 $matrix = [ [ 0, 0, 1 ] ];
2326 elsif ($opts{preset} eq 'alpha') {
2327 if ($self->getchannels == 2 or $self->getchannels == 4) {
2328 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
2331 # the alpha is just 1 <shrug>
2332 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
2335 elsif ($opts{preset} eq 'rgb') {
2336 if ($self->getchannels == 1) {
2337 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
2339 elsif ($self->getchannels == 2) {
2340 # preserve the alpha channel
2341 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
2344 $matrix = _identity($self->getchannels);
2347 elsif ($opts{preset} eq 'addalpha') {
2348 if ($self->getchannels == 1) {
2349 $matrix = _identity(2);
2351 elsif ($self->getchannels == 3) {
2352 $matrix = _identity(4);
2355 $matrix = _identity($self->getchannels);
2359 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
2365 $matrix = $opts{matrix};
2368 my $new = Imager->new();
2369 $new->{IMG} = i_img_new();
2370 unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
2371 # most likely a bad matrix
2372 $self->{ERRSTR} = _error_as_msg();
2379 # general function to map an image through lookup tables
2382 my ($self, %opts) = @_;
2383 my @chlist = qw( red green blue alpha );
2385 if (!exists($opts{'maps'})) {
2386 # make maps from channel maps
2388 for $chnum (0..$#chlist) {
2389 if (exists $opts{$chlist[$chnum]}) {
2390 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
2391 } elsif (exists $opts{'all'}) {
2392 $opts{'maps'}[$chnum] = $opts{'all'};
2396 if ($opts{'maps'} and $self->{IMG}) {
2397 i_map($self->{IMG}, $opts{'maps'} );
2402 # destructive border - image is shrunk by one pixel all around
2405 my ($self,%opts)=@_;
2406 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
2407 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
2411 # Get the width of an image
2415 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2416 return (i_img_info($self->{IMG}))[0];
2419 # Get the height of an image
2423 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2424 return (i_img_info($self->{IMG}))[1];
2427 # Get number of channels in an image
2431 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2432 return i_img_getchannels($self->{IMG});
2439 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2440 return i_img_getmask($self->{IMG});
2448 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2449 i_img_setmask( $self->{IMG} , $opts{mask} );
2452 # Get number of colors in an image
2456 my %opts=('maxcolors'=>2**30,@_);
2457 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
2458 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
2459 return ($rc==-1? undef : $rc);
2462 # draw string to an image
2466 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2468 my %input=('x'=>0, 'y'=>0, @_);
2469 $input{string}||=$input{text};
2471 unless(exists $input{string}) {
2472 $self->{ERRSTR}="missing required parameter 'string'";
2476 unless($input{font}) {
2477 $self->{ERRSTR}="missing required parameter 'font'";
2481 unless ($input{font}->draw(image=>$self, %input)) {
2482 $self->{ERRSTR} = $self->_error_as_msg();
2489 # Shortcuts that can be exported
2491 sub newcolor { Imager::Color->new(@_); }
2492 sub newfont { Imager::Font->new(@_); }
2494 *NC=*newcolour=*newcolor;
2501 #### Utility routines
2504 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
2508 my ($self, $msg) = @_;
2511 $self->{ERRSTR} = $msg;
2518 # Default guess for the type of an image from extension
2520 sub def_guess_type {
2523 $ext=($name =~ m/\.([^\.]+)$/)[0];
2524 return 'tiff' if ($ext =~ m/^tiff?$/);
2525 return 'jpeg' if ($ext =~ m/^jpe?g$/);
2526 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
2527 return 'png' if ($ext eq "png");
2528 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
2529 return 'tga' if ($ext eq "tga");
2530 return 'rgb' if ($ext eq "rgb");
2531 return 'gif' if ($ext eq "gif");
2532 return 'raw' if ($ext eq "raw");
2536 # get the minimum of a list
2540 for(@_) { if ($_<$mx) { $mx=$_; }}
2544 # get the maximum of a list
2548 for(@_) { if ($_>$mx) { $mx=$_; }}
2552 # string stuff for iptc headers
2556 $str = substr($str,3);
2557 $str =~ s/[\n\r]//g;
2564 # A little hack to parse iptc headers.
2569 my($caption,$photogr,$headln,$credit);
2571 my $str=$self->{IPTCRAW};
2575 @ar=split(/8BIM/,$str);
2580 @sar=split(/\034\002/);
2581 foreach $item (@sar) {
2582 if ($item =~ m/^x/) {
2583 $caption=&clean($item);
2586 if ($item =~ m/^P/) {
2587 $photogr=&clean($item);
2590 if ($item =~ m/^i/) {
2591 $headln=&clean($item);
2594 if ($item =~ m/^n/) {
2595 $credit=&clean($item);
2601 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
2604 # Autoload methods go after =cut, and are processed by the autosplit program.
2608 # Below is the stub of documentation for your module. You better edit it!
2612 Imager - Perl extension for Generating 24 bit Images
2622 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
2627 my $img = Imager->new();
2628 $img->open(file=>$file) or die $img->errstr();
2630 $file =~ s/\.[^.]*$//;
2632 # Create smaller version
2633 my $thumb = $img->scale(scalefactor=>.3);
2635 # Autostretch individual channels
2636 $thumb->filter(type=>'autolevels');
2638 # try to save in one of these formats
2641 for $format ( qw( png gif jpg tiff ppm ) ) {
2642 # Check if given format is supported
2643 if ($Imager::formats{$format}) {
2644 $file.="_low.$format";
2645 print "Storing image as: $file\n";
2646 $thumb->write(file=>$file) or
2653 # Logo Generator Example
2659 Imager is a module for creating and altering images. It can read and
2660 write various image formats, draw primitive shapes like lines,and
2661 polygons, blend multiple images together in various ways, scale, crop,
2662 render text and more.
2664 =head2 Overview of documentation
2670 This document - Synopsis Example, Table of Contents and Overview.
2672 =item Imager::ImageTypes
2674 Direct type/virtual images, RGB(A)/paletted images, 8/16/double
2675 bits/channel, color maps, channel masks, image tags, color
2680 IO interaction, reading/writing images, format specific tags.
2684 Drawing Primitives, lines, boxes, circles, arcs, flood fill.
2688 Color specification.
2692 Fill pattern specification.
2696 General font rendering, bounding boxes and font metrics.
2698 =item Imager::Transformations
2700 Copying, scaling, cropping, flipping, blending, pasting, convert and
2703 =item Imager::Engines
2705 Programmable transformations through C<transform()>, C<transform2()>
2706 and C<matrix_transform()>.
2708 =item Imager::Filters
2710 Filters, sharpen, blur, noise, convolve etc. and filter plugins.
2714 Expressions for evaluation engine used by transform2().
2716 =item Imager::Matrix2d
2718 Helper class for affine transformations.
2720 =item Imager::Fountain
2722 Helper for making gradient profiles.
2728 =head2 Basic Overview
2730 An Image object is created with C<$img = Imager-E<gt>new()>.
2733 $img=Imager->new(); # create empty image
2734 $img->open(file=>'lena.png',type=>'png') or # read image from file
2735 die $img->errstr(); # give an explanation
2736 # if something failed
2738 or if you want to create an empty image:
2740 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
2742 This example creates a completely black image of width 400 and height
2745 When an operation fails which can be directly associated with an image
2746 the error message is stored can be retrieved with
2747 C<$img-E<gt>errstr()>.
2749 In cases where no image object is associated with an operation
2750 C<$Imager::ERRSTR> is used to report errors not directly associated
2751 with an image object.
2755 You can ask for help, report bugs or express your undying love for
2756 Imager on the Imager-devel mailing list.
2758 To subscribe send a message with C<subscribe> in the body to:
2760 imager-devel+request@molar.is
2764 http://www.molar.is/en/lists/imager-devel/
2765 (annonymous is temporarily off due to spam)
2767 where you can also find the mailing list archive.
2769 If you're into IRC, you can typically find the developers in #Imager
2770 on irc.rhizomatic.net. As with any IRC channel, the participants
2771 could be occupied or asleep, so please be patient.
2775 Bugs are listed individually for relevant pod pages.
2779 Arnar M. Hrafnkelsson (addi@imager.perl.org) and Tony Cook
2780 (tony@imager.perl.org) See the README for a complete list.
2784 perl(1), Imager::ImageTypes(3), Imager::Files(3), Imager::Draw(3),
2785 Imager::Color(3), Imager::Fill(3), Imager::Font(3),
2786 Imager::Transformations(3), Imager::Engines(3), Imager::Filters(3),
2787 Imager::Expr(3), Imager::Matrix2d(3), Imager::Fountain(3)
2789 Affix::Infix2Postfix(3), Parse::RecDescent(3)
2790 http://www.eecs.umich.edu/~addi/perl/Imager/