#!/usr/bin/perl

use Gimp;
use Gimp::Fu;
use PDL::LiteF;

sub iterate {
   my ($drawable,$message,$kernel)=@_;

   Gimp->progress_init ($message);

   my @bounds = $drawable->bounds;
   my @off = $drawable->offsets;
   $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);

      my $iter = Gimp->pixel_rgns_register ($dst);
      my $area = $bounds[2]*$bounds[3];
      my $progress = 0;

      do {
         my ($x,$y,$w,$h)=($dst->x,$dst->y,$dst->w,$dst->h);
         $dst->data($kernel->($src->get_rect($x,$y,$w+1,$h+1)->convert(short)));
         $progress += $w*$h/$area;
         Gimp->progress_update ($progress);
      } while (Gimp->pixel_rgns_process ($iter));
   }
   Gimp->progress_update (1);

   $drawable->merge_shadow (1);
   $drawable->update (@bounds);

   ();
}

register "blur_2x2",
         "smooth (low pass filter) an image using a fast 2x2 kernel",
         "Low-pass filtering (smoothing) using a fast 2x2 kernel",
         '', '', '',
       N_"<Image>/Filters/Blur/2x2 Blur",
         '', '',
         sub {
   my($image,$drawable)=@_;

   iterate $drawable,
           "2x2 smoothing...",
           sub {
              ($_[0]->slice(":,0:-2,0:-2")+
               $_[0]->slice(":,1:-1,0:-2")+
               $_[0]->slice(":,1:-1,1:-1")+
               $_[0]->slice(":,0:-2,1:-1"))>>2;
           };
};

register "contrast_enhance_2x2",
         "contrast enhance an image using a fast 2x2 kernel",
         "Contrast Enhance an image using a fast 2x2 kernel",
         '', '', '',
         N_"<Image>/Filters/Enhance/2x2 Contrast Enhance",
         '', '',
         sub {
   my($image,$drawable)=@_;

   iterate $drawable,
           "2x2 contrast enhancing...",
           sub {
              my $T = $_[0]->slice(":,0:-2,0:-2");
              my $D = $_[0]->slice(":,1:-1,1:-1");

              (($T<<1)-$D)->clip(0,255);
           };
};

register "edge_detect_2x2",
         "detects edges in an image using a fast 2x2 kernel",
         "Detect edges in the image using a 2x2 kernel. It is similar to Sobel, yet sharper (and lower quality).",
         '', '', '',
         N_"<Image>/Filters/Edge-Detect/2x2 Edge Detect",
         '', '',
         sub {
   my($image,$drawable)=@_;

   iterate $drawable,
           "2x2 cross gradient...",
           sub {
              my $T = $_[0]->slice(":,0:-2,0:-2");
              my $R = $_[0]->slice(":,1:-1,0:-2");
              my $D = $_[0]->slice(":,1:-1,1:-1");

              abs(cat($T-$R,$T-$D))
              ->convert(byte)
              ->mv(3,0)
              ->maximum;
           };
};

exit main;
__END__

=head1 NAME

blur_2x2/contrast_enhance_2x2/edge_detect_2x2 - Use a fast 2x2 kernel
to detect edges/enhance/smooth image

=head1 SYNOPSIS

  <Image>/Filters/Edge-Detect/2x2 Edge Detect
  <Image>/Filters/Blur/2x2 Blur
  <Image>/Filters/Enhance/2x2 Contrast Enhance

=head1 DESCRIPTION

Detect edges in the image using a 2x2 kernel. It is similar to Sobel,
yet sharper (and lower quality).

Implements some algorithms described in (the otherwise very bad)
L<http://www.biocomputer.com/Thesis.html>

These are all simple 2x2 kernels, fast but relatively effective.

=head1 PARAMETERS

 # none

=head1 IMAGE TYPES

RGB*, GRAY*

=head1 AUTHOR

Marc Lehmann <pcg@goof.com>

=head1 DATE

19990725

=head1 LICENSE

Distributed under the same terms as Gimp-Perl.
