X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/6d5c85a2f47f23387f7e6ef35cb5606cdeb2fc6c..12bb8239ed0db89b24912e0c7ed32b0cde004406:/Imager.pm diff --git a/Imager.pm b/Imager.pm index bd645bb5..71af0686 100644 --- a/Imager.pm +++ b/Imager.pm @@ -24,11 +24,6 @@ use Imager::Font; i_color_set i_color_info - i_img_empty - i_img_empty_ch - i_img_exorcise - i_img_destroy - i_img_info i_img_setmask @@ -148,16 +143,9 @@ BEGIN { if ($ex_version < 5.57) { @ISA = qw(Exporter); } - $VERSION = '0.85'; - eval { - require XSLoader; - XSLoader::load(Imager => $VERSION); - 1; - } or do { - require DynaLoader; - push @ISA, 'DynaLoader'; - bootstrap Imager $VERSION; - } + $VERSION = '0.92'; + require XSLoader; + XSLoader::load(Imager => $VERSION); } my %formats_low; @@ -629,11 +617,13 @@ sub _combine { } sub _valid_image { - my ($self) = @_; + my ($self, $method) = @_; $self->{IMG} and return 1; - $self->_set_error('empty input image'); + my $msg = 'empty input image'; + $msg = "$method: $msg" if $method; + $self->_set_error($msg); return; } @@ -918,8 +908,8 @@ sub img_set { $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels}); } else { - $self->{IMG}=Imager::ImgRaw::new($hsh{'xsize'}, $hsh{'ysize'}, - $hsh{'channels'}); + $self->{IMG}= i_img_8_new($hsh{'xsize'}, $hsh{'ysize'}, + $hsh{'channels'}); } unless ($self->{IMG}) { @@ -987,6 +977,25 @@ sub to_paletted { return $result; } +sub make_palette { + my ($class, $quant, @images) = @_; + + unless (@images) { + Imager->_set_error("make_palette: supply at least one image"); + return; + } + my $index = 1; + for my $img (@images) { + unless ($img->{IMG}) { + Imager->_set_error("make_palette: image $index is empty"); + return; + } + ++$index; + } + + return i_img_make_palette($quant, map $_->{IMG}, @images); +} + # convert a paletted (or any image) to an 8-bit/channel RGB image sub to_rgb8 { my $self = shift; @@ -1414,8 +1423,15 @@ sub read { $type = i_test_format_probe($IO, -1); } + if ($input{file} && !$type) { + # guess the type + $type = $FORMATGUESS->($input{file}); + } + unless ($type) { - $self->_set_error('type parameter missing and not possible to guess from extension'); + my $msg = "type parameter missing and it couldn't be determined from the file contents"; + $input{file} and $msg .= " or file name"; + $self->_set_error($msg); return undef; } @@ -1453,41 +1469,6 @@ sub read { $self->{DEBUG} && print "loading a bmp file\n"; } - if ( $type eq 'gif' ) { - if ($input{colors} && !ref($input{colors})) { - # must be a reference to a scalar that accepts the colour map - $self->{ERRSTR} = "option 'colors' must be a scalar reference"; - return undef; - } - if ($input{'gif_consolidate'}) { - if ($input{colors}) { - my $colors; - ($self->{IMG}, $colors) =i_readgif_wiol( $IO ); - if ($colors) { - ${ $input{colors} } = [ map { NC(@$_) } @$colors ]; - } - } - else { - $self->{IMG} =i_readgif_wiol( $IO ); - } - } - else { - my $page = $input{'page'}; - defined $page or $page = 0; - $self->{IMG} = i_readgif_single_wiol( $IO, $page ); - if ($self->{IMG} && $input{colors}) { - ${ $input{colors} } = - [ i_getcolors($self->{IMG}, 0, i_colorcount($self->{IMG})) ]; - } - } - - if ( !defined($self->{IMG}) ) { - $self->{ERRSTR}=$self->_error_as_msg(); - return undef; - } - $self->{DEBUG} && print "loading a gif file\n"; - } - if ( $type eq 'tga' ) { $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed if ( !defined($self->{IMG}) ) { @@ -1619,10 +1600,11 @@ sub _load_file { return 1; } else { - my $work = $@ || "Unknown error loading $file"; + my $work = $@ || "Unknown error"; chomp $work; $work =~ s/\n?Compilation failed in require at .*Imager\.pm line .*\z//m; $work =~ s/\n/\\n/g; + $work =~ s/\s*\.?\z/ loading $file/; $file_load_errors{$file} = $work; $$error = $work; return 0; @@ -1958,7 +1940,9 @@ sub read_multi { } unless ($type) { - $ERRSTR = "No type parameter supplied and it couldn't be guessed"; + my $msg = "type parameter missing and it couldn't be determined from the file contents"; + $opts{file} and $msg .= " or file name"; + Imager->_set_error($msg); return; } @@ -2643,7 +2627,7 @@ sub rotate { } } elsif (defined $opts{radians} || defined $opts{degrees}) { - my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180; + my $amount = $opts{radians} || $opts{degrees} * 3.14159265358979 / 180; my $back = $opts{back}; my $result = Imager->new; @@ -3124,6 +3108,9 @@ sub flood_fill { sub setpixel { my ($self, %opts) = @_; + $self->_valid_image("setpixel") + or return; + my $color = $opts{color}; unless (defined $color) { $color = $self->{fg}; @@ -3131,36 +3118,53 @@ sub setpixel { } unless (ref $color && UNIVERSAL::isa($color, "Imager::Color")) { - $color = _color($color) - or return undef; + unless ($color = _color($color, 'setpixel')) { + $self->_set_error("setpixel: " . Imager->errstr); + return; + } } unless (exists $opts{'x'} && exists $opts{'y'}) { - $self->{ERRSTR} = 'missing x and y parameters'; - return undef; + $self->_set_error('setpixel: missing x or y parameter'); + return; } my $x = $opts{'x'}; my $y = $opts{'y'}; - if (ref $x && ref $y) { - unless (@$x == @$y) { - $self->{ERRSTR} = 'length of x and y mismatch'; + if (ref $x || ref $y) { + $x = ref $x ? $x : [ $x ]; + $y = ref $y ? $y : [ $y ]; + unless (@$x) { + $self->_set_error("setpixel: x is a reference to an empty array"); return; } + unless (@$y) { + $self->_set_error("setpixel: y is a reference to an empty array"); + return; + } + + # make both the same length, replicating the last element + if (@$x < @$y) { + $x = [ @$x, ($x->[-1]) x (@$y - @$x) ]; + } + elsif (@$y < @$x) { + $y = [ @$y, ($y->[-1]) x (@$x - @$y) ]; + } + my $set = 0; if ($color->isa('Imager::Color')) { - for my $i (0..$#{$opts{'x'}}) { + for my $i (0..$#$x) { i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color) or ++$set; } } else { - for my $i (0..$#{$opts{'x'}}) { + for my $i (0..$#$x) { i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color) or ++$set; } } - $set or return; + return $set; } else { @@ -3174,7 +3178,7 @@ sub setpixel { } } - $self; + return $self; } sub getpixel { @@ -3182,41 +3186,66 @@ sub getpixel { my %opts = ( "type"=>'8bit', @_); + $self->_valid_image("getpixel") + or return; + unless (exists $opts{'x'} && exists $opts{'y'}) { - $self->{ERRSTR} = 'missing x and y parameters'; - return undef; + $self->_set_error('getpixel: missing x or y parameter'); + return; } my $x = $opts{'x'}; my $y = $opts{'y'}; - if (ref $x && ref $y) { - unless (@$x == @$y) { - $self->{ERRSTR} = 'length of x and y mismatch'; - return undef; + my $type = $opts{'type'}; + if (ref $x || ref $y) { + $x = ref $x ? $x : [ $x ]; + $y = ref $y ? $y : [ $y ]; + unless (@$x) { + $self->_set_error("getpixel: x is a reference to an empty array"); + return; + } + unless (@$y) { + $self->_set_error("getpixel: y is a reference to an empty array"); + return; + } + + # make both the same length, replicating the last element + if (@$x < @$y) { + $x = [ @$x, ($x->[-1]) x (@$y - @$x) ]; + } + elsif (@$y < @$x) { + $y = [ @$y, ($y->[-1]) x (@$x - @$y) ]; } + my @result; - if ($opts{"type"} eq '8bit') { - for my $i (0..$#{$opts{'x'}}) { + if ($type eq '8bit') { + for my $i (0..$#$x) { push(@result, i_get_pixel($self->{IMG}, $x->[$i], $y->[$i])); } } - else { - for my $i (0..$#{$opts{'x'}}) { + elsif ($type eq 'float' || $type eq 'double') { + for my $i (0..$#$x) { push(@result, i_gpixf($self->{IMG}, $x->[$i], $y->[$i])); } } + else { + $self->_set_error("getpixel: type must be '8bit' or 'float'"); + return; + } return wantarray ? @result : \@result; } else { - if ($opts{"type"} eq '8bit') { + if ($type eq '8bit') { return i_get_pixel($self->{IMG}, $x, $y); } - else { + elsif ($type eq 'float' || $type eq 'double') { return i_gpixf($self->{IMG}, $x, $y); } + else { + $self->_set_error("getpixel: type must be '8bit' or 'float'"); + return; + } } - - $self; } sub getscanline { @@ -3326,24 +3355,20 @@ sub getsamples { return; } - unless ($opts{channels}) { - $opts{channels} = [ 0 .. $self->getchannels()-1 ]; - } - if ($opts{target}) { my $target = $opts{target}; my $offset = $opts{offset}; if ($opts{type} eq '8bit') { my @samples = i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, - $opts{y}, @{$opts{channels}}) + $opts{y}, $opts{channels}) or return; - @{$target}{$offset .. $offset + @samples - 1} = @samples; + @{$target}[$offset .. $offset + @samples - 1] = @samples; return scalar(@samples); } elsif ($opts{type} eq 'float') { my @samples = i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, - $opts{y}, @{$opts{channels}}); - @{$target}{$offset .. $offset + @samples - 1} = @samples; + $opts{y}, $opts{channels}); + @{$target}[$offset .. $offset + @samples - 1] = @samples; return scalar(@samples); } elsif ($opts{type} =~ /^(\d+)bit$/) { @@ -3352,7 +3377,7 @@ sub getsamples { my @data; my $count = i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, $opts{y}, $bits, $target, - $offset, @{$opts{channels}}); + $offset, $opts{channels}); unless (defined $count) { $self->_set_error(Imager->_error_as_msg); return; @@ -3368,18 +3393,18 @@ sub getsamples { else { if ($opts{type} eq '8bit') { return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, - $opts{y}, @{$opts{channels}}); + $opts{y}, $opts{channels}); } elsif ($opts{type} eq 'float') { return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, - $opts{y}, @{$opts{channels}}); + $opts{y}, $opts{channels}); } elsif ($opts{type} =~ /^(\d+)bit$/) { my $bits = $1; my @data; i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, - $opts{y}, $bits, \@data, 0, @{$opts{channels}}) + $opts{y}, $bits, \@data, 0, $opts{channels}) or return; return @data; } @@ -3399,28 +3424,44 @@ sub setsamples { return; } - unless(defined $opts{data} && ref $opts{data}) { - $self->_set_error('setsamples: data parameter missing or invalid'); + my $data = $opts{data}; + unless(defined $data) { + $self->_set_error('setsamples: data parameter missing'); return; } - unless ($opts{channels}) { - $opts{channels} = [ 0 .. $self->getchannels()-1 ]; - } + my $type = $opts{type}; + defined $type or $type = '8bit'; - unless ($opts{type} && $opts{type} =~ /^(\d+)bit$/) { - $self->_set_error('setsamples: type parameter missing or invalid'); - return; + my $width = defined $opts{width} ? $opts{width} + : $self->getwidth() - $opts{x}; + + my $count; + if ($type eq '8bit') { + $count = i_psamp($self->{IMG}, $opts{x}, $opts{y}, $opts{channels}, + $data, $opts{offset}, $width); } - my $bits = $1; + elsif ($type eq 'float') { + $count = i_psampf($self->{IMG}, $opts{x}, $opts{y}, $opts{channels}, + $data, $opts{offset}, $width); + } + elsif ($type =~ /^([0-9]+)bit$/) { + my $bits = $1; + + unless (ref $data) { + $self->_set_error("setsamples: data must be an array ref for type not 8bit or float"); + return; + } - unless (defined $opts{width}) { - $opts{width} = $self->getwidth() - $opts{x}; + $count = i_psamp_bits($self->{IMG}, $opts{x}, $opts{y}, $bits, + $opts{channels}, $data, $opts{offset}, + $width); + } + else { + $self->_set_error('setsamples: type parameter invalid'); + return; } - my $count = i_psamp_bits($self->{IMG}, $opts{x}, $opts{y}, $bits, - $opts{channels}, $opts{data}, $opts{offset}, - $opts{width}); unless (defined $count) { $self->_set_error(Imager->_error_as_msg); return; @@ -3854,6 +3895,41 @@ sub get_file_limits { i_get_image_file_limits(); } +my @check_args = qw(width height channels sample_size); + +sub check_file_limits { + my $class = shift; + + my %opts = + ( + channels => 3, + sample_size => 1, + @_, + ); + + if ($opts{sample_size} && $opts{sample_size} eq 'float') { + $opts{sample_size} = length(pack("d", 0)); + } + + for my $name (@check_args) { + unless (defined $opts{$name}) { + $class->_set_error("check_file_limits: $name must be defined"); + return; + } + unless ($opts{$name} == int($opts{$name})) { + $class->_set_error("check_file_limits: $name must be a positive integer"); + return; + } + } + + my $result = i_int_check_image_file_limits(@opts{@check_args}); + unless ($result) { + $class->_set_error($class->_error_as_msg()); + } + + return $result; +} + # Shortcuts that can be exported sub newcolor { Imager::Color->new(@_); } @@ -3890,21 +3966,39 @@ sub _set_error { # Default guess for the type of an image from extension +my @simple_types = qw(png tga gif raw ico cur xpm mng jng ilbm pcx psd eps); + +my %ext_types = + ( + ( map { $_ => $_ } @simple_types ), + tiff => "tiff", + tif => "tiff", + pbm => "pnm", + pgm => "pnm", + ppm => "pnm", + pnm => "pnm", # technically wrong, but historically it works in Imager + jpeg => "jpeg", + jpg => "jpeg", + bmp => "bmp", + dib => "bmp", + rgb => "sgi", + bw => "sgi", + sgi => "sgi", + fit => "fits", + fits => "fits", + rle => "utah", + ); + sub def_guess_type { my $name=lc(shift); - my $ext; - $ext=($name =~ m/\.([^\.]+)$/)[0]; - return 'tiff' if ($ext =~ m/^tiff?$/); - return 'jpeg' if ($ext =~ m/^jpe?g$/); - return 'pnm' if ($ext =~ m/^p[pgb]m$/); - return 'png' if ($ext eq "png"); - return 'bmp' if ($ext eq "bmp" || $ext eq "dib"); - return 'tga' if ($ext eq "tga"); - return 'sgi' if ($ext eq "rgb" || $ext eq "bw" || $ext eq "sgi" || $ext eq "rgba"); - return 'gif' if ($ext eq "gif"); - return 'raw' if ($ext eq "raw"); - return lc $ext; # best guess - return (); + + my ($ext) = $name =~ /\.([^.]+)$/ + or return; + + my $type = $ext_types{$ext} + or return; + + return $type; } sub combines { @@ -3995,7 +4089,7 @@ sub Imager::ImgRaw::CLONE_SKIP { 1 } sub preload { # this serves two purposes: - # - a class method to load the file support modules included with Image + # - a class method to load the file support modules included with Imager # (or were included, once the library dependent modules are split out) # - something for Module::ScanDeps to analyze # https://rt.cpan.org/Ticket/Display.html?id=6566 @@ -4265,6 +4359,10 @@ L - using Imager's C API from Inline::C L - tools to get access to Imager's C API. +=item * + +L - brief security notes. + =back =head2 Basic Overview @@ -4334,6 +4432,8 @@ image box() - L - draw a filled or outline box. +check_file_limits() - L + circle() - L - draw a filled circle close_log() - L - close the Imager @@ -4393,7 +4493,7 @@ getcolorusage() - L getcolorusagehash() - L -get_file_limits() - L +get_file_limits() - L getheight() - L - height of the image in pixels @@ -4431,7 +4531,10 @@ load_plugin() - L log() - L - send a message to the debugging log. -map() - L - remap color +make_palette() - L - produce a +color palette from one or more input images. + +map() - L - remap color channel values masked() - L - make a masked image @@ -4454,7 +4557,7 @@ newfont() - L NF() - L -open() - L - an alias for read() +open() - L - an alias for read() open_log() - L - open the debug log. @@ -4502,7 +4605,7 @@ scaleY() - L setcolors() - L - set palette colors in a paletted image -set_file_limits() - L +set_file_limits() - L setmask() - L @@ -4681,6 +4784,8 @@ saving an image - L scaling - L +security - L + SGI files - L sharpen - L, L @@ -4788,13 +4893,29 @@ Tracker. =head2 Patches -I accept patches, preferably against the main branch in subversion. -You should include an explanation of the reason for why the patch is -needed or useful. +I accept patches, preferably against the master branch in git. Please +include an explanation of the reason for why the patch is needed or +useful. Your patch should include regression tests where possible, otherwise it will be delayed until I get a chance to write them. +To browse Imager's git repository: + + http://git.imager.perl.org/imager.git + +or: + + https://github.com/tonycoz/imager + +To clone: + + git clone git://git.imager.perl.org/imager.git + +or: + + git clone git://github.com/tonycoz/imager.git + =head1 AUTHOR Tony Cook is the current maintainer for Imager. @@ -4811,9 +4932,10 @@ Imager is licensed under the same terms as perl itself. =for stopwords makeblendedfont Fontforge -A test font, FT2/fontfiles/MMOne.pfb, contains a Postscript operator -definition copyrighted by Adobe. See F in the source for -license information. +A test font, generated by the Debian packaged Fontforge, +F, contains a Postscript operator definition +copyrighted by Adobe. See F in the source for license +information. =head1 SEE ALSO @@ -4829,6 +4951,10 @@ L(3), L(3) Other perl imaging modules include: -L(3), L(3), L(3). +L(3), L(3), L(3), +L, L. + +If you're trying to use Imager for array processing, you should +probably using L. =cut