]> git.imager.perl.org - imager.git/blobdiff - Imager.pm
added POD to trans2.c
[imager.git] / Imager.pm
index a091901bde97bc991828ff7bda0f2b604518dcf3..abcc89d9953ede803b380705797dd9e7a6b1ad85 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -168,6 +168,16 @@ BEGIN {
 
   $DEBUG=0;
 
+  # the members of the subhashes under %filters are:
+  #  callseq - a list of the parameters to the underlying filter in the
+  #            order they are passed
+  #  callsub - a code ref that takes a named parameter list and calls the
+  #            underlying filter
+  #  defaults - a hash of default values
+  #  names - defines names for value of given parameters so if the names 
+  #          field is foo=> { bar=>1 }, and the user supplies "bar" as the
+  #          foo parameter, the filter will receive 1 for the foo
+  #          parameter
   $filters{contrast}={
                      callseq => ['image','intensity'],
                      callsub => sub { my %hsh=@_; i_contrast($hsh{image},$hsh{intensity}); } 
@@ -235,12 +245,37 @@ BEGIN {
     {
      callseq => [ qw(image bump elevation lightx lighty st) ],
      defaults => { elevation=>0, st=> 2 },
-     callsub => sub { 
+     callsub => sub {
        my %hsh = @_;
        i_bumpmap($hsh{image}, $hsh{bump}{IMG}, $hsh{elevation},
                  $hsh{lightx}, $hsh{lighty}, $hsh{st});
      },
     };
+  $filters{bumpmap_complex} =
+    {
+     callseq => [ qw(image bump channel tx ty Lx Ly Lz cd cs n Ia Il Is) ],
+     defaults => {
+                 channel => 0,
+                 tx => 0,
+                 ty => 0,
+                 Lx => 0.2,
+                 Ly => 0.4,
+                 Lz => -1.0,
+                 cd => 1.0,
+                 cs => 40,
+                 n => 1.3,
+                 Ia => Imager::Color->new(rgb=>[0,0,0]),
+                 Il => Imager::Color->new(rgb=>[255,255,255]),
+                 Is => Imager::Color->new(rgb=>[255,255,255]),
+                },
+     callsub => sub {
+       my %hsh = @_;
+       i_bumpmap_complex($hsh{image}, $hsh{bump}{IMG}, $hsh{channel},
+                 $hsh{tx}, $hsh{ty}, $hsh{Lx}, $hsh{Ly}, $hsh{Lz},
+                $hsh{cd}, $hsh{cs}, $hsh{n}, $hsh{Ia}, $hsh{Il},
+                $hsh{Is});
+     },
+    };
   $filters{postlevels} =
     {
      callseq  => [ qw(image levels) ],
@@ -258,6 +293,72 @@ BEGIN {
                    $hsh{pixdiff}); 
      },
     };
+  $filters{fountain} =
+    {
+     callseq  => [ qw(image xa ya xb yb ftype repeat combine super_sample ssample_param segments) ],
+     names    => {
+                  ftype => { linear         => 0,
+                             bilinear       => 1,
+                             radial         => 2,
+                             radial_square  => 3,
+                             revolution     => 4,
+                             conical        => 5 },
+                  repeat => { none      => 0,
+                              sawtooth  => 1,
+                              triangle  => 2,
+                              saw_both  => 3,
+                              tri_both  => 4,
+                            },
+                  super_sample => {
+                                   none    => 0,
+                                   grid    => 1,
+                                   random  => 2,
+                                   circle  => 3,
+                                  },
+                  combine => {
+                              none      => 0,
+                              normal    => 1,
+                              multiply  => 2, mult => 2,
+                              dissolve  => 3,
+                              add       => 4,
+                              subtract  => 5, sub => 5,
+                              diff      => 6,
+                              lighten   => 7,
+                              darken    => 8,
+                              hue       => 9,
+                              sat       => 10,
+                              value     => 11,
+                              color     => 12,
+                             },
+                 },
+     defaults => { ftype => 0, repeat => 0, combine => 0,
+                   super_sample => 0, ssample_param => 4,
+                   segments=>[ 
+                              [ 0, 0.5, 1,
+                                Imager::Color->new(0,0,0),
+                                Imager::Color->new(255, 255, 255),
+                                0, 0,
+                              ],
+                             ],
+                 },
+     callsub  => 
+     sub {
+       my %hsh = @_;
+       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});
+     },
+    };
+  $filters{unsharpmask} =
+    {
+     callseq => [ qw(image stddev scale) ],
+     defaults => { stddev=>2.0, scale=>1.0 },
+     callsub => 
+     sub { 
+       my %hsh = @_;
+       i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
+     },
+    };
 
   $FORMATGUESS=\&def_guess_type;
 }
@@ -461,6 +562,9 @@ sub img_set {
     $self->{IMG} = i_img_pal_new($hsh{xsize}, $hsh{ysize}, $hsh{channels},
                                  $hsh{maxcolors} || 256);
   }
+  elsif ($hsh{bits} eq 'double') {
+    $self->{IMG} = i_img_double_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
+  }
   elsif ($hsh{bits} == 16) {
     $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
   }
@@ -582,7 +686,11 @@ sub findcolor {
 
 sub bits {
   my $self = shift;
-  $self->{IMG} and i_img_bits($self->{IMG});
+  my $bits = $self->{IMG} && i_img_bits($self->{IMG});
+  if ($bits && $bits == length(pack("d", 1)) * 8) {
+    $bits = 'double';
+  }
+  $bits;
 }
 
 sub type {
@@ -743,7 +851,7 @@ sub read {
     $self->{ERRSTR}='format not supported'; return undef;
   }
 
-  my %iolready=(jpeg=>1, png=>1, tiff=>1, pnm=>1, raw=>1, bmp=>1);
+  my %iolready=(jpeg=>1, png=>1, tiff=>1, pnm=>1, raw=>1, bmp=>1, tga=>1);
 
   if ($iolready{$input{type}}) {
     # Setup data source
@@ -794,6 +902,16 @@ sub read {
       $self->{DEBUG} && print "loading a bmp file\n";
     }
 
+    if ( $input{type} eq 'tga' ) {
+      $self->{IMG}=i_readtga_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
+      if ( !defined($self->{IMG}) ) {
+       $self->{ERRSTR}=$self->_error_as_msg();
+#      $self->{ERRSTR}='unable to read tga image';
+       return undef;
+      }
+      $self->{DEBUG} && print "loading a tga file\n";
+    }
+
     if ( $input{type} eq 'raw' ) {
       my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
 
@@ -887,7 +1005,7 @@ sub write {
             fax_fine=>1, @_);
   my ($fh, $rc, $fd, $IO);
 
-  my %iolready=( tiff=>1, raw=>1, png=>1, pnm=>1, bmp=>1, jpeg=>1 ); # this will be SO MUCH BETTER once they are all in there
+  my %iolready=( tiff=>1, raw=>1, png=>1, pnm=>1, bmp=>1, jpeg=>1, tga=>1 ); # this will be SO MUCH BETTER once they are all in there
 
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 
@@ -945,7 +1063,7 @@ sub write {
       $self->{DEBUG} && print "writing a png file\n";
     } elsif ( $input{type} eq 'jpeg' ) {
       if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
-       $self->{ERRSTR}='unable to write jpeg image'; 
+        $self->{ERRSTR} = $self->_error_as_msg();
        return undef;
       }
       $self->{DEBUG} && print "writing a jpeg file\n";
@@ -955,6 +1073,13 @@ sub write {
        return undef;
       }
       $self->{DEBUG} && print "writing a bmp file\n";
+    } elsif ( $input{type} eq 'tga' ) {
+      if ( !i_writetga_wiol($self->{IMG}, $IO) ) {
+       $self->{ERRSTR}=$self->_error_as_msg();
+#      $self->{ERRSTR}='unable to write tga image';
+       return undef;
+      }
+      $self->{DEBUG} && print "writing a tga file\n";
     }
 
     if (exists $input{'data'}) {
@@ -1171,6 +1296,14 @@ sub filter {
     $self->{ERRSTR}='type parameter not matching any filter'; return undef;
   }
 
+  if ($filters{$input{type}}{names}) {
+    my $names = $filters{$input{type}}{names};
+    for my $name (keys %$names) {
+      if (defined $input{$name} && exists $names->{$name}{$input{$name}}) {
+        $input{$name} = $names->{$name}{$input{$name}};
+      }
+    }
+  }
   if (defined($filters{$input{type}}{defaults})) {
     %hsh=('image',$self->{IMG},%{$filters{$input{type}}{defaults}},%input);
   } else {
@@ -1363,65 +1496,57 @@ sub transform {
 }
 
 
-{
-  my $got_expr;
-  sub transform2 {
-    my ($opts, @imgs) = @_;
-
-    if (!$got_expr) {
-      # this is fairly big, delay loading it
-      eval "use Imager::Expr";
-      die $@ if $@;
-      ++$got_expr;
-    }
-
-    $opts->{variables} = [ qw(x y) ];
-    my ($width, $height) = @{$opts}{qw(width height)};
-    if (@imgs) {
-       $width ||= $imgs[0]->getwidth();
-       $height ||= $imgs[0]->getheight();
-       my $img_num = 1;
-       for my $img (@imgs) {
-           $opts->{constants}{"w$img_num"} = $img->getwidth();
-           $opts->{constants}{"h$img_num"} = $img->getheight();
-           $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
-           $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
-           ++$img_num;
-       }
-    }
-    if ($width) {
-      $opts->{constants}{w} = $width;
-      $opts->{constants}{cx} = $width/2;
-    }
-    else {
-      $Imager::ERRSTR = "No width supplied";
-      return;
-    }
-    if ($height) {
-      $opts->{constants}{h} = $height;
-      $opts->{constants}{cy} = $height/2;
-    }
-    else {
-      $Imager::ERRSTR = "No height supplied";
-      return;
-    }
-    my $code = Imager::Expr->new($opts);
-    if (!$code) {
-      $Imager::ERRSTR = Imager::Expr::error();
-      return;
-    }
-
-    my $img = Imager->new();
-    $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, $code->code(),
-                              $code->nregs(), $code->cregs(),
-                              [ map { $_->{IMG} } @imgs ]);
-    if (!defined $img->{IMG}) {
-      $Imager::ERRSTR = "transform2 failed";
-      return;
+sub transform2 {
+  my ($opts, @imgs) = @_;
+  
+  require "Imager/Expr.pm";
+
+  $opts->{variables} = [ qw(x y) ];
+  my ($width, $height) = @{$opts}{qw(width height)};
+  if (@imgs) {
+    $width ||= $imgs[0]->getwidth();
+    $height ||= $imgs[0]->getheight();
+    my $img_num = 1;
+    for my $img (@imgs) {
+      $opts->{constants}{"w$img_num"} = $img->getwidth();
+      $opts->{constants}{"h$img_num"} = $img->getheight();
+      $opts->{constants}{"cx$img_num"} = $img->getwidth()/2;
+      $opts->{constants}{"cy$img_num"} = $img->getheight()/2;
+      ++$img_num;
     }
-
-    return $img;
   }
+  if ($width) {
+    $opts->{constants}{w} = $width;
+    $opts->{constants}{cx} = $width/2;
+  }
+  else {
+    $Imager::ERRSTR = "No width supplied";
+    return;
+  }
+  if ($height) {
+    $opts->{constants}{h} = $height;
+    $opts->{constants}{cy} = $height/2;
+  }
+  else {
+    $Imager::ERRSTR = "No height supplied";
+    return;
+  }
+  my $code = Imager::Expr->new($opts);
+  if (!$code) {
+    $Imager::ERRSTR = Imager::Expr::error();
+    return;
+  }
+  
+  my $img = Imager->new();
+  $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, $code->code(),
+                             $code->nregs(), $code->cregs(),
+                             [ map { $_->{IMG} } @imgs ]);
+  if (!defined $img->{IMG}) {
+    $Imager::ERRSTR = Imager->_error_as_msg();
+    return;
+  }
+  
+  return $img;
 }
 
 sub rubthrough {
@@ -1543,8 +1668,25 @@ sub box {
     $opts{'ymax'} = max($opts{'box'}->[1],$opts{'box'}->[3]);
   }
 
-  if ($opts{filled}) { i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},$opts{color}); }
-  else { i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},$opts{color}); }
+  if ($opts{filled}) { 
+    i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
+                 $opts{ymax},$opts{color}); 
+  }
+  elsif ($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 undef;
+      }
+    }
+    i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
+                $opts{ymax},$opts{fill}{fill});
+  }
+  else { 
+    i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},$opts{color});
+  }
   return $self;
 }
 
@@ -1559,7 +1701,28 @@ sub arc {
            'x'=>$self->getwidth()/2,
            'y'=>$self->getheight()/2,
            'd1'=>0, 'd2'=>361, @_);
-  i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},$opts{'d2'},$opts{'color'}); 
+  if ($opts{fill}) {
+    unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
+      # assume it's a hash ref
+      require 'Imager/Fill.pm';
+      $opts{fill} = Imager::Fill->new(%{$opts{fill}});
+    }
+    i_arc_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
+                $opts{'d2'}, $opts{fill}{fill});
+  }
+  else {
+    if ($opts{d1} == 0 && $opts{d2} == 361 && $opts{aa}) {
+      i_circle_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, 
+                  $opts{'color'});
+    }
+    else {
+      #      i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'}, $opts{'d2'},$opts{'color'});
+      if ($opts{'d1'} <= $opts{'d2'}) { i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},$opts{'d2'},$opts{'color'}); }
+      else                            { i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},        361,$opts{'color'});
+                                       i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},          0,$opts{'d2'},$opts{'color'}); }
+    }
+  }
+
   return $self;
 }
 
@@ -1641,6 +1804,30 @@ sub polybezier {
   return $self;
 }
 
+sub flood_fill {
+  my $self = shift;
+  my %opts = ( color=>Imager::Color->new(255, 255, 255), @_ );
+
+  unless (exists $opts{x} && exists $opts{'y'}) {
+    $self->{ERRSTR} = "missing seed x and y parameters";
+    return undef;
+  }
+  
+  if ($opts{fill}) {
+    unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
+      # assume it's a hash ref
+      require 'Imager/Fill.pm';
+      $opts{fill} = Imager::Fill->new(%{$opts{fill}});
+    }
+    i_flood_cfill($self->{IMG}, $opts{x}, $opts{'y'}, $opts{fill}{fill});
+  }
+  else {
+    i_flood_fill($self->{IMG}, $opts{x}, $opts{'y'}, $opts{color});
+  }
+
+  $self;
+}
+
 # make an identity matrix of the given size
 sub _identity {
   my ($size) = @_;
@@ -1892,6 +2079,7 @@ sub def_guess_type {
   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 'gif'  if ($ext eq "gif");
   return ();
 }
@@ -2050,15 +2238,22 @@ Warning: if you draw on a paletted image with colors that aren't in
 the palette, the image will be internally converted to a normal image.
 
 For improved color precision you can use the bits parameter to specify
-16 bites per channel:
+16 bit per channel:
 
   $img = Imager->new(xsize=>200, ysize=>200, channels=>3, bits=>16);
 
-Note that as of this writing all functions should work on 16-bit
-images, but at only 8-bit/channel precision.
+or for even more precision:
+
+  $img = Imager->new(xsize=>200, ysize=>200, channels=>3, bits=>'double');
+
+to get an image that uses a double for each channel.
 
-Currently only 8 and 16/bit per channel image types are available,
-this may change later.
+Note that as of this writing all functions should work on images with
+more than 8-bits/channel, but many will only work at only
+8-bit/channel precision.
+
+Currently only 8-bit, 16-bit, and double per channel image types are
+available, this may change later.
 
 Color objects are created by calling the Imager::Color->new()
 method:
@@ -2123,7 +2318,12 @@ the file descriptor for the file:
 For writing using the 'fd' option you will probably want to set $| for
 that descriptor, since the writes to the file descriptor bypass Perl's
 (or the C libraries) buffering.  Setting $| should avoid out of order
-output.
+output.  For example a common idiom when writing a CGI script is:
+
+  # the $| _must_ come before you send the content-type
+  $| = 1;
+  print "Content-Type: image/jpeg\n\n";
+  $img->write(fd=>fileno(STDOUT), type=>'jpeg') or die $img->errstr;
 
 *Note that load() is now an alias for read but will be removed later*
 
@@ -2340,6 +2540,11 @@ which makes the animation of the images repeat.
 
 This is currently unimplemented due to some limitations in giflib.
 
+=item gif_eliminate_unused
+
+If this is true, when you write a paletted image any unused colors
+will be eliminated from its palette.  This is set by default.
+
 =back
 
 =head2 Quantization options
@@ -2600,7 +2805,8 @@ the function return undef.  Examples:
   }
 
 The bits() method retrieves the number of bits used to represent each
-channel in a pixel, typically 8.  The type() method returns either
+channel in a pixel, 8 for a normal image, 16 for 16-bit image and
+'double' for a double/channel image.  The type() method returns either
 'direct' for truecolor images or 'paletted' for paletted images.  The
 virtual() method returns non-zero if the image contains no actual
 pixels, for example masked images.
@@ -2672,6 +2878,18 @@ Arc:
 This creates a filled red arc with a 'center' at (200, 100) and spans
 10 degrees and the slice has a radius of 20. SEE section on BUGS.
 
+Both the arc() and box() methods can take a C<fill> parameter which
+can either be an Imager::Fill object, or a reference to a hash
+containing the parameters used to create the fill:
+
+  $img->box(xmin=>10, ymin=>30, xmax=>150, ymax=>60,
+            fill => { hatch=>'cross2' });
+  use Imager::Fill;
+  my $fill = Imager::Fill->new(hatch=>'stipple');
+  $img->box(fill=>$fill);
+
+See L<Imager::Fill> for the type of fills you can use.
+
 Circle:
   $img->circle(color=>$green, r=50, x=>200, y=>100);
 
@@ -2693,6 +2911,20 @@ The point set can either be specified as an arrayref to an array of
 array references (where each such array represents a point).  The
 other way is to specify two array references.
 
+You can fill a region that all has the same color using the
+flood_fill() method, for example:
+
+  $img->flood_fill(x=>50, y=>50, color=>$color);
+
+will fill all regions the same color connected to the point (50, 50).
+
+You can also use a general fill, so you could fill the same region
+with a check pattern using:
+
+  $img->flood_fill(x=>50, y=>50, fill=>{ hatch=>'check2x2' });
+
+See L<Imager::Fill> for more information on general fills.
+
 =head2 Text rendering
 
 Text rendering is described in the Imager::Font manpage.
@@ -2770,7 +3002,8 @@ parameter which can take the values C<h>, C<v>, C<vh> and C<hv>.
 
 =head2 Rotating images
 
-Use the rotate() method to rotate an image.
+Use the rotate() method to rotate an image.  This method will return a
+new, rotated image.
 
 To rotate by an exact amount in degrees or radians, use the 'degrees'
 or 'radians' parameter:
@@ -2778,6 +3011,9 @@ or 'radians' parameter:
   my $rot20 = $img->rotate(degrees=>20);
   my $rotpi4 = $img->rotate(radians=>3.14159265/4);
 
+Exact image rotation uses the same underlying transformation engine as
+the matrix_transform() method.
+
 To rotate in steps of 90 degrees, use the 'right' parameter:
 
   my $rotated = $img->rotate(right=>270);
@@ -2796,11 +3032,11 @@ That will take paste C<$srcimage> into C<$img> with the upper
 left corner at (30,50).  If no values are given for C<left>
 or C<top> they will default to 0.
 
-A more complicated way of blending images is where one image is 
+A more complicated way of blending images is where one image is
 put 'over' the other with a certain amount of opaqueness.  The
 method that does this is rubthrough.
 
-  $img->rubthrough(src=>$srcimage,tx=>30,ty=>50); 
+  $img->rubthrough(src=>$srcimage,tx=>30,ty=>50);
 
 That will take the image C<$srcimage> and overlay it with the upper
 left corner at (30,50).  You can rub 2 or 4 channel images onto a 3
@@ -2822,15 +3058,22 @@ source.
   Filter          Arguments
   autolevels      lsat(0.1) usat(0.1) skew(0)
   bumpmap         bump elevation(0) lightx lighty st(2)
+  bumpmap_complex bump channel(0) tx(0) ty(0) Lx(0.2) Ly(0.4)
+                  Lz(-1) cd(1.0) cs(40.0) n(1.3) Ia(0 0 0) Il(255 255 255)
+                  Is(255 255 255)
   contrast        intensity
   conv            coef
+  fountain        xa ya xb yb ftype(linear) repeat(none) combine(none)
+                  super_sample(none) ssample_param(4) segments(see below)
   gaussian        stddev
   gradgen         xo yo colors dist
   hardinvert
+  mosaic          size(20)
   noise           amount(3) subtype(0)
   postlevels      levels(10)
   radnoise        xo(100) yo(100) ascale(17.0) rscale(0.02)
   turbnoise       xo(0.0) yo(0.0) scale(10.0)
+  unsharpmask     stddev(2.0) scale(1.0)
   watermark       wmark pixdiff(10) tx(0) ty(0)
 
 The default values are in parenthesis.  All parameters must have some
@@ -2854,6 +3097,16 @@ uses the channel I<elevation> image I<bump> as a bumpmap on your
 image, with the light at (I<lightx>, I<lightty>), with a shadow length
 of I<st>.
 
+=item bumpmap_complex
+
+uses the channel I<channel> image I<bump> as a bumpmap on your image.
+If Lz<0 the three L parameters are considered to be the direction of
+the light.  If Lz>0 the L parameters are considered to be the light
+position.  I<Ia> is the ambient colour, I<Il> is the light colour,
+I<Is> is the color of specular highlights.  I<cd> is the diffuse
+coefficient and I<cs> is the specular coefficient.  I<n> is the
+shininess of the surface.
+
 =item contrast
 
 scales each channel by I<intensity>.  Values of I<intensity> < 1.0
@@ -2864,6 +3117,164 @@ will reduce the contrast.
 performs 2 1-dimensional convolutions on the image using the values
 from I<coef>.  I<coef> should be have an odd length.
 
+=item fountain
+
+renders a fountain fill, similar to the gradient tool in most paint
+software.  The default fill is a linear fill from opaque black to
+opaque white.  The points A(xa, ya) and B(xb, yb) control the way the
+fill is performed, depending on the ftype parameter:
+
+=over
+
+=item linear
+
+the fill ramps from A through to B.
+
+=item bilinear
+
+the fill ramps in both directions from A, where AB defines the length
+of the gradient.
+
+=item radial
+
+A is the center of a circle, and B is a point on it's circumference.
+The fill ramps from the center out to the circumference.
+
+=item radial_square
+
+A is the center of a square and B is the center of one of it's sides.
+This can be used to rotate the square.  The fill ramps out to the
+edges of the square.
+
+=item revolution
+
+A is the centre of a circle and B is a point on it's circumference.  B
+marks the 0 and 360 point on the circle, with the fill ramping
+clockwise.
+
+=item conical
+
+A is the center of a circle and B is a point on it's circumference.  B
+marks the 0 and point on the circle, with the fill ramping in both
+directions to meet opposite.
+
+=back
+
+The I<repeat> option controls how the fill is repeated for some
+I<ftype>s after it leaves the AB range:
+
+=over
+
+=item none
+
+no repeats, points outside of each range are treated as if they were
+on the extreme end of that range.
+
+=item sawtooth
+
+the fill simply repeats in the positive direction
+
+=item triangle
+
+the fill repeats in reverse and then forward and so on, in the
+positive direction
+
+=item saw_both
+
+the fill repeats in both the positive and negative directions (only
+meaningful for a linear fill).
+
+=item tri_both
+
+as for triangle, but in the negative direction too (only meaningful
+for a linear fill).
+
+=back
+
+By default the fill simply overwrites the whole image (unless you have
+parts of the range 0 through 1 that aren't covered by a segment), if
+any segments of your fill have any transparency, you can set the
+I<combine> option to 'normal' to have the fill combined with the
+existing pixels.  See the description of I<combine> in L<Imager/Fill>.
+
+If your fill has sharp edges, for example between steps if you use
+repeat set to 'triangle', you may see some aliased or ragged edges.
+You can enable super-sampling which will take extra samples within the
+pixel in an attempt anti-alias the fill.
+
+The possible values for the super_sample option are:
+
+=over
+
+=item none
+
+no super-sampling is done
+
+=item grid
+
+a square grid of points are sampled.  The number of points sampled is
+the square of ceil(0.5 + sqrt(ssample_param)).
+
+=item random
+
+a random set of points within the pixel are sampled.  This looks
+pretty bad for low ssample_param values.  
+
+=item circle
+
+the points on the radius of a circle within the pixel are sampled.
+This seems to produce the best results, but is fairly slow (for now).
+
+=back
+
+You can control the level of sampling by setting the ssample_param
+option.  This is roughly the number of points sampled, but depends on
+the type of sampling.
+
+The segments option is an arrayref of segments.  You really should use
+the Imager::Fountain class to build your fountain fill.  Each segment
+is an array ref containing:
+
+=over
+
+=item start
+
+a floating point number between 0 and 1, the start of the range of fill parameters covered by this segment.
+
+=item middle
+
+a floating point number between start and end which can be used to
+push the color range towards one end of the segment.
+
+=item end
+
+a floating point number between 0 and 1, the end of the range of fill
+parameters covered by this segment.  This should be greater than
+start.
+
+=item c0 
+
+=item c1
+
+The colors at each end of the segment.  These can be either
+Imager::Color or Imager::Color::Float objects.
+
+=item segment type
+
+The type of segment, this controls the way the fill parameter varies
+over the segment. 0 for linear, 1 for curved (unimplemented), 2 for
+sine, 3 for sphere increasing, 4 for sphere decreasing.
+
+=item color type
+
+The way the color varies within the segment, 0 for simple RGB, 1 for
+hue increasing and 2 for hue decreasing.
+
+=back
+
+Don't forgot to use Imager::Fountain instead of building your own.
+Really.  It even loads GIMP gradient files.
+
 =item gaussian
 
 performs a gaussian blur of the image, using I<stddev> as the standard
@@ -2884,6 +3295,10 @@ for Euclidean squared, and 2 for Manhattan distance.
 inverts the image, black to white, white to black.  All channels are
 inverted, including the alpha channel if any.
 
+=item mosaic
+
+produces averaged tiles of the given I<size>.
+
 =item noise
 
 adds noise of the given I<amount> to the image.  If I<subtype> is
@@ -2907,6 +3322,13 @@ renders Perlin turbulent noise.  (I<xo>, I<yo>) controls the origin of
 the noise, and I<scale> the scale of the noise, with lower numbers
 giving more detail.
 
+=item unsharpmask
+
+performs an unsharp mask on the image.  This is the result of
+subtracting a gaussian blurred version of the image from the original.
+I<stddev> controls the stddev parameter of the gaussian blur.  Each
+output pixel is: in + I<scale> * (in - blurred).
+
 =item watermark
 
 applies I<wmark> as a watermark on the image with strength I<pixdiff>,
@@ -3490,7 +3912,7 @@ the i_aspect_only tag is non-zero.
 
 =back
 
-The following tags are set when reading a Windows BMP file is read:
+The following tags are set when a Windows BMP file is read:
 
 =over