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 m_init_log($_[0],$_[1]);
387 log_entry("Imager $VERSION starting\n", 1);
392 my %parms=(loglevel=>1,@_);
394 init_log($parms{'log'},$parms{'loglevel'});
397 if (exists $parms{'warn_obsolete'}) {
398 $warn_obsolete = $parms{'warn_obsolete'};
401 # if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
402 # if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
406 if (exists $parms{'t1log'}) {
407 i_init_fonts($parms{'t1log'});
413 print "shutdown code\n";
414 # for(keys %instances) { $instances{$_}->DESTROY(); }
415 malloc_state(); # how do decide if this should be used? -- store something from the import
416 print "Imager exiting\n";
420 # Load a filter plugin
425 my ($DSO_handle,$str)=DSO_open($filename);
426 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
427 my %funcs=DSO_funclist($DSO_handle);
428 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
430 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
432 $DSOs{$filename}=[$DSO_handle,\%funcs];
435 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
436 $DEBUG && print "eval string:\n",$evstr,"\n";
448 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
449 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
450 for(keys %{$funcref}) {
452 $DEBUG && print "unloading: $_\n";
454 my $rc=DSO_close($DSO_handle);
455 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
459 # take the results of i_error() and make a message out of it
461 return join(": ", map $_->[0], i_errors());
464 # this function tries to DWIM for color parameters
465 # color objects are used as is
466 # simple scalars are simply treated as single parameters to Imager::Color->new
467 # hashrefs are treated as named argument lists to Imager::Color->new
468 # arrayrefs are treated as list arguments to Imager::Color->new iff any
470 # other arrayrefs are treated as list arguments to Imager::Color::Float
474 # perl 5.6.0 seems to do weird things to $arg if we don't make an
475 # explicitly stringified copy
476 # I vaguely remember a bug on this on p5p, but couldn't find it
477 # through bugs.perl.org (I had trouble getting it to find any bugs)
478 my $copy = $arg . "";
482 if (UNIVERSAL::isa($arg, "Imager::Color")
483 || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
487 if ($copy =~ /^HASH\(/) {
488 $result = Imager::Color->new(%$arg);
490 elsif ($copy =~ /^ARRAY\(/) {
491 if (grep $_ > 1, @$arg) {
492 $result = Imager::Color->new(@$arg);
495 $result = Imager::Color::Float->new(@$arg);
499 $Imager::ERRSTR = "Not a color";
504 # assume Imager::Color::new knows how to handle it
505 $result = Imager::Color->new($arg);
513 # Methods to be called on objects.
516 # Create a new Imager object takes very few parameters.
517 # usually you call this method and then call open from
518 # the resulting object
525 $self->{IMG}=undef; # Just to indicate what exists
526 $self->{ERRSTR}=undef; #
527 $self->{DEBUG}=$DEBUG;
528 $self->{DEBUG} && print "Initialized Imager\n";
529 if ($hsh{xsize} && $hsh{ysize}) { $self->img_set(%hsh); }
533 # Copy an entire image with no changes
534 # - if an image has magic the copy of it will not be magical
538 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
540 my $newcopy=Imager->new();
541 $newcopy->{IMG}=i_img_new();
542 i_copy($newcopy->{IMG},$self->{IMG});
550 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
551 my %input=(left=>0, top=>0, @_);
552 unless($input{img}) {
553 $self->{ERRSTR}="no source image";
556 $input{left}=0 if $input{left} <= 0;
557 $input{top}=0 if $input{top} <= 0;
559 my($r,$b)=i_img_info($src->{IMG});
561 i_copyto($self->{IMG}, $src->{IMG},
562 0,0, $r, $b, $input{left}, $input{top});
563 return $self; # What should go here??
566 # Crop an image - i.e. return a new image that is smaller
570 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
571 my %hsh=(left=>0,right=>0,top=>0,bottom=>0,@_);
573 my ($w,$h,$l,$r,$b,$t)=($self->getwidth(),$self->getheight(),
574 @hsh{qw(left right bottom top)});
575 $l=0 if not defined $l;
576 $t=0 if not defined $t;
578 $r||=$l+delete $hsh{'width'} if defined $l and exists $hsh{'width'};
579 $b||=$t+delete $hsh{'height'} if defined $t and exists $hsh{'height'};
580 $l||=$r-delete $hsh{'width'} if defined $r and exists $hsh{'width'};
581 $t||=$b-delete $hsh{'height'} if defined $b and exists $hsh{'height'};
583 $r=$self->getwidth if not defined $r;
584 $b=$self->getheight if not defined $b;
586 ($l,$r)=($r,$l) if $l>$r;
587 ($t,$b)=($b,$t) if $t>$b;
590 $l=int(0.5+($w-$hsh{'width'})/2);
595 if ($hsh{'height'}) {
596 $b=int(0.5+($h-$hsh{'height'})/2);
597 $t=$h+$hsh{'height'};
599 $hsh{'height'}=$b-$t;
602 # print "l=$l, r=$r, h=$hsh{'width'}\n";
603 # print "t=$t, b=$b, w=$hsh{'height'}\n";
605 my $dst=Imager->new(xsize=>$hsh{'width'}, ysize=>$hsh{'height'}, channels=>$self->getchannels());
607 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
611 # Sets an image to a certain size and channel number
612 # if there was previously data in the image it is discarded
617 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
619 if (defined($self->{IMG})) {
620 # let IIM_DESTROY destroy it, it's possible this image is
621 # referenced from a virtual image (like masked)
622 #i_img_destroy($self->{IMG});
626 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
627 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
628 $hsh{maxcolors} || 256);
630 elsif ($hsh{bits} eq 'double') {
631 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
633 elsif ($hsh{bits} == 16) {
634 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
637 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
642 # created a masked version of the current image
646 $self or return undef;
647 my %opts = (left => 0,
649 right => $self->getwidth,
650 bottom => $self->getheight,
652 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
654 my $result = Imager->new;
655 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
656 $opts{top}, $opts{right} - $opts{left},
657 $opts{bottom} - $opts{top});
658 # keep references to the mask and base images so they don't
660 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
665 # convert an RGB image into a paletted image
669 if (@_ != 1 && !ref $_[0]) {
676 my $result = Imager->new;
677 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
679 #print "Type ", i_img_type($result->{IMG}), "\n";
681 $result->{IMG} or undef $result;
686 # convert a paletted (or any image) to an 8-bit/channel RGB images
692 $result = Imager->new;
693 $result->{IMG} = i_img_to_rgb($self->{IMG})
702 my %opts = (colors=>[], @_);
704 @{$opts{colors}} or return undef;
706 $self->{IMG} and i_addcolors($self->{IMG}, @{$opts{colors}});
711 my %opts = (start=>0, colors=>[], @_);
712 @{$opts{colors}} or return undef;
714 $self->{IMG} and i_setcolors($self->{IMG}, $opts{start}, @{$opts{colors}});
720 if (!exists $opts{start} && !exists $opts{count}) {
723 $opts{count} = $self->colorcount;
725 elsif (!exists $opts{count}) {
728 elsif (!exists $opts{start}) {
733 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
737 i_colorcount($_[0]{IMG});
741 i_maxcolors($_[0]{IMG});
747 $opts{color} or return undef;
749 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
754 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
755 if ($bits && $bits == length(pack("d", 1)) * 8) {
764 return i_img_type($self->{IMG}) ? "paletted" : "direct";
770 $self->{IMG} and i_img_virtual($self->{IMG});
774 my ($self, %opts) = @_;
776 $self->{IMG} or return;
778 if (defined $opts{name}) {
782 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
783 push @result, (i_tags_get($self->{IMG}, $found))[1];
786 return wantarray ? @result : $result[0];
788 elsif (defined $opts{code}) {
792 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
793 push @result, (i_tags_get($self->{IMG}, $found))[1];
800 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
803 return i_tags_count($self->{IMG});
812 return -1 unless $self->{IMG};
814 if (defined $opts{value}) {
815 if ($opts{value} =~ /^\d+$/) {
817 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
820 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
823 elsif (defined $opts{data}) {
824 # force addition as a string
825 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
828 $self->{ERRSTR} = "No value supplied";
832 elsif ($opts{code}) {
833 if (defined $opts{value}) {
834 if ($opts{value} =~ /^\d+$/) {
836 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
839 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
842 elsif (defined $opts{data}) {
843 # force addition as a string
844 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
847 $self->{ERRSTR} = "No value supplied";
860 return 0 unless $self->{IMG};
862 if (defined $opts{'index'}) {
863 return i_tags_delete($self->{IMG}, $opts{'index'});
865 elsif (defined $opts{name}) {
866 return i_tags_delbyname($self->{IMG}, $opts{name});
868 elsif (defined $opts{code}) {
869 return i_tags_delbycode($self->{IMG}, $opts{code});
872 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
878 my ($self, %opts) = @_;
881 $self->deltag(name=>$opts{name});
882 return $self->addtag(name=>$opts{name}, value=>$opts{value});
884 elsif (defined $opts{code}) {
885 $self->deltag(code=>$opts{code});
886 return $self->addtag(code=>$opts{code}, value=>$opts{value});
893 my @needseekcb = qw/tiff/;
894 my %needseekcb = map { $_, $_ } @needseekcb;
898 my ($self, $input, $type) = @_;
901 return io_new_fd($input->{fd});
903 elsif ($input->{fh}) {
904 my $fd = fileno($input->{fh});
906 $self->_set_error("Handle in fh option not opened");
909 return io_new_fd($fd);
911 elsif ($input->{file}) {
912 my $file = IO::File->new($input->{file}, "r");
914 $self->_set_error("Could not open $input->{file}: $!");
918 return (io_new_fd(fileno($file)), $file);
920 elsif ($input->{data}) {
921 return io_new_buffer($input->{data});
923 elsif ($input->{callback} || $input->{readcb}) {
924 if ($needseekcb{$type} && !$input->{seekcb}) {
925 $self->_set_error("Format $type needs a seekcb parameter");
927 if ($input->{maxbuffer}) {
928 return io_new_cb($input->{writecb},
929 $input->{callback} || $input->{readcb},
930 $input->{seekcb}, $input->{closecb},
931 $input->{maxbuffer});
934 return io_new_cb($input->{writecb},
935 $input->{callback} || $input->{readcb},
936 $input->{seekcb}, $input->{closecb});
940 $self->_set_error("file/fd/fh/data/callback parameter missing");
946 my ($self, $input, $type) = @_;
949 return io_new_fd($input->{fd});
951 elsif ($input->{fh}) {
952 my $fd = fileno($input->{fh});
954 $self->_set_error("Handle in fh option not opened");
958 my $oldfh = select($input->{fh});
959 # flush anything that's buffered, and make sure anything else is flushed
962 return io_new_fd($fd);
964 elsif ($input->{file}) {
965 my $fh = new IO::File($input->{file},"w+");
967 $self->_set_error("Could not open file $input->{file}: $!");
971 return (io_new_fd(fileno($fh)), $fh);
973 elsif ($input->{data}) {
974 return io_new_bufchain();
976 elsif ($input->{callback} || $input->{writecb}) {
977 if ($input->{maxbuffer}) {
978 return io_new_cb($input->{callback} || $input->{writecb},
980 $input->{seekcb}, $input->{closecb},
981 $input->{maxbuffer});
984 return io_new_cb($input->{callback} || $input->{writecb},
986 $input->{seekcb}, $input->{closecb});
990 $self->_set_error("file/fd/fh/data/callback parameter missing");
995 # Read an image from file
1001 if (defined($self->{IMG})) {
1002 # let IIM_DESTROY do the destruction, since the image may be
1003 # referenced from elsewhere
1004 #i_img_destroy($self->{IMG});
1005 undef($self->{IMG});
1008 # FIXME: Find the format here if not specified
1009 # yes the code isn't here yet - next week maybe?
1010 # Next week? Are you high or something? That comment
1011 # has been there for half a year dude.
1012 # Look, i just work here, ok?
1014 if (!$input{'type'} and $input{file}) {
1015 $input{'type'}=$FORMATGUESS->($input{file});
1017 unless ($input{'type'}) {
1018 $self->_set_error('type parameter missing and not possible to guess from extension');
1021 if (!$formats{$input{'type'}}) {
1022 $self->{ERRSTR}='format not supported'; return undef;
1025 my %iolready=(jpeg=>1, png=>1, tiff=>1, pnm=>1, raw=>1, bmp=>1, tga=>1, rgb=>1, gif=>1);
1027 if ($iolready{$input{'type'}}) {
1029 my ($IO, $fh) = $self->_get_reader_io(\%input, $input{'type'})
1032 if ( $input{'type'} eq 'jpeg' ) {
1033 ($self->{IMG},$self->{IPTCRAW})=i_readjpeg_wiol( $IO );
1034 if ( !defined($self->{IMG}) ) {
1035 $self->{ERRSTR}='unable to read jpeg image'; return undef;
1037 $self->{DEBUG} && print "loading a jpeg file\n";
1041 if ( $input{'type'} eq 'tiff' ) {
1042 $self->{IMG}=i_readtiff_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1043 if ( !defined($self->{IMG}) ) {
1044 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1046 $self->{DEBUG} && print "loading a tiff file\n";
1050 if ( $input{'type'} eq 'pnm' ) {
1051 $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1052 if ( !defined($self->{IMG}) ) {
1053 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); return undef;
1055 $self->{DEBUG} && print "loading a pnm file\n";
1059 if ( $input{'type'} eq 'png' ) {
1060 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1061 if ( !defined($self->{IMG}) ) {
1062 $self->{ERRSTR}='unable to read png image';
1065 $self->{DEBUG} && print "loading a png file\n";
1068 if ( $input{'type'} eq 'bmp' ) {
1069 $self->{IMG}=i_readbmp_wiol( $IO );
1070 if ( !defined($self->{IMG}) ) {
1071 $self->{ERRSTR}=$self->_error_as_msg();
1074 $self->{DEBUG} && print "loading a bmp file\n";
1077 if ( $input{'type'} eq 'gif' ) {
1078 if ($input{colors} && !ref($input{colors})) {
1079 # must be a reference to a scalar that accepts the colour map
1080 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1083 if ($input{colors}) {
1085 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1087 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1091 $self->{IMG} =i_readgif_wiol( $IO );
1093 if ( !defined($self->{IMG}) ) {
1094 $self->{ERRSTR}=$self->_error_as_msg();
1097 $self->{DEBUG} && print "loading a gif file\n";
1100 if ( $input{'type'} eq 'tga' ) {
1101 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1102 if ( !defined($self->{IMG}) ) {
1103 $self->{ERRSTR}=$self->_error_as_msg();
1106 $self->{DEBUG} && print "loading a tga file\n";
1109 if ( $input{'type'} eq 'rgb' ) {
1110 $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1111 if ( !defined($self->{IMG}) ) {
1112 $self->{ERRSTR}=$self->_error_as_msg();
1115 $self->{DEBUG} && print "loading a tga file\n";
1119 if ( $input{'type'} eq 'raw' ) {
1120 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1122 if ( !($params{xsize} && $params{ysize}) ) {
1123 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1127 $self->{IMG} = i_readraw_wiol( $IO,
1130 $params{datachannels},
1131 $params{storechannels},
1132 $params{interleave});
1133 if ( !defined($self->{IMG}) ) {
1134 $self->{ERRSTR}='unable to read raw image';
1137 $self->{DEBUG} && print "loading a raw file\n";
1142 # Old code for reference while changing the new stuff
1144 if (!$input{'type'} and $input{file}) {
1145 $input{'type'}=$FORMATGUESS->($input{file});
1148 if (!$input{'type'}) {
1149 $self->{ERRSTR}='type parameter missing and not possible to guess from extension'; return undef;
1152 if (!$formats{$input{'type'}}) {
1153 $self->{ERRSTR}='format not supported';
1159 $fh = new IO::File($input{file},"r");
1161 $self->{ERRSTR}='Could not open file';
1165 $fd = $fh->fileno();
1172 if ( $input{'type'} eq 'gif' ) {
1174 if ($input{colors} && !ref($input{colors})) {
1175 # must be a reference to a scalar that accepts the colour map
1176 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1179 if (exists $input{data}) {
1180 if ($input{colors}) {
1181 ($self->{IMG}, $colors) = i_readgif_scalar($input{data});
1183 $self->{IMG}=i_readgif_scalar($input{data});
1186 if ($input{colors}) {
1187 ($self->{IMG}, $colors) = i_readgif( $fd );
1189 $self->{IMG} = i_readgif( $fd )
1193 # we may or may not change i_readgif to return blessed objects...
1194 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1196 if ( !defined($self->{IMG}) ) {
1197 $self->{ERRSTR}= 'reading GIF:'._error_as_msg();
1200 $self->{DEBUG} && print "loading a gif file\n";
1206 sub _fix_gif_positions {
1207 my ($opts, $opt, $msg, @imgs) = @_;
1209 my $positions = $opts->{'gif_positions'};
1211 for my $pos (@$positions) {
1212 my ($x, $y) = @$pos;
1213 my $img = $imgs[$index++];
1214 $img->settag(name=>'gif_left', value=>$x);
1215 $img->settag(name=>'gif_top', value=>$y) if defined $y;
1217 $$msg .= "replaced with the gif_left and gif_top tags";
1222 gif_each_palette=>'gif_local_map',
1223 interlace => 'gif_interlace',
1224 gif_delays => 'gif_delay',
1225 gif_positions => \&_fix_gif_positions,
1226 gif_loop_count => 'gif_loop',
1230 my ($self, $opts, $prefix, @imgs) = @_;
1232 for my $opt (keys %$opts) {
1234 if ($obsolete_opts{$opt}) {
1235 my $new = $obsolete_opts{$opt};
1236 my $msg = "Obsolete option $opt ";
1238 $new->($opts, $opt, \$msg, @imgs);
1241 $msg .= "replaced with the $new tag ";
1244 $msg .= "line ".(caller(2))[2]." of file ".(caller(2))[1];
1245 warn $msg if $warn_obsolete && $^W;
1247 next unless $tagname =~ /^\Q$prefix/;
1248 my $value = $opts->{$opt};
1250 if (UNIVERSAL::isa($value, "Imager::Color")) {
1251 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1252 for my $img (@imgs) {
1253 $img->settag(name=>$tagname, value=>$tag);
1256 elsif (ref($value) eq 'ARRAY') {
1257 for my $i (0..$#$value) {
1258 my $val = $value->[$i];
1260 if (UNIVERSAL::isa($val, "Imager::Color")) {
1261 my $tag = sprintf("color(%d,%d,%d,%d)", $value->rgba);
1263 $imgs[$i]->settag(name=>$tagname, value=>$tag);
1266 $self->_set_error("Unknown reference type " . ref($value) .
1267 " supplied in array for $opt");
1273 and $imgs[$i]->settag(name=>$tagname, value=>$val);
1278 $self->_set_error("Unknown reference type " . ref($value) .
1279 " supplied for $opt");
1284 # set it as a tag for every image
1285 for my $img (@imgs) {
1286 $img->settag(name=>$tagname, value=>$value);
1294 # Write an image to file
1297 my %input=(jpegquality=>75,
1307 $self->_set_opts(\%input, "i_", $self)
1310 my %iolready=( tiff=>1, raw=>1, png=>1, pnm=>1, bmp=>1, jpeg=>1, tga=>1,
1311 gif=>1 ); # this will be SO MUCH BETTER once they are all in there
1313 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1315 if (!$input{'type'} and $input{file}) {
1316 $input{'type'}=$FORMATGUESS->($input{file});
1318 if (!$input{'type'}) {
1319 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1323 if (!$formats{$input{'type'}}) { $self->{ERRSTR}='format not supported'; return undef; }
1325 my ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1328 # this conditional is probably obsolete
1329 if ($iolready{$input{'type'}}) {
1331 if ($input{'type'} eq 'tiff') {
1332 $self->_set_opts(\%input, "tiff_", $self)
1334 $self->_set_opts(\%input, "exif_", $self)
1337 if (defined $input{class} && $input{class} eq 'fax') {
1338 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1339 $self->{ERRSTR}='Could not write to buffer';
1343 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1344 $self->{ERRSTR}='Could not write to buffer';
1348 } elsif ( $input{'type'} eq 'pnm' ) {
1349 $self->_set_opts(\%input, "pnm_", $self)
1351 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1352 $self->{ERRSTR}='unable to write pnm image';
1355 $self->{DEBUG} && print "writing a pnm file\n";
1356 } elsif ( $input{'type'} eq 'raw' ) {
1357 $self->_set_opts(\%input, "raw_", $self)
1359 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1360 $self->{ERRSTR}='unable to write raw image';
1363 $self->{DEBUG} && print "writing a raw file\n";
1364 } elsif ( $input{'type'} eq 'png' ) {
1365 $self->_set_opts(\%input, "png_", $self)
1367 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1368 $self->{ERRSTR}='unable to write png image';
1371 $self->{DEBUG} && print "writing a png file\n";
1372 } elsif ( $input{'type'} eq 'jpeg' ) {
1373 $self->_set_opts(\%input, "jpeg_", $self)
1375 $self->_set_opts(\%input, "exif_", $self)
1377 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1378 $self->{ERRSTR} = $self->_error_as_msg();
1381 $self->{DEBUG} && print "writing a jpeg file\n";
1382 } elsif ( $input{'type'} eq 'bmp' ) {
1383 $self->_set_opts(\%input, "bmp_", $self)
1385 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1386 $self->{ERRSTR}='unable to write bmp image';
1389 $self->{DEBUG} && print "writing a bmp file\n";
1390 } elsif ( $input{'type'} eq 'tga' ) {
1391 $self->_set_opts(\%input, "tga_", $self)
1394 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1395 $self->{ERRSTR}=$self->_error_as_msg();
1398 $self->{DEBUG} && print "writing a tga file\n";
1399 } elsif ( $input{'type'} eq 'gif' ) {
1400 $self->_set_opts(\%input, "gif_", $self)
1402 # compatibility with the old interfaces
1403 if ($input{gifquant} eq 'lm') {
1404 $input{make_colors} = 'addi';
1405 $input{translate} = 'perturb';
1406 $input{perturb} = $input{lmdither};
1407 } elsif ($input{gifquant} eq 'gen') {
1408 # just pass options through
1410 $input{make_colors} = 'webmap'; # ignored
1411 $input{translate} = 'giflib';
1413 $rc = i_writegif_wiol($IO, \%input, $self->{IMG});
1416 if (exists $input{'data'}) {
1417 my $data = io_slurp($IO);
1419 $self->{ERRSTR}='Could not slurp from buffer';
1422 ${$input{data}} = $data;
1431 my ($class, $opts, @images) = @_;
1433 if (!$opts->{'type'} && $opts->{'file'}) {
1434 $opts->{'type'} = $FORMATGUESS->($opts->{'file'});
1436 unless ($opts->{'type'}) {
1437 $class->_set_error('type parameter missing and not possible to guess from extension');
1440 # translate to ImgRaw
1441 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1442 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1445 $class->_set_opts($opts, "i_", @images)
1447 my @work = map $_->{IMG}, @images;
1448 my ($IO, $file) = $class->_get_writer_io($opts, $opts->{'type'})
1450 if ($opts->{'type'} eq 'gif') {
1451 $class->_set_opts($opts, "gif_", @images)
1453 my $gif_delays = $opts->{gif_delays};
1454 local $opts->{gif_delays} = $gif_delays;
1455 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1456 # assume the caller wants the same delay for each frame
1457 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1459 my $res = i_writegif_wiol($IO, $opts, @work);
1460 $res or $class->_set_error($class->_error_as_msg());
1463 elsif ($opts->{'type'} eq 'tiff') {
1464 $class->_set_opts($opts, "tiff_", @images)
1466 $class->_set_opts($opts, "exif_", @images)
1469 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1470 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1471 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1474 $res = i_writetiff_multi_wiol($IO, @work);
1476 $res or $class->_set_error($class->_error_as_msg());
1480 $ERRSTR = "Sorry, write_multi doesn't support $opts->{'type'} yet";
1485 # read multiple images from a file
1487 my ($class, %opts) = @_;
1489 if ($opts{file} && !exists $opts{'type'}) {
1491 my $type = $FORMATGUESS->($opts{file});
1492 $opts{'type'} = $type;
1494 unless ($opts{'type'}) {
1495 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1499 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1501 if ($opts{'type'} eq 'gif') {
1503 @imgs = i_readgif_multi_wiol($IO);
1506 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1510 $ERRSTR = _error_as_msg();
1514 elsif ($opts{'type'} eq 'tiff') {
1515 my @imgs = i_readtiff_multi_wiol($IO, -1);
1518 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1522 $ERRSTR = _error_as_msg();
1527 $ERRSTR = "Cannot read multiple images from $opts{'type'} files";
1531 # Destroy an Imager object
1535 # delete $instances{$self};
1536 if (defined($self->{IMG})) {
1537 # the following is now handled by the XS DESTROY method for
1538 # Imager::ImgRaw object
1539 # Re-enabling this will break virtual images
1540 # tested for in t/t020masked.t
1541 # i_img_destroy($self->{IMG});
1542 undef($self->{IMG});
1544 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1548 # Perform an inplace filter of an image
1549 # that is the image will be overwritten with the data
1555 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1557 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1559 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1560 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1563 if ($filters{$input{'type'}}{names}) {
1564 my $names = $filters{$input{'type'}}{names};
1565 for my $name (keys %$names) {
1566 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1567 $input{$name} = $names->{$name}{$input{$name}};
1571 if (defined($filters{$input{'type'}}{defaults})) {
1572 %hsh=('image',$self->{IMG},%{$filters{$input{'type'}}{defaults}},%input);
1574 %hsh=('image',$self->{IMG},%input);
1577 my @cs=@{$filters{$input{'type'}}{callseq}};
1580 if (!defined($hsh{$_})) {
1581 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1585 &{$filters{$input{'type'}}{callsub}}(%hsh);
1589 $self->{DEBUG} && print "callseq is: @cs\n";
1590 $self->{DEBUG} && print "matching callseq is: @b\n";
1595 # Scale an image to requested size and return the scaled version
1599 my %opts=(scalefactor=>0.5,'type'=>'max',qtype=>'normal',@_);
1600 my $img = Imager->new();
1601 my $tmp = Imager->new();
1603 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1605 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
1606 my ($xpix,$ypix)=( $opts{xpixels}/$self->getwidth() , $opts{ypixels}/$self->getheight() );
1607 if ($opts{'type'} eq 'min') { $opts{scalefactor}=min($xpix,$ypix); }
1608 if ($opts{'type'} eq 'max') { $opts{scalefactor}=max($xpix,$ypix); }
1609 } elsif ($opts{xpixels}) { $opts{scalefactor}=$opts{xpixels}/$self->getwidth(); }
1610 elsif ($opts{ypixels}) { $opts{scalefactor}=$opts{ypixels}/$self->getheight(); }
1612 if ($opts{qtype} eq 'normal') {
1613 $tmp->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
1614 if ( !defined($tmp->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1615 $img->{IMG}=i_scaleaxis($tmp->{IMG},$opts{scalefactor},1);
1616 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1619 if ($opts{'qtype'} eq 'preview') {
1620 $img->{IMG}=i_scale_nn($self->{IMG},$opts{'scalefactor'},$opts{'scalefactor'});
1621 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1624 $self->{ERRSTR}='scale: invalid value for qtype'; return undef;
1627 # Scales only along the X axis
1631 my %opts=(scalefactor=>0.5,@_);
1633 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1635 my $img = Imager->new();
1637 if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getwidth(); }
1639 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1640 $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
1642 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1646 # Scales only along the Y axis
1650 my %opts=(scalefactor=>0.5,@_);
1652 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1654 my $img = Imager->new();
1656 if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getheight(); }
1658 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1659 $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},1);
1661 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1666 # Transform returns a spatial transformation of the input image
1667 # this moves pixels to a new location in the returned image.
1668 # NOTE - should make a utility function to check transforms for
1673 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1675 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
1677 # print Dumper(\%opts);
1680 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
1682 eval ("use Affix::Infix2Postfix;");
1685 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
1688 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
1689 {op=>'-',trans=>'Sub'},
1690 {op=>'*',trans=>'Mult'},
1691 {op=>'/',trans=>'Div'},
1692 {op=>'-','type'=>'unary',trans=>'u-'},
1694 {op=>'func','type'=>'unary'}],
1695 'grouping'=>[qw( \( \) )],
1696 'func'=>[qw( sin cos )],
1701 @xt=$I2P->translate($opts{'xexpr'});
1702 @yt=$I2P->translate($opts{'yexpr'});
1704 $numre=$I2P->{'numre'};
1707 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
1708 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
1709 @{$opts{'parm'}}=@pt;
1712 # print Dumper(\%opts);
1714 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
1715 $self->{ERRSTR}='transform: no xopcodes given.';
1719 @op=@{$opts{'xopcodes'}};
1721 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
1722 $self->{ERRSTR}="transform: illegal opcode '$_'.";
1725 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
1731 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
1732 $self->{ERRSTR}='transform: no yopcodes given.';
1736 @op=@{$opts{'yopcodes'}};
1738 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
1739 $self->{ERRSTR}="transform: illegal opcode '$_'.";
1742 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
1747 if ( !exists $opts{'parm'}) {
1748 $self->{ERRSTR}='transform: no parameter arg given.';
1752 # print Dumper(\@ropx);
1753 # print Dumper(\@ropy);
1754 # print Dumper(\@ropy);
1756 my $img = Imager->new();
1757 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
1758 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
1764 my ($opts, @imgs) = @_;
1766 require "Imager/Expr.pm";
1768 $opts->{variables} = [ qw(x y) ];
1769 my ($width, $height) = @{$opts}{qw(width height)};
1771 $width ||= $imgs[0]->getwidth();
1772 $height ||= $imgs[0]->getheight();
1774 for my $img (@imgs) {
1775 $opts->{constants}{"w$img_num"} = $img->getwidth();
1776 $opts->{constants}{"h$img_num"} = $img->getheight();
1777 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
1778 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
1783 $opts->{constants}{w} = $width;
1784 $opts->{constants}{cx} = $width/2;
1787 $Imager::ERRSTR = "No width supplied";
1791 $opts->{constants}{h} = $height;
1792 $opts->{constants}{cy} = $height/2;
1795 $Imager::ERRSTR = "No height supplied";
1798 my $code = Imager::Expr->new($opts);
1800 $Imager::ERRSTR = Imager::Expr::error();
1804 my $img = Imager->new();
1805 $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, $code->code(),
1806 $code->nregs(), $code->cregs(),
1807 [ map { $_->{IMG} } @imgs ]);
1808 if (!defined $img->{IMG}) {
1809 $Imager::ERRSTR = Imager->_error_as_msg();
1818 my %opts=(tx=>0,ty=>0,@_);
1820 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1821 unless ($opts{src} && $opts{src}->{IMG}) { $self->{ERRSTR}='empty input image for source'; return undef; }
1823 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx},$opts{ty})) {
1824 $self->{ERRSTR} = $self->_error_as_msg();
1834 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
1836 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
1837 $dir = $xlate{$opts{'dir'}};
1838 return $self if i_flipxy($self->{IMG}, $dir);
1845 if (defined $opts{right}) {
1846 my $degrees = $opts{right};
1848 $degrees += 360 * int(((-$degrees)+360)/360);
1850 $degrees = $degrees % 360;
1851 if ($degrees == 0) {
1852 return $self->copy();
1854 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
1855 my $result = Imager->new();
1856 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
1860 $self->{ERRSTR} = $self->_error_as_msg();
1865 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
1869 elsif (defined $opts{radians} || defined $opts{degrees}) {
1870 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
1872 my $result = Imager->new;
1873 if ($result->{IMG} = i_rotate_exact($self->{IMG}, $amount)) {
1877 $self->{ERRSTR} = $self->_error_as_msg();
1882 $self->{ERRSTR} = "Only the 'right' parameter is available";
1887 sub matrix_transform {
1891 if ($opts{matrix}) {
1892 my $xsize = $opts{xsize} || $self->getwidth;
1893 my $ysize = $opts{ysize} || $self->getheight;
1895 my $result = Imager->new;
1896 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
1903 $self->{ERRSTR} = "matrix parameter required";
1909 *yatf = \&matrix_transform;
1911 # These two are supported for legacy code only
1914 return Imager::Color->new(@_);
1918 return Imager::Color::set(@_);
1921 # Draws a box between the specified corner points.
1924 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1925 my $dflcl=i_color_new(255,255,255,255);
1926 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
1928 if (exists $opts{'box'}) {
1929 $opts{'xmin'} = min($opts{'box'}->[0],$opts{'box'}->[2]);
1930 $opts{'xmax'} = max($opts{'box'}->[0],$opts{'box'}->[2]);
1931 $opts{'ymin'} = min($opts{'box'}->[1],$opts{'box'}->[3]);
1932 $opts{'ymax'} = max($opts{'box'}->[1],$opts{'box'}->[3]);
1935 if ($opts{filled}) {
1936 my $color = _color($opts{'color'});
1938 $self->{ERRSTR} = $Imager::ERRSTR;
1941 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
1942 $opts{ymax}, $color);
1944 elsif ($opts{fill}) {
1945 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
1946 # assume it's a hash ref
1947 require 'Imager/Fill.pm';
1948 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
1949 $self->{ERRSTR} = $Imager::ERRSTR;
1953 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
1954 $opts{ymax},$opts{fill}{fill});
1957 my $color = _color($opts{'color'});
1959 $self->{ERRSTR} = $Imager::ERRSTR;
1962 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
1968 # Draws an arc - this routine SUCKS and is buggy - it sometimes doesn't work when the arc is a convex polygon
1972 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1973 my $dflcl=i_color_new(255,255,255,255);
1974 my %opts=(color=>$dflcl,
1975 'r'=>min($self->getwidth(),$self->getheight())/3,
1976 'x'=>$self->getwidth()/2,
1977 'y'=>$self->getheight()/2,
1978 'd1'=>0, 'd2'=>361, @_);
1980 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
1981 # assume it's a hash ref
1982 require 'Imager/Fill.pm';
1983 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
1984 $self->{ERRSTR} = $Imager::ERRSTR;
1988 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
1989 $opts{'d2'}, $opts{fill}{fill});
1992 my $color = _color($opts{'color'});
1994 $self->{ERRSTR} = $Imager::ERRSTR;
1997 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
1998 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
2002 if ($opts{'d1'} <= $opts{'d2'}) {
2003 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2004 $opts{'d1'}, $opts{'d2'}, $color);
2007 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2008 $opts{'d1'}, 361, $color);
2009 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
2010 0, $opts{'d2'}, $color);
2018 # Draws a line from one point to (but not including) the destination point
2022 my $dflcl=i_color_new(0,0,0,0);
2023 my %opts=(color=>$dflcl,@_);
2024 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2026 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
2027 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
2029 my $color = _color($opts{'color'});
2031 $self->{ERRSTR} = $Imager::ERRSTR;
2034 $opts{antialias} = $opts{aa} if defined $opts{aa};
2035 if ($opts{antialias}) {
2036 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2039 i_draw($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
2045 # Draws a line between an ordered set of points - It more or less just transforms this
2046 # into a list of lines.
2050 my ($pt,$ls,@points);
2051 my $dflcl=i_color_new(0,0,0,0);
2052 my %opts=(color=>$dflcl,@_);
2054 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2056 if (exists($opts{points})) { @points=@{$opts{points}}; }
2057 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
2058 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
2061 # print Dumper(\@points);
2063 my $color = _color($opts{'color'});
2065 $self->{ERRSTR} = $Imager::ERRSTR;
2068 $opts{antialias} = $opts{aa} if defined $opts{aa};
2069 if ($opts{antialias}) {
2072 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color);
2079 i_draw($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color);
2089 my ($pt,$ls,@points);
2090 my $dflcl = i_color_new(0,0,0,0);
2091 my %opts = (color=>$dflcl, @_);
2093 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2095 if (exists($opts{points})) {
2096 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
2097 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
2100 if (!exists $opts{'x'} or !exists $opts{'y'}) {
2101 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
2104 if ($opts{'fill'}) {
2105 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
2106 # assume it's a hash ref
2107 require 'Imager/Fill.pm';
2108 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
2109 $self->{ERRSTR} = $Imager::ERRSTR;
2113 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
2114 $opts{'fill'}{'fill'});
2117 my $color = _color($opts{'color'});
2119 $self->{ERRSTR} = $Imager::ERRSTR;
2122 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2129 # this the multipoint bezier curve
2130 # this is here more for testing that actual usage since
2131 # this is not a good algorithm. Usually the curve would be
2132 # broken into smaller segments and each done individually.
2136 my ($pt,$ls,@points);
2137 my $dflcl=i_color_new(0,0,0,0);
2138 my %opts=(color=>$dflcl,@_);
2140 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2142 if (exists $opts{points}) {
2143 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
2144 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
2147 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
2148 $self->{ERRSTR}='Missing or invalid points.';
2152 my $color = _color($opts{'color'});
2154 $self->{ERRSTR} = $Imager::ERRSTR;
2157 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2163 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2165 unless (exists $opts{'x'} && exists $opts{'y'}) {
2166 $self->{ERRSTR} = "missing seed x and y parameters";
2171 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2172 # assume it's a hash ref
2173 require 'Imager/Fill.pm';
2174 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2175 $self->{ERRSTR} = $Imager::ERRSTR;
2179 i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2182 my $color = _color($opts{'color'});
2184 $self->{ERRSTR} = $Imager::ERRSTR;
2187 i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2196 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2198 unless (exists $opts{'x'} && exists $opts{'y'}) {
2199 $self->{ERRSTR} = 'missing x and y parameters';
2205 my $color = _color($opts{color})
2207 if (ref $x && ref $y) {
2208 unless (@$x == @$y) {
2209 $self->{ERRSTR} = 'length of x and y mismatch';
2212 if ($color->isa('Imager::Color')) {
2213 for my $i (0..$#{$opts{'x'}}) {
2214 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color);
2218 for my $i (0..$#{$opts{'x'}}) {
2219 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color);
2224 if ($color->isa('Imager::Color')) {
2225 i_ppix($self->{IMG}, $x, $y, $color);
2228 i_ppixf($self->{IMG}, $x, $y, $color);
2238 my %opts = ( "type"=>'8bit', @_);
2240 unless (exists $opts{'x'} && exists $opts{'y'}) {
2241 $self->{ERRSTR} = 'missing x and y parameters';
2247 if (ref $x && ref $y) {
2248 unless (@$x == @$y) {
2249 $self->{ERRSTR} = 'length of x and y mismatch';
2253 if ($opts{"type"} eq '8bit') {
2254 for my $i (0..$#{$opts{'x'}}) {
2255 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2259 for my $i (0..$#{$opts{'x'}}) {
2260 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2263 return wantarray ? @result : \@result;
2266 if ($opts{"type"} eq '8bit') {
2267 return i_get_pixel($self->{IMG}, $x, $y);
2270 return i_gpixf($self->{IMG}, $x, $y);
2277 # make an identity matrix of the given size
2281 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
2282 for my $c (0 .. ($size-1)) {
2283 $matrix->[$c][$c] = 1;
2288 # general function to convert an image
2290 my ($self, %opts) = @_;
2293 # the user can either specify a matrix or preset
2294 # the matrix overrides the preset
2295 if (!exists($opts{matrix})) {
2296 unless (exists($opts{preset})) {
2297 $self->{ERRSTR} = "convert() needs a matrix or preset";
2301 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
2302 # convert to greyscale, keeping the alpha channel if any
2303 if ($self->getchannels == 3) {
2304 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
2306 elsif ($self->getchannels == 4) {
2307 # preserve the alpha channel
2308 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
2313 $matrix = _identity($self->getchannels);
2316 elsif ($opts{preset} eq 'noalpha') {
2317 # strip the alpha channel
2318 if ($self->getchannels == 2 or $self->getchannels == 4) {
2319 $matrix = _identity($self->getchannels);
2320 pop(@$matrix); # lose the alpha entry
2323 $matrix = _identity($self->getchannels);
2326 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
2328 $matrix = [ [ 1 ] ];
2330 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
2331 $matrix = [ [ 0, 1 ] ];
2333 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
2334 $matrix = [ [ 0, 0, 1 ] ];
2336 elsif ($opts{preset} eq 'alpha') {
2337 if ($self->getchannels == 2 or $self->getchannels == 4) {
2338 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
2341 # the alpha is just 1 <shrug>
2342 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
2345 elsif ($opts{preset} eq 'rgb') {
2346 if ($self->getchannels == 1) {
2347 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
2349 elsif ($self->getchannels == 2) {
2350 # preserve the alpha channel
2351 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
2354 $matrix = _identity($self->getchannels);
2357 elsif ($opts{preset} eq 'addalpha') {
2358 if ($self->getchannels == 1) {
2359 $matrix = _identity(2);
2361 elsif ($self->getchannels == 3) {
2362 $matrix = _identity(4);
2365 $matrix = _identity($self->getchannels);
2369 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
2375 $matrix = $opts{matrix};
2378 my $new = Imager->new();
2379 $new->{IMG} = i_img_new();
2380 unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
2381 # most likely a bad matrix
2382 $self->{ERRSTR} = _error_as_msg();
2389 # general function to map an image through lookup tables
2392 my ($self, %opts) = @_;
2393 my @chlist = qw( red green blue alpha );
2395 if (!exists($opts{'maps'})) {
2396 # make maps from channel maps
2398 for $chnum (0..$#chlist) {
2399 if (exists $opts{$chlist[$chnum]}) {
2400 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
2401 } elsif (exists $opts{'all'}) {
2402 $opts{'maps'}[$chnum] = $opts{'all'};
2406 if ($opts{'maps'} and $self->{IMG}) {
2407 i_map($self->{IMG}, $opts{'maps'} );
2413 my ($self, %opts) = @_;
2415 defined $opts{mindist} or $opts{mindist} = 0;
2417 defined $opts{other}
2418 or return $self->_set_error("No 'other' parameter supplied");
2419 defined $opts{other}{IMG}
2420 or return $self->_set_error("No image data in 'other' image");
2423 or return $self->_set_error("No image data");
2425 my $result = Imager->new;
2426 $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG},
2428 or return $self->_set_error($self->_error_as_msg());
2433 # destructive border - image is shrunk by one pixel all around
2436 my ($self,%opts)=@_;
2437 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
2438 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
2442 # Get the width of an image
2446 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2447 return (i_img_info($self->{IMG}))[0];
2450 # Get the height of an image
2454 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2455 return (i_img_info($self->{IMG}))[1];
2458 # Get number of channels in an image
2462 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2463 return i_img_getchannels($self->{IMG});
2470 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2471 return i_img_getmask($self->{IMG});
2479 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2480 i_img_setmask( $self->{IMG} , $opts{mask} );
2483 # Get number of colors in an image
2487 my %opts=('maxcolors'=>2**30,@_);
2488 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
2489 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
2490 return ($rc==-1? undef : $rc);
2493 # draw string to an image
2497 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2499 my %input=('x'=>0, 'y'=>0, @_);
2500 $input{string}||=$input{text};
2502 unless(exists $input{string}) {
2503 $self->{ERRSTR}="missing required parameter 'string'";
2507 unless($input{font}) {
2508 $self->{ERRSTR}="missing required parameter 'font'";
2512 unless ($input{font}->draw(image=>$self, %input)) {
2513 $self->{ERRSTR} = $self->_error_as_msg();
2520 # Shortcuts that can be exported
2522 sub newcolor { Imager::Color->new(@_); }
2523 sub newfont { Imager::Font->new(@_); }
2525 *NC=*newcolour=*newcolor;
2532 #### Utility routines
2535 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
2539 my ($self, $msg) = @_;
2542 $self->{ERRSTR} = $msg;
2550 # Default guess for the type of an image from extension
2552 sub def_guess_type {
2555 $ext=($name =~ m/\.([^\.]+)$/)[0];
2556 return 'tiff' if ($ext =~ m/^tiff?$/);
2557 return 'jpeg' if ($ext =~ m/^jpe?g$/);
2558 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
2559 return 'png' if ($ext eq "png");
2560 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
2561 return 'tga' if ($ext eq "tga");
2562 return 'rgb' if ($ext eq "rgb");
2563 return 'gif' if ($ext eq "gif");
2564 return 'raw' if ($ext eq "raw");
2568 # get the minimum of a list
2572 for(@_) { if ($_<$mx) { $mx=$_; }}
2576 # get the maximum of a list
2580 for(@_) { if ($_>$mx) { $mx=$_; }}
2584 # string stuff for iptc headers
2588 $str = substr($str,3);
2589 $str =~ s/[\n\r]//g;
2596 # A little hack to parse iptc headers.
2601 my($caption,$photogr,$headln,$credit);
2603 my $str=$self->{IPTCRAW};
2607 @ar=split(/8BIM/,$str);
2612 @sar=split(/\034\002/);
2613 foreach $item (@sar) {
2614 if ($item =~ m/^x/) {
2615 $caption=&clean($item);
2618 if ($item =~ m/^P/) {
2619 $photogr=&clean($item);
2622 if ($item =~ m/^i/) {
2623 $headln=&clean($item);
2626 if ($item =~ m/^n/) {
2627 $credit=&clean($item);
2633 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
2636 # Autoload methods go after =cut, and are processed by the autosplit program.
2640 # Below is the stub of documentation for your module. You better edit it!
2644 Imager - Perl extension for Generating 24 bit Images
2654 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
2659 my $img = Imager->new();
2660 $img->open(file=>$file) or die $img->errstr();
2662 $file =~ s/\.[^.]*$//;
2664 # Create smaller version
2665 my $thumb = $img->scale(scalefactor=>.3);
2667 # Autostretch individual channels
2668 $thumb->filter(type=>'autolevels');
2670 # try to save in one of these formats
2673 for $format ( qw( png gif jpg tiff ppm ) ) {
2674 # Check if given format is supported
2675 if ($Imager::formats{$format}) {
2676 $file.="_low.$format";
2677 print "Storing image as: $file\n";
2678 $thumb->write(file=>$file) or
2689 Imager is a module for creating and altering images. It can read and
2690 write various image formats, draw primitive shapes like lines,and
2691 polygons, blend multiple images together in various ways, scale, crop,
2692 render text and more.
2694 =head2 Overview of documentation
2700 This document - Synopsis Example, Table of Contents and Overview.
2702 =item Imager::ImageTypes
2704 Direct type/virtual images, RGB(A)/paletted images, 8/16/double
2705 bits/channel, color maps, channel masks, image tags, color
2710 IO interaction, reading/writing images, format specific tags.
2714 Drawing Primitives, lines, boxes, circles, arcs, flood fill.
2718 Color specification.
2722 Fill pattern specification.
2726 General font rendering, bounding boxes and font metrics.
2728 =item Imager::Transformations
2730 Copying, scaling, cropping, flipping, blending, pasting, convert and
2733 =item Imager::Engines
2735 Programmable transformations through C<transform()>, C<transform2()>
2736 and C<matrix_transform()>.
2738 =item Imager::Filters
2740 Filters, sharpen, blur, noise, convolve etc. and filter plugins.
2744 Expressions for evaluation engine used by transform2().
2746 =item Imager::Matrix2d
2748 Helper class for affine transformations.
2750 =item Imager::Fountain
2752 Helper for making gradient profiles.
2758 =head2 Basic Overview
2760 An Image object is created with C<$img = Imager-E<gt>new()>.
2763 $img=Imager->new(); # create empty image
2764 $img->open(file=>'lena.png',type=>'png') or # read image from file
2765 die $img->errstr(); # give an explanation
2766 # if something failed
2768 or if you want to create an empty image:
2770 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
2772 This example creates a completely black image of width 400 and height
2775 When an operation fails which can be directly associated with an image
2776 the error message is stored can be retrieved with
2777 C<$img-E<gt>errstr()>.
2779 In cases where no image object is associated with an operation
2780 C<$Imager::ERRSTR> is used to report errors not directly associated
2781 with an image object.
2785 You can ask for help, report bugs or express your undying love for
2786 Imager on the Imager-devel mailing list.
2788 To subscribe send a message with C<subscribe> in the body to:
2790 imager-devel+request@molar.is
2794 http://www.molar.is/en/lists/imager-devel/
2795 (annonymous is temporarily off due to spam)
2797 where you can also find the mailing list archive.
2799 If you're into IRC, you can typically find the developers in #Imager
2800 on irc.rhizomatic.net. As with any IRC channel, the participants
2801 could be occupied or asleep, so please be patient.
2805 Bugs are listed individually for relevant pod pages.
2809 Arnar M. Hrafnkelsson (addi@imager.perl.org) and Tony Cook
2810 (tony@imager.perl.org) See the README for a complete list.
2814 perl(1), Imager::ImageTypes(3), Imager::Files(3), Imager::Draw(3),
2815 Imager::Color(3), Imager::Fill(3), Imager::Font(3),
2816 Imager::Transformations(3), Imager::Engines(3), Imager::Filters(3),
2817 Imager::Expr(3), Imager::Matrix2d(3), Imager::Fountain(3)
2819 Affix::Infix2Postfix(3), Parse::RecDescent(3)
2820 http://www.eecs.umich.edu/~addi/perl/Imager/