4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %formats $DEBUG %filters %DSOs $ERRSTR $fontstate %OPCODES $I2P $FORMATGUESS);
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;
373 # NOTE: this might be moved to an import override later on
377 # (look through @_ for special tags, process, and remove them);
379 # print Dumper($pack);
384 my %parms=(loglevel=>1,@_);
386 init_log($parms{'log'},$parms{'loglevel'});
389 # if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
390 # if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
398 print "shutdown code\n";
399 # for(keys %instances) { $instances{$_}->DESTROY(); }
400 malloc_state(); # how do decide if this should be used? -- store something from the import
401 print "Imager exiting\n";
405 # Load a filter plugin
410 my ($DSO_handle,$str)=DSO_open($filename);
411 if (!defined($DSO_handle)) { $Imager::ERRSTR="Couldn't load plugin '$filename'\n"; return undef; }
412 my %funcs=DSO_funclist($DSO_handle);
413 if ($DEBUG) { print "loading module $filename\n"; $i=0; for(keys %funcs) { printf(" %2d: %s\n",$i++,$_); } }
415 for(keys %funcs) { if ($filters{$_}) { $ERRSTR="filter '$_' already exists\n"; DSO_close($DSO_handle); return undef; } }
417 $DSOs{$filename}=[$DSO_handle,\%funcs];
420 my $evstr="\$filters{'".$_."'}={".$funcs{$_}.'};';
421 $DEBUG && print "eval string:\n",$evstr,"\n";
433 if (!$DSOs{$filename}) { $ERRSTR="plugin '$filename' not loaded."; return undef; }
434 my ($DSO_handle,$funcref)=@{$DSOs{$filename}};
435 for(keys %{$funcref}) {
437 $DEBUG && print "unloading: $_\n";
439 my $rc=DSO_close($DSO_handle);
440 if (!defined($rc)) { $ERRSTR="unable to unload plugin '$filename'."; return undef; }
444 # take the results of i_error() and make a message out of it
446 return join(": ", map $_->[0], i_errors());
449 # this function tries to DWIM for color parameters
450 # color objects are used as is
451 # simple scalars are simply treated as single parameters to Imager::Color->new
452 # hashrefs are treated as named argument lists to Imager::Color->new
453 # arrayrefs are treated as list arguments to Imager::Color->new iff any
455 # other arrayrefs are treated as list arguments to Imager::Color::Float
462 if (UNIVERSAL::isa($arg, "Imager::Color")
463 || UNIVERSAL::isa($arg, "Imager::Color::Float")) {
467 if ($arg =~ /^HASH\(/) {
468 $result = Imager::Color->new(%$arg);
470 elsif ($arg =~ /^ARRAY\(/) {
471 if (grep $_ > 1, @$arg) {
472 $result = Imager::Color->new(@$arg);
475 $result = Imager::Color::Float->new(@$arg);
479 $Imager::ERRSTR = "Not a color";
484 # assume Imager::Color::new knows how to handle it
485 $result = Imager::Color->new($arg);
493 # Methods to be called on objects.
496 # Create a new Imager object takes very few parameters.
497 # usually you call this method and then call open from
498 # the resulting object
505 $self->{IMG}=undef; # Just to indicate what exists
506 $self->{ERRSTR}=undef; #
507 $self->{DEBUG}=$DEBUG;
508 $self->{DEBUG} && print "Initialized Imager\n";
509 if ($hsh{xsize} && $hsh{ysize}) { $self->img_set(%hsh); }
513 # Copy an entire image with no changes
514 # - if an image has magic the copy of it will not be magical
518 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
520 my $newcopy=Imager->new();
521 $newcopy->{IMG}=i_img_new();
522 i_copy($newcopy->{IMG},$self->{IMG});
530 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
531 my %input=(left=>0, top=>0, @_);
532 unless($input{img}) {
533 $self->{ERRSTR}="no source image";
536 $input{left}=0 if $input{left} <= 0;
537 $input{top}=0 if $input{top} <= 0;
539 my($r,$b)=i_img_info($src->{IMG});
541 i_copyto($self->{IMG}, $src->{IMG},
542 0,0, $r, $b, $input{left}, $input{top});
543 return $self; # What should go here??
546 # Crop an image - i.e. return a new image that is smaller
550 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
551 my %hsh=(left=>0,right=>0,top=>0,bottom=>0,@_);
553 my ($w,$h,$l,$r,$b,$t)=($self->getwidth(),$self->getheight(),
554 @hsh{qw(left right bottom top)});
555 $l=0 if not defined $l;
556 $t=0 if not defined $t;
558 $r||=$l+delete $hsh{'width'} if defined $l and exists $hsh{'width'};
559 $b||=$t+delete $hsh{'height'} if defined $t and exists $hsh{'height'};
560 $l||=$r-delete $hsh{'width'} if defined $r and exists $hsh{'width'};
561 $t||=$b-delete $hsh{'height'} if defined $b and exists $hsh{'height'};
563 $r=$self->getwidth if not defined $r;
564 $b=$self->getheight if not defined $b;
566 ($l,$r)=($r,$l) if $l>$r;
567 ($t,$b)=($b,$t) if $t>$b;
570 $l=int(0.5+($w-$hsh{'width'})/2);
575 if ($hsh{'height'}) {
576 $b=int(0.5+($h-$hsh{'height'})/2);
577 $t=$h+$hsh{'height'};
579 $hsh{'height'}=$b-$t;
582 # print "l=$l, r=$r, h=$hsh{'width'}\n";
583 # print "t=$t, b=$b, w=$hsh{'height'}\n";
585 my $dst=Imager->new(xsize=>$hsh{'width'}, ysize=>$hsh{'height'}, channels=>$self->getchannels());
587 i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
591 # Sets an image to a certain size and channel number
592 # if there was previously data in the image it is discarded
597 my %hsh=(xsize=>100, ysize=>100, channels=>3, bits=>8, type=>'direct', @_);
599 if (defined($self->{IMG})) {
600 # let IIM_DESTROY destroy it, it's possible this image is
601 # referenced from a virtual image (like masked)
602 #i_img_destroy($self->{IMG});
606 if ($hsh{type} eq 'paletted' || $hsh{type} eq 'pseudo') {
607 $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
608 $hsh{maxcolors} || 256);
610 elsif ($hsh{bits} eq 'double') {
611 $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
613 elsif ($hsh{bits} == 16) {
614 $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
617 $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'},
622 # created a masked version of the current image
626 $self or return undef;
627 my %opts = (left => 0,
629 right => $self->getwidth,
630 bottom => $self->getheight,
632 my $mask = $opts{mask} ? $opts{mask}{IMG} : undef;
634 my $result = Imager->new;
635 $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left},
636 $opts{top}, $opts{right} - $opts{left},
637 $opts{bottom} - $opts{top});
638 # keep references to the mask and base images so they don't
640 $result->{DEPENDS} = [ $self->{IMG}, $mask ];
645 # convert an RGB image into a paletted image
649 if (@_ != 1 && !ref $_[0]) {
656 my $result = Imager->new;
657 $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
659 #print "Type ", i_img_type($result->{IMG}), "\n";
661 $result->{IMG} or undef $result;
666 # convert a paletted (or any image) to an 8-bit/channel RGB images
672 $result = Imager->new;
673 $result->{IMG} = i_img_to_rgb($self->{IMG})
682 my %opts = (colors=>[], @_);
684 @{$opts{colors}} or return undef;
686 $self->{IMG} and i_addcolors($self->{IMG}, @{$opts{colors}});
691 my %opts = (start=>0, colors=>[], @_);
692 @{$opts{colors}} or return undef;
694 $self->{IMG} and i_setcolors($self->{IMG}, $opts{start}, @{$opts{colors}});
700 if (!exists $opts{start} && !exists $opts{count}) {
703 $opts{count} = $self->colorcount;
705 elsif (!exists $opts{count}) {
708 elsif (!exists $opts{start}) {
713 return i_getcolors($self->{IMG}, $opts{start}, $opts{count});
717 i_colorcount($_[0]{IMG});
721 i_maxcolors($_[0]{IMG});
727 $opts{color} or return undef;
729 $self->{IMG} and i_findcolor($self->{IMG}, $opts{color});
734 my $bits = $self->{IMG} && i_img_bits($self->{IMG});
735 if ($bits && $bits == length(pack("d", 1)) * 8) {
744 return i_img_type($self->{IMG}) ? "paletted" : "direct";
750 $self->{IMG} and i_img_virtual($self->{IMG});
754 my ($self, %opts) = @_;
756 $self->{IMG} or return;
758 if (defined $opts{name}) {
762 while (defined($found = i_tags_find($self->{IMG}, $opts{name}, $start))) {
763 push @result, (i_tags_get($self->{IMG}, $found))[1];
766 return wantarray ? @result : $result[0];
768 elsif (defined $opts{code}) {
772 while (defined($found = i_tags_findn($self->{IMG}, $opts{code}, $start))) {
773 push @result, (i_tags_get($self->{IMG}, $found))[1];
780 return map { [ i_tags_get($self->{IMG}, $_) ] } 0.. i_tags_count($self->{IMG})-1;
783 return i_tags_count($self->{IMG});
792 return -1 unless $self->{IMG};
794 if (defined $opts{value}) {
795 if ($opts{value} =~ /^\d+$/) {
797 return i_tags_addn($self->{IMG}, $opts{name}, 0, $opts{value});
800 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{value}, 0);
803 elsif (defined $opts{data}) {
804 # force addition as a string
805 return i_tags_add($self->{IMG}, $opts{name}, 0, $opts{data}, 0);
808 $self->{ERRSTR} = "No value supplied";
812 elsif ($opts{code}) {
813 if (defined $opts{value}) {
814 if ($opts{value} =~ /^\d+$/) {
816 return i_tags_addn($self->{IMG}, $opts{code}, 0, $opts{value});
819 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{value}, 0);
822 elsif (defined $opts{data}) {
823 # force addition as a string
824 return i_tags_add($self->{IMG}, $opts{code}, 0, $opts{data}, 0);
827 $self->{ERRSTR} = "No value supplied";
840 return 0 unless $self->{IMG};
842 if (defined $opts{'index'}) {
843 return i_tags_delete($self->{IMG}, $opts{'index'});
845 elsif (defined $opts{name}) {
846 return i_tags_delbyname($self->{IMG}, $opts{name});
848 elsif (defined $opts{code}) {
849 return i_tags_delbycode($self->{IMG}, $opts{code});
852 $self->{ERRSTR} = "Need to supply index, name, or code parameter";
857 my @needseekcb = qw/tiff/;
858 my %needseekcb = map { $_, $_ } @needseekcb;
862 my ($self, $input, $type) = @_;
865 return io_new_fd($input->{fd});
867 elsif ($input->{fh}) {
868 my $fd = fileno($input->{fh});
870 $self->_set_error("Handle in fh option not opened");
873 return io_new_fd($fd);
875 elsif ($input->{file}) {
876 my $file = IO::File->new($input->{file}, "r");
878 $self->_set_error("Could not open $input->{file}: $!");
882 return (io_new_fd(fileno($file)), $file);
884 elsif ($input->{data}) {
885 return io_new_buffer($input->{data});
887 elsif ($input->{callback} || $input->{readcb}) {
888 if ($needseekcb{$type} && !$input->{seekcb}) {
889 $self->_set_error("Format $type needs a seekcb parameter");
891 if ($input->{maxbuffer}) {
892 return io_new_cb($input->{writecb},
893 $input->{callback} || $input->{readcb},
894 $input->{seekcb}, $input->{closecb},
895 $input->{maxbuffer});
898 return io_new_cb($input->{writecb},
899 $input->{callback} || $input->{readcb},
900 $input->{seekcb}, $input->{closecb});
904 $self->_set_error("file/fd/fh/data/callback parameter missing");
910 my ($self, $input, $type) = @_;
913 return io_new_fd($input->{fd});
915 elsif ($input->{fh}) {
916 my $fd = fileno($input->{fh});
918 $self->_set_error("Handle in fh option not opened");
921 return io_new_fd($fd);
923 elsif ($input->{file}) {
924 my $fh = new IO::File($input->{file},"w+");
926 $self->_set_error("Could not open file $input->{file}: $!");
930 return (io_new_fd(fileno($fh)), $fh);
932 elsif ($input->{data}) {
933 return io_new_bufchain();
935 elsif ($input->{callback} || $input->{writecb}) {
936 if ($input->{maxbuffer}) {
937 return io_new_cb($input->{callback} || $input->{writecb},
939 $input->{seekcb}, $input->{closecb},
940 $input->{maxbuffer});
943 return io_new_cb($input->{callback} || $input->{writecb},
945 $input->{seekcb}, $input->{closecb});
949 $self->_set_error("file/fd/fh/data/callback parameter missing");
954 # Read an image from file
960 if (defined($self->{IMG})) {
961 # let IIM_DESTROY do the destruction, since the image may be
962 # referenced from elsewhere
963 #i_img_destroy($self->{IMG});
967 # FIXME: Find the format here if not specified
968 # yes the code isn't here yet - next week maybe?
969 # Next week? Are you high or something? That comment
970 # has been there for half a year dude.
971 # Look, i just work here, ok?
973 if (!$input{'type'} and $input{file}) {
974 $input{'type'}=$FORMATGUESS->($input{file});
976 unless ($input{'type'}) {
977 $self->_set_error('type parameter missing and not possible to guess from extension');
980 if (!$formats{$input{'type'}}) {
981 $self->{ERRSTR}='format not supported'; return undef;
984 my %iolready=(jpeg=>1, png=>1, tiff=>1, pnm=>1, raw=>1, bmp=>1, tga=>1, rgb=>1, gif=>1);
986 if ($iolready{$input{'type'}}) {
988 my ($IO, $fh) = $self->_get_reader_io(\%input, $input{'type'})
991 if ( $input{'type'} eq 'jpeg' ) {
992 ($self->{IMG},$self->{IPTCRAW})=i_readjpeg_wiol( $IO );
993 if ( !defined($self->{IMG}) ) {
994 $self->{ERRSTR}='unable to read jpeg image'; return undef;
996 $self->{DEBUG} && print "loading a jpeg file\n";
1000 if ( $input{'type'} eq 'tiff' ) {
1001 $self->{IMG}=i_readtiff_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1002 if ( !defined($self->{IMG}) ) {
1003 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
1005 $self->{DEBUG} && print "loading a tiff file\n";
1009 if ( $input{'type'} eq 'pnm' ) {
1010 $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1011 if ( !defined($self->{IMG}) ) {
1012 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); return undef;
1014 $self->{DEBUG} && print "loading a pnm file\n";
1018 if ( $input{'type'} eq 'png' ) {
1019 $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1020 if ( !defined($self->{IMG}) ) {
1021 $self->{ERRSTR}='unable to read png image';
1024 $self->{DEBUG} && print "loading a png file\n";
1027 if ( $input{'type'} eq 'bmp' ) {
1028 $self->{IMG}=i_readbmp_wiol( $IO );
1029 if ( !defined($self->{IMG}) ) {
1030 $self->{ERRSTR}=$self->_error_as_msg();
1033 $self->{DEBUG} && print "loading a bmp file\n";
1036 if ( $input{'type'} eq 'gif' ) {
1037 if ($input{colors} && !ref($input{colors})) {
1038 # must be a reference to a scalar that accepts the colour map
1039 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1042 if ($input{colors}) {
1044 ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
1046 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1050 $self->{IMG} =i_readgif_wiol( $IO );
1052 if ( !defined($self->{IMG}) ) {
1053 $self->{ERRSTR}=$self->_error_as_msg();
1056 $self->{DEBUG} && print "loading a gif file\n";
1059 if ( $input{'type'} eq 'tga' ) {
1060 $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1061 if ( !defined($self->{IMG}) ) {
1062 $self->{ERRSTR}=$self->_error_as_msg();
1065 $self->{DEBUG} && print "loading a tga file\n";
1068 if ( $input{'type'} eq 'rgb' ) {
1069 $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1070 if ( !defined($self->{IMG}) ) {
1071 $self->{ERRSTR}=$self->_error_as_msg();
1074 $self->{DEBUG} && print "loading a tga file\n";
1078 if ( $input{'type'} eq 'raw' ) {
1079 my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
1081 if ( !($params{xsize} && $params{ysize}) ) {
1082 $self->{ERRSTR}='missing xsize or ysize parameter for raw';
1086 $self->{IMG} = i_readraw_wiol( $IO,
1089 $params{datachannels},
1090 $params{storechannels},
1091 $params{interleave});
1092 if ( !defined($self->{IMG}) ) {
1093 $self->{ERRSTR}='unable to read raw image';
1096 $self->{DEBUG} && print "loading a raw file\n";
1101 # Old code for reference while changing the new stuff
1103 if (!$input{'type'} and $input{file}) {
1104 $input{'type'}=$FORMATGUESS->($input{file});
1107 if (!$input{'type'}) {
1108 $self->{ERRSTR}='type parameter missing and not possible to guess from extension'; return undef;
1111 if (!$formats{$input{'type'}}) {
1112 $self->{ERRSTR}='format not supported';
1118 $fh = new IO::File($input{file},"r");
1120 $self->{ERRSTR}='Could not open file';
1124 $fd = $fh->fileno();
1131 if ( $input{'type'} eq 'gif' ) {
1133 if ($input{colors} && !ref($input{colors})) {
1134 # must be a reference to a scalar that accepts the colour map
1135 $self->{ERRSTR} = "option 'colors' must be a scalar reference";
1138 if (exists $input{data}) {
1139 if ($input{colors}) {
1140 ($self->{IMG}, $colors) = i_readgif_scalar($input{data});
1142 $self->{IMG}=i_readgif_scalar($input{data});
1145 if ($input{colors}) {
1146 ($self->{IMG}, $colors) = i_readgif( $fd );
1148 $self->{IMG} = i_readgif( $fd )
1152 # we may or may not change i_readgif to return blessed objects...
1153 ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
1155 if ( !defined($self->{IMG}) ) {
1156 $self->{ERRSTR}= 'reading GIF:'._error_as_msg();
1159 $self->{DEBUG} && print "loading a gif file\n";
1165 # Write an image to file
1168 my %input=(jpegquality=>75,
1178 my %iolready=( tiff=>1, raw=>1, png=>1, pnm=>1, bmp=>1, jpeg=>1, tga=>1,
1179 gif=>1 ); # this will be SO MUCH BETTER once they are all in there
1181 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1183 if (!$input{'type'} and $input{file}) {
1184 $input{'type'}=$FORMATGUESS->($input{file});
1186 if (!$input{'type'}) {
1187 $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
1191 if (!$formats{$input{'type'}}) { $self->{ERRSTR}='format not supported'; return undef; }
1193 my ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
1196 # this conditional is probably obsolete
1197 if ($iolready{$input{'type'}}) {
1199 if ($input{'type'} eq 'tiff') {
1200 if (defined $input{class} && $input{class} eq 'fax') {
1201 if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
1202 $self->{ERRSTR}='Could not write to buffer';
1206 if (!i_writetiff_wiol($self->{IMG}, $IO)) {
1207 $self->{ERRSTR}='Could not write to buffer';
1211 } elsif ( $input{'type'} eq 'pnm' ) {
1212 if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
1213 $self->{ERRSTR}='unable to write pnm image';
1216 $self->{DEBUG} && print "writing a pnm file\n";
1217 } elsif ( $input{'type'} eq 'raw' ) {
1218 if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
1219 $self->{ERRSTR}='unable to write raw image';
1222 $self->{DEBUG} && print "writing a raw file\n";
1223 } elsif ( $input{'type'} eq 'png' ) {
1224 if ( !i_writepng_wiol($self->{IMG}, $IO) ) {
1225 $self->{ERRSTR}='unable to write png image';
1228 $self->{DEBUG} && print "writing a png file\n";
1229 } elsif ( $input{'type'} eq 'jpeg' ) {
1230 if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
1231 $self->{ERRSTR} = $self->_error_as_msg();
1234 $self->{DEBUG} && print "writing a jpeg file\n";
1235 } elsif ( $input{'type'} eq 'bmp' ) {
1236 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1237 $self->{ERRSTR}='unable to write bmp image';
1240 $self->{DEBUG} && print "writing a bmp file\n";
1241 } elsif ( $input{'type'} eq 'tga' ) {
1243 if ( !i_writetga_wiol($self->{IMG}, $IO, $input{wierdpack}, $input{compress}, $input{idstring}) ) {
1244 $self->{ERRSTR}=$self->_error_as_msg();
1247 $self->{DEBUG} && print "writing a tga file\n";
1248 } elsif ( $input{'type'} eq 'gif' ) {
1249 # compatibility with the old interfaces
1250 if ($input{gifquant} eq 'lm') {
1251 $input{make_colors} = 'addi';
1252 $input{translate} = 'perturb';
1253 $input{perturb} = $input{lmdither};
1254 } elsif ($input{gifquant} eq 'gen') {
1255 # just pass options through
1257 $input{make_colors} = 'webmap'; # ignored
1258 $input{translate} = 'giflib';
1260 $rc = i_writegif_wiol($IO, \%input, $self->{IMG});
1263 if (exists $input{'data'}) {
1264 my $data = io_slurp($IO);
1266 $self->{ERRSTR}='Could not slurp from buffer';
1269 ${$input{data}} = $data;
1278 my ($class, $opts, @images) = @_;
1280 if (!$opts->{'type'} && $opts->{'file'}) {
1281 $opts->{'type'} = $FORMATGUESS->($opts->{'file'});
1283 unless ($opts->{'type'}) {
1284 $class->_set_error('type parameter missing and not possible to guess from extension');
1287 # translate to ImgRaw
1288 if (grep !UNIVERSAL::isa($_, 'Imager') || !$_->{IMG}, @images) {
1289 $class->_set_error('Usage: Imager->write_multi({ options }, @images)');
1292 my @work = map $_->{IMG}, @images;
1293 my ($IO, $file) = $class->_get_writer_io($opts, $opts->{'type'})
1295 if ($opts->{'type'} eq 'gif') {
1296 my $gif_delays = $opts->{gif_delays};
1297 local $opts->{gif_delays} = $gif_delays;
1298 if ($opts->{gif_delays} && !ref $opts->{gif_delays}) {
1299 # assume the caller wants the same delay for each frame
1300 $opts->{gif_delays} = [ ($gif_delays) x @images ];
1302 my $res = i_writegif_wiol($IO, $opts, @work);
1303 $res or $class->_set_error($class->_error_as_msg());
1306 elsif ($opts->{'type'} eq 'tiff') {
1308 $opts->{fax_fine} = 1 unless exists $opts->{fax_fine};
1309 if ($opts->{'class'} && $opts->{'class'} eq 'fax') {
1310 $res = i_writetiff_multi_wiol_faxable($IO, $opts->{fax_fine}, @work);
1313 $res = i_writetiff_multi_wiol($IO, @work);
1315 $res or $class->_set_error($class->_error_as_msg());
1319 $ERRSTR = "Sorry, write_multi doesn't support $opts->{'type'} yet";
1324 # read multiple images from a file
1326 my ($class, %opts) = @_;
1328 if ($opts{file} && !exists $opts{'type'}) {
1330 my $type = $FORMATGUESS->($opts{file});
1331 $opts{'type'} = $type;
1333 unless ($opts{'type'}) {
1334 $ERRSTR = "No type parameter supplied and it couldn't be guessed";
1338 my ($IO, $file) = $class->_get_reader_io(\%opts, $opts{'type'})
1340 if ($opts{'type'} eq 'gif') {
1342 @imgs = i_readgif_multi_wiol($IO);
1345 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1349 $ERRSTR = _error_as_msg();
1353 elsif ($opts{'type'} eq 'tiff') {
1354 my @imgs = i_readtiff_multi_wiol($IO, -1);
1357 bless { IMG=>$_, DEBUG=>$DEBUG, ERRSTR=>undef }, 'Imager'
1361 $ERRSTR = _error_as_msg();
1366 $ERRSTR = "Cannot read multiple images from $opts{'type'} files";
1370 # Destroy an Imager object
1374 # delete $instances{$self};
1375 if (defined($self->{IMG})) {
1376 # the following is now handled by the XS DESTROY method for
1377 # Imager::ImgRaw object
1378 # Re-enabling this will break virtual images
1379 # tested for in t/t020masked.t
1380 # i_img_destroy($self->{IMG});
1381 undef($self->{IMG});
1383 # print "Destroy Called on an empty image!\n"; # why did I put this here??
1387 # Perform an inplace filter of an image
1388 # that is the image will be overwritten with the data
1394 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1396 if (!$input{'type'}) { $self->{ERRSTR}='type parameter missing'; return undef; }
1398 if ( (grep { $_ eq $input{'type'} } keys %filters) != 1) {
1399 $self->{ERRSTR}='type parameter not matching any filter'; return undef;
1402 if ($filters{$input{'type'}}{names}) {
1403 my $names = $filters{$input{'type'}}{names};
1404 for my $name (keys %$names) {
1405 if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
1406 $input{$name} = $names->{$name}{$input{$name}};
1410 if (defined($filters{$input{'type'}}{defaults})) {
1411 %hsh=('image',$self->{IMG},%{$filters{$input{'type'}}{defaults}},%input);
1413 %hsh=('image',$self->{IMG},%input);
1416 my @cs=@{$filters{$input{'type'}}{callseq}};
1419 if (!defined($hsh{$_})) {
1420 $self->{ERRSTR}="missing parameter '$_' for filter ".$input{'type'}; return undef;
1424 &{$filters{$input{'type'}}{callsub}}(%hsh);
1428 $self->{DEBUG} && print "callseq is: @cs\n";
1429 $self->{DEBUG} && print "matching callseq is: @b\n";
1434 # Scale an image to requested size and return the scaled version
1438 my %opts=(scalefactor=>0.5,'type'=>'max',qtype=>'normal',@_);
1439 my $img = Imager->new();
1440 my $tmp = Imager->new();
1442 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1444 if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
1445 my ($xpix,$ypix)=( $opts{xpixels}/$self->getwidth() , $opts{ypixels}/$self->getheight() );
1446 if ($opts{'type'} eq 'min') { $opts{scalefactor}=min($xpix,$ypix); }
1447 if ($opts{'type'} eq 'max') { $opts{scalefactor}=max($xpix,$ypix); }
1448 } elsif ($opts{xpixels}) { $opts{scalefactor}=$opts{xpixels}/$self->getwidth(); }
1449 elsif ($opts{ypixels}) { $opts{scalefactor}=$opts{ypixels}/$self->getheight(); }
1451 if ($opts{qtype} eq 'normal') {
1452 $tmp->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
1453 if ( !defined($tmp->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1454 $img->{IMG}=i_scaleaxis($tmp->{IMG},$opts{scalefactor},1);
1455 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1458 if ($opts{'qtype'} eq 'preview') {
1459 $img->{IMG}=i_scale_nn($self->{IMG},$opts{'scalefactor'},$opts{'scalefactor'});
1460 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1463 $self->{ERRSTR}='scale: invalid value for qtype'; return undef;
1466 # Scales only along the X axis
1470 my %opts=(scalefactor=>0.5,@_);
1472 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1474 my $img = Imager->new();
1476 if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getwidth(); }
1478 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1479 $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
1481 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1485 # Scales only along the Y axis
1489 my %opts=(scalefactor=>0.5,@_);
1491 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1493 my $img = Imager->new();
1495 if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getheight(); }
1497 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1498 $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},1);
1500 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
1505 # Transform returns a spatial transformation of the input image
1506 # this moves pixels to a new location in the returned image.
1507 # NOTE - should make a utility function to check transforms for
1512 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1514 my (@op,@ropx,@ropy,$iop,$or,@parm,$expr,@xt,@yt,@pt,$numre);
1516 # print Dumper(\%opts);
1519 if ( $opts{'xexpr'} and $opts{'yexpr'} ) {
1521 eval ("use Affix::Infix2Postfix;");
1524 $self->{ERRSTR}='transform: expr given and Affix::Infix2Postfix is not avaliable.';
1527 $I2P=Affix::Infix2Postfix->new('ops'=>[{op=>'+',trans=>'Add'},
1528 {op=>'-',trans=>'Sub'},
1529 {op=>'*',trans=>'Mult'},
1530 {op=>'/',trans=>'Div'},
1531 {op=>'-','type'=>'unary',trans=>'u-'},
1533 {op=>'func','type'=>'unary'}],
1534 'grouping'=>[qw( \( \) )],
1535 'func'=>[qw( sin cos )],
1540 @xt=$I2P->translate($opts{'xexpr'});
1541 @yt=$I2P->translate($opts{'yexpr'});
1543 $numre=$I2P->{'numre'};
1546 for(@xt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'xopcodes'}},'Parm',$#pt); } else { push(@{$opts{'xopcodes'}},$_); } }
1547 for(@yt) { if (/$numre/) { push(@pt,$_); push(@{$opts{'yopcodes'}},'Parm',$#pt); } else { push(@{$opts{'yopcodes'}},$_); } }
1548 @{$opts{'parm'}}=@pt;
1551 # print Dumper(\%opts);
1553 if ( !exists $opts{'xopcodes'} or @{$opts{'xopcodes'}}==0) {
1554 $self->{ERRSTR}='transform: no xopcodes given.';
1558 @op=@{$opts{'xopcodes'}};
1560 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
1561 $self->{ERRSTR}="transform: illegal opcode '$_'.";
1564 push(@ropx,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
1570 if ( !exists $opts{'yopcodes'} or @{$opts{'yopcodes'}}==0) {
1571 $self->{ERRSTR}='transform: no yopcodes given.';
1575 @op=@{$opts{'yopcodes'}};
1577 if (!defined ($OPCODES{$iop}) and ($iop !~ /^\d+$/) ) {
1578 $self->{ERRSTR}="transform: illegal opcode '$_'.";
1581 push(@ropy,(exists $OPCODES{$iop}) ? @{$OPCODES{$iop}} : $iop );
1586 if ( !exists $opts{'parm'}) {
1587 $self->{ERRSTR}='transform: no parameter arg given.';
1591 # print Dumper(\@ropx);
1592 # print Dumper(\@ropy);
1593 # print Dumper(\@ropy);
1595 my $img = Imager->new();
1596 $img->{IMG}=i_transform($self->{IMG},\@ropx,\@ropy,$opts{'parm'});
1597 if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='transform: failed'; return undef; }
1603 my ($opts, @imgs) = @_;
1605 require "Imager/Expr.pm";
1607 $opts->{variables} = [ qw(x y) ];
1608 my ($width, $height) = @{$opts}{qw(width height)};
1610 $width ||= $imgs[0]->getwidth();
1611 $height ||= $imgs[0]->getheight();
1613 for my $img (@imgs) {
1614 $opts->{constants}{"w$img_num"} = $img->getwidth();
1615 $opts->{constants}{"h$img_num"} = $img->getheight();
1616 $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
1617 $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
1622 $opts->{constants}{w} = $width;
1623 $opts->{constants}{cx} = $width/2;
1626 $Imager::ERRSTR = "No width supplied";
1630 $opts->{constants}{h} = $height;
1631 $opts->{constants}{cy} = $height/2;
1634 $Imager::ERRSTR = "No height supplied";
1637 my $code = Imager::Expr->new($opts);
1639 $Imager::ERRSTR = Imager::Expr::error();
1643 my $img = Imager->new();
1644 $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, $code->code(),
1645 $code->nregs(), $code->cregs(),
1646 [ map { $_->{IMG} } @imgs ]);
1647 if (!defined $img->{IMG}) {
1648 $Imager::ERRSTR = Imager->_error_as_msg();
1657 my %opts=(tx=>0,ty=>0,@_);
1659 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1660 unless ($opts{src} && $opts{src}->{IMG}) { $self->{ERRSTR}='empty input image for source'; return undef; }
1662 unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx},$opts{ty})) {
1663 $self->{ERRSTR} = $self->_error_as_msg();
1673 my %xlate = (h=>0, v=>1, hv=>2, vh=>2);
1675 return () unless defined $opts{'dir'} and defined $xlate{$opts{'dir'}};
1676 $dir = $xlate{$opts{'dir'}};
1677 return $self if i_flipxy($self->{IMG}, $dir);
1684 if (defined $opts{right}) {
1685 my $degrees = $opts{right};
1687 $degrees += 360 * int(((-$degrees)+360)/360);
1689 $degrees = $degrees % 360;
1690 if ($degrees == 0) {
1691 return $self->copy();
1693 elsif ($degrees == 90 || $degrees == 180 || $degrees == 270) {
1694 my $result = Imager->new();
1695 if ($result->{IMG} = i_rotate90($self->{IMG}, $degrees)) {
1699 $self->{ERRSTR} = $self->_error_as_msg();
1704 $self->{ERRSTR} = "Parameter 'right' must be a multiple of 90 degrees";
1708 elsif (defined $opts{radians} || defined $opts{degrees}) {
1709 my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
1711 my $result = Imager->new;
1712 if ($result->{IMG} = i_rotate_exact($self->{IMG}, $amount)) {
1716 $self->{ERRSTR} = $self->_error_as_msg();
1721 $self->{ERRSTR} = "Only the 'right' parameter is available";
1726 sub matrix_transform {
1730 if ($opts{matrix}) {
1731 my $xsize = $opts{xsize} || $self->getwidth;
1732 my $ysize = $opts{ysize} || $self->getheight;
1734 my $result = Imager->new;
1735 $result->{IMG} = i_matrix_transform($self->{IMG}, $xsize, $ysize,
1742 $self->{ERRSTR} = "matrix parameter required";
1748 *yatf = \&matrix_transform;
1750 # These two are supported for legacy code only
1753 return Imager::Color->new(@_);
1757 return Imager::Color::set(@_);
1760 # Draws a box between the specified corner points.
1763 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1764 my $dflcl=i_color_new(255,255,255,255);
1765 my %opts=(color=>$dflcl,xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
1767 if (exists $opts{'box'}) {
1768 $opts{'xmin'} = min($opts{'box'}->[0],$opts{'box'}->[2]);
1769 $opts{'xmax'} = max($opts{'box'}->[0],$opts{'box'}->[2]);
1770 $opts{'ymin'} = min($opts{'box'}->[1],$opts{'box'}->[3]);
1771 $opts{'ymax'} = max($opts{'box'}->[1],$opts{'box'}->[3]);
1774 if ($opts{filled}) {
1775 my $color = _color($opts{'color'});
1777 $self->{ERRSTR} = $Imager::ERRSTR;
1780 i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
1781 $opts{ymax}, $color);
1783 elsif ($opts{fill}) {
1784 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
1785 # assume it's a hash ref
1786 require 'Imager/Fill.pm';
1787 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
1788 $self->{ERRSTR} = $Imager::ERRSTR;
1792 i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
1793 $opts{ymax},$opts{fill}{fill});
1796 my $color = _color($opts{'color'});
1798 $self->{ERRSTR} = $Imager::ERRSTR;
1801 i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
1807 # Draws an arc - this routine SUCKS and is buggy - it sometimes doesn't work when the arc is a convex polygon
1811 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1812 my $dflcl=i_color_new(255,255,255,255);
1813 my %opts=(color=>$dflcl,
1814 'r'=>min($self->getwidth(),$self->getheight())/3,
1815 'x'=>$self->getwidth()/2,
1816 'y'=>$self->getheight()/2,
1817 'd1'=>0, 'd2'=>361, @_);
1819 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
1820 # assume it's a hash ref
1821 require 'Imager/Fill.pm';
1822 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
1823 $self->{ERRSTR} = $Imager::ERRSTR;
1827 i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
1828 $opts{'d2'}, $opts{fill}{fill});
1831 my $color = _color($opts{'color'});
1833 $self->{ERRSTR} = $Imager::ERRSTR;
1836 if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
1837 i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'},
1841 if ($opts{'d1'} <= $opts{'d2'}) {
1842 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
1843 $opts{'d1'}, $opts{'d2'}, $color);
1846 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
1847 $opts{'d1'}, 361, $color);
1848 i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
1849 0, $opts{'d2'}, $color);
1857 # Draws a line from one point to (but not including) the destination point
1861 my $dflcl=i_color_new(0,0,0,0);
1862 my %opts=(color=>$dflcl,@_);
1863 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1865 unless (exists $opts{x1} and exists $opts{y1}) { $self->{ERRSTR}='missing begining coord'; return undef; }
1866 unless (exists $opts{x2} and exists $opts{y2}) { $self->{ERRSTR}='missing ending coord'; return undef; }
1868 my $color = _color($opts{'color'});
1870 $self->{ERRSTR} = $Imager::ERRSTR;
1873 $opts{antialias} = $opts{aa} if defined $opts{aa};
1874 if ($opts{antialias}) {
1875 i_line_aa($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
1878 i_draw($self->{IMG},$opts{x1}, $opts{y1}, $opts{x2}, $opts{y2},
1884 # Draws a line between an ordered set of points - It more or less just transforms this
1885 # into a list of lines.
1889 my ($pt,$ls,@points);
1890 my $dflcl=i_color_new(0,0,0,0);
1891 my %opts=(color=>$dflcl,@_);
1893 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1895 if (exists($opts{points})) { @points=@{$opts{points}}; }
1896 if (!exists($opts{points}) and exists($opts{'x'}) and exists($opts{'y'}) ) {
1897 @points=map { [ $opts{'x'}->[$_],$opts{'y'}->[$_] ] } (0..(scalar @{$opts{'x'}}-1));
1900 # print Dumper(\@points);
1902 my $color = _color($opts{'color'});
1904 $self->{ERRSTR} = $Imager::ERRSTR;
1907 $opts{antialias} = $opts{aa} if defined $opts{aa};
1908 if ($opts{antialias}) {
1911 i_line_aa($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color);
1918 i_draw($self->{IMG},$ls->[0],$ls->[1],$pt->[0],$pt->[1],$color);
1928 my ($pt,$ls,@points);
1929 my $dflcl = i_color_new(0,0,0,0);
1930 my %opts = (color=>$dflcl, @_);
1932 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1934 if (exists($opts{points})) {
1935 $opts{'x'} = [ map { $_->[0] } @{$opts{points}} ];
1936 $opts{'y'} = [ map { $_->[1] } @{$opts{points}} ];
1939 if (!exists $opts{'x'} or !exists $opts{'y'}) {
1940 $self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
1943 if ($opts{'fill'}) {
1944 unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
1945 # assume it's a hash ref
1946 require 'Imager/Fill.pm';
1947 unless ($opts{'fill'} = Imager::Fill->new(%{$opts{'fill'}})) {
1948 $self->{ERRSTR} = $Imager::ERRSTR;
1952 i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
1953 $opts{'fill'}{'fill'});
1956 my $color = _color($opts{'color'});
1958 $self->{ERRSTR} = $Imager::ERRSTR;
1961 i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
1968 # this the multipoint bezier curve
1969 # this is here more for testing that actual usage since
1970 # this is not a good algorithm. Usually the curve would be
1971 # broken into smaller segments and each done individually.
1975 my ($pt,$ls,@points);
1976 my $dflcl=i_color_new(0,0,0,0);
1977 my %opts=(color=>$dflcl,@_);
1979 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
1981 if (exists $opts{points}) {
1982 $opts{'x'}=map { $_->[0]; } @{$opts{'points'}};
1983 $opts{'y'}=map { $_->[1]; } @{$opts{'points'}};
1986 unless ( @{$opts{'x'}} and @{$opts{'x'}} == @{$opts{'y'}} ) {
1987 $self->{ERRSTR}='Missing or invalid points.';
1991 my $color = _color($opts{'color'});
1993 $self->{ERRSTR} = $Imager::ERRSTR;
1996 i_bezier_multi($self->{IMG},$opts{'x'},$opts{'y'},$color);
2002 my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
2004 unless (exists $opts{'x'} && exists $opts{'y'}) {
2005 $self->{ERRSTR} = "missing seed x and y parameters";
2010 unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
2011 # assume it's a hash ref
2012 require 'Imager/Fill.pm';
2013 unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
2014 $self->{ERRSTR} = $Imager::ERRSTR;
2018 i_flood_cfill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{fill}{fill});
2021 my $color = _color($opts{'color'});
2023 $self->{ERRSTR} = $Imager::ERRSTR;
2026 i_flood_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
2035 my %opts = ( color=>$self->{fg} || NC(255, 255, 255), @_);
2037 unless (exists $opts{'x'} && exists $opts{'y'}) {
2038 $self->{ERRSTR} = 'missing x and y parameters';
2044 my $color = _color($opts{color})
2046 if (ref $x && ref $y) {
2047 unless (@$x == @$y) {
2048 $self->{ERRSTR} = 'length of x and y mistmatch';
2051 if ($color->isa('Imager::Color')) {
2052 for my $i (0..$#{$opts{'x'}}) {
2053 i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color);
2057 for my $i (0..$#{$opts{'x'}}) {
2058 i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color);
2063 if ($color->isa('Imager::Color')) {
2064 i_ppix($self->{IMG}, $x, $y, $color);
2067 i_ppixf($self->{IMG}, $x, $y, $color);
2077 my %opts = ( type=>'8bit', @_);
2079 unless (exists $opts{'x'} && exists $opts{'y'}) {
2080 $self->{ERRSTR} = 'missing x and y parameters';
2086 if (ref $x && ref $y) {
2087 unless (@$x == @$y) {
2088 $self->{ERRSTR} = 'length of x and y mismatch';
2092 if ($opts{type} eq '8bit') {
2093 for my $i (0..$#{$opts{'x'}}) {
2094 push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i]));
2098 for my $i (0..$#{$opts{'x'}}) {
2099 push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i]));
2102 return wantarray ? @result : \@result;
2105 if ($opts{type} eq '8bit') {
2106 return i_get_pixel($self->{IMG}, $x, $y);
2109 return i_gpixf($self->{IMG}, $x, $y);
2116 # make an identity matrix of the given size
2120 my $matrix = [ map { [ (0) x $size ] } 1..$size ];
2121 for my $c (0 .. ($size-1)) {
2122 $matrix->[$c][$c] = 1;
2127 # general function to convert an image
2129 my ($self, %opts) = @_;
2132 # the user can either specify a matrix or preset
2133 # the matrix overrides the preset
2134 if (!exists($opts{matrix})) {
2135 unless (exists($opts{preset})) {
2136 $self->{ERRSTR} = "convert() needs a matrix or preset";
2140 if ($opts{preset} eq 'gray' || $opts{preset} eq 'grey') {
2141 # convert to greyscale, keeping the alpha channel if any
2142 if ($self->getchannels == 3) {
2143 $matrix = [ [ 0.222, 0.707, 0.071 ] ];
2145 elsif ($self->getchannels == 4) {
2146 # preserve the alpha channel
2147 $matrix = [ [ 0.222, 0.707, 0.071, 0 ],
2152 $matrix = _identity($self->getchannels);
2155 elsif ($opts{preset} eq 'noalpha') {
2156 # strip the alpha channel
2157 if ($self->getchannels == 2 or $self->getchannels == 4) {
2158 $matrix = _identity($self->getchannels);
2159 pop(@$matrix); # lose the alpha entry
2162 $matrix = _identity($self->getchannels);
2165 elsif ($opts{preset} eq 'red' || $opts{preset} eq 'channel0') {
2167 $matrix = [ [ 1 ] ];
2169 elsif ($opts{preset} eq 'green' || $opts{preset} eq 'channel1') {
2170 $matrix = [ [ 0, 1 ] ];
2172 elsif ($opts{preset} eq 'blue' || $opts{preset} eq 'channel2') {
2173 $matrix = [ [ 0, 0, 1 ] ];
2175 elsif ($opts{preset} eq 'alpha') {
2176 if ($self->getchannels == 2 or $self->getchannels == 4) {
2177 $matrix = [ [ (0) x ($self->getchannels-1), 1 ] ];
2180 # the alpha is just 1 <shrug>
2181 $matrix = [ [ (0) x $self->getchannels, 1 ] ];
2184 elsif ($opts{preset} eq 'rgb') {
2185 if ($self->getchannels == 1) {
2186 $matrix = [ [ 1 ], [ 1 ], [ 1 ] ];
2188 elsif ($self->getchannels == 2) {
2189 # preserve the alpha channel
2190 $matrix = [ [ 1, 0 ], [ 1, 0 ], [ 1, 0 ], [ 0, 1 ] ];
2193 $matrix = _identity($self->getchannels);
2196 elsif ($opts{preset} eq 'addalpha') {
2197 if ($self->getchannels == 1) {
2198 $matrix = _identity(2);
2200 elsif ($self->getchannels == 3) {
2201 $matrix = _identity(4);
2204 $matrix = _identity($self->getchannels);
2208 $self->{ERRSTR} = "Unknown convert preset $opts{preset}";
2214 $matrix = $opts{matrix};
2217 my $new = Imager->new();
2218 $new->{IMG} = i_img_new();
2219 unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
2220 # most likely a bad matrix
2221 $self->{ERRSTR} = _error_as_msg();
2228 # general function to map an image through lookup tables
2231 my ($self, %opts) = @_;
2232 my @chlist = qw( red green blue alpha );
2234 if (!exists($opts{'maps'})) {
2235 # make maps from channel maps
2237 for $chnum (0..$#chlist) {
2238 if (exists $opts{$chlist[$chnum]}) {
2239 $opts{'maps'}[$chnum] = $opts{$chlist[$chnum]};
2240 } elsif (exists $opts{'all'}) {
2241 $opts{'maps'}[$chnum] = $opts{'all'};
2245 if ($opts{'maps'} and $self->{IMG}) {
2246 i_map($self->{IMG}, $opts{'maps'} );
2251 # destructive border - image is shrunk by one pixel all around
2254 my ($self,%opts)=@_;
2255 my($tx,$ty)=($self->getwidth()-1,$self->getheight()-1);
2256 $self->polyline('x'=>[0,$tx,$tx,0,0],'y'=>[0,0,$ty,$ty,0],%opts);
2260 # Get the width of an image
2264 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2265 return (i_img_info($self->{IMG}))[0];
2268 # Get the height of an image
2272 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2273 return (i_img_info($self->{IMG}))[1];
2276 # Get number of channels in an image
2280 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2281 return i_img_getchannels($self->{IMG});
2288 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2289 return i_img_getmask($self->{IMG});
2297 if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
2298 i_img_setmask( $self->{IMG} , $opts{mask} );
2301 # Get number of colors in an image
2305 my %opts=('maxcolors'=>2**30,@_);
2306 if (!defined($self->{IMG})) { $self->{ERRSTR}='image is empty'; return undef; }
2307 my $rc=i_count_colors($self->{IMG},$opts{'maxcolors'});
2308 return ($rc==-1? undef : $rc);
2311 # draw string to an image
2315 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
2317 my %input=('x'=>0, 'y'=>0, @_);
2318 $input{string}||=$input{text};
2320 unless(exists $input{string}) {
2321 $self->{ERRSTR}="missing required parameter 'string'";
2325 unless($input{font}) {
2326 $self->{ERRSTR}="missing required parameter 'font'";
2330 unless ($input{font}->draw(image=>$self, %input)) {
2331 $self->{ERRSTR} = $self->_error_as_msg();
2338 # Shortcuts that can be exported
2340 sub newcolor { Imager::Color->new(@_); }
2341 sub newfont { Imager::Font->new(@_); }
2343 *NC=*newcolour=*newcolor;
2350 #### Utility routines
2353 ref $_[0] ? $_[0]->{ERRSTR} : $ERRSTR
2357 my ($self, $msg) = @_;
2360 $self->{ERRSTR} = $msg;
2367 # Default guess for the type of an image from extension
2369 sub def_guess_type {
2372 $ext=($name =~ m/\.([^\.]+)$/)[0];
2373 return 'tiff' if ($ext =~ m/^tiff?$/);
2374 return 'jpeg' if ($ext =~ m/^jpe?g$/);
2375 return 'pnm' if ($ext =~ m/^p[pgb]m$/);
2376 return 'png' if ($ext eq "png");
2377 return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
2378 return 'tga' if ($ext eq "tga");
2379 return 'rgb' if ($ext eq "rgb");
2380 return 'gif' if ($ext eq "gif");
2381 return 'raw' if ($ext eq "raw");
2385 # get the minimum of a list
2389 for(@_) { if ($_<$mx) { $mx=$_; }}
2393 # get the maximum of a list
2397 for(@_) { if ($_>$mx) { $mx=$_; }}
2401 # string stuff for iptc headers
2405 $str = substr($str,3);
2406 $str =~ s/[\n\r]//g;
2413 # A little hack to parse iptc headers.
2418 my($caption,$photogr,$headln,$credit);
2420 my $str=$self->{IPTCRAW};
2424 @ar=split(/8BIM/,$str);
2429 @sar=split(/\034\002/);
2430 foreach $item (@sar) {
2431 if ($item =~ m/^x/) {
2432 $caption=&clean($item);
2435 if ($item =~ m/^P/) {
2436 $photogr=&clean($item);
2439 if ($item =~ m/^i/) {
2440 $headln=&clean($item);
2443 if ($item =~ m/^n/) {
2444 $credit=&clean($item);
2450 return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
2453 # Autoload methods go after =cut, and are processed by the autosplit program.
2457 # Below is the stub of documentation for your module. You better edit it!
2461 Imager - Perl extension for Generating 24 bit Images
2471 die "Usage: thumbmake.pl filename\n" if !-f $ARGV[0];
2476 my $img = Imager->new();
2477 $img->open(file=>$file) or die $img->errstr();
2479 $file =~ s/\.[^.]*$//;
2481 # Create smaller version
2482 my $thumb = $img->scale(scalefactor=>.3);
2484 # Autostretch individual channels
2485 $thumb->filter(type=>'autolevels');
2487 # try to save in one of these formats
2490 for $format ( qw( png gif jpg tiff ppm ) ) {
2491 # Check if given format is supported
2492 if ($Imager::formats{$format}) {
2493 $file.="_low.$format";
2494 print "Storing image as: $file\n";
2495 $thumb->write(file=>$file) or
2502 # Logo Generator Example
2508 Imager is a module for creating and altering images. It can read and
2509 write various image formats, draw primitive shapes like lines,and
2510 polygons, blend multiple images together in various ways, scale, crop,
2511 render text and more.
2513 =head2 Overview of documentation
2519 This document - Synopsis Example, Table of Contents and Overview.
2521 =item Imager::ImageTypes
2523 Direct type/virtual images, RGB(A)/paletted images, 8/16/double
2524 bits/channel, color maps, channel masks, image tags, color
2529 IO interaction, reading/writing images, format specific tags.
2533 Drawing Primitives, lines, boxes, circles, arcs, flood fill.
2537 Color specification.
2541 Fill pattern specification.
2545 General font rendering, bounding boxes and font metrics.
2547 =item Imager::Transformations
2549 Copying, scaling, cropping, flipping, blending, pasting, convert and
2552 =item Imager::Engines
2554 Programmable transformations through C<transform()>, C<transform2()>
2555 and C<matrix_transform()>.
2557 =item Imager::Filters
2559 Filters, sharpen, blur, noise, convolve etc. and filter plugins.
2563 Expressions for evaluation engine used by transform2().
2565 =item Imager::Matrix2d
2567 Helper class for affine transformations.
2569 =item Imager::Fountain
2571 Helper for making gradient profiles.
2577 =head2 Basic Overview
2579 An Image object is created with C<$img = Imager-E<gt>new()> Should
2580 this fail for some reason an explanation can be found in
2581 C<$Imager::ERRSTR> usually error messages are stored in
2582 C<$img-E<gt>{ERRSTR}>, but since no object is created this is the only
2583 way to give back errors. C<$Imager::ERRSTR> is also used to report
2584 all errors not directly associated with an image object. Examples:
2586 $img=Imager->new(); # This is an empty image (size is 0 by 0)
2587 $img->open(file=>'lena.png',type=>'png'); # initializes from file
2589 or if you want to create an empty image:
2591 $img=Imager->new(xsize=>400,ysize=>300,channels=>4);
2593 This example creates a completely black image of width 400 and height
2598 You can ask for help, report bugs or express your undying love for
2599 Imager on the Imager-devel mailing list.
2601 To subscribe send a message with C<subscribe> in the body to:
2603 imager-devel+request@molar.is
2607 http://www.molar.is/en/lists/imager-devel/
2609 where you can also find the mailing list archive.
2613 Bugs are listed individually for relevant pod pages.
2617 Arnar M. Hrafnkelsson (addi@umich.edu) and Tony Cook
2618 (tony@imager.perl.org) See the README for a complete list.
2622 perl(1), Imager::Color(3), Imager::Font(3), Imager::Matrix2d(3),
2623 Affix::Infix2Postfix(3), Parse::RecDescent(3)
2624 http://www.eecs.umich.edu/~addi/perl/Imager/