]> git.imager.perl.org - imager.git/blobdiff - Imager.pm
rename font.c to fontft1.c, since it only does FT1 now
[imager.git] / Imager.pm
index c69e1d6920aa3cf7c18508bb4e226479f4e82c46..399a20936054f7e970c801da4537060ca01f09d6 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -19,17 +19,11 @@ use Imager::Font;
                unload_plugin
 
                i_list_formats
                unload_plugin
 
                i_list_formats
-               i_has_format
 
                i_color_new
                i_color_set
                i_color_info
 
 
                i_color_new
                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
                i_img_info
 
                i_img_setmask
@@ -61,14 +55,6 @@ use Imager::Font;
 
                i_img_diff
 
 
                i_img_diff
 
-               i_init_fonts
-               i_t1_new
-               i_t1_destroy
-               i_t1_set_aa
-               i_t1_cp
-               i_t1_text
-               i_t1_bbox
-
                i_tt_set_aa
                i_tt_cp
                i_tt_text
                i_tt_set_aa
                i_tt_cp
                i_tt_text
@@ -103,14 +89,6 @@ use Imager::Font;
 );
 
 @EXPORT=qw(
 );
 
 @EXPORT=qw(
-          init_log
-          i_list_formats
-          i_has_format
-          malloc_state
-          i_color_new
-
-          i_img_empty
-          i_img_empty_ch
          );
 
 %EXPORT_TAGS=
          );
 
 %EXPORT_TAGS=
@@ -136,6 +114,13 @@ my %writers;
 # modules we attempted to autoload
 my %attempted_to_load;
 
 # modules we attempted to autoload
 my %attempted_to_load;
 
+# errors from loading files
+my %file_load_errors;
+
+# what happened when we tried to load
+my %reader_load_errors;
+my %writer_load_errors;
+
 # library keys that are image file formats
 my %file_formats = map { $_ => 1 } qw/tiff pnm gif png jpeg raw bmp tga/;
 
 # library keys that are image file formats
 my %file_formats = map { $_ => 1 } qw/tiff pnm gif png jpeg raw bmp tga/;
 
@@ -154,17 +139,13 @@ my %defaults;
 
 BEGIN {
   require Exporter;
 
 BEGIN {
   require Exporter;
-  @ISA = qw(Exporter);
-  $VERSION = '0.78';
-  eval {
-    require XSLoader;
-    XSLoader::load(Imager => $VERSION);
-    1;
-  } or do {
-    require DynaLoader;
-    push @ISA, 'DynaLoader';
-    bootstrap Imager $VERSION;
+  my $ex_version = eval $Exporter::VERSION;
+  if ($ex_version < 5.57) {
+    @ISA = qw(Exporter);
   }
   }
+  $VERSION = '0.92';
+  require XSLoader;
+  XSLoader::load(Imager => $VERSION);
 }
 
 my %formats_low;
 }
 
 my %formats_low;
@@ -176,6 +157,7 @@ my %format_classes =
    jpeg => "Imager::File::JPEG",
    w32 => "Imager::Font::W32",
    ft2 => "Imager::Font::FT2",
    jpeg => "Imager::File::JPEG",
    w32 => "Imager::Font::W32",
    ft2 => "Imager::Font::FT2",
+   t1 => "Imager::Font::T1",
   );
 
 tie %formats, "Imager::FORMATS", \%formats_low, \%format_classes;
   );
 
 tie %formats, "Imager::FORMATS", \%formats_low, \%format_classes;
@@ -459,28 +441,67 @@ sub import {
 }
 
 sub init_log {
 }
 
 sub init_log {
-  i_init_log($_[0],$_[1]);
-  i_log_entry("Imager $VERSION starting\n", 1);
+  Imager->open_log(log => $_[0], level => $_[1]);
 }
 
 
 sub init {
   my %parms=(loglevel=>1,@_);
 }
 
 
 sub init {
   my %parms=(loglevel=>1,@_);
-  if ($parms{'log'}) {
-    init_log($parms{'log'},$parms{'loglevel'});
-  }
 
   if (exists $parms{'warn_obsolete'}) {
     $warn_obsolete = $parms{'warn_obsolete'};
   }
 
 
   if (exists $parms{'warn_obsolete'}) {
     $warn_obsolete = $parms{'warn_obsolete'};
   }
 
-#    if ($parms{T1LIB_CONFIG}) { $ENV{T1LIB_CONFIG}=$parms{T1LIB_CONFIG}; }
-#    if ( $ENV{T1LIB_CONFIG} and ( $fontstate eq 'missing conf' )) {
-#      i_init_fonts();
-#      $fontstate='ok';
-#    }
+  if ($parms{'log'}) {
+    Imager->open_log(log => $parms{log}, level => $parms{loglevel})
+      or return;
+  }
+
   if (exists $parms{'t1log'}) {
   if (exists $parms{'t1log'}) {
-    i_init_fonts($parms{'t1log'});
+    if ($formats{t1}) {
+      if (Imager::Font::T1::i_init_t1($parms{'t1log'})) {
+       Imager->_set_error(Imager->_error_as_msg);
+       return;
+      }
+    }
+  }
+
+  return 1;
+}
+
+{
+  my $is_logging = 0;
+
+  sub open_log {
+    my $class = shift;
+    my (%opts) = ( loglevel => 1, @_ );
+
+    $is_logging = i_init_log($opts{log}, $opts{loglevel});
+    unless ($is_logging) {
+      Imager->_set_error(Imager->_error_as_msg());
+      return;
+    }
+
+    Imager->log("Imager $VERSION starting\n", 1);
+
+    return $is_logging;
+  }
+
+  sub close_log {
+    i_init_log(undef, -1);
+    $is_logging = 0;
+  }
+
+  sub log {
+    my ($class, $message, $level) = @_;
+
+    defined $level or $level = 1;
+
+    i_log_entry($message, $level);
+  }
+
+  sub is_logging {
+    return $is_logging;
   }
 }
 
   }
 }
 
@@ -596,11 +617,13 @@ sub _combine {
 }
 
 sub _valid_image {
 }
 
 sub _valid_image {
-  my ($self) = @_;
+  my ($self, $method) = @_;
 
   $self->{IMG} and return 1;
 
 
   $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;
 }
 
   return;
 }
@@ -885,8 +908,8 @@ sub img_set {
     $self->{IMG} = i_img_16_new($hsh{xsize}, $hsh{ysize}, $hsh{channels});
   }
   else {
     $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}) {
   }
 
   unless ($self->{IMG}) {
@@ -913,11 +936,16 @@ sub masked {
   $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left}, 
                                     $opts{top}, $opts{right} - $opts{left},
                                     $opts{bottom} - $opts{top});
   $result->{IMG} = i_img_masked_new($self->{IMG}, $mask, $opts{left}, 
                                     $opts{top}, $opts{right} - $opts{left},
                                     $opts{bottom} - $opts{top});
+  unless ($result->{IMG}) {
+    $self->_set_error(Imager->_error_as_msg);
+    return;
+  }
+
   # keep references to the mask and base images so they don't
   # disappear on us
   $result->{DEPENDS} = [ $self->{IMG}, $mask ];
 
   # keep references to the mask and base images so they don't
   # disappear on us
   $result->{DEPENDS} = [ $self->{IMG}, $mask ];
 
-  $result;
+  return $result;
 }
 
 # convert an RGB image into a paletted image
 }
 
 # convert an RGB image into a paletted image
@@ -937,24 +965,40 @@ sub to_paletted {
     return;
   }
 
     return;
   }
 
+  $self->_valid_image
+    or return;
+
   my $result = Imager->new;
   my $result = Imager->new;
-  $result->{IMG} = i_img_to_pal($self->{IMG}, $opts);
+  unless ($result->{IMG} = i_img_to_pal($self->{IMG}, $opts)) {
+    $self->_set_error(Imager->_error_as_msg);
+    return;
+  }
+
+  return $result;
+}
 
 
-  #print "Type ", i_img_type($result->{IMG}), "\n";
+sub make_palette {
+  my ($class, $quant, @images) = @_;
 
 
-  if ($result->{IMG}) {
-    return $result;
-  }
-  else {
-    $self->{ERRSTR} = $self->_error_as_msg;
+  unless (@images) {
+    Imager->_set_error("make_palette: supply at least one image");
     return;
   }
     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 images
+# convert a paletted (or any image) to an 8-bit/channel RGB image
 sub to_rgb8 {
   my $self = shift;
 sub to_rgb8 {
   my $self = shift;
-  my $result;
 
   unless (defined wantarray) {
     my @caller = caller;
 
   unless (defined wantarray) {
     my @caller = caller;
@@ -962,30 +1006,57 @@ sub to_rgb8 {
     return;
   }
 
     return;
   }
 
-  if ($self->{IMG}) {
-    $result = Imager->new;
-    $result->{IMG} = i_img_to_rgb($self->{IMG})
-      or undef $result;
+  $self->_valid_image
+    or return;
+
+  my $result = Imager->new;
+  unless ($result->{IMG} = i_img_to_rgb($self->{IMG})) {
+    $self->_set_error(Imager->_error_as_msg());
+    return;
   }
 
   return $result;
 }
 
   }
 
   return $result;
 }
 
-# convert a paletted (or any image) to an 8-bit/channel RGB images
+# convert a paletted (or any image) to a 16-bit/channel RGB image
 sub to_rgb16 {
   my $self = shift;
 sub to_rgb16 {
   my $self = shift;
-  my $result;
 
   unless (defined wantarray) {
     my @caller = caller;
 
   unless (defined wantarray) {
     my @caller = caller;
-    warn "to_rgb16() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
+    warn "to_rgb16() called in void context - to_rgb16() returns the converted image at $caller[1] line $caller[2]\n";
     return;
   }
 
     return;
   }
 
-  if ($self->{IMG}) {
-    $result = Imager->new;
-    $result->{IMG} = i_img_to_rgb16($self->{IMG})
-      or undef $result;
+  $self->_valid_image
+    or return;
+
+  my $result = Imager->new;
+  unless ($result->{IMG} = i_img_to_rgb16($self->{IMG})) {
+    $self->_set_error(Imager->_error_as_msg());
+    return;
+  }
+
+  return $result;
+}
+
+# convert a paletted (or any image) to an double/channel RGB image
+sub to_rgb_double {
+  my $self = shift;
+
+  unless (defined wantarray) {
+    my @caller = caller;
+    warn "to_rgb16() called in void context - to_rgb_double() returns the converted image at $caller[1] line $caller[2]\n";
+    return;
+  }
+
+  $self->_valid_image
+    or return;
+
+  my $result = Imager->new;
+  unless ($result->{IMG} = i_img_to_drgb($self->{IMG})) {
+    $self->_set_error(Imager->_error_as_msg());
+    return;
   }
 
   return $result;
   }
 
   return $result;
@@ -1274,13 +1345,17 @@ sub _get_reader_io {
 }
 
 sub _get_writer_io {
 }
 
 sub _get_writer_io {
-  my ($self, $input, $type) = @_;
+  my ($self, $input) = @_;
 
 
+  my $buffered = exists $input->{buffered} ? $input->{buffered} : 1;
+
+  my $io;
+  my @extras;
   if ($input->{io}) {
   if ($input->{io}) {
-    return $input->{io};
+    $io = $input->{io};
   }
   elsif ($input->{fd}) {
   }
   elsif ($input->{fd}) {
-    return io_new_fd($input->{fd});
+    $io = io_new_fd($input->{fd});
   }
   elsif ($input->{fh}) {
     my $fd = fileno($input->{fh});
   }
   elsif ($input->{fh}) {
     my $fd = fileno($input->{fh});
@@ -1293,7 +1368,7 @@ sub _get_writer_io {
     # flush anything that's buffered, and make sure anything else is flushed
     $| = 1;
     select($oldfh);
     # flush anything that's buffered, and make sure anything else is flushed
     $| = 1;
     select($oldfh);
-    return io_new_fd($fd);
+    $io = io_new_fd($fd);
   }
   elsif ($input->{file}) {
     my $fh = new IO::File($input->{file},"w+");
   }
   elsif ($input->{file}) {
     my $fh = new IO::File($input->{file},"w+");
@@ -1302,28 +1377,30 @@ sub _get_writer_io {
       return;
     }
     binmode($fh) or die;
       return;
     }
     binmode($fh) or die;
-    return (io_new_fd(fileno($fh)), $fh);
+    $io = io_new_fd(fileno($fh));
+    push @extras, $fh;
   }
   elsif ($input->{data}) {
   }
   elsif ($input->{data}) {
-    return io_new_bufchain();
+    $io = io_new_bufchain();
   }
   elsif ($input->{callback} || $input->{writecb}) {
   }
   elsif ($input->{callback} || $input->{writecb}) {
-    if ($input->{maxbuffer}) {
-      return io_new_cb($input->{callback} || $input->{writecb},
-                       $input->{readcb},
-                       $input->{seekcb}, $input->{closecb},
-                       $input->{maxbuffer});
-    }
-    else {
-      return io_new_cb($input->{callback} || $input->{writecb},
-                       $input->{readcb},
-                       $input->{seekcb}, $input->{closecb});
+    if ($input->{maxbuffer} && $input->{maxbuffer} == 1) {
+      $buffered = 0;
     }
     }
+    $io = io_new_cb($input->{callback} || $input->{writecb},
+                   $input->{readcb},
+                   $input->{seekcb}, $input->{closecb});
   }
   else {
     $self->_set_error("file/fd/fh/data/callback parameter missing");
     return;
   }
   }
   else {
     $self->_set_error("file/fd/fh/data/callback parameter missing");
     return;
   }
+
+  unless ($buffered) {
+    $io->set_buffered(0);
+  }
+
+  return ($io, @extras);
 }
 
 # Read an image from file
 }
 
 # Read an image from file
@@ -1341,31 +1418,39 @@ sub read {
 
   my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
 
 
   my ($IO, $fh) = $self->_get_reader_io(\%input) or return;
 
-  unless ($input{'type'}) {
-    $input{'type'} = i_test_format_probe($IO, -1);
+  my $type = $input{'type'};
+  unless ($type) {
+    $type = i_test_format_probe($IO, -1);
+  }
+
+  if ($input{file} && !$type) {
+    # guess the type 
+    $type = $FORMATGUESS->($input{file});
   }
 
   }
 
-  unless ($input{'type'}) {
-         $self->_set_error('type parameter missing and not possible to guess from extension'); 
+  unless ($type) {
+    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;
   }
 
     return undef;
   }
 
-  _reader_autoload($input{type});
+  _reader_autoload($type);
 
 
-  if ($readers{$input{type}} && $readers{$input{type}}{single}) {
-    return $readers{$input{type}}{single}->($self, $IO, %input);
+  if ($readers{$type} && $readers{$type}{single}) {
+    return $readers{$type}{single}->($self, $IO, %input);
   }
 
   }
 
-  unless ($formats_low{$input{'type'}}) {
+  unless ($formats_low{$type}) {
     my $read_types = join ', ', sort Imager->read_types();
     my $read_types = join ', ', sort Imager->read_types();
-    $self->_set_error("format '$input{'type'}' not supported - formats $read_types available for reading");
+    $self->_set_error("format '$type' not supported - formats $read_types available for reading - $reader_load_errors{$type}");
     return;
   }
 
   my $allow_incomplete = $input{allow_incomplete};
   defined $allow_incomplete or $allow_incomplete = 0;
 
     return;
   }
 
   my $allow_incomplete = $input{allow_incomplete};
   defined $allow_incomplete or $allow_incomplete = 0;
 
-  if ( $input{'type'} eq 'pnm' ) {
+  if ( $type eq 'pnm' ) {
     $self->{IMG}=i_readpnm_wiol( $IO, $allow_incomplete );
     if ( !defined($self->{IMG}) ) {
       $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); 
     $self->{IMG}=i_readpnm_wiol( $IO, $allow_incomplete );
     if ( !defined($self->{IMG}) ) {
       $self->{ERRSTR}='unable to read pnm image: '._error_as_msg(); 
@@ -1375,7 +1460,7 @@ sub read {
     return $self;
   }
 
     return $self;
   }
 
-  if ( $input{'type'} eq 'bmp' ) {
+  if ( $type eq 'bmp' ) {
     $self->{IMG}=i_readbmp_wiol( $IO, $allow_incomplete );
     if ( !defined($self->{IMG}) ) {
       $self->{ERRSTR}=$self->_error_as_msg();
     $self->{IMG}=i_readbmp_wiol( $IO, $allow_incomplete );
     if ( !defined($self->{IMG}) ) {
       $self->{ERRSTR}=$self->_error_as_msg();
@@ -1384,42 +1469,7 @@ sub read {
     $self->{DEBUG} && print "loading a bmp file\n";
   }
 
     $self->{DEBUG} && print "loading a bmp file\n";
   }
 
-  if ( $input{'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 ( $input{'type'} eq 'tga' ) {
+  if ( $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->{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();
@@ -1428,7 +1478,7 @@ sub read {
     $self->{DEBUG} && print "loading a tga file\n";
   }
 
     $self->{DEBUG} && print "loading a tga file\n";
   }
 
-  if ( $input{'type'} eq 'raw' ) {
+  if ( $type eq 'raw' ) {
     unless ( $input{xsize} && $input{ysize} ) {
       $self->_set_error('missing xsize or ysize parameter for raw');
       return undef;
     unless ( $input{xsize} && $input{ysize} ) {
       $self->_set_error('missing xsize or ysize parameter for raw');
       return undef;
@@ -1527,6 +1577,41 @@ sub write_types {
   return keys %types;
 }
 
   return keys %types;
 }
 
+sub _load_file {
+  my ($file, $error) = @_;
+
+  if ($attempted_to_load{$file}) {
+    if ($file_load_errors{$file}) {
+      $$error = $file_load_errors{$file};
+      return 0;
+    }
+    else {
+      return 1;
+    }
+  }
+  else {
+    local $SIG{__DIE__};
+    my $loaded = eval {
+      ++$attempted_to_load{$file};
+      require $file;
+      return 1;
+    };
+    if ($loaded) {
+      return 1;
+    }
+    else {
+      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;
+    }
+  }
+}
+
 # probes for an Imager::File::whatever module
 sub _reader_autoload {
   my $type = shift;
 # probes for an Imager::File::whatever module
 sub _reader_autoload {
   my $type = shift;
@@ -1537,50 +1622,42 @@ sub _reader_autoload {
 
   my $file = "Imager/File/\U$type\E.pm";
 
 
   my $file = "Imager/File/\U$type\E.pm";
 
-  unless ($attempted_to_load{$file}) {
-    eval {
-      ++$attempted_to_load{$file};
-      require $file;
-    };
-    if ($@) {
-      # try to get a reader specific module
-      my $file = "Imager/File/\U$type\EReader.pm";
-      unless ($attempted_to_load{$file}) {
-       eval {
-         ++$attempted_to_load{$file};
-         require $file;
-       };
-      }
+  my $error;
+  my $loaded = _load_file($file, \$error);
+  if (!$loaded && $error =~ /^Can't locate /) {
+    my $filer = "Imager/File/\U$type\EReader.pm";
+    $loaded = _load_file($filer, \$error);
+    if ($error =~ /^Can't locate /) {
+      $error = "Can't locate $file or $filer";
     }
   }
     }
   }
+  unless ($loaded) {
+    $reader_load_errors{$type} = $error;
+  }
 }
 
 # probes for an Imager::File::whatever module
 sub _writer_autoload {
   my $type = shift;
 
 }
 
 # probes for an Imager::File::whatever module
 sub _writer_autoload {
   my $type = shift;
 
-  return if $formats_low{$type} || $readers{$type};
+  return if $formats_low{$type} || $writers{$type};
 
   return unless $type =~ /^\w+$/;
 
   my $file = "Imager/File/\U$type\E.pm";
 
 
   return unless $type =~ /^\w+$/;
 
   my $file = "Imager/File/\U$type\E.pm";
 
-  unless ($attempted_to_load{$file}) {
-    eval {
-      ++$attempted_to_load{$file};
-      require $file;
-    };
-    if ($@) {
-      # try to get a writer specific module
-      my $file = "Imager/File/\U$type\EWriter.pm";
-      unless ($attempted_to_load{$file}) {
-       eval {
-         ++$attempted_to_load{$file};
-         require $file;
-       };
-      }
+  my $error;
+  my $loaded = _load_file($file, \$error);
+  if (!$loaded && $error =~ /^Can't locate /) {
+    my $filew = "Imager/File/\U$type\EWriter.pm";
+    $loaded = _load_file($filew, \$error);
+    if ($error =~ /^Can't locate /) {
+      $error = "Can't locate $file or $filew";
     }
   }
     }
   }
+  unless ($loaded) {
+    $writer_load_errors{$type} = $error;
+  }
 }
 
 sub _fix_gif_positions {
 }
 
 sub _fix_gif_positions {
@@ -1699,35 +1776,36 @@ sub write {
 
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 
 
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
 
-  if (!$input{'type'} and $input{file}) { 
-    $input{'type'}=$FORMATGUESS->($input{file});
+  my $type = $input{'type'};
+  if (!$type and $input{file}) { 
+    $type = $FORMATGUESS->($input{file});
   }
   }
-  if (!$input{'type'}) { 
+  unless ($type) { 
     $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
     return undef;
   }
 
     $self->{ERRSTR}='type parameter missing and not possible to guess from extension';
     return undef;
   }
 
-  _writer_autoload($input{type});
+  _writer_autoload($type);
 
   my ($IO, $fh);
 
   my ($IO, $fh);
-  if ($writers{$input{type}} && $writers{$input{type}}{single}) {
-    ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
+  if ($writers{$type} && $writers{$type}{single}) {
+    ($IO, $fh) = $self->_get_writer_io(\%input)
       or return undef;
 
       or return undef;
 
-    $writers{$input{type}}{single}->($self, $IO, %input)
+    $writers{$type}{single}->($self, $IO, %input, type => $type)
       or return undef;
   }
   else {
       or return undef;
   }
   else {
-    if (!$formats_low{$input{'type'}}) { 
+    if (!$formats_low{$type}) { 
       my $write_types = join ', ', sort Imager->write_types();
       my $write_types = join ', ', sort Imager->write_types();
-      $self->_set_error("format '$input{'type'}' not supported - formats $write_types available for writing");
+      $self->_set_error("format '$type' not supported - formats $write_types available for writing - $writer_load_errors{$type}");
       return undef;
     }
     
       return undef;
     }
     
-    ($IO, $fh) = $self->_get_writer_io(\%input, $input{'type'})
+    ($IO, $fh) = $self->_get_writer_io(\%input, $type)
       or return undef;
       or return undef;
-    
-    if ( $input{'type'} eq 'pnm' ) {
+  
+    if ( $type eq 'pnm' ) {
       $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) ) {
@@ -1735,7 +1813,8 @@ sub write {
         return undef;
       }
       $self->{DEBUG} && print "writing a pnm file\n";
         return undef;
       }
       $self->{DEBUG} && print "writing a pnm file\n";
-    } elsif ( $input{'type'} eq 'raw' ) {
+    }
+    elsif ( $type eq 'raw' ) {
       $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) ) {
@@ -1743,17 +1822,8 @@ sub write {
         return undef;
       }
       $self->{DEBUG} && print "writing a raw file\n";
         return undef;
       }
       $self->{DEBUG} && print "writing a raw file\n";
-    } elsif ( $input{'type'} eq 'jpeg' ) {
-      $self->_set_opts(\%input, "jpeg_", $self)
-        or return undef;
-      $self->_set_opts(\%input, "exif_", $self)
-        or return undef;
-      if ( !i_writejpeg_wiol($self->{IMG}, $IO, $input{jpegquality})) {
-        $self->{ERRSTR} = $self->_error_as_msg();
-        return undef;
-      }
-      $self->{DEBUG} && print "writing a jpeg file\n";
-    } elsif ( $input{'type'} eq 'bmp' ) {
+    }
+    elsif ( $type eq 'bmp' ) {
       $self->_set_opts(\%input, "bmp_", $self)
         or return undef;
       if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
       $self->_set_opts(\%input, "bmp_", $self)
         or return undef;
       if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
@@ -1761,7 +1831,8 @@ sub write {
         return undef;
       }
       $self->{DEBUG} && print "writing a bmp file\n";
         return undef;
       }
       $self->{DEBUG} && print "writing a bmp file\n";
-    } elsif ( $input{'type'} eq 'tga' ) {
+    }
+    elsif ( $type eq 'tga' ) {
       $self->_set_opts(\%input, "tga_", $self)
         or return undef;
       
       $self->_set_opts(\%input, "tga_", $self)
         or return undef;
       
@@ -1770,24 +1841,6 @@ sub write {
         return undef;
       }
       $self->{DEBUG} && print "writing a tga file\n";
         return undef;
       }
       $self->{DEBUG} && print "writing a tga file\n";
-    } elsif ( $input{'type'} eq 'gif' ) {
-      $self->_set_opts(\%input, "gif_", $self)
-        or return undef;
-      # compatibility with the old interfaces
-      if ($input{gifquant} eq 'lm') {
-        $input{make_colors} = 'addi';
-        $input{translate} = 'perturb';
-        $input{perturb} = $input{lmdither};
-      } elsif ($input{gifquant} eq 'gen') {
-        # just pass options through
-      } else {
-        $input{make_colors} = 'webmap'; # ignored
-        $input{translate} = 'giflib';
-      }
-      if (!i_writegif_wiol($IO, \%input, $self->{IMG})) {
-        $self->{ERRSTR} = $self->_error_as_msg;
-        return;
-      }
     }
   }
 
     }
   }
 
@@ -1887,7 +1940,9 @@ sub read_multi {
   }
 
   unless ($type) {
   }
 
   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;
   }
 
     return;
   }
 
@@ -2507,16 +2562,20 @@ sub compose {
     defined $mask_top or $mask_top = $opts{mask_miny};
     defined $mask_top or $mask_top = 0;
 
     defined $mask_top or $mask_top = $opts{mask_miny};
     defined $mask_top or $mask_top = 0;
 
-    i_compose_mask($self->{IMG}, $src->{IMG}, $opts{mask}{IMG}, 
+    unless (i_compose_mask($self->{IMG}, $src->{IMG}, $opts{mask}{IMG}, 
                   $left, $top, $src_left, $src_top,
                   $mask_left, $mask_top, $width, $height, 
                   $left, $top, $src_left, $src_top,
                   $mask_left, $mask_top, $width, $height, 
-                  $combine, $opts{opacity})
-      or return;
+                          $combine, $opts{opacity})) {
+      $self->_set_error(Imager->_error_as_msg);
+      return;
+    }
   }
   else {
   }
   else {
-    i_compose($self->{IMG}, $src->{IMG}, $left, $top, $src_left, $src_top,
-             $width, $height, $combine, $opts{opacity})
-      or return;
+    unless (i_compose($self->{IMG}, $src->{IMG}, $left, $top, $src_left, $src_top,
+                     $width, $height, $combine, $opts{opacity})) {
+      $self->_set_error(Imager->_error_as_msg);
+      return;
+    }
   }
 
   return $self;
   }
 
   return $self;
@@ -2568,7 +2627,7 @@ sub rotate {
     }
   }
   elsif (defined $opts{radians} || defined $opts{degrees}) {
     }
   }
   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;
 
     my $back = $opts{back};
     my $result = Imager->new;
@@ -2687,7 +2746,12 @@ sub box {
       $color = i_color_new(255,255,255,255);
     }
 
       $color = i_color_new(255,255,255,255);
     }
 
-    i_box_filled($raw, $xmin, $ymin,$xmax, $ymax, $color);
+    if ($color->isa("Imager::Color")) {
+      i_box_filled($raw, $xmin, $ymin,$xmax, $ymax, $color);
+    }
+    else {
+      i_box_filledf($raw, $xmin, $ymin,$xmax, $ymax, $color);
+    }
   }
   elsif ($opts{fill}) {
     unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
   }
   elsif ($opts{fill}) {
     unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
@@ -3044,6 +3108,9 @@ sub flood_fill {
 sub setpixel {
   my ($self, %opts) = @_;
 
 sub setpixel {
   my ($self, %opts) = @_;
 
+  $self->_valid_image("setpixel")
+    or return;
+
   my $color = $opts{color};
   unless (defined $color) {
     $color = $self->{fg};
   my $color = $opts{color};
   unless (defined $color) {
     $color = $self->{fg};
@@ -3051,36 +3118,53 @@ sub setpixel {
   }
 
   unless (ref $color && UNIVERSAL::isa($color, "Imager::Color")) {
   }
 
   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'}) {
   }
 
   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'};
   }
 
   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;
     }
       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')) {
     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 {
         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;
       }
     }
         i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color)
          or ++$set;
       }
     }
-    $set or return;
+
     return $set;
   }
   else {
     return $set;
   }
   else {
@@ -3094,7 +3178,7 @@ sub setpixel {
     }
   }
 
     }
   }
 
-  $self;
+  return $self;
 }
 
 sub getpixel {
 }
 
 sub getpixel {
@@ -3102,41 +3186,66 @@ sub getpixel {
 
   my %opts = ( "type"=>'8bit', @_);
 
 
   my %opts = ( "type"=>'8bit', @_);
 
+  $self->_valid_image("getpixel")
+    or return;
+
   unless (exists $opts{'x'} && exists $opts{'y'}) {
   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'};
   }
 
   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;
     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]));
       }
     }
         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]));
       }
     }
         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 {
     return wantarray ? @result : \@result;
   }
   else {
-    if ($opts{"type"} eq '8bit') {
+    if ($type eq '8bit') {
       return i_get_pixel($self->{IMG}, $x, $y);
     }
       return i_get_pixel($self->{IMG}, $x, $y);
     }
-    else {
+    elsif ($type eq 'float' || $type eq 'double') {
       return i_gpixf($self->{IMG}, $x, $y);
     }
       return i_gpixf($self->{IMG}, $x, $y);
     }
+    else {
+      $self->_set_error("getpixel: type must be '8bit' or 'float'");
+      return;
+    }
   }
   }
-
-  $self;
 }
 
 sub getscanline {
 }
 
 sub getscanline {
@@ -3246,24 +3355,20 @@ sub getsamples {
     return;
   }
   
     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},
   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;
        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},
       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$/) {
       return scalar(@samples);
     }
     elsif ($opts{type} =~ /^(\d+)bit$/) {
@@ -3272,7 +3377,7 @@ sub getsamples {
       my @data;
       my $count = i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width}, 
                               $opts{y}, $bits, $target, 
       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;
       unless (defined $count) {
        $self->_set_error(Imager->_error_as_msg);
        return;
@@ -3288,18 +3393,18 @@ sub getsamples {
   else {
     if ($opts{type} eq '8bit') {
       return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
   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},
     }
     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}, 
     }
     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;
     }
        or return;
       return @data;
     }
@@ -3319,28 +3424,44 @@ sub setsamples {
     return;
   }
 
     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;
   }
 
     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 (defined $opts{width}) {
-    $opts{width} = $self->getwidth() - $opts{x};
+    unless (ref $data) {
+      $self->_set_error("setsamples: data must be an array ref for type not 8bit or float");
+      return;
+    }
+
+    $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;
   unless (defined $count) {
     $self->_set_error(Imager->_error_as_msg);
     return;
@@ -3774,6 +3895,41 @@ sub get_file_limits {
   i_get_image_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(@_); }
 # Shortcuts that can be exported
 
 sub newcolor { Imager::Color->new(@_); }
@@ -3810,21 +3966,39 @@ sub _set_error {
 
 # Default guess for the type of an image from extension
 
 
 # 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);
 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 {
 }
 
 sub combines {
@@ -3913,6 +4087,24 @@ sub Inline {
 # threads shouldn't try to close raw Imager objects
 sub Imager::ImgRaw::CLONE_SKIP { 1 }
 
 # threads shouldn't try to close raw Imager objects
 sub Imager::ImgRaw::CLONE_SKIP { 1 }
 
+sub preload {
+  # this serves two purposes:
+  # - 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
+  local $@;
+  eval { require Imager::File::GIF };
+  eval { require Imager::File::JPEG };
+  eval { require Imager::File::PNG };
+  eval { require Imager::File::SGI };
+  eval { require Imager::File::TIFF };
+  eval { require Imager::File::ICO };
+  eval { require Imager::Font::W32 };
+  eval { require Imager::Font::FT2 };
+  eval { require Imager::Font::T1 };
+}
+
 # backward compatibility for %formats
 package Imager::FORMATS;
 use strict;
 # backward compatibility for %formats
 package Imager::FORMATS;
 use strict;
@@ -3932,10 +4124,16 @@ sub _check {
 
   (my $file = $self->[IX_CLASSES]{$key} . ".pm") =~ s(::)(/)g;
   my $value;
 
   (my $file = $self->[IX_CLASSES]{$key} . ".pm") =~ s(::)(/)g;
   my $value;
-  if (eval { require $file; 1 }) {
+  my $error;
+  my $loaded = Imager::_load_file($file, \$error);
+  if ($loaded) {
     $value = 1;
   }
   else {
     $value = 1;
   }
   else {
+    if ($error =~ /^Can't locate /) {
+      $error = "Can't locate $file";
+    }
+    $reader_load_errors{$key} = $writer_load_errors{$key} = $error;
     $value = undef;
   }
   $self->[IX_FORMATS]{$key} = $value;
     $value = undef;
   }
   $self->[IX_FORMATS]{$key} = $value;
@@ -4036,7 +4234,7 @@ Imager - Perl extension for Generating 24 bit Images
   my $format;
 
   # see Imager::Files for information on the read() method
   my $format;
 
   # see Imager::Files for information on the read() method
-  my $im = Imager->new(file=>$file)
+  my $img = Imager->new(file=>$file)
     or die Imager->errstr();
 
   $file =~ s/\.[^.]*$//;
     or die Imager->errstr();
 
   $file =~ s/\.[^.]*$//;
@@ -4161,6 +4359,14 @@ L<Imager::Inline> - using Imager's C API from Inline::C
 
 L<Imager::ExtUtils> - tools to get access to Imager's C API.
 
 
 L<Imager::ExtUtils> - tools to get access to Imager's C API.
 
+=item *
+
+L<Imager::Security> - brief security notes.
+
+=item *
+
+L<Imager::Threads> - brief information on working with threads.
+
 =back
 
 =head2 Basic Overview
 =back
 
 =head2 Basic Overview
@@ -4187,7 +4393,7 @@ the C<errstr()> method to find out why:
 
 =over
 
 
 =over
 
-=item C<errstr>
+=item errstr()
 
 Returns the last error message in that context.
 
 
 Returns the last error message in that context.
 
@@ -4215,234 +4421,255 @@ 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> - add colors to a
+addcolors() - L<Imager::ImageTypes/addcolors()> - add colors to a
 paletted image
 
 paletted image
 
-addtag() -  L<Imager::ImageTypes/addtag> - add image tags
+addtag() -  L<Imager::ImageTypes/addtag()> - add image tags
 
 
-align_string() - L<Imager::Draw/align_string> - draw text aligned on a
+align_string() - L<Imager::Draw/align_string()> - draw text aligned on a
 point
 
 point
 
-arc() - L<Imager::Draw/arc> - draw a filled arc
+arc() - L<Imager::Draw/arc()> - draw a filled arc
 
 
-bits() - L<Imager::ImageTypes/bits> - number of bits per sample for the
+bits() - L<Imager::ImageTypes/bits()> - number of bits per sample for the
 image
 
 image
 
-box() - L<Imager::Draw/box> - draw a filled or outline box.
+box() - L<Imager::Draw/box()> - draw a filled or outline box.
+
+check_file_limits() - L<Imager::Files/check_file_limits()>
+
+circle() - L<Imager::Draw/circle()> - draw a filled circle
 
 
-circle() - L<Imager::Draw/circle> - draw a filled circle
+close_log() - L<Imager::ImageTypes/close_log()> - close the Imager
+debugging log.
 
 
-colorcount() - L<Imager::Draw/colorcount> - the number of colors in an
-image's palette (paletted images only)
+colorcount() - L<Imager::ImageTypes/colorcount()> - the number of
+colors in an image's palette (paletted images only)
 
 
-combine() - L<Imager::Transformations/combine> - combine channels from one or
-more images.
+combine() - L<Imager::Transformations/combine()> - combine channels
+from one or more images.
 
 
-combines() - L<Imager::Draw/combines> - return a list of the different
-combine type keywords
+combines() - L<Imager::Draw/combines()> - return a list of the
+different combine type keywords
 
 
-compose() - L<Imager::Transformations/compose> - compose one image
+compose() - L<Imager::Transformations/compose()> - compose one image
 over another.
 
 over another.
 
-convert() - L<Imager::Transformations/"Color transformations"> -
-transform the color space
+convert() - L<Imager::Transformations/convert()> - transform the color
+space
 
 
-copy() - L<Imager::Transformations/copy> - make a duplicate of an
+copy() - L<Imager::Transformations/copy()> - make a duplicate of an
 image
 
 image
 
-crop() - L<Imager::Transformations/crop> - extract part of an image
+crop() - L<Imager::Transformations/crop()> - extract part of an image
 
 
-def_guess_type() - L<Imager::Files/def_guess_type> - default function
+def_guess_type() - L<Imager::Files/def_guess_type()> - default function
 used to guess the output file format based on the output file name
 
 used to guess the output file format based on the output file name
 
-deltag() -  L<Imager::ImageTypes/deltag> - delete image tags
+deltag() -  L<Imager::ImageTypes/deltag()> - delete image tags
 
 
-difference() - L<Imager::Filters/"Image Difference"> - produce a
-difference images from two input images.
+difference() - L<Imager::Filters/difference()> - produce a difference
+images from two input images.
 
 
-errstr() - L<"Basic Overview"> - the error from the last failed
-operation.
+errstr() - L</errstr()> - the error from the last failed operation.
 
 
-filter() - L<Imager::Filters> - image filtering
+filter() - L<Imager::Filters/filter()> - image filtering
 
 
-findcolor() - L<Imager::ImageTypes/findcolor> - search the image
+findcolor() - L<Imager::ImageTypes/findcolor()> - search the image
 palette, if it has one
 
 palette, if it has one
 
-flip() - L<Imager::Transformations/flip> - flip an image, vertically,
+flip() - L<Imager::Transformations/flip()> - flip an image, vertically,
 horizontally
 
 horizontally
 
-flood_fill() - L<Imager::Draw/flood_fill> - fill an enclosed or same
+flood_fill() - L<Imager::Draw/flood_fill()> - fill an enclosed or same
 color area
 
 color area
 
-getchannels() - L<Imager::ImageTypes/getchannels> - the number of
+getchannels() - L<Imager::ImageTypes/getchannels()> - the number of
 samples per pixel for an image
 
 samples per pixel for an image
 
-getcolorcount() - L<Imager::ImageTypes/getcolorcount> - the number of
+getcolorcount() - L<Imager::ImageTypes/getcolorcount()> - the number of
 different colors used by an image (works for direct color images)
 
 different colors used by an image (works for direct color images)
 
-getcolors() - L<Imager::ImageTypes/getcolors> - 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
 
-getcolorusage() - L<Imager::ImageTypes/getcolorusage>
+getcolorusage() - L<Imager::ImageTypes/getcolorusage()>
 
 
-getcolorusagehash() - L<Imager::ImageTypes/getcolorusagehash>
+getcolorusagehash() - L<Imager::ImageTypes/getcolorusagehash()>
 
 
-get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
+get_file_limits() - L<Imager::Files/get_file_limits()>
 
 
-getheight() - L<Imager::ImageTypes/getwidth> - height of the image in
+getheight() - L<Imager::ImageTypes/getheight()> - height of the image in
 pixels
 
 pixels
 
-getmask() - L<Imager::ImageTypes/getmask> - write mask for the image
+getmask() - L<Imager::ImageTypes/getmask()> - write mask for the image
 
 
-getpixel() - L<Imager::Draw/getpixel> - retrieve one or more pixel
+getpixel() - L<Imager::Draw/getpixel()> - retrieve one or more pixel
 colors
 
 colors
 
-getsamples() - L<Imager::Draw/getsamples> - retrieve samples from a
+getsamples() - L<Imager::Draw/getsamples()> - retrieve samples from a
 row or partial row of pixels.
 
 row or partial row of pixels.
 
-getscanline() - L<Imager::Draw/getscanline> - retrieve colors for a
+getscanline() - L<Imager::Draw/getscanline()> - retrieve colors for a
 row or partial row of pixels.
 
 row or partial row of pixels.
 
-getwidth() - L<Imager::ImageTypes/getwidth> - width of the image in
+getwidth() - L<Imager::ImageTypes/getwidth()> - width of the image in
 pixels.
 
 pixels.
 
-img_set() - L<Imager::ImageTypes/img_set> - re-use an Imager object
+img_set() - L<Imager::ImageTypes/img_set()> - re-use an Imager object
 for a new image.
 
 for a new image.
 
-init() - L<Imager::ImageTypes/init>
+init() - L<Imager::ImageTypes/init()>
 
 
-is_bilevel() - L<Imager::ImageTypes/is_bilevel> - returns whether
+is_bilevel() - L<Imager::ImageTypes/is_bilevel()> - returns whether
 image write functions should write the image in their bilevel (blank
 and white, no gray levels) format
 
 image write functions should write the image in their bilevel (blank
 and white, no gray levels) format
 
-line() - L<Imager::Draw/line> - draw an interval
+is_logging() L<Imager::ImageTypes/is_logging()> - test if the debug
+log is active.
 
 
-load_plugin() - L<Imager::Filters/load_plugin>
+line() - L<Imager::Draw/line()> - draw an interval
 
 
-map() - L<Imager::Transformations/"Color Mappings"> - remap color
+load_plugin() - L<Imager::Filters/load_plugin()>
+
+log() - L<Imager::ImageTypes/log()> - send a message to the debugging
+log.
+
+make_palette() - L<Imager::ImageTypes/make_palette()> - produce a
+color palette from one or more input images.
+
+map() - L<Imager::Transformations/map()> - remap color
 channel values
 
 channel values
 
-masked() -  L<Imager::ImageTypes/masked> - make a masked image
+masked() -  L<Imager::ImageTypes/masked()> - make a masked image
+
+matrix_transform() - L<Imager::Engines/matrix_transform()>
 
 
-matrix_transform() - L<Imager::Engines/matrix_transform>
+maxcolors() - L<Imager::ImageTypes/maxcolors()>
 
 
-maxcolors() - L<Imager::ImageTypes/maxcolors>
+NC() - L<Imager::Handy/NC()>
 
 
-NC() - L<Imager::Handy/NC>
+NCF() - L<Imager::Handy/NCF()>
 
 
-NCF() - L<Imager::Handy/NCF>
+new() - L<Imager::ImageTypes/new()>
 
 
-new() - L<Imager::ImageTypes/new>
+newcolor() - L<Imager::Handy/newcolor()>
 
 
-newcolor() - L<Imager::Handy/newcolor>
+newcolour() - L<Imager::Handy/newcolour()>
 
 
-newcolour() - L<Imager::Handy/newcolour>
+newfont() - L<Imager::Handy/newfont()>
 
 
-newfont() - L<Imager::Handy/newfont>
+NF() - L<Imager::Handy/NF()>
 
 
-NF() - L<Imager::Handy/NF>
+open() - L<Imager::Files/read()> - an alias for read()
 
 
-open() - L<Imager::Files> - an alias for read()
+open_log() - L<Imager::ImageTypes/open_log()> - open the debug log.
 
 =for stopwords IPTC
 
 
 =for stopwords IPTC
 
-parseiptc() - L<Imager::Files/parseiptc> - parse IPTC data from a JPEG
+parseiptc() - L<Imager::Files/parseiptc()> - parse IPTC data from a JPEG
 image
 
 image
 
-paste() - L<Imager::Transformations/paste> - draw an image onto an image
+paste() - L<Imager::Transformations/paste()> - draw an image onto an
+image
+
+polygon() - L<Imager::Draw/polygon()>
 
 
-polygon() - L<Imager::Draw/polygon>
+polyline() - L<Imager::Draw/polyline()>
 
 
-polyline() - L<Imager::Draw/polyline>
+preload() - L<Imager::Files/preload()>
 
 
-read() - L<Imager::Files> - read a single image from an image file
+read() - L<Imager::Files/read()> - read a single image from an image file
 
 
-read_multi() - L<Imager::Files> - read multiple images from an image
+read_multi() - L<Imager::Files/read_multi()> - read multiple images from an image
 file
 
 file
 
-read_types() - L<Imager::Files/read_types> - list image types Imager
+read_types() - L<Imager::Files/read_types()> - list image types Imager
 can read.
 
 can read.
 
-register_filter() - L<Imager::Filters/register_filter>
+register_filter() - L<Imager::Filters/register_filter()>
+
+register_reader() - L<Imager::Files/register_reader()>
 
 
-register_reader() - L<Imager::Files/register_reader>
+register_writer() - L<Imager::Files/register_writer()>
 
 
-register_writer() - L<Imager::Files/register_writer>
+rotate() - L<Imager::Transformations/rotate()>
 
 
-rotate() - L<Imager::Transformations/rotate>
+rubthrough() - L<Imager::Transformations/rubthrough()> - draw an image
+onto an image and use the alpha channel
 
 
-rubthrough() - L<Imager::Transformations/rubthrough> - draw an image onto an
-image and use the alpha channel
+scale() - L<Imager::Transformations/scale()>
 
 
-scale() - L<Imager::Transformations/scale>
+scale_calculate() - L<Imager::Transformations/scale_calculate()>
 
 
-scale_calculate() - L<Imager::Transformations/scale_calculate>
+scaleX() - L<Imager::Transformations/scaleX()>
 
 
-scaleX() - L<Imager::Transformations/scaleX>
+scaleY() - L<Imager::Transformations/scaleY()>
 
 
-scaleY() - L<Imager::Transformations/scaleY>
+setcolors() - L<Imager::ImageTypes/setcolors()> - set palette colors
+in a paletted image
 
 
-setcolors() - L<Imager::ImageTypes/setcolors> - set palette colors in
-a paletted image
+set_file_limits() - L<Imager::Files/set_file_limits()>
 
 
-set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
+setmask() - L<Imager::ImageTypes/setmask()>
 
 
-setmask() - L<Imager::ImageTypes/setmask>
+setpixel() - L<Imager::Draw/setpixel()>
 
 
-setpixel() - L<Imager::Draw/setpixel>
+setsamples() - L<Imager::Draw/setsamples()>
 
 
-setsamples() - L<Imager::Draw/setsamples>
+setscanline() - L<Imager::Draw/setscanline()>
 
 
-setscanline() - L<Imager::Draw/setscanline>
+settag() - L<Imager::ImageTypes/settag()>
 
 
-settag() - L<Imager::ImageTypes/settag>
+string() - L<Imager::Draw/string()> - draw text on an image
 
 
-string() - L<Imager::Draw/string> - draw text on an image
+tags() -  L<Imager::ImageTypes/tags()> - fetch image tags
 
 
-tags() -  L<Imager::ImageTypes/tags> - fetch image tags
+to_paletted() -  L<Imager::ImageTypes/to_paletted()>
 
 
-to_paletted() -  L<Imager::ImageTypes/to_paletted>
+to_rgb16() - L<Imager::ImageTypes/to_rgb16()>
 
 
-to_rgb16() - L<Imager::ImageTypes/to_rgb16>
+to_rgb8() - L<Imager::ImageTypes/to_rgb8()>
 
 
-to_rgb8() - L<Imager::ImageTypes/to_rgb8>
+to_rgb_double() - L<Imager::ImageTypes/to_rgb_double()> - convert to
+double per sample image.
 
 
-transform() - L<Imager::Engines/"transform">
+transform() - L<Imager::Engines/"transform()">
 
 
-transform2() - L<Imager::Engines/"transform2">
+transform2() - L<Imager::Engines/"transform2()">
 
 
-type() -  L<Imager::ImageTypes/type> - type of image (direct vs paletted)
+type() -  L<Imager::ImageTypes/type()> - type of image (direct vs paletted)
 
 
-unload_plugin() - L<Imager::Filters/unload_plugin>
+unload_plugin() - L<Imager::Filters/unload_plugin()>
 
 
-virtual() - L<Imager::ImageTypes/virtual> - 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 an image to a file
+write() - L<Imager::Files/write()> - write an image to a file
 
 
-write_multi() - L<Imager::Files> - write multiple image to an image
+write_multi() - L<Imager::Files/write_multi()> - write multiple image to an image
 file.
 
 file.
 
-write_types() - L<Imager::Files/read_types> - list image types Imager
+write_types() - L<Imager::Files/read_types()> - list image types Imager
 can write.
 
 =head1 CONCEPT INDEX
 
 animated GIF - L<Imager::Files/"Writing an animated GIF">
 
 can write.
 
 =head1 CONCEPT INDEX
 
 animated GIF - L<Imager::Files/"Writing an animated GIF">
 
-aspect ratio - L<Imager::ImageTypes/i_xres>,
-L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
+aspect ratio - C<i_xres>, C<i_yres>, C<i_aspect_only> in
+L<Imager::ImageTypes/"Common Tags">.
 
 blend - alpha blending one image onto another
 
 blend - alpha blending one image onto another
-L<Imager::Transformations/rubthrough>
+L<Imager::Transformations/rubthrough()>
 
 
-blur - L<Imager::Filters/guassian>, L<Imager::Filters/conv>
+blur - L<Imager::Filters/gaussian>, L<Imager::Filters/conv>
 
 
-boxes, drawing - L<Imager::Draw/box>
+boxes, drawing - L<Imager::Draw/box()>
 
 changes between image - L<Imager::Filters/"Image Difference">
 
 
 changes between image - L<Imager::Filters/"Image Difference">
 
-channels, combine into one image - L<Imager::Transformations/combine>
+channels, combine into one image - L<Imager::Transformations/combine()>
 
 color - L<Imager::Color>
 
 
 color - L<Imager::Color>
 
@@ -4456,22 +4683,22 @@ contrast - L<Imager::Filters/contrast>, L<Imager::Filters/autolevels>
 
 convolution - L<Imager::Filters/conv>
 
 
 convolution - L<Imager::Filters/conv>
 
-cropping - L<Imager::Transformations/crop>
+cropping - L<Imager::Transformations/crop()>
 
 CUR files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
 
 C<diff> images - L<Imager::Filters/"Image Difference">
 
 
 CUR files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
 
 C<diff> images - L<Imager::Filters/"Image Difference">
 
-dpi - L<Imager::ImageTypes/i_xres>, 
+dpi - C<i_xres>, C<i_yres> in L<Imager::ImageTypes/"Common Tags">,
 L<Imager::Cookbook/"Image spatial resolution">
 
 L<Imager::Cookbook/"Image spatial resolution">
 
-drawing boxes - L<Imager::Draw/box>
+drawing boxes - L<Imager::Draw/box()>
 
 
-drawing lines - L<Imager::Draw/line>
+drawing lines - L<Imager::Draw/line()>
 
 
-drawing text - L<Imager::Draw/string>, L<Imager::Draw/align_string>
+drawing text - L<Imager::Draw/string()>, L<Imager::Draw/align_string()>
 
 
-error message - L<"ERROR HANDLING">
+error message - L</"ERROR HANDLING">
 
 files, font - L<Imager::Font>
 
 
 files, font - L<Imager::Font>
 
@@ -4479,18 +4706,18 @@ files, image - L<Imager::Files>
 
 filling, types of fill - L<Imager::Fill>
 
 
 filling, types of fill - L<Imager::Fill>
 
-filling, boxes - L<Imager::Draw/box>
+filling, boxes - L<Imager::Draw/box()>
 
 
-filling, flood fill - L<Imager::Draw/flood_fill>
+filling, flood fill - L<Imager::Draw/flood_fill()>
 
 
-flood fill - L<Imager::Draw/flood_fill>
+flood fill - L<Imager::Draw/flood_fill()>
 
 fonts - L<Imager::Font>
 
 
 fonts - L<Imager::Font>
 
-fonts, drawing with - L<Imager::Draw/string>,
-L<Imager::Draw/align_string>, L<Imager::Font::Wrap>
+fonts, drawing with - L<Imager::Draw/string()>,
+L<Imager::Draw/align_string()>, L<Imager::Font::Wrap>
 
 
-fonts, metrics - L<Imager::Font/bounding_box>, L<Imager::Font::BBox>
+fonts, metrics - L<Imager::Font/bounding_box()>, L<Imager::Font::BBox>
 
 fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
 
 
 fonts, multiple master - L<Imager::Font/"MULTIPLE MASTER FONTS">
 
@@ -4500,15 +4727,15 @@ L<Imager::Filters/gradgen>
 
 GIF files - L<Imager::Files/"GIF">
 
 
 GIF files - L<Imager::Files/"GIF">
 
-GIF files, animated - L<Imager::File/"Writing an animated GIF">
+GIF files, animated - L<Imager::Files/"Writing an animated GIF">
 
 gradient fill - L<Imager::Fill/"Fountain fills">,
 L<Imager::Filters/fountain>, L<Imager::Fountain>,
 L<Imager::Filters/gradgen>
 
 
 gradient fill - L<Imager::Fill/"Fountain fills">,
 L<Imager::Filters/fountain>, L<Imager::Fountain>,
 L<Imager::Filters/gradgen>
 
-gray scale, convert image to - L<Imager::Transformations/convert>
+gray scale, convert image to - L<Imager::Transformations/convert()>
 
 
-guassian blur - L<Imager::Filters/guassian>
+gaussian blur - L<Imager::Filters/gaussian>
 
 hatch fills - L<Imager::Fill/"Hatched fills">
 
 
 hatch fills - L<Imager::Fill/"Hatched fills">
 
@@ -4521,11 +4748,11 @@ JPEG - L<Imager::Files/"JPEG">
 
 limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
 
 
 limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
 
-lines, drawing - L<Imager::Draw/line>
+lines, drawing - L<Imager::Draw/line()>
 
 matrix - L<Imager::Matrix2d>, 
 
 matrix - L<Imager::Matrix2d>, 
-L<Imager::Transformations/"Matrix Transformations">,
-L<Imager::Font/transform>
+L<Imager::Engines/"Matrix Transformations">,
+L<Imager::Font/transform()>
 
 metadata, image - L<Imager::ImageTypes/"Tags">
 
 
 metadata, image - L<Imager::ImageTypes/"Tags">
 
@@ -4536,11 +4763,11 @@ noise, filter - L<Imager::Filters/noise>
 noise, rendered - L<Imager::Filters/turbnoise>,
 L<Imager::Filters/radnoise>
 
 noise, rendered - L<Imager::Filters/turbnoise>,
 L<Imager::Filters/radnoise>
 
-paste - L<Imager::Transformations/paste>,
-L<Imager::Transformations/rubthrough>
+paste - L<Imager::Transformations/paste()>,
+L<Imager::Transformations/rubthrough()>
 
 
-pseudo-color image - L<Imager::ImageTypes/to_paletted>,
-L<Imager::ImageTypes/new>
+pseudo-color image - L<Imager::ImageTypes/to_paletted()>,
+L<Imager::ImageTypes/new()>
 
 =for stopwords posterize
 
 
 =for stopwords posterize
 
@@ -4550,37 +4777,44 @@ PNG files - L<Imager::Files>, L<Imager::Files/"PNG">
 
 PNM - L<Imager::Files/"PNM (Portable aNy Map)">
 
 
 PNM - L<Imager::Files/"PNM (Portable aNy Map)">
 
-rectangles, drawing - L<Imager::Draw/box>
+rectangles, drawing - L<Imager::Draw/box()>
 
 
-resizing an image - L<Imager::Transformations/scale>, 
-L<Imager::Transformations/crop>
+resizing an image - L<Imager::Transformations/scale()>, 
+L<Imager::Transformations/crop()>
 
 RGB (SGI) files - L<Imager::Files/"SGI (RGB, BW)">
 
 saving an image - L<Imager::Files>
 
 
 RGB (SGI) files - L<Imager::Files/"SGI (RGB, BW)">
 
 saving an image - L<Imager::Files>
 
-scaling - L<Imager::Transformations/scale>
+scaling - L<Imager::Transformations/scale()>
+
+security - L<Imager::Security>
 
 SGI files - L<Imager::Files/"SGI (RGB, BW)">
 
 sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
 
 
 SGI files - L<Imager::Files/"SGI (RGB, BW)">
 
 sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
 
-size, image - L<Imager::ImageTypes/getwidth>,
-L<Imager::ImageTypes/getheight>
+size, image - L<Imager::ImageTypes/getwidth()>,
+L<Imager::ImageTypes/getheight()>
 
 
-size, text - L<Imager::Font/bounding_box>
+size, text - L<Imager::Font/bounding_box()>
 
 tags, image metadata - L<Imager::ImageTypes/"Tags">
 
 
 tags, image metadata - L<Imager::ImageTypes/"Tags">
 
-text, drawing - L<Imager::Draw/string>, L<Imager::Draw/align_string>,
+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>
 
 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>
+text, measuring - L<Imager::Font/bounding_box()>, L<Imager::Font::BBox>
+
+threads - L<Imager::Threads>
 
 tiles, color - L<Imager::Filters/mosaic>
 
 
 tiles, color - L<Imager::Filters/mosaic>
 
+transparent images - L<Imager::ImageTypes>,
+L<Imager::Cookbook/"Transparent PNG">
+
 =for stopwords unsharp
 
 unsharp mask - L<Imager::Filters/unsharpmask>
 =for stopwords unsharp
 
 unsharp mask - L<Imager::Filters/unsharpmask>
@@ -4589,15 +4823,6 @@ watermark - L<Imager::Filters/watermark>
 
 writing an image to a file - L<Imager::Files>
 
 
 writing an image to a file - L<Imager::Files>
 
-=head1 THREADS
-
-Imager doesn't support perl threads.
-
-Imager has limited code to prevent double frees if you create images,
-colors etc, and then create a thread, but has no code to prevent two
-threads entering Imager's error handling code, and none is likely to
-be added.
-
 =head1 SUPPORT
 
 The best place to get help with Imager is the mailing list.
 =head1 SUPPORT
 
 The best place to get help with Imager is the mailing list.
@@ -4665,16 +4890,32 @@ Tracker.
 
 =head2 Patches
 
 
 =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.
 
 
 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
 
 =head1 AUTHOR
 
-Tony Cook <tony@imager.perl.org> is the current maintainer for Imager.
+Tony Cook <tonyc@cpan.org> is the current maintainer for Imager.
 
 Arnar M. Hrafnkelsson is the original author of Imager.
 
 
 Arnar M. Hrafnkelsson is the original author of Imager.
 
@@ -4688,9 +4929,10 @@ Imager is licensed under the same terms as perl itself.
 =for stopwords
 makeblendedfont Fontforge
 
 =for stopwords
 makeblendedfont Fontforge
 
-A test font, FT2/fontfiles/MMOne.pfb, contains a Postscript operator
-definition copyrighted by Adobe.  See adobe.txt in the source for
-license information.
+A test font, generated by the Debian packaged Fontforge,
+F<FT2/fontfiles/MMOne.pfb>, contains a Postscript operator definition
+copyrighted by Adobe.  See F<adobe.txt> in the source for license
+information.
 
 =head1 SEE ALSO
 
 
 =head1 SEE ALSO
 
@@ -4706,6 +4948,10 @@ L<Affix::Infix2Postfix>(3), L<Parse::RecDescent>(3)
 
 Other perl imaging modules include:
 
 
 Other perl imaging modules include:
 
-L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3).
+L<GD>(3), L<Image::Magick>(3), L<Graphics::Magick>(3),
+L<Prima::Image>, L<IPA>.
+
+If you're trying to use Imager for array processing, you should
+probably using L<PDL>.
 
 =cut
 
 =cut