[gimp-perl] Test and document PDL in plugin mode. Bug 725619



commit 4a01b925ce43e620812011ecec4d31b838fc317f
Author: Ed J <m8r-35s8eo mailinator com>
Date:   Thu Apr 10 06:06:38 2014 +0100

    Test and document PDL in plugin mode. Bug 725619

 Gimp.pm                |   59 ++++++++-------
 Gimp/ColorDB.pm        |    2 +-
 Gimp/Config.pm.in      |    5 +-
 Gimp/Fu.pm             |  147 ++++++++++++++++++++++++-------------
 Gimp/Lib.xs            |   53 ++-----------
 Gimp/Makefile.PL       |    5 +-
 Gimp/Pixel.pod         |  119 ------------------------------
 Gimp/PixelRgn.pod      |  191 ++++++++++++++++++++++++++++++++++++++++++++++++
 MANIFEST               |    3 +-
 Makefile.PL            |    2 -
 Net/Net.xs             |    2 +-
 TODO                   |    2 -
 UI/Makefile.PL         |    2 +-
 UI/UI.pm               |    5 +-
 config.pl              |   17 +---
 examples/Makefile.PL   |    8 +-
 examples/colorhtml     |  172 +++++++++++++++++++++----------------------
 examples/dataurl       |  150 ++++++++++++++++++--------------------
 examples/dialogtest    |   50 +++++++++++++
 examples/ditherize     |    2 +-
 examples/exceptiontest |   30 ++++++++
 examples/gouge         |    4 +-
 examples/innerbevel    |    2 +-
 examples/warp-sharp    |    2 +-
 t/gimpsetup.pl         |    8 +-
 t/pdl.t                |  151 ++++++++++++++++++++++++++++++++++++++
 t/supplied.t           |  112 ++++++++++++++++------------
 typemap.pdl            |   14 ----
 utils/gimpdoc          |    6 +-
 29 files changed, 810 insertions(+), 515 deletions(-)
---
diff --git a/Gimp.pm b/Gimp.pm
index cf954b8..a9ec9b2 100644
--- a/Gimp.pm
+++ b/Gimp.pm
@@ -428,7 +428,7 @@ push @Gimp::Channel::ISA, qw(Gimp::Drawable);
 push @Gimp::Layer::ISA, qw(Gimp::Drawable);
 
 # "C"-Classes
-_pseudoclass qw(GimpDrawable   gimp_drawable_);
+_pseudoclass qw(GimpDrawable   gimp_gdrawable_);
 _pseudoclass qw(PixelRgn       gimp_pixel_rgn_);
 _pseudoclass qw(Tile           gimp_tile_);
 
@@ -442,19 +442,16 @@ _pseudoclass qw(Gradients gimp_gradients_);
 _pseudoclass qw(Patterns       gimp_patterns_);
 _pseudoclass qw(Pattern                gimp_pattern_);
 
-package Gimp::Tile;
-
-unshift (@Tile::ISA, "Gimp::Tile");
-
+{
 package Gimp::PixelRgn;
 
-push(@PixelRgn::ISA, "Gimp::PixelRgn");
-
 sub new($$$$$$$$) {
    shift;
-   init Gimp::PixelRgn(@_);
+   Gimp::PixelRgn->init(@_);
+}
 }
 
+{
 package Gimp::Parasite;
 
 sub is_type($$)                { $_[0]->[0] eq $_[1] }
@@ -469,13 +466,16 @@ sub compare($$)           { $_[0]->[0] eq $_[1]->[0] and
                          $_[0]->[1] eq $_[1]->[1] and
                          $_[0]->[2] eq $_[1]->[2] }
 sub new($$$$)          { shift; [ _] }
+}
 
+{
 package Gimp::run_mode;
 
 # I guess I now use almost every perl feature available ;)
 
 use overload fallback => 1,
              '0+'     => sub { ${$_[0]} };
+}
 
 =head1 NAME
 
@@ -578,7 +578,7 @@ most objects.
 =item *
 Use either a plain pdb (scheme-like) interface or an object-oriented
 syntax, i.e. C<gimp_image_new(600,300,RGB)> is the same as C<new
-Image(600,300,RGB)>
+Gimp::Image(600,300,RGB)>
 
 =item *
 Networked plug-ins look/behave the same as those running from within gimp.
@@ -588,8 +588,9 @@ Gimp::Fu will start GIMP for you, if it cannot connect to an existing
 GIMP process.
 
 =item *
-You can access the pixel-data functions using piddles (see L<PDL>) giving
-the same level of control as a C plug-in, with a data language wrapper.
+You can access the pixel-data functions using piddles (see
+L<Gimp::PixelRgn>) giving the same level of control as a C plug-in,
+with a data language wrapper.
 
 =item *
 Over 50 example scripts to give you a good starting point, or use as is.
@@ -628,7 +629,7 @@ The architecture may be visualised like this:
 
 This has certain consequences; native GIMP objects like images and layers
 obviously persist between Perl method calls, but C<libgimp> entities such
-as C<GimpDrawable>, with the perl interface C<Gimp::PixelRgn>, require
+as C<GimpDrawable>, with the perl interface L<Gimp::PixelRgn>, require
 special handling. Currently they do not work when used over C<Gimp::Net>.
 
 =head1 OUTLINE OF A GIMP PLUG-IN
@@ -694,7 +695,7 @@ You can get a listing and description of every PDB function by starting
 the B<DB Browser> extension in GIMP's B<Xtns> menu (but remember to change
  "-" (dashes) to  "_" (underscores)).
 
-B<libgimp> functions can't be traced (and won't be traceable in the
+C<libgimp> functions can't be traced (and won't be traceable in the
 foreseeable future).
 
 To call pdb functions (or equivalent libgimp functions), just treat them like
@@ -713,7 +714,7 @@ using OO-Syntax:
  Gimp::Palette->set_foreground('#1230f0');
 
 As you can see, you can also drop part of the name prefixes with this
-syntax, so its actually shorter to write and hopefully clearer to read.
+syntax, so it's actually shorter to write and hopefully clearer to read.
 
 =head1 SPECIAL FUNCTIONS
 
@@ -752,7 +753,7 @@ This function has not been well tested.
 This is how to use Gimp-Perl in "net mode". Previous versions of this
 package required a call to Gimp::init. This is no longer necessary. The
 technical reason for this change is that when C<Gimp.pm> loads, it must
-connect to GIMP to load its constants, like PDB_INT32.
+connect to GIMP to load its constants, like C<PDB_INT32>.
 
 =item Gimp::lock(), Gimp::unlock()
 
@@ -784,24 +785,25 @@ calling a perl subroutine of the same name as the GIMP function.
 
 The first argument is the name of a registered gimp function that you want
 to overwrite ('perl_fu_make_something'), and the second argument can be
-either a name of the corresponding perl sub ('Elsewhere::make_something')
-or a code reference (\&my_make).
+either a name of the corresponding perl sub (C<'Elsewhere::make_something'>)
+or a code reference (C<\&my_make>).
 
 =item Gimp::canonicalize_colour/Gimp::canonicalize_color
 
 Take in a color specifier in a variety of different formats, and return
-a valid gimp color specifier, consisting of 3 or 4 numbers in the range
-between 0 and 1.0.
+a valid GIMP color specifier (a C<GimpRGB>), consisting of 3 or 4 numbers
+in the range between 0 and 1.0.
 
 For example:
 
- $color = canonicalize_colour ("#ff00bb");
- $color = canonicalize_colour ([255,255,34]);
- $color = canonicalize_colour ([255,255,34,255]);
- $color = canonicalize_colour ([1.0,1.0,0.32]);
- $color = canonicalize_colour ('red');
+ $color = canonicalize_colour ("#ff00bb"); # html format
+ $color = canonicalize_colour ([255,255,34]); # RGB
+ $color = canonicalize_colour ([255,255,34,255]); # RGBA
+ $color = canonicalize_colour ([1.0,1.0,0.32]); # actual GimpRGB
+ $color = canonicalize_colour ('red'); # uses the color database
 
-Note that bounds checking is excessively lax; this assumes relatively good input
+Note that bounds checking is somewhat lax; this assumes relatively
+good input.
 
 =back
 
@@ -836,7 +838,7 @@ are documented in L<Gimp::Pixel>, to keep this manual page short.
 
 =item gimp_call_procedure(procname, arguments...)
 
-This function is actually used to implement the fancy stuff. Its your basic
+This function is actually used to implement the fancy stuff. It's your basic
 interface to the PDB. Every function call is eventually done through his
 function, i.e.:
 
@@ -898,7 +900,10 @@ How to debug your scripts:
 If set to true, will make Gimp say what it's doing on STDOUT. It will
 also stop L<Gimp::Net>'s normal behaviour of the server-side closing
 STDIN, STDOUT and STDERR. If you want it to be set during loading Gimp.pm,
-make sure to do so in a C<BEGIN> block.
+make sure to do so in a prior C<BEGIN> block:
+
+ BEGIN { $Gimp::verbose = 1; }
+ use Gimp;
 
 =item Gimp::set_trace (tracemask)
 
diff --git a/Gimp/ColorDB.pm b/Gimp/ColorDB.pm
index 804ea47..21bae5d 100644
--- a/Gimp/ColorDB.pm
+++ b/Gimp/ColorDB.pm
@@ -32,7 +32,7 @@ sub canonicalize_colour {
       @loc_col = map {$_ = ($_>1) ? $_/255.0 : $_} @loc_col;
       return [ loc_col];
    } elsif (
-      $_[0] =~ /^#([0-9a-fA-F]{2,2})([0-9a-fA-F]{2,2})([0-9a-fA-F]{2,2})$/
+      $_[0] =~ /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
    ) {
       # convert hex specfier of #xxyyzz
       return [ map { eval "0x$_/255.0" } ($1, $2, $3) ];
diff --git a/Gimp/Config.pm.in b/Gimp/Config.pm.in
index da999c9..bb0946e 100644
--- a/Gimp/Config.pm.in
+++ b/Gimp/Config.pm.in
@@ -1,7 +1,5 @@
 package Gimp::Config;
 
-=cut
-
 =head1 NAME
 
   Gimp::Config - config options found during configure time.
@@ -15,8 +13,7 @@ C<$Gimp::Config{KEY}>. Some important keys are:
 
   IN_GIMP      => true when gimp-perl was part of the Gimp distribution.
   GIMP         => the path of the gimp executable
-  prefix       => the installation prefix
-  bindir       => paths where gimp binaries are installed
+  GIMPTOOL     => the path of the gimptool executable
   gimpplugindir        => the gimp plug-in directory (without the /plug-ins-suffix)
 
 =head1 SEE ALSO
diff --git a/Gimp/Fu.pm b/Gimp/Fu.pm
index 1dd3052..a476370 100644
--- a/Gimp/Fu.pm
+++ b/Gimp/Fu.pm
@@ -298,8 +298,10 @@ Gimp::on_net {
    }
 
    # Go for it
-   $perl_sub->(($interact>0 ? &Gimp::RUN_FULLINTERACTIVE : &Gimp::RUN_NONINTERACTIVE),
-               @args);
+   $perl_sub->(
+      ($interact>0 ? &Gimp::RUN_FULLINTERACTIVE : &Gimp::RUN_NONINTERACTIVE),
+      @args
+   );
 };
 
 Gimp::on_query {
@@ -307,8 +309,7 @@ Gimp::on_query {
    script:
    for(@scripts) {
       my($perl_sub,$function,$blurb,$help,$author,$copyright,$date,
-         $menupath,$imagetypes,$params,$results,$code,$type,
-         $defargs)= $_;
+         $menupath,$imagetypes,$params,$results,$code,$type)= $_;
 
       for (@$results) {
          next if ref $_;
@@ -344,6 +345,7 @@ Gimp::on_query {
          $_->[0]=datatype($_->[3],@{$_->[4]}) if $_->[0] == PF_ADJUSTMENT;
       }
 
+      warn "$$-Gimp::Fu gimp_install_procedure params (@$params)" if $Gimp::verbose;
       Gimp->install_procedure(
        $function,
        $blurb,
@@ -425,17 +427,53 @@ I recommend ISO format (yyyymmdd or yyyy-mm-dd). Default value is "=pod(DATE)".
 
 =item menu path
 
-The menu entry GIMP should create. It should start either with <Image>, if
-you want an entry in the image menu (the one that opens when right-clicking
-an image), <Toolbox>/Xtns for the Xtns menu, or <None> if the script does
-not need to have a menu entry.
+The menu entry GIMP should create. B<Note> this is different from
+Script-Fu, which asks only for which B<menu> in which to place the entry,
+using the second argument to (its equivalent of) C<register> as the actual
+label; here, you spell out the B<full> menu entry including label name.
+
+It should start with one of the following:
+
+=over 2
+
+=item <Image>/*/Plugin-menu-label
+
+If the plugin works on or produces an image.
+
+If the "image types" argument (see below) is defined and non-zero-length,
+L<Gimp::Fu> will supply a C<PF_IMAGE> and C<PF_DRAWABLE> as the first
+two parameters to the plugin. If the plugin is intending to create
+an image rather than to work on an existing one, make sure you supply
+C<undef> or C<""> as the "image types".
+
+In any case, the plugin will be installed in the specified menu location;
+almost always under C<File/Create> or C<Filters>.
+
+=item <Save>/FILETYPE
+
+If the script is an export-handler. Make sure you also have something like:
+
+ Gimp::on_query {
+   Gimp->register_save_handler("file_filetype_save", "filetype", "");
+ };
+
+=item <Toolbox>/Xtns/Label
+
+This will place the plugin in a special section (as of GIMP 2.8) of the
+"Filters" menu. This type of plugin will also not have the image and
+drawable passed, nor will it require it.
+
+=item <None>
+
+If the script does not need to have a menu entry.
+
+=back
 
 =item image types
 
 The types of images your script will accept. Examples are "RGB", "RGB*",
 "GRAY, RGB" etc... Most scripts will want to use "*", meaning "any type".
-For scripts registering under <Toolbox>/Xtns the script should use the
-empty string "".
+Either C<undef> or "" will mean "none".
 
 =item the parameter array
 
@@ -448,11 +486,12 @@ Each array element has the form C<[type, name, description, default_value,
 extra_args]>.
 
 <Image>-type plugins get two additional parameters, image (C<PF_IMAGE>)
-and drawable (C<PF_DRAWABLE>) B<if and only if> the menu path does not start
-C<E<lt>ImageE<gt>/File/Create>. Do not specify these yourself. Also, the
-C<run_mode> argument is never given to the script but its value can be
-accessed in the package-global C<$run_mode>. The B<name> is used in the
-dialog box as a hint. The B<description> will be used as a tooltip.
+and drawable (C<PF_DRAWABLE>) B<if and only if> the "image types"
+are defined and non-zero-length. Do not specify these yourself - see
+the C<menupath> entry above. Also, the C<run_mode> argument is never
+given to the script but its value can be accessed in the package-global
+C<$Gimp::Fu::run_mode>. The B<name> is used in the dialog box as a hint. The
+B<description> will be used as a tooltip.
 
 See the section PARAMETER TYPES for the supported types.
 
@@ -608,36 +647,33 @@ sub register($$$$$$$$$;@) {
    no strict 'refs';
    my ($function, $blurb, $help, $author, $copyright, $date,
        $menupath, $imagetypes, $params) = splice @_, 0, 9;
-   my ($results, $code, $type, $defargs);
+   my ($results, $code, $type);
 
    $results  = (ref $_[0] eq "ARRAY") ? shift : [];
    $code = shift;
 
-   for($menupath) {
-      if (/^<Image>\//) {
-         $type = &Gimp::PLUGIN;
-         unshift @$params, @image_params unless m#^<Image>/File/Create#;
-         $defargs = @image_params;
-      } elsif (/^<Load>\//) {
-         $type = &Gimp::PLUGIN;
-         unshift @$params, @load_params;
-         unshift @$results, @load_retvals;
-         $defargs = @load_params;
-      } elsif (/^<Save>\//) {
-         $type = &Gimp::PLUGIN;
-         unshift @$params, @save_params;
-         $defargs = @save_params;
-      } elsif (/^<Toolbox>\//) {
-         $type = &Gimp::PLUGIN;
-         $defargs = 0;
-      } elsif (/^<None>/) {
-         $type = &Gimp::PLUGIN;
-         $defargs = 0;
-      } else {
-         die __"menupath _must_ start with <Image>, <Toolbox>, <Load>, <Save> or <None>!";
+   if ($menupath =~ /^<Image>\//) {
+      $type = &Gimp::PLUGIN;
+      if (defined $imagetypes and length $imagetypes) {
+        unshift @$params, @image_params;
       }
+   } elsif ($menupath =~ /^<Load>\//) {
+      $type = &Gimp::PLUGIN;
+      unshift @$params, @load_params;
+      unshift @$results, @load_retvals;
+   } elsif ($menupath =~ /^<Save>\//) {
+      $type = &Gimp::PLUGIN;
+      unshift @$params, @save_params;
+   } elsif ($menupath =~ m#^<Toolbox>/Xtns/#) {
+      $type = &Gimp::PLUGIN;
+      undef $imagetypes;
+   } elsif ($menupath =~ /^<None>/) {
+      $type = &Gimp::PLUGIN;
+      undef $menupath;
+      undef $imagetypes;
+   } else {
+      die __"menupath _must_ start with <Image>, <Load>, <Save>, <Toolbox>/Xtns/, or <None>!";
    }
-   undef $menupath if $menupath eq "<None>";#d#
 
    @_==0 or die __"register called with too many or wrong arguments\n";
 
@@ -662,7 +698,8 @@ sub register($$$$$$$$$;@) {
       my(@pre,@defaults,@lastvals,$input_image);
 
       Gimp::ignore_functions(@Gimp::GUI_FUNCTIONS)
-       unless $run_mode == &Gimp::RUN_INTERACTIVE;
+        unless $run_mode == &Gimp::RUN_INTERACTIVE or
+               $run_mode == &Gimp::RUN_FULLINTERACTIVE;
 
       # set default arguments
       for (0..$#{$params}) {
@@ -674,34 +711,39 @@ sub register($$$$$$$$$;@) {
 
       for($menupath) {
          if (/^<Image>\//) {
-            @_ >= 2 or die __"<Image> plug-in called without both image and drawable arguments!\n";
-            @pre = (shift,shift);
-         } elsif (/^<Toolbox>\// or !defined $menupath) {
-            # valid ;)
+           if (defined $imagetypes and length $imagetypes) {
+              @_ >= 2 or die __"<Image> plug-in called without both image and drawable arguments!\n";
+              @pre = (shift,shift);
+           }
          } elsif (/^<Load>\//) {
             @_ >= 2 or die __"<Load> plug-in called without the 3 standard arguments!\n";
             @pre = (shift,shift);
          } elsif (/^<Save>\//) {
             @_ >= 4 or die __"<Save> plug-in called without the 5 standard arguments!\n";
             @pre = (shift,shift,shift,shift);
+        } elsif (m#^<Toolbox>/Xtns/#) {
+           # no-op
          } elsif (defined $_) {
-            die __"menupath _must_ start with <Image>, <Toolbox>, <Load>, <Save> or <None>!";
+           die __"menupath _must_ start with <Image>, <Load>, <Save>, <Toolbox>/Xtns/, or <None>!";
          }
       }
+      warn "perlsub: rm=$run_mode" if $Gimp::verbose;
       if ($run_mode == &Gimp::RUN_INTERACTIVE
           || $run_mode == &Gimp::RUN_WITH_LAST_VALS) {
          my $fudata = $Gimp::Data{"$function/_fu_data"};
+        if ($Gimp::verbose) {
+           require Data::Dumper;
+           warn "$$-retrieved fudata: ", Data::Dumper::Dumper($fudata);
+        }
 
          if ($run_mode == &Gimp::RUN_WITH_LAST_VALS && $fudata) {
             @_ = @$fudata;
          } else {
             if (@_) {
                # prevent the standard arguments from showing up in interact
-               my @hide = splice @$params, 0, scalar pre;
+               my @hide = splice @$params, 0, scalar @pre;
 
                my $res;
-               local $^W=0; # perl -w is braindamaged
-               # gimp is braindamaged, is doesn't deliver useful values!!
                ($res,@_)=interact($function,$blurb,$help,$params,@{$fudata});
                return unless $res;
 
@@ -723,9 +765,13 @@ sub register($$$$$$$$$;@) {
       $input_image = $_[0]   if ref $_[0]   eq "Gimp::Image";
       $input_image = $pre[0] if ref $pre[0] eq "Gimp::Image";
 
+      if ($Gimp::verbose) {
+        require Data::Dumper;
+        warn "$$-storing fudata: ", Data::Dumper::Dumper(\ _);
+      }
       $Gimp::Data{"$function/_fu_data"}=[ _];
 
-      print $function,"(",join(",",(@pre,@_)),")\n" if $Gimp::verbose;
+      print "$$-Gimp::Fu-generated sub: $function(",join(",",(@pre,@_)),")\n" if $Gimp::verbose;
 
       Gimp::set_trace ($old_trace);
       my @retvals = $code->(@pre,@_);
@@ -760,8 +806,7 @@ sub register($$$$$$$$$;@) {
 
    Gimp::register_callback($function,$perl_sub);
    push(@scripts,[$perl_sub,$function,$blurb,$help,$author,$copyright,$date,
-                  $menupath,$imagetypes,$params,$results,$code,$type,
-                  $defargs]);
+                  $menupath,$imagetypes,$params,$results,$code,$type]);
 }
 
 =cut
diff --git a/Gimp/Lib.xs b/Gimp/Lib.xs
index 165f97c..c2dfd33 100644
--- a/Gimp/Lib.xs
+++ b/Gimp/Lib.xs
@@ -5,10 +5,8 @@
 
 #include <libgimp/gimp.h>
 
-#if HAVE_PDL
 #define PDL_clean_namespace
 #include <pdlcore.h>
-#endif
 
 /* various functions allocate static buffers, STILL.  */
 #define MAX_STRING 4096
@@ -52,8 +50,6 @@
 
 static int trace = TRACE_NONE;
 
-#if HAVE_PDL
-
 typedef GimpPixelRgn GimpPixelRgn_PDL;
 
 static Core* PDL; /* Structure hold core C functions */
@@ -133,8 +129,6 @@ static pdl *redim_pdl (pdl *p, int ndim, int newsize)
   return r;
 }
 
-#endif
-
 /* set when it's safe to call gimp functions.  */
 static int gimp_is_initialized = 0;
 
@@ -351,9 +345,7 @@ static GimpPixelRgn *old_pixelrgn (SV *sv)
 
 static GimpPixelRgn *old_pixelrgn_pdl (SV *sv)
 {
-#if HAVE_PDL
   need_pdl ();
-#endif
   return old_pixelrgn (sv);
 }
 
@@ -1613,11 +1605,9 @@ PPCODE:
       sprintf (croak_str, "%s: %s", proc_name, gimp_get_pdb_error ());
     if (trace & TRACE_CALL) {
       trace_printf ("(");
-      if ((trace & TRACE_DESC) == TRACE_DESC)
-       trace_printf ("\n\t");
+      if ((trace & TRACE_DESC) == TRACE_DESC) trace_printf ("\n\t");
       trace_printf (__("EXCEPTION: \"%s\""), croak_str);
-      if ((trace & TRACE_DESC) == TRACE_DESC)
-       trace_printf ("\n\t");
+      if ((trace & TRACE_DESC) == TRACE_DESC) trace_printf ("\n\t");
       trace_printf (")\n");
     }
     goto error;
@@ -1737,10 +1727,7 @@ gimp_set_data(id, data)
        CODE:
        {
                STRLEN dlen;
-               void *dta;
-
-               dta = SvPV (data, dlen);
-
+               void *dta = SvPV (data, dlen);
                gimp_set_data (SvPV_nolen (id), dta, dlen);
        }
 
@@ -1809,8 +1796,10 @@ gimp_drawable_get(drawable_ID)
        RETVAL
 
 void
-gimp_drawable_flush(drawable)
-       GimpDrawable *  drawable
+gimp_gdrawable_flush(gdrawable)
+       GimpDrawable *  gdrawable
+       CODE:
+       gimp_drawable_flush(gdrawable);
 
 SV *
 gimp_pixel_rgn_init(gdrawable, x, y, width, height, dirty, shadow)
@@ -2070,10 +2059,8 @@ gimp_pixel_rgn_set_rect2(pr, data, x, y, w=pr->w)
        gimp_pixel_rgn_set_rect (pr, dta, x, y, w, dlen / (w*pr->bpp));
 }
 
-#if HAVE_PDL
-
 SV *
-gimp_drawable_get_tile(gdrawable, shadow, row, col)
+gimp_gdrawable_get_tile(gdrawable, shadow, row, col)
        SV *    gdrawable
        gint    shadow
        gint    row
@@ -2085,7 +2072,7 @@ gimp_drawable_get_tile(gdrawable, shadow, row, col)
        RETVAL
 
 SV *
-gimp_drawable_get_tile2(gdrawable, shadow, x, y)
+gimp_gdrawable_get_tile2(gdrawable, shadow, x, y)
        SV *    gdrawable
        gint    shadow
        gint    x
@@ -2255,28 +2242,6 @@ gimp_tile_set_data(tile,data)
        gimp_tile_ref_zero (tile);
        gimp_tile_unref (tile, 1);
 
-#else
-
-void
-gimp_pixel_rgn_data(...)
-       ALIAS:
-         gimp_drawable_get_tile        = 1
-         gimp_drawable_get_tile2       = 2
-         gimp_pixel_rgn_get_pixel      = 3
-         gimp_pixel_rgn_get_row        = 4
-         gimp_pixel_rgn_get_col        = 5
-         gimp_pixel_rgn_get_rect       = 6
-         gimp_pixel_rgn_set_pixel      = 7
-         gimp_pixel_rgn_set_row        = 8
-         gimp_pixel_rgn_set_col        = 9
-         gimp_pixel_rgn_set_rect       = 10
-         gimp_tile_get_data            = 11
-         gimp_tile_set_data            = 12
-       CODE:
-       croak (__("This module was built without support for PDL."));
-
-#endif
-
 BOOT:
 #if (GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 36))
        g_type_init();
diff --git a/Gimp/Makefile.PL b/Gimp/Makefile.PL
index 2074034..b94e062 100644
--- a/Gimp/Makefile.PL
+++ b/Gimp/Makefile.PL
@@ -1,12 +1,13 @@
 use ExtUtils::MakeMaker;
 use ExtUtils::Depends;
+require PDL::Core::Dev;
 
 require '../config.pl';
 
 my $pkg = new ExtUtils::Depends Gimp;
-$pkg->set_inc($cfg{GIMP_CFLAGS});
+$pkg->set_inc($cfg{GIMP_CFLAGS}.' '.&PDL::Core::Dev::PDL_INCLUDE);
 $pkg->set_libs("$cfg{GIMP_LIBS} $cfg{INTLLIBS}");
-$pkg->add_typemaps("$topdir/typemap", @{$cfg{pdl_typemaps}});
+$pkg->add_typemaps("$topdir/typemap", &PDL::Core::Dev::PDL_TYPEMAP);
 $pkg->add_pm(map { ($_ => "\$(INST_LIB)/Gimp/$_") } glob '*.pm');
 
 WriteMakefile(
diff --git a/Gimp/PixelRgn.pod b/Gimp/PixelRgn.pod
new file mode 100644
index 0000000..0c1c27f
--- /dev/null
+++ b/Gimp/PixelRgn.pod
@@ -0,0 +1,191 @@
+=head1 NAME
+
+Gimp::PixelRgn - how to operate on raw pixels.
+
+=head1 SYNOPSIS
+
+  use Gimp;
+  use PDL; # to do sensible things with the pixels
+  my $i = Gimp::Image->new(10,10,RGB);
+  my $l = $i->layer_new(10,10,RGBA_IMAGE,"new layer",100,VALUE_MODE);
+  $i->insert_layer($l,0,0);
+  my $gd = $l->get;
+  my $region = $gd->pixel_rgn(0,0,10,10,0,0);
+  my $piddle = $region->get_pixel($x,$y);
+  print "@{[ unpdl $piddle ]}\n";
+
+=head1 DESCRIPTION
+
+Perl interface to GIMP's low-level pixel-access functions. In
+Gimp-Perl (mirroring how GIMP does it), to access these functions you must
+get a C<Gimp::GimpDrawable> from a C<Gimp::Drawable>. You can then
+get either a C<Gimp::Tile> or C<Gimp::PixelRgn> object, and work with
+that. Since the tile interface is very low-level, it is not further
+documented here. The C<Gimp::PixelRgn> methods take and return L<PDL>
+objects to handle the data.
+
+=head1 COLOURS
+
+It is B<vital> to note that while GIMP uses the C<GimpRGB> format
+(each colour a floating point number from 0 to 1.0) to pass colours
+around as parameters, the pixel functions all work on bytes, integers
+with values from 0 to 255. Depending on the type of layer/image colour
+mode (e.g. RGB vs indexed), the meaning of the integers' values may
+also vary.
+
+=head1 Gimp::GimpDrawable
+
+In GIMP, drawables (also known as PARAM_DRAWABLE or Gimp::Drawable)
+are things you can draw on: layers or channels.  While in GIMP most
+functions named C<gimp_drawable_something> operate on C<drawable_ID>s,
+some functions (notably the ones operating on raw pixel data!) need a
+C<GimpDrawable> instead. In Gimp-Perl, this distinction is made explicit
+in that every function that operates on a C<GimpDrawable> is no longer
+called C<gimp_drawable_something> but C<gimp_gdrawable_something>.
+
+Every drawable has a corresponding C<GimpDrawable>, you can get it with
+the C<gimp_drawable_get> function:
+
+  my $gdrawable = $drawable->get;
+
+When the C<$gdrawable> is destroyed, it is automatically flushed &
+detached, so you don't need to do this yourself. Do not call this method
+more than once; each time it is called, GIMP makes a new internal list
+of tiles, which will cause mayhem if done more than once.
+
+=head1 Gimp::PixelRgn
+
+GIMP's C<PixelRgn>s are rectangular parts of a drawable. You can access
+single pixels, rows, columns and rectangles within these regions.
+
+To create a pixel region, you first get a GimpDrawable structure as
+above. Then you can create a C<Gimp::PixelRgn> structure:
+
+  $region = $gdrawable->pixel_rgn(0,0,50,30,0,0); # read-only
+  $region = $gdrawable->pixel_rgn(0,0,50,30,1,1); # read-write
+  $region = $gdrawable->pixel_rgn(0,0,50,30,1,0); # means undo won't work!
+
+The last two parameters are respectively C<dirty> and C<shadow>.
+Be warned that if you set C<shadow> to be true, the "shadow" tile(s)
+start out as all-zero. If you only set some, e.g. with C<set_pixel>,
+then once you have called C<$drawable-E<gt>merge_shadow($undo)>, nearly
+all the drawable's contents will be zeros.
+
+The main "use case" for this functionality is to have a read-only "source"
+region, and a writable "destination" region:
+
+  $gdrawable = $drawable->get;
+  $src = $gdrawable->pixel_rgn(0,0,50,30,0,0); # read-only
+  $dst = $gdrawable->pixel_rgn(0,0,50,30,1,1); # read-write
+  my ($x,$y,$w,$h)=($dst->x,$dst->y,$dst->w,$dst->h);
+  my $pdl = $src->get_rect($x,$y,$w,$h);
+  $pdl += 7; # trivial operation
+  $dst->data($pdl);
+  $drawable->merge_shadow(1);
+
+However, it B<is> possible to use dirty=1, shadow=0; see the "setpixel"
+example below. The GIMP API document says that it "could prevent the
+Undo-System from working as expected".
+
+The following functions return pixel data in L<PDL> objects:
+
+  $piddle = $region->get_pixel(45,60); # return the pixel at (45|60)
+  $piddle = $region->get_row(45,60,10); # return ten horizontal pixels
+  $piddle = $region->get_col(45,60,10); # same but vertically
+  $piddle = $region->get_rect(45,60,10,12); # a 10x12 rectangle
+
+And the corresponding set-functions:
+
+  $region->set_pixel($piddle,45,60);   # set pixel at (45|60)
+  $region->set_row($piddle,45,60);     # set a row
+  $region->set_col($piddle,45,60);     # set a column
+  $region->set_rect($piddle,45,60);    # set a whole rectangle
+
+Please note that (unlike the C functions they call), the size arguments
+(width and/or height) are omitted; they are calculated from the piddle.
+
+=head1 EXAMPLES
+
+Functions demonstrating getting and setting the colour of a pixel on an
+RGB layer:
+
+  use PDL;
+  sub setpixel {
+    my ($i, $l, $x, $y, $colour) = @_;
+    my @bounds = $l->bounds;
+    my $region = $l->get->pixel_rgn(@bounds,1,0); # warning! see above
+    my $piddle = pdl [ @{$colour}[0..2] ]; # remove any alpha
+    $piddle *= 255; # so it's bytes, not floats
+    $region->set_pixel($piddle, $x, $y);
+    $l->update(@bounds);
+  }
+
+  sub getpixel {
+    my ($i, $l, $x, $y) = @_;
+    my $region = $l->get->pixel_rgn($l->bounds,0,0);
+    my $piddle = $region->get_pixel($x,$y);
+    return unpdl $piddle;
+  }
+
+=head2 Iterators
+
+GIMP uses "tiles" as a way of breaking drawables into smaller
+chunks. This allows a potentially very large image to be process in
+manageable pieces. To use this, GIMP (and therefore Gimp-Perl) provides
+an "iterator" functionality to process each part of the image. This is
+best explained with a simple working example:
+
+  sub iterate {
+    my ($i, $l, $inc) = @_;
+    my @bounds = $l->bounds;
+    {
+      # in block so $src/$dst go out of scope before merge
+      my $src = Gimp::PixelRgn->new($l,@bounds,0,0);
+      my $dst = Gimp::PixelRgn->new($l,@bounds,1,1);
+      my $iter = Gimp->pixel_rgns_register($dst);
+      do {
+       my ($x,$y,$w,$h)=($dst->x,$dst->y,$dst->w,$dst->h);
+       my $pdl = $src->get_rect($x,$y,$w,$h);
+       $pdl += $inc;
+       $dst->data($pdl);
+      } while (Gimp->pixel_rgns_process($iter));
+    }
+    $l->merge_shadow(1);
+    $l->update(@bounds);
+  }
+
+The key points are:
+
+=over 2
+
+=item Iterator registration and processing
+
+Done respectively with C<$iter = Gimp-E<gt>pixel_rgns_register($dst)>
+and C<do { ... } while (Gimp-E<gt>pixel_rgns_process($iter))>.
+
+=item Block scope
+
+The source and destination C<Gimp::PixelRgn>s are in a block so
+their lexical variables go out of scope at the end, and therefore the
+objects get destroyed, and they get flushed and detached.
+
+=item Merge shadow tiles
+
+Once the operation is complete and the shadow tiles have all been set with
+the right data, C<$drawable-E<gt>merge_shadow($undo)> is called. C<$undo>
+is a boolean telling GIMP "whether to add an undo step for the operation".
+
+=back
+
+=head1 AUTHOR
+
+Ed J, based on C<Gimp::Pixel.pod> by Marc Lehmann <pcg goof com>
+
+=head1 SEE ALSO
+
+perl(1), Gimp(1), L<PDL>.
+
+These GIMP API docs are also relevant:
+
+L<http://developer.gimp.org/api/2.0/libgimp/libgimp-gimppixelrgn.html>
+L<http://developer.gimp.org/api/2.0/libgimp/libgimp-gimpdrawable.html>
diff --git a/MANIFEST b/MANIFEST
index f5a7859..3cdc3a7 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -46,6 +46,7 @@ examples/burst
 examples/centerguide
 examples/colorhtml
 examples/dataurl
+examples/dialogtest
 examples/ditherize
 examples/dots
 examples/dust
@@ -142,10 +143,10 @@ t/import.t
 t/perlplugin.t
 t/loadlib.t
 t/load.t
+t/pdl.t
 t/run.t
 t/supplied.t
 typemap
-typemap.pdl
 utils/embedxpm
 utils/gimpdoc
 utils/scm2perl
diff --git a/Makefile.PL b/Makefile.PL
index 335b664..0bfde5e 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -26,12 +26,10 @@ setver:
 EOF
 }
 
-print "writing Gimp/Config.pm... ";
 my $cfg = io("Gimp/Config.pm.in")->all or die "Gimp/Config.pm.in: $!\n";
 $Data::Dumper::Terse = 1; $Data::Dumper::Indent = 0;
 $cfg =~ s/#CFG#/join "", map { "  $_ => ".Dumper($cfg{$_}).",\n" } keys %cfg/e;
 io("Gimp/Config.pm")->print($cfg) or die "Gimp/Config.pm: $!\n";
-print "ok\n";
 
 my $pkg = new ExtUtils::Depends Gimp, Gtk2;
 $pkg->set_inc($cfg{GIMP_CFLAGS});
diff --git a/Net/Net.xs b/Net/Net.xs
index 483a56c..33fcb69 100644
--- a/Net/Net.xs
+++ b/Net/Net.xs
@@ -25,7 +25,7 @@
 #define is_dynamic(sv)                         \
        (strEQ ((sv), "Gimp::Tile")             \
          || strEQ ((sv), "Gimp::PixelRgn")     \
-         || strEQ ((sv), "Gimp::GDrawable"))
+         || strEQ ((sv), "Gimp::GimpDrawable"))
 
 static HV *object_cache;
 static int object_id = 100;
diff --git a/TODO b/TODO
index 2de5c31..afbbd60 100644
--- a/TODO
+++ b/TODO
@@ -12,8 +12,6 @@ Items as of 2014-03-31 (by Ed J)
   - https://mail.gnome.org/mailman/listinfo/gimp-developer-list
   - https://bugzilla.gnome.org/buglist.cgi?quicksearch=product:gimp-perl
 * Get gimp PDL objects working right over Gimp::Net - infrastructure is there
-  - gimp-tile set dirty automatically(!)
-* Document on_* and callback architecture
 * Restructure dirs so all libs under lib/ using ExtUtils::MakeMaker::BigHelper
 * http://search.cpan.org/dist/Glib-Object-Introspection/
 * Add a gtk2 gimp-perl console - cf http://registry.gimp.org/node/29348
diff --git a/UI/Makefile.PL b/UI/Makefile.PL
index 67df816..50aacdd 100644
--- a/UI/Makefile.PL
+++ b/UI/Makefile.PL
@@ -7,7 +7,7 @@ my $pkg = new ExtUtils::Depends Gimp, Gtk2;
 $pkg->set_inc($cfg{GIMP_CFLAGS});
 $pkg->set_libs($cfg{GIMP_LIBS});
 $pkg->add_pm('UI.pm' => '$(INST_LIBDIR)/UI.pm');
-$pkg->add_typemaps("$topdir/typemap", @pdl_typemaps);
+$pkg->add_typemaps("$topdir/typemap");
 
 WriteMakefile(
   'NAME'       => 'Gimp::UI',
diff --git a/UI/UI.pm b/UI/UI.pm
index b0f01ee..1d8294f 100644
--- a/UI/UI.pm
+++ b/UI/UI.pm
@@ -440,6 +440,7 @@ sub _instrument {
 }
 
 sub interact($$$$@) {
+   warn __PACKAGE__ . "::interact(@_)" if $Gimp::verbose;
    my $function = shift;
    my $blurb = shift;
    my $help = shift;
@@ -525,7 +526,7 @@ sub interact($$$$@) {
            push @setvals, sub { $b->set_font($_[0]) };
            push @getvals, sub { $b->get_font };
            set_tip $t $b,$desc;
-          _instrument($b);
+#         _instrument($b);
 
 if (0) {
            my $fs = new Gtk2::FontSelectionDialog sprintf __"Font Selection Dialog (%s)", $desc;
@@ -583,7 +584,7 @@ if (0) {
            push @setvals, sub { $b->set_color (defined $_[0] ? Gimp::canonicalize_color $_[0] : 
[0.8,0.6,0.1]) };
            push @getvals, sub { $b->get_color };
            set_tip $t $b,$desc;
-          _instrument($b);
+#         _instrument($b);
 
 #           my $c = new Gtk2::Button __"FG";
 #           signal_connect $c clicked => sub {
diff --git a/config.pl b/config.pl
index 8943582..652f9d1 100644
--- a/config.pl
+++ b/config.pl
@@ -1,10 +1,9 @@
 use Cwd 'abs_path';
 use ExtUtils::PkgConfig;
 
-# make $topdir be where the gimp-perl sources start
 $topdir = ".";
 $topdir .= "/.." while ! -f "$topdir/MANIFEST";
-$topdir = abs_path $topdir;
+$topdir = abs_path $topdir; # where gimp-perl sources start
 
 my %gimpcfg = ExtUtils::PkgConfig->find("gimp-2.0");
 my $gimppath = ExtUtils::PkgConfig->variable("gimp-2.0", "exec_prefix")."/bin/";
@@ -15,20 +14,14 @@ my $gimpbinname = ExtUtils::PkgConfig->modversion("gimp-2.0");
 $gimpbinname =~ s/^(\d\.\d).*/$1/; # strip off minor versions
 die "Need GIMP version at least 2.8.0\n" unless $gimpbinname >= 2.8;
 
-eval "use PDL";
-$PDL= !$@;
-require PDL::Core::Dev;
-
 %cfg = (
   GIMP => expand($gimppath . "gimp-" . $gimpbinname),
   GIMPTOOL => $gimptool,
+  gimpplugindir => $plugindir,
   GIMP_LIBS => exp_topdir($pluginlibs),
   GIMP_LIBS_NOUI => exp_topdir($gimpcfg{"libs"}),
-  gimpplugindir => $plugindir,
-  pdl_typemaps => [$PDL ? &PDL::Core::Dev::PDL_TYPEMAP : "$topdir/typemap.pdl"],
-  GIMP_CFLAGS => " -I$topdir -Ddatadir=\"\\\"".expand($datadir)."\\\"\" "
-    . ($PDL ? "-DHAVE_PDL=1 " . &PDL::Core::Dev::PDL_INCLUDE : '')
-    . ' ' . (add_ingimp(exp_topdir($gimpcfg{"cflags"}))) . ' ',
+  GIMP_CFLAGS => " -I$topdir -Ddatadir=\"\\\"".expand($datadir).'\\"" '
+    . (add_ingimp(exp_topdir($gimpcfg{"cflags"}))) . ' ',
   INTLLIBS => expand(q[]),
 );
 
@@ -44,6 +37,6 @@ sub expand {
 }
 
 sub exp_topdir { local $_ = shift; s%\$topdir%$topdir%g; $_ }
-sub add_ingimp { local $_ = shift; $_ = "-I$topdir/../.. $_"  if $IN_GIMP; $_ }
+sub add_ingimp { $IN_GIMP ? "-I$topdir/../.. $_[0]" : $_[0] }
 
 1;
diff --git a/examples/Makefile.PL b/examples/Makefile.PL
index d019151..f1a185e 100644
--- a/examples/Makefile.PL
+++ b/examples/Makefile.PL
@@ -8,6 +8,8 @@ require '../config.pl';
 @pins = qw(
   Perl-Server
   dataurl
+  dialogtest
+  exceptiontest
   colorhtml
   fade-alpha
   animate_cells
@@ -16,13 +18,13 @@ require '../config.pl';
   ditherize dots dust
   frame_filter frame_reshuffle
   glowing_steel goldenmean guidegrid guides_to_selection
-  image_tile innerbevel
+  innerbevel
   layerfuncs mirrorsplit
   map_to_gradient
   perlotine prep4gif
   repdup roundsel
   scratches sethspin stamps
-  tex-to-float translogo
+  translogo
   randomart1 randomblends
   selective_sharpen
   warp-sharp webify windify
@@ -37,7 +39,7 @@ sub plugin_target {
   my $plugin = shift;
   my $dest = '$(INST_PLUGINS)/'.basename($plugin);
   <<EOF;
-$dest : $plugin \$(FIRST_MAKEFILE) \$(INST_PLUGINS)\$(DFSEP).exists
+$dest : $plugin \$(INST_PLUGINS)\$(DFSEP).exists
        \$(NOECHO) \$(RM_F) $dest
        \$(CP) $plugin $dest
        \$(FIXIN) $dest
diff --git a/examples/colorhtml b/examples/colorhtml
index 42a50f4..9d64f0c 100755
--- a/examples/colorhtml
+++ b/examples/colorhtml
@@ -3,84 +3,81 @@
 use Gimp;
 use Gimp::Fu;
 use Gimp::UI;
-use Fcntl;
+use IO::All;
 my %replace = (
-   "&" => "&amp;",
-   "<" => "&lt;",
-   ">" => "&gt;",
+  "&" => "&amp;",
+  "<" => "&lt;",
+  ">" => "&gt;",
 );
-# read some file, make text out of it
-sub read_text {
-   my $fh = shift;
-   local $/;
-   my $data = <$fh>;
-   $data;
-}
 
-register "file_colorhtml_save",
-        "Saves the image as coloured html text",
-        "=pod",
-        "Marc Lehmann",
-        "Marc Lehmann <pcg\ goof com>",
-        "1999-11-22",
-        "<Save>/COLORHTML",
-        "*",
-        [
-         [PF_RADIO,    "character_source", "where to take the characters from", 0,
-                       [sourcecode => 0, textfile => 1, filename => 2]],
-         [PF_FILE,     "characters",     "the filename to read or the characters to use", ""],
-         [PF_STRING,   "font_size",      "the html font size (1..7 or -7 .. +7)", 2],
-         [PF_BOOL,     "use_css",        "use CSS?", 1],
-         [PF_BOOL,     "compatible",     "html-4.0 compliancy?", 1],
-         [PF_BOOL,     "closetag",       "add closing tag?", 1],
-        ],
-        sub {
-   my($img,$drawable,$filename,$filename2,$source,$text,$size,$css,$html40,$closetag) = @_;
-   my($new_img,$new_drawable);
-   my $max;
-   my $export = Gimp::UI::export_image ($new_img=$img, $new_drawable=$drawable, "COLORHTML",
-                                       EXPORT_CAN_HANDLE_RGB);
-   die __"export failed" if $export == EXPORT_CANCEL;
-   my ($w,$h) = ($new_drawable->width, $new_drawable->height);
-   Gimp->tile_cache_ntiles($w / Gimp->tile_width + 1);
-   sysopen FILE,$filename,O_CREAT|O_TRUNC|O_WRONLY or die __"Unable to open '$filename' for writing: $!\n";
-   my $cssfile;
-   if ($css) {
+register
+  "file_colorhtml_save",
+  "Saves the image as coloured html text",
+  "=pod",
+  "Marc Lehmann",
+  "Marc Lehmann <pcg\ goof com>",
+  "1999-11-22",
+  "<Save>/COLORHTML",
+  "*",
+  [
+    [PF_RADIO, "character_source", "where to take the characters from", 0,
+                 [sourcecode => 0, textfile => 1, textblock => 2]],
+    [
+      PF_FILE, "characters",
+      "the filename to read or the characters to use", ""
+    ],
+    [PF_STRING, "font_size", "the html font size (1..7 or -7 .. +7)", 2],
+    [PF_BOOL, "use_css", "use CSS?", 1],
+    [PF_BOOL, "compatible", "html-4.0 compliance?", 1],
+    [PF_BOOL, "closetag", "add closing tag?", 1],
+  ],
+  sub {
+    my($img,$drawable,$filename,$filename2,$source,$text,$size,$css,$html40,$closetag) = @_;
+    my($new_img,$new_drawable);
+    my $export = Gimp::UI::export_image(
+      $new_img=$img,
+      $new_drawable=$drawable,
+      "COLORHTML",
+      EXPORT_CAN_HANDLE_RGB
+    );
+    die __"Export cancelled" if $export == EXPORT_CANCEL;
+    my ($w,$h) = ($new_drawable->width, $new_drawable->height);
+    Gimp->tile_cache_ntiles($w / Gimp->tile_width + 1);
+    my $io = io($filename) or die __"write '$filename': $!\n";
+    my ($cssfile, $cssio);
+    if ($css) {
       if ($filename =~ /(.*)\.[^.]+$/) {
-        $cssfile = "$1.css"
+       $cssfile = "$1.css"
       } elsif ($filename =~ /\.$/) {
-        $cssfile = "${filename}css"
+       $cssfile = "${filename}css"
       } else {
-        $cssfile = "$filename.css"
+       $cssfile = "$filename.css"
       }
-      sysopen CSS,$cssfile,O_CREAT|O_TRUNC|O_WRONLY or die __"Unable to open '$cssfile' for writing: $!\n";
-   }
-   my $data;
-   if ($source == 0) {
+      $cssio = io($cssfile) or die __"write '$cssfile': $!\n";
+    }
+    my $data;
+    if ($source == 0) {
       seek DATA, 0, 0;
-      $data = read_text DATA;
-   } elsif ($source == 1) {
-      local *FILE;
-      open FILE, "<$text" or die "$text: $!\n";
-      $data = read_text FILE;
-   } elsif ($source == 2) {
+      local $/;
+      $data = <DATA>;
+    } elsif ($source == 1) {
+      $data = io($text)->all or die "$text: $!\n";
+    } elsif ($source == 2) {
       $data = $text;
-   }
-   my @data;
-   $data =~ y/\x21-\x7f//cd;
-   @data = split //, $data;
-   for (@data) {
-      s/([&<>])/$replace{$1}/e;
-   }
-   @data = ("X") x 80 unless @data;
-   my @chars;
-   my $region = $new_drawable->pixel_rgn (0, 0, $w, $h, 0, 0);
-   init Progress __"Saving '$filename' as COLORHTML...";
-   $closetag = $closetag ? "</font>" : "";
-   if ($css) {
+    }
+    my @data;
+    $data =~ y/\x21-\x7f//cd;
+    @data = split //, $data;
+    for (@data) { s/([&<>])/$replace{$1}/e; }
+    @data = ("X") x 80 unless @data;
+    my @chars;
+    my $region = $new_drawable->get->pixel_rgn(0, 0, $w, $h, 0, 0);
+    Gimp::Progress->init(__"Saving '$filename' as COLORHTML...");
+    $closetag = $closetag ? "</font>" : "";
+    if ($css) {
       my $file = $cssfile;
       $file = $1 if ($cssfile =~ m@/([^/]+)$@);
-      print FILE <<HEADER;
+      $io->print(<<HEADER);
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
@@ -91,20 +88,21 @@ register "file_colorhtml_save",
 <body><pre>
 HEADER
      $size = 8 + ($size - 2) * 2;
-     print CSS <<HEADER;
+     $cssio->print(<<HEADER);
 body {
-   width: 100%;
-   font-weight: bold;
-   font-family: Courier, "Courier New", "Andale Mono", Monaco, monospace;
-   font-size: ${size}px;
-   background-color: #000000;
-   color: #ffffff;
+width: 100%;
+font-weight: bold;
+font-family: Courier, "Courier New", "Andale Mono", Monaco, monospace;
+font-size: ${size}px;
+background-color: #000000;
+color: #ffffff;
+}
 HEADER
-   } else {
-      print FILE "<html><body bgcolor=black>\n<font size=\"$size\"><pre>\n";
-   }
-   my %colors;
-   for (my $y = 0; $y < $h; $y++) {
+    } else {
+      $io->print("<html><body bgcolor=black>\n<font size=\"$size\"><pre>\n");
+    }
+    my %colors;
+    for (my $y = 0; $y < $h; $y++) {
       my $pel = $region->get_row2 (0, $y, $w);
       push @chars,@data while @chars < $w;
       if ($css) {
@@ -113,7 +111,7 @@ HEADER
         }ges;
         while ($pel =~ /"N([0-9a-fA-F]{6})"/g) {
             my $color = $1;
-            print CSS "span.N$color { color: #$color; background-color: #000000; }\n" unless exists 
$colors{$color};
+            $cssio->print("span.N$color { color: #$color; background-color: #000000; }\n") unless exists 
$colors{$color};
             $colors{$color}++;
         }
       } elsif ($html40) {
@@ -126,13 +124,13 @@ HEADER
         }ges;
       }
 
-      print FILE $pel,"\n";
-      update Progress $y/$h;
-   }
-   print FILE "</pre>\n</html>\n";
-   $new_img->delete if $export == EXPORT_EXPORT;
-   ();
-};
+      $io->print($pel,"\n");
+      Gimp::Progress->update($y/$h);
+    }
+    $io->print("</pre>\n</html>\n");
+    $new_img->delete if $export == EXPORT_EXPORT;
+    ();
+  };
 
 Gimp::on_query {
    Gimp->register_save_handler("file_colorhtml_save", "colorhtml", "");
diff --git a/examples/dataurl b/examples/dataurl
index 045a747..c5de4ef 100755
--- a/examples/dataurl
+++ b/examples/dataurl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/local/bin/perl
 
 eval 'exec /usr/bin/perl  -S $0 ${1+"$@"}'
     if 0; # not running under some shell
@@ -19,85 +19,75 @@ sub encode_base64($) {
     $res;
 }
 
-register "file_dataurl_save",
-         "Saves the image as many small tiles using data:-urls",
-         "=pod",
-         "Marc Lehmann",
-         "Marc Lehmann <pcg\ goof com>",
-         "1999-11-20",
-         "<Save>/DATAURL",
-         "*",
-         [
-          [PF_SPINNER, "tile_x",       "tile width",   32, [0, 8192, 1, 10]],
-          [PF_SPINNER, "tile_y",       "tile height",  32, [0, 8192, 1, 10]],
-          [PF_RADIO,   "filetype",     "underlying file type", 0,
-                        [GIF => 0, JFIF => 1, PNG => 2]],
-         ],
-         sub {
-   my($img,$drawable,$filename,$filename2,$tx,$ty,$type) = @_;
-   my($new_img,$new_drawable);
-   my $max;
-   my $export = Gimp::UI::export_image ($new_img=$img, $new_drawable=$drawable, "DATAURL",
-                                        $type==0 ? EXPORT_CAN_HANDLE_INDEXED|EXPORT_CAN_HANDLE_ALPHA
-                                      : $type==1 ? EXPORT_CAN_HANDLE_RGB|EXPORT_CAN_HANDLE_GRAY
-                                      : $type==2 ? 
EXPORT_CAN_HANDLE_RGB|EXPORT_CAN_HANDLE_GRAY|EXPORT_CAN_HANDLE_INDEXED
-                                      :            0 );
-   die __"export failed" if $export == EXPORT_CANCEL;
-
-   my ($w,$h) = ($new_drawable->width, $new_drawable->height);
-
-   my $tmp = Gimp->temp_name(".img~");
-
-   sysopen FILE,$filename,O_CREAT|O_TRUNC|O_WRONLY or die __"Unable to open '$filename' for writing: $!\n";
-
-   print FILE "<html><body>\n";
-
-   init Progress __"Saving '$filename' as DATAURL...";
-
-   my $media = $type==0 ? "gif"
-             : $type==1 ? "jpeg"
-             : $type==2 ? "png"
-             :            "";
-
-   print FILE "<table width=$w cellspacing=0 cellpadding=0 border=0>";
-   for(my $y=0; $y<$h; $y+=$ty) {
-      my $wy = $h-$y < $ty ? $h-$y : $ty;
-      print FILE "<tr>";
-      for(my $x=0; $x<$w; $x+=$tx) {
-         my $wx = $w-$x < $tx ? $w-$x : $tx;
-
-         my $img = $new_img->duplicate;
-         $img->crop($wx,$wy,$x,$y);
-         ($img->get_layers)[0]->file_gif_save  (($tmp)x2, 0, 0, 0, 0)                   if $type==0;
-         ($img->get_layers)[0]->file_jpeg_save (($tmp)x2, 0.7, 0, 1, 0, "", 0, 1, 0, 0) if $type==1;
-         ($img->get_layers)[0]->file_png_save  (($tmp)x2, 0, 7, 0, 0, 0, 0, 0)          if $type==2;
-         $img->delete;
-
-         my $data = do {
-            local(*TEMP,$/);
-            open TEMP, "<$tmp" or die __"Unable to read temporary image tile $tmp: $!";
-            <TEMP>;
-         };
-         unlink $tmp;
-
-         $url = "data:image/$media;base64,".(encode_base64 $data);
-         $max = length($url) if length($url) > $max;
-
-         print FILE "<td><img src=\"", $url, "\">";
-
-         update Progress (($y*$w+$x*$ty)/($w*$h));
+register
+   "file_dataurl_save",
+   "Saves the image as many small tiles using data:-urls",
+   "=pod",
+   "Marc Lehmann",
+   "Marc Lehmann <pcg\ goof com>",
+   "1999-11-20",
+   "<Save>/DATAURL",
+   "*",
+   [
+    [PF_SPINNER,       "tile_x",       "tile width",   32, [0, 8192, 1, 10]],
+    [PF_SPINNER,       "tile_y",       "tile height",  32, [0, 8192, 1, 10]],
+    [PF_RADIO, "filetype",     "underlying file type", 0,
+                 [GIF => 0, JFIF => 1, PNG => 2]],
+   ],
+   sub {
+      my($img,$drawable,$filename,$filename2,$tx,$ty,$type) = @_;
+      my($new_img,$new_drawable);
+      my $max;
+      my $export = Gimp::UI::export_image(
+        $new_img=$img, $new_drawable=$drawable,
+        "DATAURL",
+        $type==0 ? EXPORT_CAN_HANDLE_INDEXED|EXPORT_CAN_HANDLE_ALPHA
+        : $type==1 ? EXPORT_CAN_HANDLE_RGB|EXPORT_CAN_HANDLE_GRAY
+        : $type==2 ? EXPORT_CAN_HANDLE_RGB|EXPORT_CAN_HANDLE_GRAY|EXPORT_CAN_HANDLE_INDEXED
+        : 0
+      );
+      die __"export failed" if $export == EXPORT_CANCEL;
+      my ($w,$h) = ($new_drawable->width, $new_drawable->height);
+      my $tmp = Gimp->temp_name(".img~");
+      local *FILE;
+      sysopen FILE,$filename,O_CREAT|O_TRUNC|O_WRONLY or die __"Unable to open '$filename' for writing: 
$!\n";
+      print FILE "<html><body>\n";
+      Gimp::Progress->init(__"Saving '$filename' as DATAURL...");
+      my $media = $type==0 ? "gif"
+               : $type==1 ? "jpeg"
+               : $type==2 ? "png"
+               :            "";
+      print FILE "<table width=$w cellspacing=0 cellpadding=0 border=0>";
+      for (my $y=0; $y<$h; $y+=$ty) {
+        my $wy = $h-$y < $ty ? $h-$y : $ty;
+        print FILE "<tr>";
+        for(my $x=0; $x<$w; $x+=$tx) {
+           my $wx = $w-$x < $tx ? $w-$x : $tx;
+           my $img = $new_img->duplicate;
+           $img->crop($wx,$wy,$x,$y);
+           ($img->get_layers)[0]->file_gif_save  (($tmp)x2, 0, 0, 0, 0)                   if $type==0;
+           ($img->get_layers)[0]->file_jpeg_save (($tmp)x2, 0.7, 0, 1, 0, "", 0, 1, 0, 0) if $type==1;
+           ($img->get_layers)[0]->file_png_save  (($tmp)x2, 0, 7, 0, 0, 0, 0, 0)          if $type==2;
+           $img->delete;
+           my $data = do {
+              local(*TEMP,$/);
+              open TEMP, "<$tmp" or die __"Unable to read temporary image tile $tmp: $!";
+              <TEMP>;
+           };
+           unlink $tmp;
+           $url = "data:image/$media;base64,".(encode_base64 $data);
+           $max = length($url) if length($url) > $max;
+           print FILE "<td><img src=\"", $url, "\">";
+           Gimp::Progress->update(($y*$w+$x*$ty)/($w*$h));
+        }
       }
-   }
-
-   print FILE "</table>\n";
-   print FILE "</html>\n";
-   close FILE;
-
-   warn __"url size is too large ($max > 1024)\n" if $max > 1024;
-
-   $new_img->delete if $export == EXPORT_EXPORT;
-   ();
-};
+      print FILE "</table>\n";
+      print FILE "</html>\n";
+      close FILE;
+      warn __"url size is too large ($max > 1024)\n" if $max > 1024;
+      $new_img->delete if $export == EXPORT_EXPORT;
+      ();
+   };
 
 Gimp::on_query {
    Gimp->register_save_handler("file_dataurl_save", "dataurl", "");
@@ -111,7 +101,7 @@ After reading rfc2397, which describes the C<data:> url scheme, I got the
 idea of embedding a normal image into a html document, without resorting
 to external files.
 
-This is acomplished by embedding small tiles of the image directly
+This is accomplished by embedding small tiles of the image directly
 into data:-urls. Since attribute values are by default limited to 1024
 bytes this limits the size of a tile to approximately 34x34 pixels (gif
 compression).
diff --git a/examples/dialogtest b/examples/dialogtest
new file mode 100755
index 0000000..e0d6b22
--- /dev/null
+++ b/examples/dialogtest
@@ -0,0 +1,50 @@
+#!/usr/local/bin/perl -w
+
+use strict;
+use Gimp qw(:auto __ N_);
+use Gimp::Fu;
+#BEGIN { $Gimp::verbose = 1; }
+#Gimp::set_trace(TRACE_ALL);
+
+sub boilerplate_params {
+  my ($testing, $menuloc) = @_;
+  (
+    ("exercise gimp-perl filter testing $testing") x 2,
+    ("boilerplate id") x 2,
+    "20140310",
+    N_$menuloc,
+    "*",
+  );
+}
+
+if (0) {
+&register(
+  "test_dialogs2",
+  boilerplate_params(
+    'menu entries',
+    '<Image>/Filters/Perl/Dialog Test',
+  ),
+  [
+    [ PF_COLOR, "colour", "Image colour", [255, 127, 0], ],
+    [ PF_FONT, "font", "Font", 'Arial', ],
+    [ PF_INT, "size", "Size", 100],
+  ],
+  sub { }
+);
+}
+
+&register(
+  "test_dialogs",
+  boilerplate_params(
+    'dialogs',
+    '<Toolbox>/Xtns/Perl/Test/Dialog',
+  ),
+  [
+    [ PF_COLOR, "colour", "Image colour", [255, 127, 0], ],
+    [ PF_FONT, "font", "Font", 'Arial', ],
+    [ PF_INT, "size", "Size", 100],
+  ],
+  sub { }
+);
+
+exit main;
diff --git a/examples/ditherize b/examples/ditherize
index 8b32115..81d5b87 100755
--- a/examples/ditherize
+++ b/examples/ditherize
@@ -21,7 +21,7 @@ my %imagetype2layertype = (
    INDEXED,    INDEXED_IMAGE,
 );
 
-register "plug_in_ditherize",
+register "ditherize",
         "dithers current selection",
         "This script takes the current selection and dithers it just like convert to indexed",
         "Marc Lehmann",
diff --git a/examples/exceptiontest b/examples/exceptiontest
new file mode 100755
index 0000000..b197551
--- /dev/null
+++ b/examples/exceptiontest
@@ -0,0 +1,30 @@
+#!/usr/local/bin/perl -w
+
+use strict;
+use Gimp qw(:auto __ N_);
+use Gimp::Fu;
+#BEGIN { $Gimp::verbose = 1; }
+#Gimp::set_trace(TRACE_ALL);
+
+sub boilerplate_params {
+  my ($testing, $menuloc) = @_;
+  (
+    ("exercise gimp-perl filter testing $testing") x 2,
+    ("boilerplate id") x 2,
+    "20140310",
+    N_$menuloc,
+    "*",
+  );
+}
+
+&register(
+  "test_exception",
+  boilerplate_params(
+    'exceptions',
+    '<Toolbox>/Xtns/Perl/Test/Exception',
+  ),
+  [],
+  sub { die "I DIED\n" }
+);
+
+exit main;
diff --git a/examples/gouge b/examples/gouge
index e944f5f..61fff71 100755
--- a/examples/gouge
+++ b/examples/gouge
@@ -16,8 +16,8 @@ sub iterate {
 
    my @bounds = $drawable->bounds;
    my @off = $drawable->offsets;
-   $bounds[2]-- if $bounds[0]+$bounds[2] >= ($drawable->offsets)[0]+$drawable->width;
-   $bounds[3]-- if $bounds[1]+$bounds[3] >= ($drawable->offsets)[1]+$drawable->height;
+   $bounds[2]-- if $bounds[0]+$bounds[2] >= $off[0]+$drawable->width;
+   $bounds[3]-- if $bounds[1]+$bounds[3] >= $off[1]+$drawable->height;
    {
       my $src = new Gimp::PixelRgn ($drawable,@bounds[0,1],$bounds[2]+1,$bounds[3]+1,0,0);
       my $dst = new Gimp::PixelRgn ($drawable,@bounds,1,1);
diff --git a/examples/innerbevel b/examples/innerbevel
index e1c4c2a..1c32230 100755
--- a/examples/innerbevel
+++ b/examples/innerbevel
@@ -19,7 +19,7 @@ N_"/Xtns/Render"; N_"/Xtns/Render/Logos"; # i18n workaround
 $defaultcolor1 = [124,10,18];
 $defaultcolor2 = [200,19,27];
 
-$path = N_"<Image>/File/Create/Logos";
+$path = N_"<Image>/File/Create/Logos/Inner Bevel...";
 $shortdesc = "Perform an inner bevel on text";
 $longdesc = "This uses tigert's inner bevel method on text, which can be found with his other excellent 
tutorials at http://tigert.gimp.org/";;
 $date = "1999-03-23";
diff --git a/examples/warp-sharp b/examples/warp-sharp
index 2bcccdc..1c6ae80 100755
--- a/examples/warp-sharp
+++ b/examples/warp-sharp
@@ -74,7 +74,7 @@ sub warp_sharp  {
 
 
 register
-  "plug_in_warp_sharp",
+  "warp_sharp",
   "Sharpen the current drawable",
   "Sharpen the current drawable by squeezing unsharp edges. Algorithm described by Joern Loviscach in c't 
22/1999, p 236.",
   "Simon Budig <simon\ gimp org>, Peter Daum <gator\ cs tu-berlin de>",
diff --git a/t/gimpsetup.pl b/t/gimpsetup.pl
index 9ae2be1..b81a2df 100644
--- a/t/gimpsetup.pl
+++ b/t/gimpsetup.pl
@@ -10,15 +10,13 @@ use strict;
 use Config;
 use File::Temp;
 use IO::All;
+require Gimp::Config;
 
 our $DEBUG = 0 unless defined $DEBUG;
 
-our %cfg;
-require 'config.pl';
-
-my $sysplugins = $cfg{gimpplugindir} . '/plug-ins';
+my $sysplugins = $Gimp::Config{gimpplugindir} . '/plug-ins';
 die "plugins dir: $!" unless -d $sysplugins;
-die "script-fu not executable: $!" unless-x "$sysplugins/script-fu";
+die "script-fu not executable: $!" unless -x "$sysplugins/script-fu";
 
 our $dir = File::Temp->newdir($DEBUG ? (CLEANUP => 0) : ());
 my $myplugins = "$dir/plug-ins";
diff --git a/t/pdl.t b/t/pdl.t
new file mode 100644
index 0000000..04dccc5
--- /dev/null
+++ b/t/pdl.t
@@ -0,0 +1,151 @@
+use strict;
+use Test::More;
+our ($dir, $DEBUG);
+my $pdl_operations;
+BEGIN {
+#  $Gimp::verbose = 1;
+  $DEBUG = 0;
+  require 't/gimpsetup.pl';
+  $pdl_operations = <<'EOF';
+use PDL;
+
+sub setpixel {
+  my ($i, $l, $x, $y, $colour) = @_;
+  my $region = $l->get->pixel_rgn($x, $y, 1, 1, 1, 0);
+  my $piddle = pdl [ @{$colour}[0..2] ]; # canonicalise_colour adds alpha!
+  $piddle *= 255; # so it's bytes, not floats
+  $region->set_pixel($piddle, $x, $y);
+#  $l->merge_shadow(1);
+  $l->update($l->bounds);
+}
+
+sub getpixel {
+  my ($i, $l, $x, $y) = @_;
+  my $region = $l->get->pixel_rgn($l->bounds,0,0);
+  my $piddle = $region->get_pixel($x,$y);
+  return unpdl $piddle;
+}
+
+sub iterate {
+  my ($i, $l, $inc) = @_;
+  my @bounds = $l->bounds;
+  {
+    # in block so $src/$dst go out of scope before merge
+    my $src = Gimp::PixelRgn->new($l,@bounds,0,0);
+    my $dst = Gimp::PixelRgn->new($l,@bounds,1,1);
+    my $iter = Gimp->pixel_rgns_register($dst);
+    do {
+      my ($x,$y,$w,$h)=($dst->x,$dst->y,$dst->w,$dst->h);
+      my $pdl = $src->get_rect($x,$y,$w,$h);
+      $pdl += $inc;
+      $dst->data($pdl);
+    } while (Gimp->pixel_rgns_process($iter));
+  }
+  $l->merge_shadow(1);
+  $l->update(@bounds);
+}
+EOF
+
+  use Config;
+  write_plugin($DEBUG, "test_pdl_filter", $Config{startperl}.
+    "\nBEGIN { \$Gimp::verbose = ".int($Gimp::verbose||0).'; }'.
+    <<'EOF'.$pdl_operations);
+
+use strict;
+use Gimp;
+use Gimp::Fu;
+
+sub boilerplate_params {
+  my ($testing, $menuloc) = @_;
+  (
+    ("exercise gimp-perl filter testing $testing") x 2,
+    ("boilerplate id") x 2,
+    "20140310",
+    N_$menuloc,
+    "*",
+  );
+}
+
+&register(
+  "test_pdl_getpixel",
+  boilerplate_params('filter', '<Image>/Filters'),
+  [
+    [PF_INT16, "x", "X coord of pixel", 0],
+    [PF_INT16, "y", "Y coord of pixel", 0],
+  ],
+  [
+    [PF_COLOR, "color", "Colour of pixel", ],
+  ],
+  \&getpixel,
+);
+
+&register(
+  "test_pdl_setpixel",
+  boilerplate_params('filter', '<Image>/Filters'),
+  [
+    [PF_INT16, "x", "X coord of pixel", 0],
+    [PF_INT16, "y", "Y coord of pixel", 0],
+    [PF_COLOR, "color", "Colour to set pixel", [128, 128, 128], ],
+  ],
+  [],
+  \&setpixel,
+);
+
+&register(
+  "test_pdl_iterate",
+  boilerplate_params('filter', '<Image>/Filters'),
+  [
+    [PF_INT16, "inc", "Amount to increment each byte", 1],
+  ],
+  [],
+  \&iterate,
+);
+
+exit main;
+EOF
+}
+use Gimp qw(:auto), "net_init=spawn/";
+#Gimp::set_trace(TRACE_ALL);
+
+ok((my $i = Gimp::Image->new(10,10,RGB)), 'new image');
+ok(
+  (my $l = $i->layer_new(10,10,RGB_IMAGE,"new layer",100,VALUE_MODE)),
+  'make layer',
+);
+ok(!$i->insert_layer($l,0,0), 'insert layer');
+
+my $fgcolour = [ 255, 128, 0 ];
+Gimp::Context->push;
+Gimp::Context->set_foreground($fgcolour);
+$l->fill(FOREGROUND_FILL);
+
+my @setcoords = (1, 1);
+my $setcolour = [ 16, 16, 16 ];
+is_deeply(
+  [ @{$l->test_pdl_getpixel(@setcoords)}[0..2] ],
+  Gimp::canonicalize_color($fgcolour),
+  'getpixel initial colour'
+);
+$l->test_pdl_setpixel(@setcoords, $setcolour);
+is_deeply(
+  [ @{$l->test_pdl_getpixel(@setcoords)}[0..2] ],
+  Gimp::canonicalize_color($setcolour),
+  'getpixel colour after setpixel'
+);
+is_deeply(
+  [ @{$l->test_pdl_getpixel(map { $_+1 } @setcoords)}[0..2] ],
+  Gimp::canonicalize_color($fgcolour),
+  'getpixel other pixel after setpixel'
+);
+$l->test_pdl_iterate(3);
+is_deeply(
+  [ @{$l->test_pdl_getpixel(@setcoords)}[0..2] ],
+  Gimp::canonicalize_color([ map { $_+3 } @$setcolour ]),
+  'getpixel colour after iterate'
+);
+Gimp::Context->pop;
+
+Gimp::Net::server_quit;
+Gimp::Net::server_wait;
+
+done_testing;
diff --git a/t/supplied.t b/t/supplied.t
index 0916762..beb76f0 100644
--- a/t/supplied.t
+++ b/t/supplied.t
@@ -1,3 +1,6 @@
+# get all plugin proc-names with this:
+# perl -MIO::All -e 'for $f (@ARGV) { $_ = io($f)->all; next unless @m = /\bregister\s+(\S+)["\\'\'']/sg; 
map { s#[^a-zA-Z\d_]##g; print "$f: $_\n"; } @m }' blib/plugins/*
+
 use strict;
 use Test::More;
 our ($dir, $DEBUG);
@@ -16,7 +19,7 @@ BEGIN {
   map { symlink_sysplugin($_) }
     qw(
       noise-rgb noise-solid blur-gauss grid pixelize blur-motion displace
-      bump-map checkerboard edge file-png unsharp-mask crop-auto
+      bump-map checkerboard edge file-gif-save file-png unsharp-mask crop-auto
     );
 }
 use Gimp qw(:auto), "net_init=spawn/";
@@ -39,6 +42,7 @@ use constant {
   REQ_GUIDE => 1 << 2,
   REQ_DIR   => 1 << 3,
   REQ_LAYER => 1 << 4,
+  REQ_FILE  => 1 << 5,
 };
 
 my $color1 = [0,0,1.0];
@@ -50,59 +54,69 @@ my $width     = 10;
 my $height    = 10;
 
 my @testbench = (
-["add_glow"               , 2, REQ_ALPHA, [$color1, 5] ],
-["animate_cells"          , 3, REQ_ALPHA, [0] ],
-["auto_red_eye"           , 1, REQ_NONE , [] ],
-["blowinout"              , 1, REQ_NONE , [ 30, 8, "30", 0, 0] ],
-["blur_2x2"               , 1, REQ_NONE , [] ],
-["brushed_metal"          , 1, REQ_NONE , [40,120,1,$gradient1] ],
-["burst"                  , 1, REQ_NONE , [0,0,14,30,50,80,140] ],
-["center_guide"           , 1, REQ_NONE , [0] ],
-["center_layer"           , 2, REQ_ALPHA, [] ],
-["contrast_enhance_2x2"   , 1, REQ_NONE , [] ],
-["do_bricks"              , 0, REQ_NONE , ["Leather","unused yet","",[0.5,0.5,0.5],1,8,16,256,256,0] ],
-["dots"                   , 1, REQ_NONE , [8,$color1,80,20,16,0,0] ],
-["dust"                   , 1, REQ_NONE , [0.0005,0,50] ],
-["edge_detect_2x2"        , 1, REQ_NONE , [] ],
-["glowing_steel"          , 0, REQ_NONE , ["GET LOST","Bitstream Charter Bold 72",100,$color1,$black,4,0,0] 
],
-["golden_mean"            , 0, REQ_NONE , [233, 0] ],
-["guide_grid"             , 1, REQ_NONE , [24,14,0,0,0] ],
-["guide_to_selection"     , 1, REQ_GUIDE, [CHANNEL_OP_REPLACE,0,0] ],
-["highlight_edges"        , 1, REQ_ALPHA, [ 10] ],
-["inner_bevel"            , 0, REQ_NONE , ["URW Bookman L, Bold 80","INNERBEVEL",$color1,$color2,132,30,7,2] 
],
-["layer_apply"            , 1, REQ_NONE , ['$d->gauss_rle($P*100+1,1,1)',""] ],
-["layer_reorder"          , 3, REQ_ALPHA, [1,""] ],
-["make_bevel_logos"       , 1, REQ_ALPHA, [$white,$color1,$color2,45,4,0] ],
-["make_trans_logos"       , 1, REQ_ALPHA, [0,$gradient1,$color1] ],
-["map_to_gradient"        , 1, REQ_NONE , [$gradient1] ],
-["mirror_split"           , 1, REQ_NONE , [0] ],
-["perlotine"              , 1, REQ_GUIDE|REQ_DIR, ["foo.html","t","png",0,"",1,0] ],
-["pixelgen"               , 0, REQ_NONE , [$width,$height,RGB_IMAGE,'($x*$y*0.01)->slice("*$bpp")'] ],
-["pixelmap"               , 1, REQ_NONE , ['($x*$y*0.01)->slice("*$bpp")'] ],
-["prep4gif"               , 2, REQ_ALPHA, [64,1,0,1,255] ],
-["random_art_1"           , 0, REQ_NONE , [$width,$height,20,10,1,30,0] ],
-["random_blends"          , 1, REQ_NONE , [7] ],
-["red_eye"                , 1, REQ_NONE , [0] ],
-["repdup"                 , 1, REQ_SEL  , [3,50,50] ],
-["round_sel"              , 1, REQ_SEL  , [16] ],
-["scratches"              , 1, REQ_NONE , [30,70,0.3,15,10] ],
-["selective_sharpen"      , 1, REQ_NONE , [5.0,1.0,20] ],
-["seth_spin"              , 2, REQ_LAYER, [16,$color1,40,1,1] ],
-["stamps"                 , 0, REQ_NONE , [90,$white,$color1,10,5] ],
-# ["tex_string_to_float"    , 1, REQ_NONE , ["","I can write \\\\TeX",72,6,4] ],
-# ["view3d"                 , 1, REQ_NONE , [0,1,1] ],
-["webify"                 , 1, REQ_NONE , [1,1,$white,3,32,1] ],
-["windify"                , 1, REQ_NONE , [120,80,30,1] ],
-["xach_blocks"            , 1, REQ_NONE , [10,40] ],
-["xach_shadows"           , 1, REQ_NONE , [10] ],
-["xachvision"             , 1, REQ_NONE , [$color1,25] ],
-["yinyang"                , 0, REQ_NONE , [$width,$height,1,0,"","",1] ],
+["add_glow"            , 2, REQ_ALPHA, [$color1, 5] ],
+["animate_cells"       , 3, REQ_ALPHA, [0] ],
+["auto_red_eye"        , 1, REQ_NONE , [] ],
+["blowinout"           , 1, REQ_NONE , [ 30, 8, "30", 0, 0] ],
+["blur_2x2"            , 1, REQ_NONE , [] ],
+["brushed_metal"       , 1, REQ_NONE , [40,120,1,$gradient1] ],
+["burst"               , 1, REQ_NONE , [0,0,14,30,50,80,140] ],
+["center_guide"        , 1, REQ_NONE , [0] ],
+["center_layer"        , 2, REQ_ALPHA, [] ],
+["contrast_enhance_2x2", 1, REQ_NONE , [] ],
+["ditherize"           , 1, REQ_NONE , [ 1, 10] ],
+["do_bricks"           , 0, REQ_NONE , ["Leather","unused yet","",[0.5,0.5,0.5],1,8,16,256,256,0] ],
+["dots"                , 1, REQ_NONE , [8,$color1,80,20,16,0,0] ],
+["dust"                , 1, REQ_NONE , [0.0005,0,50] ],
+["edge_detect_2x2"     , 1, REQ_NONE , [] ],
+["file_dataurl_save"   , 1, REQ_FILE , [32, 32, 0] ],
+["file_colorhtml_save" , 1, REQ_FILE , [2, "", "+1", 1, 1, 1] ],
+["glowing_steel"       , 0, REQ_NONE , ["GET LOST","Bitstream Charter Bold 72",100,$color1,$black,4,0,0] ],
+["golden_mean"         , 0, REQ_NONE , [233, 0] ],
+["guide_grid"          , 1, REQ_NONE , [24,14,0,0,0] ],
+["guide_to_selection"  , 1, REQ_GUIDE, [CHANNEL_OP_REPLACE,0,0] ],
+["highlight_edges"     , 1, REQ_ALPHA, [ 10] ],
+["inner_bevel"         , 0, REQ_NONE , ["URW Bookman L, Bold 80","INNERBEVEL",$color1,$color2,132,30,7,2] ],
+["layer_apply"         , 1, REQ_NONE , ['$d->gauss_rle($P*100+1,1,1)',""] ],
+["layer_reorder"       , 3, REQ_ALPHA, [1,""] ],
+["make_bevel_logos"    , 1, REQ_ALPHA, [$white,$color1,$color2,45,4,0] ],
+["make_trans_logos"    , 1, REQ_ALPHA, [0,$gradient1,$color1] ],
+["map_to_gradient"     , 1, REQ_NONE , [$gradient1] ],
+["mirror_split"        , 1, REQ_NONE , [0] ],
+["perlotine"           , 1, REQ_GUIDE|REQ_DIR, ["foo.html","t","png",0,"",1,0] ],
+["pixelgen"            , 0, REQ_NONE , [$width,$height,RGB_IMAGE,'($x*$y*0.01)->slice("*$bpp")'] ],
+["pixelmap"            , 1, REQ_NONE , ['($x*$y*0.01)->slice("*$bpp")'] ],
+["prep4gif"            , 2, REQ_ALPHA, [64,1,0,1,255] ],
+["random_art_1"        , 0, REQ_NONE , [$width,$height,20,10,1,30,0] ],
+["random_blends"       , 1, REQ_NONE , [7] ],
+["red_eye"             , 1, REQ_NONE , [0] ],
+["repdup"              , 1, REQ_SEL  , [3,50,50] ],
+["round_sel"           , 1, REQ_SEL  , [16] ],
+["scratches"           , 1, REQ_NONE , [30,70,0.3,15,10] ],
+["selective_sharpen"   , 1, REQ_NONE , [5.0,1.0,20] ],
+["seth_spin"           , 2, REQ_LAYER, [16,$color1,40,1,1] ],
+["stamps"              , 0, REQ_NONE , [90,$white,$color1,10,5] ],
+#["tex_string_to_float" , 1, REQ_NONE , ["","I can write \\\\TeX",72,6,4] ],
+#["view3d"             , 1, REQ_NONE , [0,1,1] ],
+#["warp_sharp"          ,
+["webify"              , 1, REQ_NONE , [1,1,$white,3,32,1] ],
+["windify"             , 1, REQ_NONE , [120,80,30,1] ],
+["xach_blocks"         , 1, REQ_NONE , [10,40] ],
+["xach_shadows"        , 1, REQ_NONE , [10] ],
+["xachvision"          , 1, REQ_NONE , [$color1,25] ],
+["yinyang"             , 0, REQ_NONE , [$width,$height,1,0,"","",1] ],
 );
 
 for my $test (@testbench) {
   my ($name, $numlays, $flags, $params) = @$test;
   my @actualparams = @$params;
-  my $tempdir;
+  my ($tempdir, $tempfile);
+  if ($flags & REQ_FILE) {
+    $tempfile = File::Temp->newdir($DEBUG ? (CLEANUP => 0) : ());
+    # put 2 copies on input params - for use with export-handler!
+    # use a dir so any side-files created will get zapped on cleanup
+    unshift @actualparams, $tempfile.'/file.xcf', $tempfile.'/file.xcf';
+  }
   if ($flags & REQ_DIR) {
     $tempdir = File::Temp->newdir($DEBUG ? (CLEANUP => 0) : ());
     unshift @actualparams, $tempdir.'';
diff --git a/utils/gimpdoc b/utils/gimpdoc
index 7043ab3..8e63524 100755
--- a/utils/gimpdoc
+++ b/utils/gimpdoc
@@ -54,9 +54,9 @@ for (@ARGV) {
          &PDB_PARASITE         => 'PARASITE',
 
          &PDB_STATUS           => 'STATUS',
-         &PDB_REGION           => 'REGION',
-         &PDB_BOUNDARY         => 'BOUNDARY',
-         &PDB_PATH             => 'PATH',
+         &PDB_ITEM             => 'ITEM',
+         &PDB_COLORARRAY       => 'COLORARRAY',
+         &PDB_VECTORS          => 'VECTORS',
 );
 
 sub type2str {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]