]> git.imager.perl.org - imager.git/blobdiff - Imager.pm
- bump to 0.48
[imager.git] / Imager.pm
index fb2799923050f1776b4400c018054f2eb8ffd9d8..0f684aec57cbbb8c4922daedfa246c0d27a3851e 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -145,11 +145,17 @@ use Imager::Font;
 
 BEGIN {
   require Exporter;
 
 BEGIN {
   require Exporter;
-  require DynaLoader;
-
-  $VERSION = '0.43_02';
-  @ISA = qw(Exporter DynaLoader);
-  bootstrap Imager $VERSION;
+  @ISA = qw(Exporter);
+  $VERSION = '0.48';
+  eval {
+    require XSLoader;
+    XSLoader::load(Imager => $VERSION);
+    1;
+  } or do {
+    require DynaLoader;
+    push @ISA, 'DynaLoader';
+    bootstrap Imager $VERSION;
+  }
 }
 
 BEGIN {
 }
 
 BEGIN {
@@ -221,17 +227,40 @@ BEGIN {
                       callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}); }
                      };
 
                       callsub => sub { my %hsh=@_; i_conv($hsh{image},$hsh{coef}); }
                      };
 
-  $filters{gradgen} ={
-                      callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
-                      defaults => { },
-                      callsub => sub { my %hsh=@_; i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, $hsh{colors}, $hsh{dist}); }
-                     };
+  $filters{gradgen} =
+    {
+     callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
+     defaults => { dist => 0 },
+     callsub => 
+     sub { 
+       my %hsh=@_;
+       my @colors = @{$hsh{colors}};
+       $_ = _color($_)
+         for @colors;
+       i_gradgen($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, $hsh{dist});
+     }
+    };
 
 
-  $filters{nearest_color} ={
-                           callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
-                           defaults => { },
-                           callsub => sub { my %hsh=@_; i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, $hsh{colors}, $hsh{dist}); }
-                          };
+  $filters{nearest_color} =
+    {
+     callseq => ['image', 'xo', 'yo', 'colors', 'dist'],
+     defaults => { },
+     callsub => 
+     sub { 
+       my %hsh=@_; 
+       # make sure the segments are specified with colors
+       my @colors;
+       for my $color (@{$hsh{colors}}) {
+         my $new_color = _color($color) 
+           or die $Imager::ERRSTR."\n";
+         push @colors, $new_color;
+       }
+
+       i_nearest_color($hsh{image}, $hsh{xo}, $hsh{yo}, \@colors, 
+                       $hsh{dist})
+         or die Imager->_error_as_msg() . "\n";
+     },
+    };
   $filters{gaussian} = {
                         callseq => [ 'image', 'stddev' ],
                         defaults => { },
   $filters{gaussian} = {
                         callseq => [ 'image', 'stddev' ],
                         defaults => { },
@@ -346,9 +375,20 @@ BEGIN {
      callsub  => 
      sub {
        my %hsh = @_;
      callsub  => 
      sub {
        my %hsh = @_;
+
+       # make sure the segments are specified with colors
+       my @segments;
+       for my $segment (@{$hsh{segments}}) {
+         my @new_segment = @$segment;
+         
+         $_ = _color($_) or die $Imager::ERRSTR."\n" for @new_segment[3,4];
+         push @segments, \@new_segment;
+       }
+
        i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
                   $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
        i_fountain($hsh{image}, $hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
                   $hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
-                  $hsh{ssample_param}, $hsh{segments});
+                  $hsh{ssample_param}, \@segments)
+         or die Imager->_error_as_msg() . "\n";
      },
     };
   $filters{unsharpmask} =
      },
     };
   $filters{unsharpmask} =
@@ -542,9 +582,14 @@ sub copy {
   my $self = shift;
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 
   my $self = shift;
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
   my $newcopy=Imager->new();
   my $newcopy=Imager->new();
-  $newcopy->{IMG}=i_img_new();
-  i_copy($newcopy->{IMG},$self->{IMG});
+  $newcopy->{IMG} = i_copy($self->{IMG});
   return $newcopy;
 }
 
   return $newcopy;
 }
 
@@ -552,19 +597,68 @@ sub copy {
 
 sub paste {
   my $self = shift;
 
 sub paste {
   my $self = shift;
-  unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
-  my %input=(left=>0, top=>0, @_);
-  unless($input{img}) {
-    $self->{ERRSTR}="no source image";
+
+  unless ($self->{IMG}) { 
+    $self->_set_error('empty input image');
+    return;
+  }
+  my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_);
+  my $src = $input{img} || $input{src};
+  unless($src) {
+    $self->_set_error("no source image");
     return;
   }
   $input{left}=0 if $input{left} <= 0;
   $input{top}=0 if $input{top} <= 0;
     return;
   }
   $input{left}=0 if $input{left} <= 0;
   $input{top}=0 if $input{top} <= 0;
-  my $src=$input{img};
+
   my($r,$b)=i_img_info($src->{IMG});
   my($r,$b)=i_img_info($src->{IMG});
+  my ($src_left, $src_top) = @input{qw/src_minx src_miny/};
+  my ($src_right, $src_bottom);
+  if ($input{src_coords}) {
+    ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}}
+  }
+  else {
+    if (defined $input{src_maxx}) {
+      $src_right = $input{src_maxx};
+    }
+    elsif (defined $input{width}) {
+      if ($input{width} <= 0) {
+        $self->_set_error("paste: width must me positive");
+        return;
+      }
+      $src_right = $src_left + $input{width};
+    }
+    else {
+      $src_right = $r;
+    }
+    if (defined $input{src_maxx}) {
+      $src_bottom = $input{src_maxy};
+    }
+    elsif (defined $input{height}) {
+      if ($input{height} < 0) {
+        $self->_set_error("paste: height must be positive");
+        return;
+      }
+      $src_bottom = $src_top + $input{height};
+    }
+    else {
+      $src_bottom = $b;
+    }
+  }
+
+  $src_right > $r and $src_right = $r;
+  $src_bottom > $r and $src_bottom = $b;
+
+  if ($src_right <= $src_left
+      || $src_bottom < $src_top) {
+    $self->_set_error("nothing to paste");
+    return;
+  }
 
   i_copyto($self->{IMG}, $src->{IMG}, 
 
   i_copyto($self->{IMG}, $src->{IMG}, 
-          0,0, $r, $b, $input{left}, $input{top});
+          $src_left, $src_top, $src_right, $src_bottom, 
+           $input{left}, $input{top});
+
   return $self;  # What should go here??
 }
 
   return $self;  # What should go here??
 }
 
@@ -573,8 +667,13 @@ sub paste {
 sub crop {
   my $self=shift;
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 sub crop {
   my $self=shift;
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
-
   
   
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "crop() called in void context - crop() returns the cropped image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
   my %hsh=@_;
 
   my ($w, $h, $l, $r, $b, $t) =
   my %hsh=@_;
 
   my ($w, $h, $l, $r, $b, $t) =
@@ -745,6 +844,12 @@ sub to_paletted {
     $opts = shift;
   }
 
     $opts = shift;
   }
 
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "to_paletted() called in void context - to_paletted() returns the converted image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
   my $result = Imager->new;
   $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
 
   my $result = Imager->new;
   $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
 
@@ -764,6 +869,12 @@ sub to_rgb8 {
   my $self = shift;
   my $result;
 
   my $self = shift;
   my $result;
 
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "to_rgb8() called in void context - to_rgb8() returns the cropped image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
   if ($self->{IMG}) {
     $result = Imager->new;
     $result->{IMG} = i_img_to_rgb($self->{IMG})
   if ($self->{IMG}) {
     $result = Imager->new;
     $result->{IMG} = i_img_to_rgb($self->{IMG})
@@ -1081,35 +1192,37 @@ sub read {
     undef($self->{IMG});
   }
 
     undef($self->{IMG});
   }
 
-  # FIXME: Find the format here if not specified
-  # yes the code isn't here yet - next week maybe?
-  # Next week?  Are you high or something?  That comment
-  # has been there for half a year dude.
-  # Look, i just work here, ok?
-
   my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
 
   unless ($input{'type'}) {
   my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
 
   unless ($input{'type'}) {
-               $input{'type'} = i_test_format_probe($IO, -1);
-       }
+    $input{'type'} = i_test_format_probe($IO, -1);
+  }
 
   unless ($input{'type'}) {
          $self->_set_error('type parameter missing and not possible to guess from extension'); 
     return undef;
   }
 
 
   unless ($input{'type'}) {
          $self->_set_error('type parameter missing and not possible to guess from extension'); 
     return undef;
   }
 
+  unless ($formats{$input{'type'}}) {
+    $self->_set_error("format '$input{'type'}' not supported");
+    return;
+  }
+
   # Setup data source
   if ( $input{'type'} eq 'jpeg' ) {
     ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
     if ( !defined($self->{IMG}) ) {
   # Setup data source
   if ( $input{'type'} eq 'jpeg' ) {
     ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
     if ( !defined($self->{IMG}) ) {
-      $self->{ERRSTR}='unable to read jpeg image'; return undef;
+      $self->{ERRSTR}=$self->_error_as_msg(); return undef;
     }
     $self->{DEBUG} && print "loading a jpeg file\n";
     return $self;
   }
 
   if ( $input{'type'} eq 'tiff' ) {
     }
     $self->{DEBUG} && print "loading a jpeg file\n";
     return $self;
   }
 
   if ( $input{'type'} eq 'tiff' ) {
-    $self->{IMG}=i_readtiff_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
+    my $page = $input{'page'};
+    defined $page or $page = 0;
+    # Fixme, check if that length parameter is ever needed
+    $self->{IMG}=i_readtiff_wiol( $IO, -1, $page ); 
     if ( !defined($self->{IMG}) ) {
       $self->{ERRSTR}=$self->_error_as_msg(); return undef;
     }
     if ( !defined($self->{IMG}) ) {
       $self->{ERRSTR}=$self->_error_as_msg(); return undef;
     }
@@ -1120,7 +1233,8 @@ sub read {
   if ( $input{'type'} eq 'pnm' ) {
     $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
     if ( !defined($self->{IMG}) ) {
   if ( $input{'type'} eq 'pnm' ) {
     $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
     if ( !defined($self->{IMG}) ) {
-      $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); return undef;
+      $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); 
+      return undef;
     }
     $self->{DEBUG} && print "loading a pnm file\n";
     return $self;
     }
     $self->{DEBUG} && print "loading a pnm file\n";
     return $self;
@@ -1129,7 +1243,7 @@ sub read {
   if ( $input{'type'} eq 'png' ) {
     $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
     if ( !defined($self->{IMG}) ) {
   if ( $input{'type'} eq 'png' ) {
     $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
     if ( !defined($self->{IMG}) ) {
-      $self->{ERRSTR}='unable to read png image';
+      $self->{ERRSTR} = $self->_error_as_msg();
       return undef;
     }
     $self->{DEBUG} && print "loading a png file\n";
       return undef;
     }
     $self->{DEBUG} && print "loading a png file\n";
@@ -1150,16 +1264,28 @@ sub read {
       $self->{ERRSTR} = "option 'colors' must be a scalar reference";
       return undef;
     }
       $self->{ERRSTR} = "option 'colors' must be a scalar reference";
       return undef;
     }
-    if ($input{colors}) {
-      my $colors;
-      ($self->{IMG}, $colors) =i_readgif_wiol( $IO );
-      if ($colors) {
-       ${ $input{colors} } = [ map { NC(@$_) } @$colors ];
+    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 {
       }
     }
     else {
-      $self->{IMG} =i_readgif_wiol( $IO );
+      my $page = $input{'page'};
+      defined $page or $page = 0;
+      $self->{IMG} = i_readgif_single_wiol( $IO, $page );
+      if ($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;
     if ( !defined($self->{IMG}) ) {
       $self->{ERRSTR}=$self->_error_as_msg();
       return undef;
@@ -1201,7 +1327,7 @@ sub read {
                                   $params{storechannels},
                                   $params{interleave});
     if ( !defined($self->{IMG}) ) {
                                   $params{storechannels},
                                   $params{interleave});
     if ( !defined($self->{IMG}) ) {
-      $self->{ERRSTR}='unable to read raw image';
+      $self->{ERRSTR}=$self->_error_as_msg();
       return undef;
     }
     $self->{DEBUG} && print "loading a raw file\n";
       return undef;
     }
     $self->{DEBUG} && print "loading a raw file\n";
@@ -1337,12 +1463,12 @@ sub write {
 
     if (defined $input{class} && $input{class} eq 'fax') {
       if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
 
     if (defined $input{class} && $input{class} eq 'fax') {
       if (!i_writetiff_wiol_faxable($self->{IMG}, $IO, $input{fax_fine})) {
-       $self->{ERRSTR}='Could not write to buffer';
+       $self->{ERRSTR} = $self->_error_as_msg();
        return undef;
       }
     } else {
       if (!i_writetiff_wiol($self->{IMG}, $IO)) {
        return undef;
       }
     } else {
       if (!i_writetiff_wiol($self->{IMG}, $IO)) {
-       $self->{ERRSTR}='Could not write to buffer';
+       $self->{ERRSTR} = $self->_error_as_msg();
        return undef;
       }
     }
        return undef;
       }
     }
@@ -1350,7 +1476,7 @@ sub write {
     $self->_set_opts(\%input, "pnm_", $self)
       or return undef;
     if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
     $self->_set_opts(\%input, "pnm_", $self)
       or return undef;
     if ( ! i_writeppm_wiol($self->{IMG},$IO) ) {
-      $self->{ERRSTR}='unable to write pnm image';
+      $self->{ERRSTR} = $self->_error_as_msg();
       return undef;
     }
     $self->{DEBUG} && print "writing a pnm file\n";
       return undef;
     }
     $self->{DEBUG} && print "writing a pnm file\n";
@@ -1358,7 +1484,7 @@ sub write {
     $self->_set_opts(\%input, "raw_", $self)
       or return undef;
     if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
     $self->_set_opts(\%input, "raw_", $self)
       or return undef;
     if ( !i_writeraw_wiol($self->{IMG},$IO) ) {
-      $self->{ERRSTR}='unable to write raw image';
+      $self->{ERRSTR} = $self->_error_as_msg();
       return undef;
     }
     $self->{DEBUG} && print "writing a raw file\n";
       return undef;
     }
     $self->{DEBUG} && print "writing a raw file\n";
@@ -1570,9 +1696,14 @@ sub filter {
     }
   }
   if (defined($filters{$input{'type'}}{defaults})) {
     }
   }
   if (defined($filters{$input{'type'}}{defaults})) {
-    %hsh=('image',$self->{IMG},%{$filters{$input{'type'}}{defaults}},%input);
+    %hsh=( image => $self->{IMG},
+           imager => $self,
+           %{$filters{$input{'type'}}{defaults}},
+           %input );
   } else {
   } else {
-    %hsh=('image',$self->{IMG},%input);
+    %hsh=( image => $self->{IMG},
+           imager => $self,
+           %input );
   }
 
   my @cs=@{$filters{$input{'type'}}{callseq}};
   }
 
   my @cs=@{$filters{$input{'type'}}{callseq}};
@@ -1583,7 +1714,14 @@ sub filter {
     }
   }
 
     }
   }
 
-  &{$filters{$input{'type'}}{callsub}}(%hsh);
+  eval {
+    local $SIG{__DIE__}; # we don't want this processed by confess, etc
+    &{$filters{$input{'type'}}{callsub}}(%hsh);
+  };
+  if ($@) {
+    chomp($self->{ERRSTR} = $@);
+    return;
+  }
 
   my @b=keys %hsh;
 
 
   my @b=keys %hsh;
 
@@ -1593,6 +1731,25 @@ sub filter {
   return $self;
 }
 
   return $self;
 }
 
+sub register_filter {
+  my $class = shift;
+  my %hsh = ( defaults => {}, @_ );
+
+  defined $hsh{type}
+    or die "register_filter() with no type\n";
+  defined $hsh{callsub}
+    or die "register_filter() with no callsub\n";
+  defined $hsh{callseq}
+    or die "register_filter() with no callseq\n";
+
+  exists $filters{$hsh{type}}
+    and return;
+
+  $filters{$hsh{type}} = \%hsh;
+
+  return 1;
+}
+
 # Scale an image to requested size and return the scaled version
 
 sub scale {
 # Scale an image to requested size and return the scaled version
 
 sub scale {
@@ -1601,75 +1758,155 @@ sub scale {
   my $img = Imager->new();
   my $tmp = Imager->new();
 
   my $img = Imager->new();
   my $tmp = Imager->new();
 
+  my $scalefactor = $opts{scalefactor};
+
   unless (defined wantarray) {
     my @caller = caller;
     warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
     return;
   }
 
   unless (defined wantarray) {
     my @caller = caller;
     warn "scale() called in void context - scale() returns the scaled image at $caller[1] line $caller[2]\n";
     return;
   }
 
-  unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
+  unless ($self->{IMG}) { 
+    $self->_set_error('empty input image'); 
+    return undef;
+  }
 
 
+  # work out the scaling
   if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
   if ($opts{xpixels} and $opts{ypixels} and $opts{'type'}) {
-    my ($xpix,$ypix)=( $opts{xpixels}/$self->getwidth() , $opts{ypixels}/$self->getheight() );
-    if ($opts{'type'} eq 'min') { $opts{scalefactor}=min($xpix,$ypix); }
-    if ($opts{'type'} eq 'max') { $opts{scalefactor}=max($xpix,$ypix); }
-  } elsif ($opts{xpixels}) { $opts{scalefactor}=$opts{xpixels}/$self->getwidth(); }
-  elsif ($opts{ypixels}) { $opts{scalefactor}=$opts{ypixels}/$self->getheight(); }
+    my ($xpix, $ypix)=( $opts{xpixels} / $self->getwidth() , 
+                       $opts{ypixels} / $self->getheight() );
+    if ($opts{'type'} eq 'min') { 
+      $scalefactor = min($xpix,$ypix); 
+    }
+    elsif ($opts{'type'} eq 'max') {
+      $scalefactor = max($xpix,$ypix);
+    }
+    else {
+      $self->_set_error('invalid value for type parameter');
+      return undef;
+    }
+  } elsif ($opts{xpixels}) { 
+    $scalefactor = $opts{xpixels} / $self->getwidth();
+  }
+  elsif ($opts{ypixels}) { 
+    $scalefactor = $opts{ypixels}/$self->getheight();
+  }
+  elsif ($opts{constrain} && ref $opts{constrain}
+        && $opts{constrain}->can('constrain')) {
+    # we've been passed an Image::Math::Constrain object or something
+    # that looks like one
+    (undef, undef, $scalefactor)
+      = $opts{constrain}->constrain($self->getwidth, $self->getheight);
+    unless ($scalefactor) {
+      $self->_set_error('constrain method failed on constrain parameter');
+      return undef;
+    }
+  }
 
   if ($opts{qtype} eq 'normal') {
 
   if ($opts{qtype} eq 'normal') {
-    $tmp->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
-    if ( !defined($tmp->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
-    $img->{IMG}=i_scaleaxis($tmp->{IMG},$opts{scalefactor},1);
-    if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
+    $tmp->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
+    if ( !defined($tmp->{IMG}) ) { 
+      $self->{ERRSTR} = 'unable to scale image';
+      return undef;
+    }
+    $img->{IMG}=i_scaleaxis($tmp->{IMG}, $scalefactor, 1);
+    if ( !defined($img->{IMG}) ) { 
+      $self->{ERRSTR}='unable to scale image'; 
+      return undef;
+    }
+
     return $img;
   }
     return $img;
   }
-  if ($opts{'qtype'} eq 'preview') {
-    $img->{IMG}=i_scale_nn($self->{IMG},$opts{'scalefactor'},$opts{'scalefactor'}); 
-    if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
+  elsif ($opts{'qtype'} eq 'preview') {
+    $img->{IMG} = i_scale_nn($self->{IMG}, $scalefactor, $scalefactor); 
+    if ( !defined($img->{IMG}) ) { 
+      $self->{ERRSTR}='unable to scale image'; 
+      return undef;
+    }
     return $img;
   }
     return $img;
   }
-  $self->{ERRSTR}='scale: invalid value for qtype'; return undef;
+  else {
+    $self->_set_error('invalid value for qtype parameter');
+    return undef;
+  }
 }
 
 # Scales only along the X axis
 
 sub scaleX {
 }
 
 # Scales only along the X axis
 
 sub scaleX {
-  my $self=shift;
-  my %opts=(scalefactor=>0.5,@_);
+  my $self = shift;
+  my %opts = ( scalefactor=>0.5, @_ );
 
 
-  unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "scaleX() called in void context - scaleX() returns the scaled image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
+  unless ($self->{IMG}) { 
+    $self->{ERRSTR} = 'empty input image';
+    return undef;
+  }
 
   my $img = Imager->new();
 
 
   my $img = Imager->new();
 
-  if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getwidth(); }
+  my $scalefactor = $opts{scalefactor};
 
 
-  unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
-  $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},0);
+  if ($opts{pixels}) { 
+    $scalefactor = $opts{pixels} / $self->getwidth();
+  }
+
+  unless ($self->{IMG}) { 
+    $self->{ERRSTR}='empty input image'; 
+    return undef;
+  }
+
+  $img->{IMG} = i_scaleaxis($self->{IMG}, $scalefactor, 0);
+
+  if ( !defined($img->{IMG}) ) { 
+    $self->{ERRSTR} = 'unable to scale image'; 
+    return undef;
+  }
 
 
-  if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
   return $img;
 }
 
 # Scales only along the Y axis
 
 sub scaleY {
   return $img;
 }
 
 # Scales only along the Y axis
 
 sub scaleY {
-  my $self=shift;
-  my %opts=(scalefactor=>0.5,@_);
+  my $self = shift;
+  my %opts = ( scalefactor => 0.5, @_ );
+
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "scaleY() called in void context - scaleY() returns the scaled image at $caller[1] line $caller[2]\n";
+    return;
+  }
 
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 
   my $img = Imager->new();
 
 
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 
   my $img = Imager->new();
 
-  if ($opts{pixels}) { $opts{scalefactor}=$opts{pixels}/$self->getheight(); }
+  my $scalefactor = $opts{scalefactor};
 
 
-  unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
-  $img->{IMG}=i_scaleaxis($self->{IMG},$opts{scalefactor},1);
+  if ($opts{pixels}) { 
+    $scalefactor = $opts{pixels} / $self->getheight();
+  }
+
+  unless ($self->{IMG}) { 
+    $self->{ERRSTR} = 'empty input image'; 
+    return undef;
+  }
+  $img->{IMG}=i_scaleaxis($self->{IMG}, $scalefactor, 1);
+
+  if ( !defined($img->{IMG}) ) {
+    $self->{ERRSTR} = 'unable to scale image';
+    return undef;
+  }
 
 
-  if ( !defined($img->{IMG}) ) { $self->{ERRSTR}='unable to scale image'; return undef; }
   return $img;
 }
 
   return $img;
 }
 
-
 # Transform returns a spatial transformation of the input image
 # this moves pixels to a new location in the returned image.
 # NOTE - should make a utility function to check transforms for
 # Transform returns a spatial transformation of the input image
 # this moves pixels to a new location in the returned image.
 # NOTE - should make a utility function to check transforms for
@@ -1829,8 +2066,14 @@ sub rubthrough {
   my $self=shift;
   my %opts=(tx => 0,ty => 0, @_);
 
   my $self=shift;
   my %opts=(tx => 0,ty => 0, @_);
 
-  unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
-  unless ($opts{src} && $opts{src}->{IMG}) { $self->{ERRSTR}='empty input image for source'; return undef; }
+  unless ($self->{IMG}) { 
+    $self->{ERRSTR}='empty input image'; 
+    return undef;
+  }
+  unless ($opts{src} && $opts{src}->{IMG}) {
+    $self->{ERRSTR}='empty input image for src'; 
+    return undef;
+  }
 
   %opts = (src_minx => 0,
           src_miny => 0,
 
   %opts = (src_minx => 0,
           src_miny => 0,
@@ -1839,8 +2082,9 @@ sub rubthrough {
           %opts);
 
   unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
           %opts);
 
   unless (i_rubthru($self->{IMG}, $opts{src}->{IMG}, $opts{tx}, $opts{ty},
-         $opts{src_minx}, $opts{src_miny}, $opts{src_maxx}, $opts{src_maxy})) {
-    $self->{ERRSTR} = $self->_error_as_msg();
+                    $opts{src_minx}, $opts{src_miny}, 
+                    $opts{src_maxx}, $opts{src_maxy})) {
+    $self->_set_error($self->_error_as_msg());
     return undef;
   }
   return $self;
     return undef;
   }
   return $self;
@@ -1861,6 +2105,13 @@ sub flip {
 sub rotate {
   my $self = shift;
   my %opts = @_;
 sub rotate {
   my $self = shift;
   my %opts = @_;
+
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "rotate() called in void context - rotate() returns the rotated image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
   if (defined $opts{right}) {
     my $degrees = $opts{right};
     if ($degrees < 0) {
   if (defined $opts{right}) {
     my $degrees = $opts{right};
     if ($degrees < 0) {
@@ -1888,9 +2139,16 @@ sub rotate {
   elsif (defined $opts{radians} || defined $opts{degrees}) {
     my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
 
   elsif (defined $opts{radians} || defined $opts{degrees}) {
     my $amount = $opts{radians} || $opts{degrees} * 3.1415926535 / 180;
 
+    my $back = $opts{back};
     my $result = Imager->new;
     my $result = Imager->new;
-    if ($opts{back}) {
-      $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $opts{back});
+    if ($back) {
+      $back = _color($back);
+      unless ($back) {
+        $self->_set_error(Imager->errstr);
+        return undef;
+      }
+
+      $result->{IMG} = i_rotate_exact($self->{IMG}, $amount, $back);
     }
     else {
       $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
     }
     else {
       $result->{IMG} = i_rotate_exact($self->{IMG}, $amount);
@@ -1913,6 +2171,12 @@ sub matrix_transform {
   my $self = shift;
   my %opts = @_;
 
   my $self = shift;
   my %opts = @_;
 
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "copy() called in void context - copy() returns the copied image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
   if ($opts{matrix}) {
     my $xsize = $opts{xsize} || $self->getwidth;
     my $ysize = $opts{ysize} || $self->getheight;
   if ($opts{matrix}) {
     my $xsize = $opts{xsize} || $self->getwidth;
     my $ysize = $opts{ysize} || $self->getheight;
@@ -1997,8 +2261,6 @@ sub box {
   return $self;
 }
 
   return $self;
 }
 
-# Draws an arc - this routine SUCKS and is buggy - it sometimes doesn't work when the arc is a convex polygon
-
 sub arc {
   my $self=shift;
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 sub arc {
   my $self=shift;
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
@@ -2008,39 +2270,56 @@ sub arc {
            'x'=>$self->getwidth()/2,
            'y'=>$self->getheight()/2,
            'd1'=>0, 'd2'=>361, @_);
            'x'=>$self->getwidth()/2,
            'y'=>$self->getheight()/2,
            'd1'=>0, 'd2'=>361, @_);
-  if ($opts{fill}) {
-    unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
-      # assume it's a hash ref
-      require 'Imager/Fill.pm';
-      unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
-        $self->{ERRSTR} = $Imager::ERRSTR;
-        return;
+  if ($opts{aa}) {
+    if ($opts{fill}) {
+      unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
+       # assume it's a hash ref
+       require 'Imager/Fill.pm';
+       unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
+         $self->{ERRSTR} = $Imager::ERRSTR;
+         return;
+       }
+      }
+      i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
+                    $opts{'d2'}, $opts{fill}{fill});
+    }
+    else {
+      my $color = _color($opts{'color'});
+      unless ($color) { 
+       $self->{ERRSTR} = $Imager::ERRSTR; 
+       return; 
+      }
+      if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
+       i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, 
+                   $color);
+      }
+      else {
+       i_arc_aa($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
+                $opts{'d1'}, $opts{'d2'}, $color); 
       }
     }
       }
     }
-    i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
-                $opts{'d2'}, $opts{fill}{fill});
   }
   else {
   }
   else {
-    my $color = _color($opts{'color'});
-    unless ($color) { 
-      $self->{ERRSTR} = $Imager::ERRSTR; 
-      return; 
-    }
-    if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
-      i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, 
-                  $color);
+    if ($opts{fill}) {
+      unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
+       # assume it's a hash ref
+       require 'Imager/Fill.pm';
+       unless ($opts{fill} = Imager::Fill->new(%{$opts{fill}})) {
+         $self->{ERRSTR} = $Imager::ERRSTR;
+         return;
+       }
+      }
+      i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
+                 $opts{'d2'}, $opts{fill}{fill});
     }
     else {
     }
     else {
-      if ($opts{'d1'} <= $opts{'d2'}) { 
-        i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
-              $opts{'d1'}, $opts{'d2'}, $color); 
-      }
-      else {
-        i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
-              $opts{'d1'}, 361,         $color);
-        i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
-              0,           $opts{'d2'}, $color); 
+      my $color = _color($opts{'color'});
+      unless ($color) { 
+       $self->{ERRSTR} = $Imager::ERRSTR; 
+       return; 
       }
       }
+      i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
+           $opts{'d1'}, $opts{'d2'}, $color); 
     }
   }
 
     }
   }
 
@@ -2311,6 +2590,111 @@ sub getpixel {
   $self;
 }
 
   $self;
 }
 
+sub getscanline {
+  my $self = shift;
+  my %opts = ( type => '8bit', x=>0, @_);
+
+  defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
+
+  unless (defined $opts{'y'}) {
+    $self->_set_error("missing y parameter");
+    return;
+  }
+
+  if ($opts{type} eq '8bit') {
+    return i_glin($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+                 $opts{y});
+  }
+  elsif ($opts{type} eq 'float') {
+    return i_glinf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+                 $opts{y});
+  }
+  else {
+    $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
+    return;
+  }
+}
+
+sub setscanline {
+  my $self = shift;
+  my %opts = ( x=>0, @_);
+
+  unless (defined $opts{'y'}) {
+    $self->_set_error("missing y parameter");
+    return;
+  }
+
+  if (!$opts{type}) {
+    if (ref $opts{pixels} && @{$opts{pixels}}) {
+      # try to guess the type
+      if ($opts{pixels}[0]->isa('Imager::Color')) {
+       $opts{type} = '8bit';
+      }
+      elsif ($opts{pixels}[0]->isa('Imager::Color::Float')) {
+       $opts{type} = 'float';
+      }
+      else {
+       $self->_set_error("missing type parameter and could not guess from pixels");
+       return;
+      }
+    }
+    else {
+      # default
+      $opts{type} = '8bit';
+    }
+  }
+
+  if ($opts{type} eq '8bit') {
+    if (ref $opts{pixels}) {
+      return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
+    }
+    else {
+      return i_plin($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
+    }
+  }
+  elsif ($opts{type} eq 'float') {
+    if (ref $opts{pixels}) {
+      return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, @{$opts{pixels}});
+    }
+    else {
+      return i_plinf($self->{IMG}, $opts{x}, $opts{'y'}, $opts{pixels});
+    }
+  }
+  else {
+    $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
+    return;
+  }
+}
+
+sub getsamples {
+  my $self = shift;
+  my %opts = ( type => '8bit', x=>0, @_);
+
+  defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
+
+  unless (defined $opts{'y'}) {
+    $self->_set_error("missing y parameter");
+    return;
+  }
+  
+  unless ($opts{channels}) {
+    $opts{channels} = [ 0 .. $self->getchannels()-1 ];
+  }
+
+  if ($opts{type} eq '8bit') {
+    return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+                  $opts{y}, @{$opts{channels}});
+  }
+  elsif ($opts{type} eq 'float') {
+    return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+                   $opts{y}, @{$opts{channels}});
+  }
+  else {
+    $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
+    return;
+  }
+}
+
 # make an identity matrix of the given size
 sub _identity {
   my ($size) = @_;
 # make an identity matrix of the given size
 sub _identity {
   my ($size) = @_;
@@ -2327,6 +2711,12 @@ sub convert {
   my ($self, %opts) = @_;
   my $matrix;
 
   my ($self, %opts) = @_;
   my $matrix;
 
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "convert() called in void context - convert() returns the converted image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
   # the user can either specify a matrix or preset
   # the matrix overrides the preset
   if (!exists($opts{matrix})) {
   # the user can either specify a matrix or preset
   # the matrix overrides the preset
   if (!exists($opts{matrix})) {
@@ -2513,8 +2903,17 @@ sub getmask {
 sub setmask {
   my $self = shift;
   my %opts = @_;
 sub setmask {
   my $self = shift;
   my %opts = @_;
-  if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
+  if (!defined($self->{IMG})) { 
+    $self->{ERRSTR} = 'image is empty';
+    return undef;
+  }
+  unless (defined $opts{mask}) {
+    $self->_set_error("mask parameter required");
+    return;
+  }
   i_img_setmask( $self->{IMG} , $opts{mask} );
   i_img_setmask( $self->{IMG} , $opts{mask} );
+
+  1;
 }
 
 # Get number of colors in an image
 }
 
 # Get number of colors in an image
@@ -2536,7 +2935,7 @@ sub string {
   my %input=('x'=>0, 'y'=>0, @_);
   $input{string}||=$input{text};
 
   my %input=('x'=>0, 'y'=>0, @_);
   $input{string}||=$input{text};
 
-  unless(exists $input{string}) {
+  unless(defined $input{string}) {
     $self->{ERRSTR}="missing required parameter 'string'";
     return;
   }
     $self->{ERRSTR}="missing required parameter 'string'";
     return;
   }
@@ -2547,13 +2946,74 @@ sub string {
   }
 
   unless ($input{font}->draw(image=>$self, %input)) {
   }
 
   unless ($input{font}->draw(image=>$self, %input)) {
-    $self->{ERRSTR} = $self->_error_as_msg();
     return;
   }
 
   return $self;
 }
 
     return;
   }
 
   return $self;
 }
 
+sub align_string {
+  my $self = shift;
+
+  my $img;
+  if (ref $self) {
+    unless ($self->{IMG}) { 
+      $self->{ERRSTR}='empty input image'; 
+      return;
+    }
+    $img = $self;
+  }
+  else {
+    $img = undef;
+  }
+
+  my %input=('x'=>0, 'y'=>0, @_);
+  $input{string}||=$input{text};
+
+  unless(exists $input{string}) {
+    $self->_set_error("missing required parameter 'string'");
+    return;
+  }
+
+  unless($input{font}) {
+    $self->_set_error("missing required parameter 'font'");
+    return;
+  }
+
+  my @result;
+  unless (@result = $input{font}->align(image=>$img, %input)) {
+    return;
+  }
+
+  return wantarray ? @result : $result[0];
+}
+
+my @file_limit_names = qw/width height bytes/;
+
+sub set_file_limits {
+  shift;
+
+  my %opts = @_;
+  my %values;
+  
+  if ($opts{reset}) {
+    @values{@file_limit_names} = (0) x @file_limit_names;
+  }
+  else {
+    @values{@file_limit_names} = i_get_image_file_limits();
+  }
+
+  for my $key (keys %values) {
+    defined $opts{$key} and $values{$key} = $opts{$key};
+  }
+
+  i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
+}
+
+sub get_file_limits {
+  i_get_image_file_limits();
+}
+
 # Shortcuts that can be exported
 
 sub newcolor { Imager::Color->new(@_); }
 # Shortcuts that can be exported
 
 sub newcolor { Imager::Color->new(@_); }
@@ -2670,7 +3130,15 @@ sub parseiptc {
   return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
 }
 
   return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit);
 }
 
-# Autoload methods go after =cut, and are processed by the autosplit program.
+sub Inline {
+  my ($lang) = @_;
+
+  $lang eq 'C'
+    or die "Only C language supported";
+
+  require Imager::ExtUtils;
+  return Imager::ExtUtils->inline_config;
+}
 
 1;
 __END__
 
 1;
 __END__
@@ -2694,8 +3162,8 @@ Imager - Perl extension for Generating 24 bit Images
   my $format;
 
   my $img = Imager->new();
   my $format;
 
   my $img = Imager->new();
-  # see Imager::Files for information on the open() method
-  $img->open(file=>$file) or die $img->errstr();
+  # see Imager::Files for information on the read() method
+  $img->read(file=>$file) or die $img->errstr();
 
   $file =~ s/\.[^.]*$//;
 
 
   $file =~ s/\.[^.]*$//;
 
@@ -2739,6 +3207,14 @@ Overview.
 
 =item *
 
 
 =item *
 
+L<Imager::Tutorial> - a brief introduction to Imager.
+
+=item *
+
+L<Imager::Cookbook> - how to do various things with Imager.
+
+=item *
+
 L<Imager::ImageTypes> - Basics of constructing image objects with
 C<new()>: Direct type/virtual images, RGB(A)/paletted images,
 8/16/double bits/channel, color maps, channel masks, image tags, color
 L<Imager::ImageTypes> - Basics of constructing image objects with
 C<new()>: Direct type/virtual images, RGB(A)/paletted images,
 8/16/double bits/channel, color maps, channel masks, image tags, color
@@ -2795,6 +3271,22 @@ L<Imager::Matrix2d> - Helper class for affine transformations.
 
 L<Imager::Fountain> - Helper for making gradient profiles.
 
 
 L<Imager::Fountain> - Helper for making gradient profiles.
 
+=item *
+
+L<Imager::API> - using Imager's C API
+
+=item *
+
+L<Imager::APIRef> - API function reference
+
+=item *
+
+L<Imager::Inline> - using Imager's C API from Inline::C
+
+=item *
+
+L<Imager::ExtUtils> - tools to get access to Imager's C API.
+
 =back
 
 =head2 Basic Overview
 =back
 
 =head2 Basic Overview
@@ -2803,7 +3295,7 @@ An Image object is created with C<$img = Imager-E<gt>new()>.
 Examples:
 
   $img=Imager->new();                         # create empty image
 Examples:
 
   $img=Imager->new();                         # create empty image
-  $img->open(file=>'lena.png',type=>'png') or # read image from file
+  $img->read(file=>'lena.png',type=>'png') or # read image from file
      die $img->errstr();                      # give an explanation
                                               # if something failed
 
      die $img->errstr();                      # give an explanation
                                               # if something failed
 
@@ -2820,7 +3312,8 @@ C<$img-E<gt>errstr()>.
 
 In cases where no image object is associated with an operation
 C<$Imager::ERRSTR> is used to report errors not directly associated
 
 In cases where no image object is associated with an operation
 C<$Imager::ERRSTR> is used to report errors not directly associated
-with an image object.
+with an image object.  You can also call C<Imager->errstr> to get this
+value.
 
 The C<Imager-E<gt>new> method is described in detail in
 L<Imager::ImageTypes>.
 
 The C<Imager-E<gt>new> method is described in detail in
 L<Imager::ImageTypes>.
@@ -2829,19 +3322,23 @@ L<Imager::ImageTypes>.
 
 Where to find information on methods for Imager class objects.
 
 
 Where to find information on methods for Imager class objects.
 
-addcolors() -  L<Imager::ImageTypes>
+addcolors() -  L<Imager::ImageTypes/addcolors>
 
 
-addtag() -  L<Imager::ImageTypes> - add image tags
+addtag() -  L<Imager::ImageTypes/addtag> - add image tags
 
 arc() - L<Imager::Draw/arc>
 
 
 arc() - L<Imager::Draw/arc>
 
-bits() - L<Imager::ImageTypes> - number of bits per sample for the
+align_string() - L<Imager::Draw/align_string>
+
+bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
 image
 
 box() - L<Imager::Draw/box>
 
 circle() - L<Imager::Draw/circle>
 
 image
 
 box() - L<Imager::Draw/box>
 
 circle() - L<Imager::Draw/circle>
 
+colorcount() - L<Imager::Draw/colorcount>
+
 convert() - L<Imager::Transformations/"Color transformations"> -
 transform the color space
 
 convert() - L<Imager::Transformations/"Color transformations"> -
 transform the color space
 
@@ -2849,44 +3346,56 @@ copy() - L<Imager::Transformations/copy>
 
 crop() - L<Imager::Transformations/crop> - extract part of an image
 
 
 crop() - L<Imager::Transformations/crop> - extract part of an image
 
-deltag() -  L<Imager::ImageTypes> - delete image tags
+deltag() -  L<Imager::ImageTypes/deltag> - delete image tags
 
 difference() - L<Imager::Filters/"Image Difference">
 
 
 difference() - L<Imager::Filters/"Image Difference">
 
+errstr() - L<"Basic Overview">
+
 filter() - L<Imager::Filters>
 
 filter() - L<Imager::Filters>
 
-findcolor() - L<Imager::ImageTypes> - search the image palette, if it
+findcolor() - L<Imager::ImageTypes/findcolor> - search the image palette, if it
 has one
 
 flip() - L<Imager::Transformations/flip>
 
 flood_fill() - L<Imager::Draw/flood_fill>
 
 has one
 
 flip() - L<Imager::Transformations/flip>
 
 flood_fill() - L<Imager::Draw/flood_fill>
 
-getchannels() -  L<Imager::ImageTypes>
+getchannels() -  L<Imager::ImageTypes/getchannels>
 
 
-getcolorcount() -  L<Imager::ImageTypes>
+getcolorcount() -  L<Imager::ImageTypes/getcolorcount>
 
 
-getcolors() - L<Imager::ImageTypes> - get colors from the image
+getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
 palette, if it has one
 
 palette, if it has one
 
-getheight() - L<Imager::ImageTypes>
+get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
+
+getheight() - L<Imager::ImageTypes/getwidth>
+
+getpixel() - L<Imager::Draw/getpixel>
+
+getsamples() - L<Imager::Draw/getsamples>
 
 
-getpixel() - L<Imager::Draw/setpixel and getpixel>
+getscanline() - L<Imager::Draw/getscanline>
 
 
-getwidth() - L<Imager::ImageTypes>
+getwidth() - L<Imager::ImageTypes/getwidth>
 
 
-img_set() - L<Imager::ImageTypes>
+img_set() - L<Imager::ImageTypes/img_set>
 
 line() - L<Imager::Draw/line>
 
 map() - L<Imager::Transformations/"Color Mappings"> - remap color
 channel values
 
 
 line() - L<Imager::Draw/line>
 
 map() - L<Imager::Transformations/"Color Mappings"> - remap color
 channel values
 
-masked() -  L<Imager::ImageTypes> - make a masked image
+masked() -  L<Imager::ImageTypes/masked> - make a masked image
 
 
-matrix_transform() - L<Imager::Engines/"Matrix Transformations">
+matrix_transform() - L<Imager::Engines/matrix_transform>
 
 
-new() - L<Imager::ImageTypes>
+maxcolors() - L<Imager::ImageTypes/maxcolors>
+
+new() - L<Imager::ImageTypes/new>
+
+open() - L<Imager::Files> - an alias for read()
 
 paste() - L<Imager::Transformations/paste> - draw an image onto an image
 
 
 paste() - L<Imager::Transformations/paste> - draw an image onto an image
 
@@ -2894,9 +3403,10 @@ polygon() - L<Imager::Draw/polygon>
 
 polyline() - L<Imager::Draw/polyline>
 
 
 polyline() - L<Imager::Draw/polyline>
 
-read() - L<Imager::Files>
+read() - L<Imager::Files> - read a single image from an image file
 
 
-read_multi() - L<Imager::Files>
+read_multi() - L<Imager::Files> - read multiple images from an image
+file
 
 rotate() - L<Imager::Transformations/rotate>
 
 
 rotate() - L<Imager::Transformations/rotate>
 
@@ -2905,30 +3415,187 @@ image and use the alpha channel
 
 scale() - L<Imager::Transformations/scale>
 
 
 scale() - L<Imager::Transformations/scale>
 
-setcolors() - L<Imager::ImageTypes> - set palette colors in a paletted image
+scaleX() - L<Imager::Transformations/scaleX>
+
+scaleY() - L<Imager::Transformations/scaleY>
+
+setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
+a paletted image
+
+setpixel() - L<Imager::Draw/setpixel>
+
+setscanline() - L<Imager::Draw/setscanline>
 
 
-setpixel() - L<Imager::Draw/setpixel and getpixel>
+settag() - L<Imager::ImageTypes/settag>
 
 
-string() - L<Imager::Font/string> - draw text on an image
+set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
 
 
-tags() -  L<Imager::ImageTypes> - fetch image tags
+string() - L<Imager::Draw/string> - draw text on an image
 
 
-to_paletted() -  L<Imager::ImageTypes>
+tags() -  L<Imager::ImageTypes/tags> - fetch image tags
 
 
-to_rgb8() - L<Imager::ImageTypes>
+to_paletted() -  L<Imager::ImageTypes/to_paletted>
+
+to_rgb8() - L<Imager::ImageTypes/to_rgb8>
 
 transform() - L<Imager::Engines/"transform">
 
 transform2() - L<Imager::Engines/"transform2">
 
 
 transform() - L<Imager::Engines/"transform">
 
 transform2() - L<Imager::Engines/"transform2">
 
-type() -  L<Imager::ImageTypes> - type of image (direct vs paletted)
+type() -  L<Imager::ImageTypes/type> - type of image (direct vs paletted)
 
 
-virtual() - L<Imager::ImageTypes> - whether the image has it's own
+virtual() - L<Imager::ImageTypes/virtual> - whether the image has it's own
 data
 
 data
 
-write() - L<Imager::Files>
+write() - L<Imager::Files> - write an image to a file
+
+write_multi() - L<Imager::Files> - write multiple image to an image
+file.
+
+=head1 CONCEPT INDEX
+
+animated GIF - L<Imager::File/"Writing an animated GIF">
+
+aspect ratio - L<Imager::ImageTypes/i_xres>,
+L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
+
+blend - alpha blending one image onto another
+L<Imager::Transformations/rubthrough>
+
+blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
+
+boxes, drawing - L<Imager::Draw/box>
+
+changes between image - L<Imager::Filter/"Image Difference">
+
+color - L<Imager::Color>
+
+color names - L<Imager::Color>, L<Imager::Color::Table>
+
+combine modes - L<Imager::Fill/combine>
+
+compare images - L<Imager::Filter/"Image Difference">
+
+contrast - L<Imager::Filter/contrast>, L<Imager::Filter/autolevels>
+
+convolution - L<Imager::Filter/conv>
+
+cropping - L<Imager::Transformations/crop>
+
+C<diff> images - L<Imager::Filter/"Image Difference">
+
+dpi - L<Imager::ImageTypes/i_xres>
+
+drawing boxes - L<Imager::Draw/box>
+
+drawing lines - L<Imager::Draw/line>
+
+drawing text - L<Imager::Font/string>, L<Imager::Font/align>
+
+error message - L<"Basic Overview">
+
+files, font - L<Imager::Font>
+
+files, image - L<Imager::Files>
+
+filling, types of fill - L<Imager::Fill>
 
 
-write_multi() - L<Imager::Files>
+filling, boxes - L<Imager::Draw/box>
+
+filling, flood fill - L<Imager::Draw/flood_fill>
+
+flood fill - L<Imager::Draw/flood_fill>
+
+fonts - L<Imager::Font>
+
+fonts, drawing with - L<Imager::Font/string>, L<Imager::Font/align>,
+L<Imager::Font::Wrap>
+
+fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
+
+fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
+
+fountain fill - L<Imager::Fill/"Fountain fills">,
+L<Imager::Filters/fountain>, L<Imager::Fountain>,
+L<Imager::Filters/gradgen>
+
+GIF files - L<Imager::Files/"GIF">
+
+GIF files, animated - L<Imager::File/"Writing an animated GIF">
+
+gradient fill - L<Imager::Fill/"Fountain fills">,
+L<Imager::Filters/fountain>, L<Imager::Fountain>,
+L<Imager::Filters/gradgen>
+
+guassian blur - L<Imager::Filter/guassian>
+
+hatch fills - L<Imager::Fill/"Hatched fills">
+
+invert image - L<Imager::Filter/hardinvert>
+
+JPEG - L<Imager::Files/"JPEG">
+
+limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
+
+lines, drawing - L<Imager::Draw/line>
+
+matrix - L<Imager::Matrix2d>, 
+L<Imager::Transformations/"Matrix Transformations">,
+L<Imager::Font/transform>
+
+metadata, image - L<Imager::ImageTypes/"Tags">
+
+mosaic - L<Imager::Filter/mosaic>
+
+noise, filter - L<Imager::Filter/noise>
+
+noise, rendered - L<Imager::Filter/turbnoise>,
+L<Imager::Filter/radnoise>
+
+paste - L<Imager::Transformations/paste>,
+L<Imager::Transformations/rubthrough>
+
+pseudo-color image - L<Imager::ImageTypes/to_paletted>,
+L<Imager::ImageTypes/new>
+
+posterize - L<Imager::Filter/postlevels>
+
+png files - L<Imager::Files>, L<Imager::Files/"PNG">
+
+pnm - L<Imager::Files/"PNM (Portable aNy Map)">
+
+rectangles, drawing - L<Imager::Draw/box>
+
+resizing an image - L<Imager::Transformations/scale>, 
+L<Imager::Transformations/crop>
+
+saving an image - L<Imager::Files>
+
+scaling - L<Imager::Transformations/scale>
+
+sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
+
+size, image - L<Imager::ImageTypes/getwidth>,
+L<Imager::ImageTypes/getheight>
+
+size, text - L<Imager::Font/bounding_box>
+
+tags, image metadata - L<Imager::ImageTypes/"Tags">
+
+text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
+L<Imager::Font::Wrap>
+
+text, wrapping text in an area - L<Imager::Font::Wrap>
+
+text, measuring - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
+
+tiles, color - L<Imager::Filter/mosaic>
+
+unsharp mask - L<Imager::Filter/unsharpmask>
+
+watermark - L<Imager::Filter/watermark>
+
+writing an image to a file - L<Imager::Files>
 
 =head1 SUPPORT
 
 
 =head1 SUPPORT
 
@@ -2941,8 +3608,11 @@ To subscribe send a message with C<subscribe> in the body to:
 
 or use the form at:
 
 
 or use the form at:
 
-   http://www.molar.is/en/lists/imager-devel/
-   (annonymous is temporarily off due to spam)
+=over
+
+L<http://www.molar.is/en/lists/imager-devel/>
+
+=back
 
 where you can also find the mailing list archive.
 
 
 where you can also find the mailing list archive.
 
@@ -2950,13 +3620,13 @@ If you're into IRC, you can typically find the developers in #Imager
 on irc.perl.org.  As with any IRC channel, the participants could be
 occupied or asleep, so please be patient.
 
 on irc.perl.org.  As with any IRC channel, the participants could be
 occupied or asleep, so please be patient.
 
-You can report bugs either by sending email to:
+You can report bugs by pointing your browser at:
 
 
-  bug-Imager@rt.cpan.org
+=over
 
 
-or by pointing your browser at:
+L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager>
 
 
-  https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Imager
+=back
 
 Please remember to include the versions of Imager, perl, supporting
 libraries, and any relevant code.  If you have specific images that
 
 Please remember to include the versions of Imager, perl, supporting
 libraries, and any relevant code.  If you have specific images that
@@ -2968,17 +3638,23 @@ Bugs are listed individually for relevant pod pages.
 
 =head1 AUTHOR
 
 
 =head1 AUTHOR
 
-Arnar M. Hrafnkelsson (addi@imager.perl.org) and Tony Cook
-(tony@imager.perl.org) See the README for a complete list.
+Arnar M. Hrafnkelsson and Tony Cook (tony@imager.perl.org) among
+others. See the README for a complete list.
 
 =head1 SEE ALSO
 
 
 =head1 SEE ALSO
 
-perl(1), Imager::ImageTypes(3), Imager::Files(3), Imager::Draw(3),
-Imager::Color(3), Imager::Fill(3), Imager::Font(3),
-Imager::Transformations(3), Imager::Engines(3), Imager::Filters(3),
-Imager::Expr(3), Imager::Matrix2d(3), Imager::Fountain(3)
+L<perl>(1), L<Imager::ImageTypes>(3), L<Imager::Files>(3),
+L<Imager::Draw>(3), L<Imager::Color>(3), L<Imager::Fill>(3),
+L<Imager::Font>(3), L<Imager::Transformations>(3),
+L<Imager::Engines>(3), L<Imager::Filters>(3), L<Imager::Expr>(3),
+L<Imager::Matrix2d>(3), L<Imager::Fountain>(3)
+
+L<http://imager.perl.org/>
+
+L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
+
+Other perl imaging modules include:
 
 
-Affix::Infix2Postfix(3), Parse::RecDescent(3)
-http://imager.perl.org/
+L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).
 
 =cut
 
 =cut