[gegl] Add new samplers from gsoc



commit 130c793c70195cf900017f74505b863a3c29a6d5
Author: Adam Turcotte <adam turcotte gmail com>
Date:   Fri Jan 15 17:33:13 2010 -0500

    Add new samplers from gsoc

 gegl/buffer/Makefile.am                   |   22 +-
 gegl/buffer/gegl-buffer-access.c          |    5 +-
 gegl/buffer/gegl-buffer.c                 |    5 +-
 gegl/buffer/gegl-buffer.h                 |    5 +-
 gegl/buffer/gegl-sampler-downsharpfast.c  |   26 +
 gegl/buffer/gegl-sampler-downsharpfast.h  |   48 ++
 gegl/buffer/gegl-sampler-downsizefast.c   |  631 +++++++++++++++
 gegl/buffer/gegl-sampler-downsizefast.h   |   48 ++
 gegl/buffer/gegl-sampler-downsmoothfast.c |   26 +
 gegl/buffer/gegl-sampler-downsmoothfast.h |   48 ++
 gegl/buffer/gegl-sampler-sharp.c          |  806 ------------------
 gegl/buffer/gegl-sampler-sharp.h          |   50 --
 gegl/buffer/gegl-sampler-upsharp.c        | 1166 ++++++++++++++++++++++++++
 gegl/buffer/gegl-sampler-upsharp.h        |   48 ++
 gegl/buffer/gegl-sampler-upsize.c         |  679 ++++++++++++++++
 gegl/buffer/gegl-sampler-upsize.h         |   50 ++
 gegl/buffer/gegl-sampler-upsmooth.c       | 1259 +++++++++++++++++++++++++++++
 gegl/buffer/gegl-sampler-upsmooth.h       |   48 ++
 gegl/buffer/gegl-sampler-yafr.c           |  687 ----------------
 gegl/buffer/gegl-sampler-yafr.h           |   50 --
 gegl/buffer/gegl-sampler.c                |   33 +-
 operations/affine/affine.c                |    2 +-
 22 files changed, 4117 insertions(+), 1625 deletions(-)
---
diff --git a/gegl/buffer/Makefile.am b/gegl/buffer/Makefile.am
index 7b0eb22..9fe52ba 100644
--- a/gegl/buffer/Makefile.am
+++ b/gegl/buffer/Makefile.am
@@ -34,10 +34,11 @@ libbuffer_la_SOURCES = \
     gegl-sampler-linear.c	\
     gegl-sampler-nearest.c	\
     gegl-sampler-downsharp.c	\
-    gegl-sampler-downsize.c \
+    gegl-sampler-downsize.c 	\
     gegl-sampler-downsmooth.c	\
-    gegl-sampler-sharp.c	\
-    gegl-sampler-yafr.c		\
+    gegl-sampler-upsharp.c	\
+    gegl-sampler-upsize.c 	\
+    gegl-sampler-upsmooth.c	\
     gegl-region-generic.c	\
     gegl-tile.c			\
     gegl-tile-source.c		\
@@ -66,10 +67,11 @@ libbuffer_la_SOURCES = \
     gegl-sampler-linear.h	\
     gegl-sampler-nearest.h	\
     gegl-sampler-downsharp.h	\
-    gegl-sampler-downsize.h \
+    gegl-sampler-downsize.h 	\
     gegl-sampler-downsmooth.h	\
-    gegl-sampler-sharp.h	\
-    gegl-sampler-yafr.h		\
+    gegl-sampler-upsharp.h	\
+    gegl-sampler-upsize.h 	\
+    gegl-sampler-upsmooth.h	\
     gegl-region.h		\
     gegl-region-generic.h	\
     gegl-tile.h			\
@@ -78,12 +80,12 @@ libbuffer_la_SOURCES = \
     gegl-tile-backend.h		\
     gegl-tile-backend-file.h	\
     gegl-tile-backend-tiledir.h	\
-    gegl-tile-backend-ram.h		\
+    gegl-tile-backend-ram.h	\
     gegl-tile-handler.h		\
-    gegl-tile-handler-chain.h		\
+    gegl-tile-handler-chain.h	\
     gegl-tile-handler-cache.h	\
     gegl-tile-handler-empty.h	\
-    gegl-tile-handler-log.h		\
-    gegl-tile-handler-zoom.h		\
+    gegl-tile-handler-log.h	\
+    gegl-tile-handler-zoom.h	\
     gegl-id-pool.h
 
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 82fdfa8..5d7773d 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -40,8 +40,9 @@
 #include "gegl-sampler-downsharp.h"
 #include "gegl-sampler-downsize.h"
 #include "gegl-sampler-downsmooth.h"
-#include "gegl-sampler-sharp.h"
-#include "gegl-sampler-yafr.h"
+#include "gegl-sampler-upsharp.h"
+#include "gegl-sampler-upsize.h"
+#include "gegl-sampler-upsmooth.h"
 #include "gegl-buffer-index.h"
 #include "gegl-tile-backend.h"
 #include "gegl-buffer-iterator.h"
diff --git a/gegl/buffer/gegl-buffer.c b/gegl/buffer/gegl-buffer.c
index 25b5aa6..b545ee3 100644
--- a/gegl/buffer/gegl-buffer.c
+++ b/gegl/buffer/gegl-buffer.c
@@ -66,8 +66,9 @@
 #include "gegl-sampler-downsharp.h"
 #include "gegl-sampler-downsize.h"
 #include "gegl-sampler-downsmooth.h"
-#include "gegl-sampler-sharp.h"
-#include "gegl-sampler-yafr.h"
+#include "gegl-sampler-upsharp.h"
+#include "gegl-sampler-upsize.h"
+#include "gegl-sampler-upsmooth.h"
 #include "gegl-types-internal.h"
 #include "gegl-utils.h"
 #include "gegl-id-pool.h"
diff --git a/gegl/buffer/gegl-buffer.h b/gegl/buffer/gegl-buffer.h
index 1d0ff57..76a82a0 100644
--- a/gegl/buffer/gegl-buffer.h
+++ b/gegl/buffer/gegl-buffer.h
@@ -300,8 +300,9 @@ typedef enum {
   GEGL_INTERPOLATION_DOWNSHARP,
   GEGL_INTERPOLATION_DOWNSIZE,
   GEGL_INTERPOLATION_DOWNSMOOTH,
-  GEGL_INTERPOLATION_SHARP,
-  GEGL_INTERPOLATION_YAFR
+  GEGL_INTERPOLATION_UPSHARP,
+  GEGL_INTERPOLATION_UPSIZE,
+  GEGL_INTERPOLATION_UPSMOOTH
 } GeglInterpolation;
 
 /**
diff --git a/gegl/buffer/gegl-sampler-downsharpfast.c b/gegl/buffer/gegl-sampler-downsharpfast.c
new file mode 100644
index 0000000..983d48d
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-downsharpfast.c
@@ -0,0 +1,26 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 2009 (c) Adam Turcotte and Nicolas Robidoux.
+ */
+
+/*
+ * The following #define sets the stage for the compilation of
+ * Downsharpfast from the gegl-sampler-downsizefast.c source code:
+ */
+#define __GEGL_SAMPLER_DOWNSHARPFAST_C__
+#include "gegl-sampler-downsizefast.c"
+#undef __GEGL_SAMPLER_DOWNSHARPFAST_C__
diff --git a/gegl/buffer/gegl-sampler-downsharpfast.h b/gegl/buffer/gegl-sampler-downsharpfast.h
new file mode 100644
index 0000000..7242187
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-downsharpfast.h
@@ -0,0 +1,48 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __GEGL_SAMPLER_DOWNSHARPFAST_H__
+#define __GEGL_SAMPLER_DOWNSHARPFAST_H__
+
+#include "gegl-sampler.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_SAMPLER_DOWNSHARPFAST            (gegl_sampler_downsharpfast_get_type ())
+#define GEGL_SAMPLER_DOWNSHARPFAST(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_SAMPLER_DOWNSHARPFAST, GeglSamplerDownsharpfast))
+#define GEGL_SAMPLER_DOWNSHARPFAST_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GEGL_TYPE_SAMPLER_DOWNSHARPFAST, GeglSamplerDownsharpfastClass))
+#define GEGL_IS_SAMPLER_DOWNSHARPFAST(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_SAMPLER_DOWNSHARPFAST))
+#define GEGL_IS_SAMPLER_DOWNSHARPFAST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GEGL_TYPE_SAMPLER_DOWNSHARPFAST))
+#define GEGL_SAMPLER_DOWNSHARPFAST_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GEGL_TYPE_SAMPLER_DOWNSHARPFAST, GeglSamplerDownsharpfastClass))
+
+typedef struct _GeglSamplerDownsharpfast      GeglSamplerDownsharpfast;
+typedef struct _GeglSamplerDownsharpfastClass GeglSamplerDownsharpfastClass;
+
+struct _GeglSamplerDownsharpfast
+{
+  GeglSampler parent_instance;
+};
+
+struct _GeglSamplerDownsharpfastClass
+{
+  GeglSamplerClass parent_class;
+};
+
+GType gegl_sampler_downsharpfast_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/gegl/buffer/gegl-sampler-downsizefast.c b/gegl/buffer/gegl-sampler-downsizefast.c
new file mode 100644
index 0000000..f7a2470
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-downsizefast.c
@@ -0,0 +1,631 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 2009 (c) Eric Daoust, Adam Turcotte, Nicolas Robidoux and Ã?yvind
+ * Kolås.
+ */
+
+/*
+ * Acknowledgements: Eric Daoust and Adam Turcotte's GEGL programming
+ * funded by Google Summer of Code 2009.  Nicolas Robidoux and Adam
+ * Turcotte's research on Nohalobox funded in part by NSERC (National
+ * Science and Engineering Research Council of Canada) Discovery and
+ * USRA grants.
+ *
+ * Nicolas Robidoux thanks Minglun Gong, Ralf Meyer, John Cupitt,
+ * Geert Jordaens and Sven Neumann for useful comments and code, with
+ * special thanks to Chantal Racette for exploring various ways of
+ * getting a rectangle with axes parallel to the axes from the affine
+ * preimage of a square with axes parallel to the axes.
+ *
+ */
+#include "config.h"
+#include <math.h>
+#include <glib-object.h>
+
+/*
+ * This file implements three fast methods tuned for transformations
+ * for which downsampling is more typical than upsampling.
+ *
+ * ===================
+ * FUTURE IMPROVEMENTS
+ * ===================
+ *
+ * All three methods will be improved so that they better handle
+ * downsampling ratios larger than about 60 by branching and using
+ * multiple gegl_sampler_get_ptr calls if necessary.
+ *
+ * Downsmoothfast can be improved so that it is less blurry but
+ * equally antialiased (and faster) by averaging on a region shaped
+ * like a stubby plus sign instead of a rectangle. Also, some of the
+ * whiles could be changed to do whiles for this method.
+ */
+
+#include "gegl.h"
+#include "gegl-types-internal.h"
+#include "gegl-buffer-private.h"
+#if   defined (__GEGL_SAMPLER_DOWNSHARPFAST_C__)
+#include "gegl-sampler-downsharpfast.h"
+#elif defined (__GEGL_SAMPLER_DOWNSMOOTHFAST_C__)
+#include "gegl-sampler-downsmoothfast.h"
+#else
+#include "gegl-sampler-downsizefast.h"
+#endif
+#include "gegl-matrix.h"
+
+/*
+ * FAST_PSEUDO_FLOOR is a floor replacement which has been found to be
+ * faster. It returns the floor of its argument unless the argument is
+ * a negative integer, in which case it returns one less than the
+ * floor. For example:
+ *
+ * FAST_PSEUDO_FLOOR(0.5) = 0
+ *
+ * FAST_PSEUDO_FLOOR(0.) = 0
+ *
+ * FAST_PSEUDO_FLOOR(-.5) = -1
+ *
+ * as expected, but
+ *
+ * FAST_PSEUDO_FLOOR(-1.) = -2
+ *
+ * The discontinuities of FAST_PSEUDO_FLOOR are on the right of
+ * negative numbers instead of on the left as is the case for floor.
+ */
+#define FAST_PSEUDO_FLOOR(x) ( (int)(x) - ( (x) < 0. ) )
+
+/*
+ * Hack to get the restrict C99 keyword going at least some of the
+ * time:
+ */
+#ifndef restrict
+#ifdef __restrict
+#define restrict __restrict
+#else
+#ifdef __restrict__
+#define restrict __restrict__
+#else
+#define restrict
+#endif
+#endif
+#endif
+
+enum
+{
+  PROP_0,
+  PROP_LAST
+};
+
+#if   defined (__GEGL_SAMPLER_DOWNSHARPFAST_C__)
+static void gegl_sampler_downsharpfast_get  (      GeglSampler* self,
+#elif defined (__GEGL_SAMPLER_DOWNSMOOTHFAST_C__)
+static void gegl_sampler_downsmoothfast_get (      GeglSampler* self,
+#else
+static void gegl_sampler_downsizefast_get   (      GeglSampler* self,
+#endif
+                                         const gdouble      absolute_x,
+                                         const gdouble      absolute_y,
+                                               void*        output );
+
+static void set_property (      GObject*    object,
+                                guint       property_id,
+                          const GValue*     value,
+                                GParamSpec* pspec);
+
+static void get_property (GObject*    object,
+                          guint       property_id,
+                          GValue*     value,
+                          GParamSpec* pspec);
+
+#if   defined (__GEGL_SAMPLER_DOWNSHARPFAST_C__)
+G_DEFINE_TYPE (GeglSamplerDownsharpfast,
+               gegl_sampler_downsharpfast,
+               GEGL_TYPE_SAMPLER)
+#elif defined (__GEGL_SAMPLER_DOWNSMOOTHFAST_C__)
+G_DEFINE_TYPE (GeglSamplerDownsmoothfast,
+               gegl_sampler_downsmoothfast,
+               GEGL_TYPE_SAMPLER)
+#else
+G_DEFINE_TYPE (GeglSamplerDownsizefast,
+               gegl_sampler_downsizefast,
+               GEGL_TYPE_SAMPLER)
+#endif
+
+static GObjectClass * parent_class = NULL;
+
+static void
+#if   defined (__GEGL_SAMPLER_DOWNSHARPFAST_C__)
+gegl_sampler_downsharpfast_class_init  (GeglSamplerDownsharpfastClass  *klass)
+#elif defined (__GEGL_SAMPLER_DOWNSMOOTHFAST_C__)
+gegl_sampler_downsmoothfast_class_init (GeglSamplerDownsmoothfastClass *klass)
+#else
+gegl_sampler_downsizefast_class_init   (GeglSamplerDownsizefastClass *klass)
+#endif
+{
+  GeglSamplerClass *sampler_class = GEGL_SAMPLER_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  parent_class               = g_type_class_peek_parent (klass);
+  object_class->set_property = set_property;
+  object_class->get_property = get_property;
+#if   defined (__GEGL_SAMPLER_DOWNSHARPFAST_C__)
+  sampler_class->get = gegl_sampler_downsharpfast_get;
+#elif defined (__GEGL_SAMPLER_DOWNSMOOTHFAST_C__)
+  sampler_class->get = gegl_sampler_downsmoothfast_get;
+#else
+  sampler_class->get = gegl_sampler_downsizefast_get;
+#endif
+}
+
+static void
+#if   defined (__GEGL_SAMPLER_DOWNSHARPFAST_C__)
+gegl_sampler_downsharpfast_init  (GeglSamplerDownsharpfast  *self)
+#elif defined (__GEGL_SAMPLER_DOWNSMOOTHFAST_C__)
+gegl_sampler_downsmoothfast_init (GeglSamplerDownsmoothfast *self)
+#else
+gegl_sampler_downsizefast_init   (GeglSamplerDownsizefast   *self)
+#endif
+{
+  /*
+   * ===================
+   * UNSATISFACTORY HACK
+   * ===================
+   *
+   * The stencil offsets context_rect.x and context.y are set to -1
+   * even though 0 should be enough. When the GEGL affine code gets
+   * cleaned up, this hack may not be necessary: Set SAFETY_OFFSET to
+   * 0.
+   */
+  #define SAFETY_OFFSET 1
+
+  /*
+   * The width and height are very likely to be modified by
+   * downsharp/size/smooth at runtime.
+   *
+   * The offsets should be 0 but they are set to -1 for safety. For
+   * mysterious reasons (having to do with negative locations near
+   * zero?), 0 does not behave quite as expected in some of the
+   * downsampling methods. If and when GEGL has more robust variable
+   * context_rect handling, it could be brought back to 0.
+   */
+  GEGL_SAMPLER (self)->context_rect.x      = -SAFETY_OFFSET;
+  GEGL_SAMPLER (self)->context_rect.y      = -SAFETY_OFFSET;
+  GEGL_SAMPLER (self)->context_rect.width  = 2 + SAFETY_OFFSET;
+  GEGL_SAMPLER (self)->context_rect.height = 2 + SAFETY_OFFSET;
+  GEGL_SAMPLER (self)->interpolate_format  = babl_format ("RaGaBaA float");
+}
+
+static void
+#if   defined (__GEGL_SAMPLER_DOWNSHARPFAST_C__)
+gegl_sampler_downsharpfast_get  (      GeglSampler* self,
+#elif defined (__GEGL_SAMPLER_DOWNSMOOTHFAST_C__)
+gegl_sampler_downsmoothfast_get (      GeglSampler* self,
+#else
+gegl_sampler_downsizefast_get   (      GeglSampler* self,
+#endif
+                             const gdouble      absolute_x,
+                             const gdouble      absolute_y,
+                                   void*        output)
+{
+  /*
+   * Needed constants related to the input pixel value pointer
+   * provided by gegl_sampler_get_ptr (self, ix,
+   * iy). pixels_per_fetched_row corresponds to fetch_rectangle.width
+   * in gegl_sampler_get_ptr.
+   *
+   * Note that the following code does loop unrolling. If channels is
+   * changed from 4, significant but trivial mods will be necessary.
+   */
+  const gint channels = 4;
+  const gint pixels_per_fetched_row = 64;
+
+  /*
+   * For affine operations, the following code, which computes the
+   * averaging box from the inverse Jacobian matrix, is kind of a
+   * waste because the Jacobian, and consequently the computed
+   * rectangle, are constant---that is, they are the same for every
+   * pixel---yet the width and height of the integration rectangle is
+   * recomputed for every sampled location.
+   *
+   * The code is written this way so that it work for perspective and
+   * more general warps, for which the rectangle is location
+   * dependent.
+   */
+  /*
+   * POSSIBLE FUTURE IMPROVEMENT: Avoid recomputation, for every
+   * pixel, of half_width and half_height from inverse_jacobian, when
+   * inverse_jacobian is constant.
+   */
+  GeglMatrix2* const inverse_jacobian = self->inverse_jacobian;
+
+  const gdouble Jinv_11 = *inverse_jacobian[0][0];
+  const gdouble Jinv_12 = *inverse_jacobian[0][1];
+  const gdouble Jinv_21 = *inverse_jacobian[1][0];
+  const gdouble Jinv_22 = *inverse_jacobian[1][1];
+
+  /*
+   * Preimages of (1,1) (top right corner) and (1,-1) (bottom right
+   * corner). By symmetry, it is not necessary to compute the
+   * preimages of the other two corners.
+   */
+  const gdouble top_preimage_x    = Jinv_11 + Jinv_12;
+  const gdouble bottom_preimage_x = Jinv_11 - Jinv_12;
+  const gdouble top_preimage_y    = Jinv_21 + Jinv_22;
+  const gdouble bottom_preimage_y = Jinv_21 - Jinv_22;
+
+  const gdouble far_x =
+    ( top_preimage_x * top_preimage_x >= bottom_preimage_x * bottom_preimage_x
+      ? top_preimage_x : bottom_preimage_x );
+  const gdouble far_y =
+    ( top_preimage_y * top_preimage_y >= bottom_preimage_y * bottom_preimage_y
+      ? top_preimage_y : bottom_preimage_y );
+
+  /*
+   * These lengths define the smallest rectangle with sides parallel
+   * to the axes which contains the preimage of an output pixel area,
+   * scaled by 1/sqrt(2) in the case of Downsharp, fixed so that the
+   * width and height are at least 1. Note that this implies that,
+   * when downsampling, Downsharp typically fetches only about half
+   * the number of pixels fetched by Downsize; Downsmooth, about four
+   * times as many.
+   */
+  const gdouble scaled_half_preimage_width  =
+    ( far_x >= 0. ? far_x : -far_x )
+#if   defined __GEGL_SAMPLER_DOWNSHARPFAST_C__
+    * ( .25 * sqrt(2.) );
+#elif defined __GEGL_SAMPLER_DOWNSMOOTHFAST_C__
+    ;
+#else
+    * .5;
+#endif
+
+  const gdouble scaled_half_preimage_height =
+    ( far_y >= 0. ? far_y : -far_y )
+#if   defined __GEGL_SAMPLER_DOWNSHARPFAST_C__
+    * ( .25 * sqrt(2.) );
+#elif defined __GEGL_SAMPLER_DOWNSMOOTHFAST_C__
+    ;
+#else
+    * .5;
+#endif
+
+  /*
+   * Make sure at least two pixels are overlapped (even if only a
+   * little bit) in each direction, by making the box's width and
+   * height at least a little bit more than 1:
+   */
+  const gdouble floored_half_preimage_width =
+    ( scaled_half_preimage_width  < .50000001
+      ? .50000001 : scaled_half_preimage_width );
+  const gdouble floored_half_preimage_height =
+    ( scaled_half_preimage_height < .50000001
+      ? .50000001 : scaled_half_preimage_height );
+  /*
+   * In order to be able to use a single gegl_sampler_get_ptr call to
+   * get the data we need, we limit the number of pixels needed in
+   * each direction to just a little less than the maximum number of
+   * pixels we can get in each direction.
+   *
+   * "- 1" is because the distance between the first and last pixel
+   * center is one less than their number. The second "- 1" is because
+   * the use of FAST_PSEUDO_FLOOR may (?)  stretch indices by 1 for
+   * negatives values. The "- .00000001" is for safety w.r.t. round
+   * off error.
+   */
+  const gdouble half_maximal_length =
+    ( pixels_per_fetched_row - 1 - 1 - SAFETY_OFFSET ) * .5 - .00000001;
+  const gdouble half_width =
+    ( floored_half_preimage_width  < half_maximal_length
+      ? floored_half_preimage_width  : half_maximal_length );
+  const gdouble half_height =
+    ( floored_half_preimage_height < half_maximal_length
+      ? floored_half_preimage_height : half_maximal_length );
+
+  /*
+   * Left/top limits of the integration box:
+   */
+  const gdouble left   = absolute_x - half_width;
+  const gdouble right  = absolute_x + half_width;
+  const gdouble top    = absolute_y - half_height;
+  const gdouble bottom = absolute_y + half_height;
+
+  /*
+   * An average is an integral divided by an area. Needed multiplier:
+   */
+  const gfloat one_over_box_area = .25 / ( half_width * half_height );
+
+  const gdouble right_plus_half  = right  + .5;
+  const gdouble bottom_plus_half = bottom + .5;
+
+  /*
+   * Index of the left/right/bottom/top-most overlapped pixels:
+   */
+  const gint absolute_left_j   = FAST_PSEUDO_FLOOR (left + .5);
+  const gint absolute_top_i    = FAST_PSEUDO_FLOOR (top  + .5);
+  const gint absolute_right_j  = FAST_PSEUDO_FLOOR (right_plus_half);
+  const gint absolute_bottom_i = FAST_PSEUDO_FLOOR (bottom_plus_half);
+
+  /*
+   * Relative indices:
+   */
+  const gint right_j  = absolute_right_j  - absolute_left_j;
+  const gint bottom_i = absolute_bottom_i - absolute_top_i;
+
+  /*
+   * "1" is because the number of pixels is one more than the index
+   * difference, "+ 2" is because we need one extra at each end.
+   */
+  const gint index_width  = right_j  + ( 1 + 2 + SAFETY_OFFSET );
+  const gint index_height = bottom_i + ( 1 + 2 + SAFETY_OFFSET );
+
+  /*
+   * Set context_rect to the appropriate values.
+   */
+  GEGL_SAMPLER (self)->context_rect.width  = index_width;
+  GEGL_SAMPLER (self)->context_rect.height = index_height;
+
+  {
+    /*
+     * Get a pointer to the first channel of the top left overlapped
+     * pixel. There is one left row/column before the
+     * (absolute_left_j,absolute_top_i) coordinate because the
+     * context_rect.x and context_rect.y offsets are set to -1.
+     */
+    const gfloat* restrict in_bptr =
+      gegl_sampler_get_ptr (self, absolute_left_j, absolute_top_i);
+
+    /*
+     * Useful pointer shifts:
+     */
+    const gint skip     = channels;
+    const gint row_skip = pixels_per_fetched_row * channels;
+
+    /*
+     * Computation of the integral of the piecewise linear "minmod
+     * surface" over the rectangle:
+     */
+    /*
+     * Accumulators for various pieces:
+     */
+    gfloat top_0 = 0.f,     top_1 = 0.f,     top_2 = 0.f,     top_3 = 0.f;
+    gfloat left_0 = 0.f,    left_1 = 0.f,    left_2 = 0.f,    left_3 = 0.f;
+    gfloat center_0 = 0.f,  center_1 = 0.f,  center_2 = 0.f,  center_3 = 0.f;
+    gfloat right_0 = 0.f,   right_1 = 0.f,   right_2 = 0.f,   right_3 = 0.f;
+    gfloat bottom_0 = 0.f,  bottom_1 = 0.f,  bottom_2 = 0.f,  bottom_3 = 0.f;
+
+    /*
+     * Top left pixel area:
+     */
+    /*
+     * First channel:
+     */
+    const gfloat top_left_0 = in_bptr[0];
+    /*
+     * Second channel:
+     */
+    const gfloat top_left_1 = in_bptr[1];
+    /*
+     * Third channel:
+     */
+    const gfloat top_left_2 = in_bptr[2];
+    /*
+     * Fourth channel:
+     */
+    const gfloat top_left_3 = in_bptr[3];
+
+    {
+      /*
+       * Integral over the top strip, excluding the top left and top
+       * right pixel areas which are done separately:
+       */
+      const gfloat* restrict in = in_bptr + skip;
+      /*
+       * Accumulators:
+       */
+      gint j = 1;
+      while (j < right_j)
+        {
+          top_0 += *in++;
+          top_1 += *in++;
+          top_2 += *in++;
+          top_3 += *in++;
+          j++;
+        }
+    }
+
+    {
+      const gint to_topright = right_j * skip;
+
+      /*
+       * Top right pixel area:
+       */
+      const gfloat top_right_0 = in_bptr[to_topright];
+      const gfloat top_right_1 = in_bptr[to_topright+1];
+      const gfloat top_right_2 = in_bptr[to_topright+2];
+      const gfloat top_right_3 = in_bptr[to_topright+3];
+
+      const gfloat delta_x_left  = absolute_left_j + .5 - left;
+      const gfloat delta_x_right = right_plus_half - absolute_right_j;
+      const gfloat delta_y_top   = absolute_top_i  + .5 - top;
+
+      gfloat integral_0 =
+        delta_y_top
+        * ( delta_x_left * top_left_0 + top_0 + delta_x_right * top_right_0 );
+      gfloat integral_1 =
+        delta_y_top
+        * ( delta_x_left * top_left_1 + top_1 + delta_x_right * top_right_1 );
+      gfloat integral_2 =
+        delta_y_top
+        * ( delta_x_left * top_left_2 + top_2 + delta_x_right * top_right_2 );
+      gfloat integral_3 =
+        delta_y_top
+        * ( delta_x_left * top_left_3 + top_3 + delta_x_right * top_right_3 );
+
+      {
+        /*
+         * Left strip, excluding top left and bottom left:
+         */
+        gint i = 1;
+        while (i < bottom_i)
+          {
+            const gfloat* restrict in = in_bptr + i * row_skip;
+            left_0 += *in++;
+            left_1 += *in++;
+            left_2 += *in++;
+            left_3 += *in++;
+            i++;
+          }
+      }
+
+      {
+        /*
+         * Pixel areas which are always fully covered by the averaging box:
+         */
+        gint i = 1;
+        while ( i < bottom_i )
+          {
+            const gfloat* restrict in = in_bptr + skip + i * row_skip;
+            gint j = 1;
+            while ( j < right_j )
+              {
+                center_0 += *in++;
+                center_1 += *in++;
+                center_2 += *in++;
+                center_3 += *in++;
+                j++;
+              }
+            i++;
+          }
+      }
+
+      {
+        /*
+         * Right strip, excluding top right and bottom right:
+         */
+        gint i = 1;
+        while (i < bottom_i)
+          {
+            const gfloat* restrict in = in_bptr + to_topright + i * row_skip;
+            right_0 += *in++;
+            right_1 += *in++;
+            right_2 += *in++;
+            right_3 += *in++;
+            i++;
+          }
+      }
+
+      integral_0 += delta_x_left * left_0 + center_0 + delta_x_right * right_0;
+      integral_1 += delta_x_left * left_1 + center_1 + delta_x_right * right_1;
+      integral_2 += delta_x_left * left_2 + center_2 + delta_x_right * right_2;
+      integral_3 += delta_x_left * left_3 + center_3 + delta_x_right * right_3;
+
+      {
+        const gint to_leftbottom = bottom_i * row_skip;
+
+        /*
+         * Bottom left pixel area:
+         */
+        const gfloat bottom_left_0 = in_bptr[to_leftbottom];
+        const gfloat bottom_left_1 = in_bptr[to_leftbottom+1];
+        const gfloat bottom_left_2 = in_bptr[to_leftbottom+2];
+        const gfloat bottom_left_3 = in_bptr[to_leftbottom+3];
+
+        {
+          /*
+           * Bottom strip, excluding bottom left and bottom right:
+           */
+          const gfloat* restrict in = in_bptr + skip + to_leftbottom;
+          gint j = 1;
+          while (j < right_j)
+            {
+              bottom_0 += *in++;
+              bottom_1 += *in++;
+              bottom_2 += *in++;
+              bottom_3 += *in++;
+              j++;
+            }
+        }
+
+        {
+          const gint to_rightbottom = to_topright + to_leftbottom;
+
+          /*
+           * Bottom right pixel area:
+           */
+          const gfloat bottom_right_0 = in_bptr[to_rightbottom];
+          const gfloat bottom_right_1 = in_bptr[to_rightbottom+1];
+          const gfloat bottom_right_2 = in_bptr[to_rightbottom+2];
+          const gfloat bottom_right_3 = in_bptr[to_rightbottom+3];
+
+          const gfloat delta_y_bottom = bottom_plus_half - absolute_bottom_i;
+
+          integral_0 +=
+            delta_y_bottom
+            * ( delta_x_left * bottom_left_0 + bottom_0
+                + delta_x_right * bottom_right_0 );
+          integral_1 +=
+            delta_y_bottom
+            * ( delta_x_left * bottom_left_1 + bottom_1
+                + delta_x_right * bottom_right_1 );
+          integral_2 +=
+            delta_y_bottom
+            * ( delta_x_left * bottom_left_2 + bottom_2
+                + delta_x_right * bottom_right_2 );
+          integral_3 +=
+            delta_y_bottom
+            * ( delta_x_left * bottom_left_3 + bottom_3
+                + delta_x_right * bottom_right_3 );
+
+          {
+            /*
+             * The newval array will contain one computed resampled value
+             * per channel:
+             */
+            gfloat newval[channels];
+            newval[0] = integral_0 * one_over_box_area;
+            newval[1] = integral_1 * one_over_box_area;
+            newval[2] = integral_2 * one_over_box_area;
+            newval[3] = integral_3 * one_over_box_area;
+
+            /*
+             * Ship out newval (array of computed new pixel values):
+             */
+            babl_process (babl_fish (self->interpolate_format, self->format),
+                          newval, output, 1);
+          }
+        }
+      }
+    }
+  }
+}
+
+
+static void
+set_property (      GObject*    object,
+                    guint       property_id,
+              const GValue*     value,
+                    GParamSpec* pspec)
+{
+/*   G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); */
+}
+
+static void
+get_property (GObject*    object,
+              guint       property_id,
+              GValue*     value,
+              GParamSpec* pspec)
+{
+/*   G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); */
+}
diff --git a/gegl/buffer/gegl-sampler-downsizefast.h b/gegl/buffer/gegl-sampler-downsizefast.h
new file mode 100644
index 0000000..abc1473
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-downsizefast.h
@@ -0,0 +1,48 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __GEGL_SAMPLER_DOWNSIZEFAST_H__
+#define __GEGL_SAMPLER_DOWNSIZEFAST_H__
+
+#include "gegl-sampler.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_SAMPLER_DOWNSIZEFAST            (gegl_sampler_downsizefast_get_type ())
+#define GEGL_SAMPLER_DOWNSIZEFAST(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_SAMPLER_DOWNSIZEFAST, GeglSamplerDownsizefast))
+#define GEGL_SAMPLER_DOWNSIZEFAST_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GEGL_TYPE_SAMPLER_DOWNSIZEFAST, GeglSamplerDownsizefastClass))
+#define GEGL_IS_SAMPLER_DOWNSIZEFAST(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_SAMPLER_DOWNSIZEFAST))
+#define GEGL_IS_SAMPLER_DOWNSIZEFAST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GEGL_TYPE_SAMPLER_DOWNSIZEFAST))
+#define GEGL_SAMPLER_DOWNSIZEFAST_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GEGL_TYPE_SAMPLER_DOWNSIZEFAST, GeglSamplerDownsizefastClass))
+
+typedef struct _GeglSamplerDownsizefast      GeglSamplerDownsizefast;
+typedef struct _GeglSamplerDownsizefastClass GeglSamplerDownsizefastClass;
+
+struct _GeglSamplerDownsizefast
+{
+  GeglSampler parent_instance;
+};
+
+struct _GeglSamplerDownsizefastClass
+{
+  GeglSamplerClass parent_class;
+};
+
+GType gegl_sampler_downsizefast_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/gegl/buffer/gegl-sampler-downsmoothfast.c b/gegl/buffer/gegl-sampler-downsmoothfast.c
new file mode 100644
index 0000000..3b70187
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-downsmoothfast.c
@@ -0,0 +1,26 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 2009 (c) Adam Turcotte and Nicolas Robidoux.
+ */
+
+/*
+ * The following #define sets the stage for the compilation of
+ * Downsmoothfast from the gegl-sampler-downsizefast.c source code:
+ */
+#define __GEGL_SAMPLER_DOWNSMOOTHFAST_C__
+#include "gegl-sampler-downsizefast.c"
+#undef __GEGL_SAMPLER_DOWNSMOOTHFAST_C__
diff --git a/gegl/buffer/gegl-sampler-downsmoothfast.h b/gegl/buffer/gegl-sampler-downsmoothfast.h
new file mode 100644
index 0000000..6c51c8f
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-downsmoothfast.h
@@ -0,0 +1,48 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __GEGL_SAMPLER_DOWNSMOOTHFAST_H__
+#define __GEGL_SAMPLER_DOWNSMOOTHFAST_H__
+
+#include "gegl-sampler.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_SAMPLER_DOWNSMOOTHFAST            (gegl_sampler_downsmoothfast_get_type ())
+#define GEGL_SAMPLER_DOWNSMOOTHFAST(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_SAMPLER_DOWNSMOOTHFAST, GeglSamplerDownsmoothfast))
+#define GEGL_SAMPLER_DOWNSMOOTHFAST_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GEGL_TYPE_SAMPLER_DOWNSMOOTHFAST, GeglSamplerDownsmoothfastClass))
+#define GEGL_IS_SAMPLER_DOWNSMOOTHFAST(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_SAMPLER_DOWNSMOOTHFAST))
+#define GEGL_IS_SAMPLER_DOWNSMOOTHFAST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GEGL_TYPE_SAMPLER_DOWNSMOOTHFAST))
+#define GEGL_SAMPLER_DOWNSMOOTHFAST_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GEGL_TYPE_SAMPLER_DOWNSMOOTHFAST, GeglSamplerDownsmoothfastClass))
+
+typedef struct _GeglSamplerDownsmoothfast      GeglSamplerDownsmoothfast;
+typedef struct _GeglSamplerDownsmoothfastClass GeglSamplerDownsmoothfastClass;
+
+struct _GeglSamplerDownsmoothfast
+{
+  GeglSampler parent_instance;
+};
+
+struct _GeglSamplerDownsmoothfastClass
+{
+  GeglSamplerClass parent_class;
+};
+
+GType gegl_sampler_downsmoothfast_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/gegl/buffer/gegl-sampler-upsharp.c b/gegl/buffer/gegl-sampler-upsharp.c
new file mode 100644
index 0000000..1212f25
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-upsharp.c
@@ -0,0 +1,1166 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 2009 (c) Adam Turcotte, Nicolas Robidoux, �yvind Kolås and Geert
+ * Jordaens.
+ */
+
+/*
+ * ===============
+ * UPSHARP SAMPLER
+ * ===============
+ *
+ * "Upsharp" is the GEGL name of the Nohalo level 2 resampler
+ *
+ * ====================================================================
+ * THIS CODE ONLY IMPLEMENTS THE SECOND LOWEST QUALITY NOHALO RESAMPLER
+ * ====================================================================
+ *
+ * This code implement Nohalo for (quality) level = 2.
+ *
+ * ================
+ * NOHALO RESAMPLER
+ * ================
+ *
+ * "Nohalo" is a family of parameterized resamplers with a mission:
+ * smoothly straightening oblique lines without undesirable
+ * side-effects, in particular, without much blurring and with
+ * absolutely no added haloing.
+ *
+ * The main parameter of the family is the number of "levels" of
+ * binary subdivision which are performed. Level = 0 can be thought of
+ * as being plain vanilla bilinear resampling; level = 1 is then the
+ * first "non-classical" method of the family.
+ *
+ * Although it increases computational cost, additional levels
+ * increase the quality of the resampled pixel value unless the
+ * resampled location happens to be exactly where a subdivided grid
+ * point (for this level) is located, in which case further levels do
+ * not change the answer, and consequently do not increase its
+ * quality.
+ *
+ * ===============
+ * MAIN PROPERTIES
+ * ===============
+ *
+ * =======================
+ * Nohalo is interpolatory
+ * =======================
+ *
+ * Nohalo preserves point values: If asked for the value at (the
+ * center of) an input pixel, the sampler returns the corresponding
+ * value, unchanged. In addition, because Nohalo is continuous, if
+ * asked for a value at a location "very close" to the center of an
+ * input pixel, then the sampler returns a value "very close" to
+ * it. (Nohalo is not smoothing like, say, B-Spline
+ * pseudo-interpolation, or Snohalo with nonzero smoothing.)
+ *
+ * ============================================
+ * Nohalo is co-monotone ("nohalo" = "no halo")
+ * ============================================
+ *
+ * What monotonicity more or less means here is that the resampled
+ * value is in the range of the four closest input
+ * values. Monotonicity implies that Nohalo does not add haloing. It
+ * also implies that clamping is unnecessary (provided abyss values
+ * are within the range of acceptable values, which is always the
+ * case). (Note: plain vanilla bilinear and nearest neighbour are also
+ * co-monotone.)
+ *
+ * Note: If the abyss policy is such that all values are within the
+ * "clamping range," and/or all the sampling locations are in the
+ * convex hull of the input image pixel locations, clamping is not
+ * necessary. If the abyss policy is an extrapolating one---for
+ * example, linear or bilinear extrapolation---clamping is still
+ * unnecessary unless one attempts to resample outside of the convex
+ * hull of the input pixel positions. Consequence: the usual
+ * "interpolatory" image size convention (often associated with "pixel
+ * center-based coordinates") does not require clamping when using
+ * linear extrapolation abyss policy when performing image resizing,
+ * but the usual "exact area" image size convention (often associated
+ * with "pixel corner-based coordinates") requires clamping at
+ * locations very close to or outside the boundary. With the usual
+ * nearest neighbour abyss policy, or a "fill with legal color" abyss
+ * policy, claming is not necessary.
+ *
+ * ========================
+ * Nohalo is a local method
+ * ========================
+ *
+ * The value of the reconstructed intensity surface at any point
+ * depends on the values of (at most) 12 nearby input values, located
+ * in a "cross" centered at the closest four input pixel centers.
+ *
+ * ===============================
+ * Nohalo is second order accurate
+ * ===============================
+ *
+ * (Except possibly near the boundary: it is easy to make this
+ * property carry over everywhere but this requires a tuned abyss
+ * policy---linear extrapolation, say---or building the boundary
+ * conditions inside the sampler.)  Nohalo is exact on linear
+ * intensity profiles, meaning that if the input pixel values (in the
+ * stencil) are obtained from a function of the form
+ *
+ * f(x,y) = a + b*x + c*y (a, b, c constants),
+ *
+ * then the computed pixel value is exactly the value of f(x,y) at the
+ * asked-for sampling location.
+ *
+ * With nearest neighbour or "extend with fixed background color,"
+ * Nohalo is NOT exact on linears near and past the boundary.
+ *
+ * ===================
+ * Nohalo is nonlinear
+ * ===================
+ *
+ * In particular, resampling a sum of images may not be the same as
+ * summing the resamples. (This occurs even without taking into
+ * account over and underflow issues: images can only take values
+ * within a banded range, and consequently non-monotone linear
+ * samplers are also not truly linear.)
+ *
+ * ==========
+ * WEAKNESSES
+ * ==========
+ *
+ * In some cases, the first level nonlinear computation is a
+ * waste. For example, in the interior of a bichromatic image region,
+ * the nonlinear component of the level 1 Nohalo is zero, and
+ * consequently Nohalo level 1 boils down to bilinear. For such
+ * images, either stick to bilinear, or use a higher level (quality)
+ * setting. (There is no real harm in using Nohalo when it boils down
+ * to bilinear if one does not mind wasting cycles.)
+ *
+ * ==================================
+ * CENTER-BASED COORDINATE CONVENTION
+ * ==================================
+ *
+ * This code uses the "center-based coordinate" convention, in which
+ * pixels are understood to be centered at integer index
+ * locations. For example, the very first actual image pixel may be
+ * located at (0,0), and the last one at (N-1,M-1), where M is the
+ * number of pixel rows of the input image, and N is its number of
+ * pixel columns.
+ */
+
+/*
+ * Acknowledgements: Adam Turcotte's Nohalo programming funded by Google
+ * Summer of Code 2009.  Nicolas Robidoux's research on Nohalo funded
+ * in part by an NSERC (National Science and Engineering Research
+ * Council of Canada) Discovery Grant.
+ *
+ * Nicolas Robidoux thanks Ralf Meyer, Geert Jordaens, �yvind Kolås,
+ * John Cupitt, Minglun Gong, and Sven Neumann for useful comments and
+ * code.
+ */
+
+#include "config.h"
+#include <glib-object.h>
+
+#include "gegl.h"
+#include "gegl-types-internal.h"
+#include "gegl-buffer-private.h"
+
+#include "gegl-sampler-upsharp.h"
+
+/*
+ * FAST_MINMOD is an implementation of the minmod function which only
+ * needs two conditional moves. FAST_MINMOD(a,b,a_times_a,a_times_b)
+ * "returns" minmod(a,b). The parameter ("input") a_times_a is assumed
+ * to contain the square of a; a_times_b, the product of a and b.
+ *
+ * This version is most suitable for images with flat (constant)
+ * colour areas, since a, which is a pixel difference, will often be
+ * 0, in which case both forward branches are likely.
+ *
+ * For uncompressed natural images in high bit depth (images for which
+ * the slopes a and b are unlikely to be equal to zero or be equal to
+ * each other), we recommend using
+ *
+ * ( (a_times_b)>=0. ? 1. : 0. ) * ( (a_times_b)<(a_times_a) ? (b) : (a) )
+ *
+ * instead. With this second version, the forward branch of the second
+ * conditional move is taken when |b|>|a| and when a*b<0. However, the
+ * "else" branch is taken when a=0 (or when a=b), which is why the
+ * above version is not recommended for images with regions with
+ * constant pixel values (or regions with pixel values which vary
+ * bilinearly).
+ */
+#define FAST_MINMOD(a,b,a_times_a,a_times_b) \
+ ( (a_times_b)>=0.f ? 1.f : 0.f ) * ( (a_times_a)<=(a_times_b) ? (a) : (b) )
+
+/*
+ * FAST_PSEUDO_FLOOR is a floor replacement which has been found to be
+ * faster. It returns the floor of its argument unless the argument is
+ * a negative integer, in which case it returns one less than the
+ * floor. For example:
+ *
+ * FAST_PSEUDO_FLOOR(0.5) = 0
+ *
+ * FAST_PSEUDO_FLOOR(0.) = 0
+ *
+ * FAST_PSEUDO_FLOOR(-.5) = -1
+ *
+ * as expected, but
+ *
+ * FAST_PSEUDO_FLOOR(-1.) = -2
+ *
+ * The discontinuities of FAST_PSEUDO_FLOOR are on the right of
+ * negative numbers instead of on the left as is the case for floor.
+ */
+#define FAST_PSEUDO_FLOOR(x) ( (gint)(x) - ( (x) < 0. ) )
+
+/*
+ * Hack to get the restrict C99 keyword going at least some of the
+ * time:
+ */
+#ifndef restrict
+#ifdef __restrict
+#define restrict __restrict
+#else
+#ifdef __restrict__
+#define restrict __restrict__
+#else
+#define restrict
+#endif
+#endif
+#endif
+
+enum
+{
+  PROP_0,
+  PROP_LAST
+};
+
+static void gegl_sampler_upsharp_get (      GeglSampler* restrict self,
+                                      const gdouble               absolute_x,
+                                      const gdouble               absolute_y,
+                                              void*      restrict output);
+
+static void set_property (      GObject*    gobject,
+                                guint       property_id,
+                          const GValue*     value,
+                                GParamSpec* pspec);
+
+static void get_property (GObject*    gobject,
+                          guint       property_id,
+                          GValue*     value,
+                          GParamSpec* pspec);
+
+G_DEFINE_TYPE (GeglSamplerUpsharp, gegl_sampler_upsharp, GEGL_TYPE_SAMPLER)
+
+static void
+gegl_sampler_upsharp_class_init (GeglSamplerUpsharpClass *klass)
+{
+  GeglSamplerClass *sampler_class = GEGL_SAMPLER_CLASS (klass);
+  GObjectClass *object_class  = G_OBJECT_CLASS (klass);
+  object_class->set_property = set_property;
+  object_class->get_property = get_property;
+  sampler_class->get = gegl_sampler_upsharp_get;
+}
+
+static void
+gegl_sampler_upsharp_init (GeglSamplerUpsharp *self)
+{
+  GEGL_SAMPLER (self)->context_rect.x = -1;
+  GEGL_SAMPLER (self)->context_rect.y = -1;
+  GEGL_SAMPLER (self)->context_rect.width = 4;
+  GEGL_SAMPLER (self)->context_rect.height = 4;
+  GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
+}
+
+static void inline
+nohalo_step1 (const gfloat           uno_thr,
+              const gfloat           uno_fou,
+              const gfloat           dos_two,
+              const gfloat           dos_thr,
+              const gfloat           dos_fou,
+              const gfloat           dos_fiv,
+              const gfloat           tre_one,
+              const gfloat           tre_two,
+              const gfloat           tre_thr,
+              const gfloat           tre_fou,
+              const gfloat           tre_fiv,
+              const gfloat           qua_one,
+              const gfloat           qua_two,
+              const gfloat           qua_thr,
+              const gfloat           qua_fou,
+              const gfloat           qua_fiv,
+              const gfloat           cin_two,
+              const gfloat           cin_thr,
+              const gfloat           cin_fou,
+                    gfloat* restrict uno_two_1,
+                    gfloat* restrict uno_thr_1,
+                    gfloat* restrict dos_one_1,
+                    gfloat* restrict dos_two_1,
+                    gfloat* restrict dos_thr_1,
+                    gfloat* restrict dos_fou_1,
+                    gfloat* restrict tre_one_1,
+                    gfloat* restrict tre_two_1,
+                    gfloat* restrict tre_thr_1,
+                    gfloat* restrict tre_fou_1,
+                    gfloat* restrict qua_two_1,
+                    gfloat* restrict qua_thr_1)
+{
+  /*
+   * This function calculates the missing ten double density pixel
+   * values, and also returns the "already known" two, so that the
+   * twelve values which make up the stencil of nohalo level 1 are
+   * available. One level of nohalo subdivision is then applied to
+   * these 12 values, prior to applying bilinear interpolation.
+   */
+  /*
+   * THE STENCIL OF INPUT VALUES:
+   *
+   * Pointer arithmetic is used to implicitly reflect the input
+   * stencil about tre_thr---assumed closer to the sampling location
+   * than other pixels (ties are OK)---in such a way that after
+   * reflection the sampling point is to the bottom right of tre_thr.
+   *
+   * The following code and picture assumes that the stencil reflexion
+   * has already been performed.
+   *
+   *
+   *                            (ix,iy-2)    (ix+1,iy-2)
+   *                            = uno_thr    = uno_fou
+   *
+   *
+   *
+   *               (ix-1,iy-1)  (ix,iy-1)    (ix+1,iy-1)  (ix+2,iy-1)
+   *               = dos_two    = dos_thr    = dos_fou    = dos_fiv
+   *
+   *
+   *
+   *  (ix-2,iy)    (ix-1,iy)    (ix,iy)      (ix+1,iy)    (ix+2,iy)
+   *  = tre_one    = tre_two    = tre_thr    = tre_fou    = tre_fiv
+   *                                     X
+   *
+   *
+   *  (ix-2,iy)    (ix-1,iy+1)  (ix,iy+1)    (ix+1,iy+1)  (ix+2,iy+1)
+   *  = qua_one    = qua_two    = qua_thr    = qua_fou    = qua_fiv
+   *
+   *
+   *
+   *               (ix-1,iy+2)  (ix,iy+2)    (ix+1,iy+2)
+   *               = cin_two    = cin_thr    = cin_fou
+   *
+   *
+   * The above input pixel values are the ones needed in order to make
+   * available to the second level the following first (and
+   * zero=input) level values:
+   *
+   *                   uno_two_1 =  uno_thr_1 =
+   *                   (ix,iy-1/2)  (ix+1/2,iy-1/2)
+   *
+   *
+   *
+   *
+   *  dos_one_1 =      dos_two_1 =  dos_thr_1 =      dos_fou_1 =
+   *  (ix-1/2,iy)      (ix,iy)      (ix+1/2,iy)      (ix+1,iy)
+   *
+   *                             X
+   *
+   *
+   *  tre_one_1 =      tre_two_1 =  tre_thr_1 =      tre_fou_1 =
+   *  (ix-1/2,iy+1/2)  (ix,iy+1/2)  (ix+1/2,iy+1/2)  (ix+1,iy+1/2)
+   *
+   *
+   *
+   *
+   *                   qua_two_1 =  qua_thr_1 =
+   *                   (ix,iy+1)    (ix+1/2,iy+1)
+   *
+   *
+   * to which nohalo level 1 is applied by the caller.
+   */
+
+  /*
+   * Computation of the nonlinear slopes: If two consecutive pixel
+   * value differences have the same sign, the smallest one (in
+   * absolute value) is taken to be the corresponding slope; if the
+   * two consecutive pixel value differences don't have the same sign,
+   * the corresponding slope is set to 0. In other words, apply minmod
+   * to comsecutive differences.
+   */
+  /*
+   * Two vertical simple differences:
+   */
+  const gfloat d_dostre_two = tre_two - dos_two;
+  const gfloat d_trequa_two = qua_two - tre_two;
+  const gfloat d_quacin_two = cin_two - qua_two;
+  /*
+   * Thr(ee) vertical differences:
+   */
+  const gfloat d_unodos_thr = dos_thr - uno_thr;
+  const gfloat d_dostre_thr = tre_thr - dos_thr;
+  const gfloat d_trequa_thr = qua_thr - tre_thr;
+  const gfloat d_quacin_thr = cin_thr - qua_thr;
+  /*
+   * Fou(r) vertical differences:
+   */
+  const gfloat d_unodos_fou = dos_fou - uno_fou;
+  const gfloat d_dostre_fou = tre_fou - dos_fou;
+  const gfloat d_trequa_fou = qua_fou - tre_fou;
+  const gfloat d_quacin_fou = cin_fou - qua_fou;
+  /*
+   * Dos horizontal differences:
+   */
+  const gfloat d_dos_twothr = dos_thr - dos_two;
+  const gfloat d_dos_thrfou = dos_fou - dos_thr;
+  const gfloat d_dos_foufiv = dos_fiv - dos_fou;
+  /*
+   * Tre(s) horizontal differences:
+   */
+  const gfloat d_tre_onetwo = tre_two - tre_one;
+  const gfloat d_tre_twothr = tre_thr - tre_two;
+  const gfloat d_tre_thrfou = tre_fou - tre_thr;
+  const gfloat d_tre_foufiv = tre_fiv - tre_fou;
+  /*
+   * Qua(ttro) horizontal differences:
+   */
+  const gfloat d_qua_onetwo = qua_two - qua_one;
+  const gfloat d_qua_twothr = qua_thr - qua_two;
+  const gfloat d_qua_thrfou = qua_fou - qua_thr;
+  const gfloat d_qua_foufiv = qua_fiv - qua_fou;
+
+  /*
+   * Recyclable vertical products and squares:
+   */
+  const gfloat d_dostre_times_trequa_two = d_dostre_two * d_trequa_two;
+  const gfloat d_trequa_two_sq           = d_trequa_two * d_trequa_two;
+  const gfloat d_trequa_times_quacin_two = d_quacin_two * d_trequa_two;
+
+  const gfloat d_unodos_times_dostre_thr = d_unodos_thr * d_dostre_thr;
+  const gfloat d_dostre_thr_sq           = d_dostre_thr * d_dostre_thr;
+  const gfloat d_dostre_times_trequa_thr = d_trequa_thr * d_dostre_thr;
+  const gfloat d_trequa_times_quacin_thr = d_trequa_thr * d_quacin_thr;
+  const gfloat d_quacin_thr_sq           = d_quacin_thr * d_quacin_thr;
+
+  const gfloat d_unodos_times_dostre_fou = d_unodos_fou * d_dostre_fou;
+  const gfloat d_dostre_fou_sq           = d_dostre_fou * d_dostre_fou;
+  const gfloat d_dostre_times_trequa_fou = d_trequa_fou * d_dostre_fou;
+  const gfloat d_trequa_times_quacin_fou = d_trequa_fou * d_quacin_fou;
+  const gfloat d_quacin_fou_sq           = d_quacin_fou * d_quacin_fou;
+  /*
+   * Recyclable horizontal products and squares:
+   */
+  const gfloat d_dos_twothr_times_thrfou = d_dos_twothr * d_dos_thrfou;
+  const gfloat d_dos_thrfou_sq           = d_dos_thrfou * d_dos_thrfou;
+  const gfloat d_dos_thrfou_times_foufiv = d_dos_foufiv * d_dos_thrfou;
+
+  const gfloat d_tre_onetwo_times_twothr = d_tre_onetwo * d_tre_twothr;
+  const gfloat d_tre_twothr_sq           = d_tre_twothr * d_tre_twothr;
+  const gfloat d_tre_twothr_times_thrfou = d_tre_thrfou * d_tre_twothr;
+  const gfloat d_tre_thrfou_times_foufiv = d_tre_thrfou * d_tre_foufiv;
+  const gfloat d_tre_foufiv_sq           = d_tre_foufiv * d_tre_foufiv;
+
+  const gfloat d_qua_onetwo_times_twothr = d_qua_onetwo * d_qua_twothr;
+  const gfloat d_qua_twothr_sq           = d_qua_twothr * d_qua_twothr;
+  const gfloat d_qua_twothr_times_thrfou = d_qua_thrfou * d_qua_twothr;
+  const gfloat d_qua_thrfou_times_foufiv = d_qua_thrfou * d_qua_foufiv;
+  const gfloat d_qua_foufiv_sq           = d_qua_foufiv * d_qua_foufiv;
+
+  /*
+   * Minmod slopes and first level pixel values:
+   */
+  const gfloat dos_thr_y =
+    FAST_MINMOD( d_dostre_thr, d_unodos_thr,
+                 d_dostre_thr_sq,
+                 d_unodos_times_dostre_thr );
+  const gfloat tre_thr_y =
+    FAST_MINMOD( d_dostre_thr, d_trequa_thr,
+                 d_dostre_thr_sq,
+                 d_dostre_times_trequa_thr );
+
+  const gfloat val_uno_two_1 =
+    .5 * ( dos_thr + tre_thr )
+    +
+    .25 * ( dos_thr_y - tre_thr_y );
+
+  const gfloat qua_thr_y =
+    FAST_MINMOD( d_quacin_thr, d_trequa_thr,
+                 d_quacin_thr_sq,
+                 d_trequa_times_quacin_thr );
+
+  const gfloat val_tre_two_1 =
+    .5 * ( tre_thr + qua_thr )
+    +
+    .25 * ( tre_thr_y - qua_thr_y );
+
+  const gfloat tre_fou_y =
+    FAST_MINMOD( d_dostre_fou, d_trequa_fou,
+                 d_dostre_fou_sq,
+                 d_dostre_times_trequa_fou );
+  const gfloat qua_fou_y =
+    FAST_MINMOD( d_quacin_fou, d_trequa_fou,
+                 d_quacin_fou_sq,
+                 d_trequa_times_quacin_fou );
+
+  const gfloat val_tre_fou_1 =
+    .5 * ( tre_fou + qua_fou )
+    +
+    .25 * ( tre_fou_y - qua_fou_y );
+
+  const gfloat tre_two_x =
+    FAST_MINMOD( d_tre_twothr, d_tre_onetwo,
+                 d_tre_twothr_sq,
+                 d_tre_onetwo_times_twothr );
+  const gfloat tre_thr_x =
+    FAST_MINMOD( d_tre_twothr, d_tre_thrfou,
+                 d_tre_twothr_sq,
+                 d_tre_twothr_times_thrfou );
+
+  const gfloat val_dos_one_1 =
+    .5 * ( tre_two + tre_thr )
+    +
+    .25 * ( tre_two_x - tre_thr_x );
+
+  const gfloat tre_fou_x =
+    FAST_MINMOD( d_tre_foufiv, d_tre_thrfou,
+                 d_tre_foufiv_sq,
+                 d_tre_thrfou_times_foufiv );
+
+  const gfloat tre_thr_x_minus_tre_fou_x =
+    tre_thr_x - tre_fou_x;
+
+  const gfloat val_dos_thr_1 =
+    .5 * ( tre_thr + tre_fou )
+    +
+    .25 * tre_thr_x_minus_tre_fou_x;
+
+  const gfloat qua_thr_x =
+    FAST_MINMOD( d_qua_twothr, d_qua_thrfou,
+                 d_qua_twothr_sq,
+                 d_qua_twothr_times_thrfou );
+  const gfloat qua_fou_x =
+    FAST_MINMOD( d_qua_foufiv, d_qua_thrfou,
+                 d_qua_foufiv_sq,
+                 d_qua_thrfou_times_foufiv );
+
+  const gfloat qua_thr_x_minus_qua_fou_x =
+    qua_thr_x - qua_fou_x;
+
+  const gfloat val_qua_thr_1 =
+    .5 * ( qua_thr + qua_fou )
+    +
+    .25 * qua_thr_x_minus_qua_fou_x;
+  const gfloat val_tre_thr_1 =
+    .125 * ( tre_thr_x_minus_tre_fou_x + qua_thr_x_minus_qua_fou_x )
+    +
+    .5 * ( val_tre_two_1 + val_tre_fou_1 );
+
+  const gfloat dos_fou_y =
+    FAST_MINMOD( d_dostre_fou, d_unodos_fou,
+                 d_dostre_fou_sq,
+                 d_unodos_times_dostre_fou );
+  const gfloat dos_thr_x =
+    FAST_MINMOD( d_dos_thrfou, d_dos_twothr,
+                 d_dos_thrfou_sq,
+                 d_dos_twothr_times_thrfou );
+  const gfloat dos_fou_x =
+    FAST_MINMOD( d_dos_thrfou, d_dos_foufiv,
+                 d_dos_thrfou_sq,
+                 d_dos_thrfou_times_foufiv );
+
+  const gfloat val_uno_thr_1 =
+    .25 * ( dos_fou - tre_thr )
+    +
+    .125 * ( dos_fou_y - tre_fou_y + dos_thr_x - dos_fou_x )
+    +
+    .5 * ( val_uno_two_1 + val_dos_thr_1 );
+
+  const gfloat qua_two_x =
+    FAST_MINMOD( d_qua_twothr, d_qua_onetwo,
+                 d_qua_twothr_sq,
+                 d_qua_onetwo_times_twothr );
+  const gfloat tre_two_y =
+    FAST_MINMOD( d_trequa_two, d_dostre_two,
+                 d_trequa_two_sq,
+                 d_dostre_times_trequa_two );
+  const gfloat qua_two_y =
+    FAST_MINMOD( d_trequa_two, d_quacin_two,
+                 d_trequa_two_sq,
+                 d_trequa_times_quacin_two );
+
+  const gfloat val_tre_one_1 =
+    .25 * ( qua_two - tre_thr )
+    +
+    .125 * ( qua_two_x - qua_thr_x + tre_two_y - qua_two_y )
+    +
+    .5 * ( val_dos_one_1 + val_tre_two_1 );
+
+  /*
+   * Return level 1 stencil values:
+   */
+  *uno_two_1 = val_uno_two_1;
+  *uno_thr_1 = val_uno_thr_1;
+  *dos_one_1 = val_dos_one_1;
+  *dos_two_1 = tre_thr;
+  *dos_thr_1 = val_dos_thr_1;
+  *dos_fou_1 = tre_fou;
+  *tre_one_1 = val_tre_one_1;
+  *tre_two_1 = val_tre_two_1;
+  *tre_thr_1 = val_tre_thr_1;
+  *tre_fou_1 = val_tre_fou_1;
+  *qua_two_1 = qua_thr;
+  *qua_thr_1 = val_qua_thr_1;
+}
+
+static inline gfloat
+nohalo_step2 (const gfloat w_times_z,
+              const gfloat x_times_z_over_4_plus_x_times_y_over_8,
+              const gfloat w_times_y_over_4_plus_x_times_y_over_8,
+              const gfloat x_times_y_over_8,
+              const gfloat uno_two,
+              const gfloat uno_thr,
+              const gfloat dos_one,
+              const gfloat dos_two,
+              const gfloat dos_thr,
+              const gfloat dos_fou,
+              const gfloat tre_one,
+              const gfloat tre_two,
+              const gfloat tre_thr,
+              const gfloat tre_fou,
+              const gfloat qua_two,
+              const gfloat qua_thr)
+{
+  /*
+   * THE STENCIL OF INPUT VALUES:
+   *
+   * The footprint (stencil) of Nohalo level 1 is the same as, say,
+   * Catmull-Rom, with the exception that the four corner values are
+   * not used:
+   *
+   *               (ix,iy-1)    (ix+1,iy-1)
+   *               = uno_two    = uno_thr
+   *
+   *  (ix-1,iy)    (ix,iy)      (ix+1,iy)    (ix+2,iy)
+   *  = dos_one    = dos_two    = dos_thr    = dos_fou
+   *
+   *  (ix-1,iy+1)  (ix,iy+1)    (ix+1,iy+1)  (ix+2,iy+1)
+   *  = tre_one    = tre_two    = tre_thr    = tre_fou
+   *
+   *               (ix,iy+2)    (ix+1,iy+2)
+   *               = qua_two    = qua_thr
+   *
+   * Here, ix is the (pseudo-)floor of the requested left-to-right
+   * location, iy is the floor of the requested up-to-down location.
+   *
+   * Pointer arithmetic is used to implicitly reflect the input
+   * stencil so that the requested pixel location is closer to
+   * dos_two, The above consequently corresponds to the case in which
+   * absolute_x is closer to ix than ix+1, and absolute_y is closer to
+   * iy than iy+1. For example, if relative_x_is_rite = 1 but
+   * relative_y_is_down = 0 (see below), then dos_two corresponds to
+   * (ix+1,iy), dos_thr corresponds to (ix,iy) etc, and the three
+   * missing double density values are halfway between dos_two and
+   * dos_thr, halfway between dos_two and tre_two, and at the average
+   * of the four central positions.
+   *
+   * The following code assumes that the stencil has been suitably
+   * reflected.
+   */
+
+  /*
+   * Computation of the nonlinear slopes: If two consecutive pixel
+   * value differences have the same sign, the smallest one (in
+   * absolute value) is taken to be the corresponding slope; if the
+   * two consecutive pixel value differences don't have the same sign,
+   * the corresponding slope is set to 0. In other words, apply minmod
+   * to comsecutive differences.
+   *
+   * Dos(s) horizontal differences:
+   */
+  const gfloat prem_dos = dos_two - dos_one;
+  const gfloat deux_dos = dos_thr - dos_two;
+  const gfloat troi_dos = dos_fou - dos_thr;
+  /*
+   * Tre(s) horizontal differences:
+   */
+  const gfloat prem_tre = tre_two - tre_one;
+  const gfloat deux_tre = tre_thr - tre_two;
+  const gfloat troi_tre = tre_fou - tre_thr;
+  /*
+   * Two vertical differences:
+   */
+  const gfloat prem_two = dos_two - uno_two;
+  const gfloat deux_two = tre_two - dos_two;
+  const gfloat troi_two = qua_two - tre_two;
+  /*
+   * Thr(ee) vertical differences:
+   */
+  const gfloat prem_thr = dos_thr - uno_thr;
+  const gfloat deux_thr = tre_thr - dos_thr;
+  const gfloat troi_thr = qua_thr - tre_thr;
+
+  /*
+   * Products useful for minmod:
+   */
+  const gfloat deux_prem_dos = deux_dos * prem_dos;
+  const gfloat deux_deux_dos = deux_dos * deux_dos;
+  const gfloat deux_troi_dos = deux_dos * troi_dos;
+
+  const gfloat deux_prem_two = deux_two * prem_two;
+  const gfloat deux_deux_two = deux_two * deux_two;
+  const gfloat deux_troi_two = deux_two * troi_two;
+
+  const gfloat deux_prem_tre = deux_tre * prem_tre;
+  const gfloat deux_deux_tre = deux_tre * deux_tre;
+  const gfloat deux_troi_tre = deux_tre * troi_tre;
+
+  const gfloat deux_prem_thr = deux_thr * prem_thr;
+  const gfloat deux_deux_thr = deux_thr * deux_thr;
+  const gfloat deux_troi_thr = deux_thr * troi_thr;
+
+  /*
+   * Terms computed here to put space between the computation of key
+   * quantities and the related conditionals:
+   */
+  const gfloat twice_dos_two_plus_dos_thr = ( dos_two + dos_thr ) * 2.f;
+  const gfloat twice_dos_two_plus_tre_two = ( dos_two + tre_two ) * 2.f;
+  const gfloat twice_deux_thr_plus_deux_dos = ( deux_thr + deux_dos ) * 2.f;
+
+  /*
+   * Compute the needed "right" (at the boundary between one input
+   * pixel areas) double resolution pixel value:
+   */
+  const gfloat four_times_dos_twothr =
+    twice_dos_two_plus_dos_thr
+    +
+    FAST_MINMOD( deux_dos, prem_dos, deux_deux_dos, deux_prem_dos )
+    -
+    FAST_MINMOD( deux_dos, troi_dos, deux_deux_dos, deux_troi_dos );
+
+  /*
+   * Compute the needed "down" double resolution pixel value:
+   */
+  const gfloat four_times_dostre_two =
+    twice_dos_two_plus_tre_two
+    +
+    FAST_MINMOD( deux_two, prem_two, deux_deux_two, deux_prem_two )
+    -
+    FAST_MINMOD( deux_two, troi_two, deux_deux_two, deux_troi_two );
+
+  /*
+   * Compute the "diagonal" (at the boundary between four input pixel
+   * areas) double resolution pixel value:
+   */
+  const gfloat partial_eight_times_dostre_twothr =
+    twice_deux_thr_plus_deux_dos
+    +
+    FAST_MINMOD( deux_tre, prem_tre, deux_deux_tre, deux_prem_tre )
+    -
+    FAST_MINMOD( deux_tre, troi_tre, deux_deux_tre, deux_troi_tre )
+    +
+    FAST_MINMOD( deux_thr, prem_thr, deux_deux_thr, deux_prem_thr )
+    -
+    FAST_MINMOD( deux_thr, troi_thr, deux_deux_thr, deux_troi_thr );
+
+  /*
+   * Compute the output pixel value with bilinear applied to the
+   * reconstructed double density data:
+   */
+  const gfloat newval =
+    w_times_z * dos_two
+    +
+    x_times_z_over_4_plus_x_times_y_over_8 * four_times_dos_twothr
+    +
+    w_times_y_over_4_plus_x_times_y_over_8 * four_times_dostre_two
+    +
+    x_times_y_over_8 * partial_eight_times_dostre_twothr;
+
+  return newval;
+}
+
+#define NOHALO_SELECT_REFLECT(tl,tr,bl,br) ( \
+  (                                          \
+    (tl) * is_top_left                       \
+    +                                        \
+    (tr) * is_top_rite                       \
+  )                                          \
+  +                                          \
+  (                                          \
+    (bl) * is_bot_left                       \
+    +                                        \
+    (br) * is_bot_rite )                     \
+  )
+
+static void
+gegl_sampler_upsharp_get (      GeglSampler* restrict self,
+                         const gdouble               absolute_x,
+                         const gdouble               absolute_y,
+                               void*        restrict output)
+{
+  /*
+   * Needed constants related to the input pixel value pointer
+   * provided by gegl_sampler_get_ptr (self, ix, iy). pixels_per_row
+   * corresponds to fetch_rectangle.width in gegl_sampler_get_ptr.
+   */
+  const gint channels  = 4;
+  const gint pixels_per_row = 64;
+  const gint row_skip = channels * pixels_per_row;
+
+  const gint ix_0 = FAST_PSEUDO_FLOOR (absolute_x + .5);
+  const gint iy_0 = FAST_PSEUDO_FLOOR (absolute_y + .5);
+
+  const gfloat* restrict input_bptr =
+    (gfloat*) gegl_sampler_get_ptr (self, ix_0, iy_0);
+
+  const gfloat x_0 = absolute_x - ix_0;
+  const gfloat y_0 = absolute_y - iy_0;
+
+  const gint sign_of_x_0 = 2 * ( x_0 >= 0. ) - 1;
+  const gint sign_of_y_0 = 2 * ( y_0 >= 0. ) - 1;
+
+  const gint shift_forw_1_pix = sign_of_x_0 * channels;
+  const gint shift_forw_1_row = sign_of_y_0 * row_skip;
+
+  const gint shift_back_1_pix = -shift_forw_1_pix;
+  const gint shift_back_1_row = -shift_forw_1_row;
+
+  const gint shift_back_2_pix = 2 * shift_back_1_pix;
+  const gint shift_back_2_row = 2 * shift_back_1_row;
+  const gint shift_forw_2_pix = 2 * shift_forw_1_pix;
+  const gint shift_forw_2_row = 2 * shift_forw_1_row;
+
+  const gint uno_thr_shift =                    shift_back_2_row;
+  const gint uno_fou_shift = shift_forw_1_pix + shift_back_2_row;
+
+  const gint dos_two_shift = shift_back_1_pix + shift_back_1_row;
+  const gint dos_thr_shift =                    shift_back_1_row;
+  const gint dos_fou_shift = shift_forw_1_pix + shift_back_1_row;
+  const gint dos_fiv_shift = shift_forw_2_pix + shift_back_1_row;
+
+  const gint tre_one_shift = shift_back_2_pix;
+  const gint tre_two_shift = shift_back_1_pix;
+  const gint tre_thr_shift = 0;
+  const gint tre_fou_shift = shift_forw_1_pix;
+  const gint tre_fiv_shift = shift_forw_2_pix;
+
+  const gint qua_one_shift = shift_back_2_pix + shift_forw_1_row;
+  const gint qua_two_shift = shift_back_1_pix + shift_forw_1_row;
+  const gint qua_thr_shift =                    shift_forw_1_row;
+  const gint qua_fou_shift = shift_forw_1_pix + shift_forw_1_row;
+  const gint qua_fiv_shift = shift_forw_2_pix + shift_forw_1_row;
+
+  const gint cin_two_shift = shift_back_1_pix + shift_forw_2_row;
+  const gint cin_thr_shift =                    shift_forw_2_row;
+  const gint cin_fou_shift = shift_forw_1_pix + shift_forw_2_row;
+
+  /*
+   * Channel by channel computation of the new pixel values:
+   */
+  gfloat            uno_two_0, uno_thr_0;
+  gfloat dos_one_0, dos_two_0, dos_thr_0, dos_fou_0;
+  gfloat tre_one_0, tre_two_0, tre_thr_0, tre_fou_0;
+  gfloat            qua_two_0, qua_thr_0;
+
+  gfloat            uno_two_1, uno_thr_1;
+  gfloat dos_one_1, dos_two_1, dos_thr_1, dos_fou_1;
+  gfloat tre_one_1, tre_two_1, tre_thr_1, tre_fou_1;
+  gfloat            qua_two_1, qua_thr_1;
+
+  gfloat            uno_two_2, uno_thr_2;
+  gfloat dos_one_2, dos_two_2, dos_thr_2, dos_fou_2;
+  gfloat tre_one_2, tre_two_2, tre_thr_2, tre_fou_2;
+  gfloat            qua_two_2, qua_thr_2;
+
+  gfloat            uno_two_3, uno_thr_3;
+  gfloat dos_one_3, dos_two_3, dos_thr_3, dos_fou_3;
+  gfloat tre_one_3, tre_two_3, tre_thr_3, tre_fou_3;
+  gfloat            qua_two_3, qua_thr_3;
+
+  /*
+   * The newval array will contain one computed resampled value per
+   * channel:
+   */
+  gfloat newval[channels];
+
+  /*
+   * First channel:
+   */
+  nohalo_step1 (input_bptr[ uno_thr_shift ],
+                input_bptr[ uno_fou_shift ],
+                input_bptr[ dos_two_shift ],
+                input_bptr[ dos_thr_shift ],
+                input_bptr[ dos_fou_shift ],
+                input_bptr[ dos_fiv_shift ],
+                input_bptr[ tre_one_shift ],
+                input_bptr[ tre_two_shift ],
+                input_bptr[ tre_thr_shift ],
+                input_bptr[ tre_fou_shift ],
+                input_bptr[ tre_fiv_shift ],
+                input_bptr[ qua_one_shift ],
+                input_bptr[ qua_two_shift ],
+                input_bptr[ qua_thr_shift ],
+                input_bptr[ qua_fou_shift ],
+                input_bptr[ qua_fiv_shift ],
+                input_bptr[ cin_two_shift ],
+                input_bptr[ cin_thr_shift ],
+                input_bptr[ cin_fou_shift ],
+                &uno_two_0,
+                &uno_thr_0,
+                &dos_one_0,
+                &dos_two_0,
+                &dos_thr_0,
+                &dos_fou_0,
+                &tre_one_0,
+                &tre_two_0,
+                &tre_thr_0,
+                &tre_fou_0,
+                &qua_two_0,
+                &qua_thr_0);
+
+  {
+    /*
+     * Computation of the needed weights (coefficients).
+     */
+    const gfloat x = ( 2 * sign_of_x_0 ) * x_0 - .5;
+    const gfloat y = ( 2 * sign_of_y_0 ) * y_0 - .5;
+
+    const gint x_is_rite = ( x >= 0. );
+    const gint y_is_down = ( y >= 0. );
+    const gint x_is_left = !x_is_rite;
+    const gint y_is___up = !y_is_down;
+
+    const gint is_bot_rite = x_is_rite & y_is_down;
+    const gint is_bot_left = x_is_left & y_is_down;
+    const gint is_top_rite = x_is_rite & y_is___up;
+    const gint is_top_left = x_is_left & y_is___up;
+
+    const gint sign_of_x = 2 * x_is_rite - 1;
+    const gint sign_of_y = 2 * y_is_down - 1;
+
+    const gfloat w_1 = ( 2 * sign_of_x ) * x;
+    const gfloat z_1 = ( 2 * sign_of_y ) * y;
+    const gfloat x_1 = 1. - w_1;
+    const gfloat w_1_times_z_1 = w_1 * z_1;
+    const gfloat x_1_times_z_1 = x_1 * z_1;
+
+    const gfloat w_1_times_y_1_over_4 = .25  * ( w_1 - w_1_times_z_1 );
+    const gfloat x_1_times_z_1_over_4 = .25  * x_1_times_z_1;
+    const gfloat x_1_times_y_1_over_8 = .125 * ( x_1 - x_1_times_z_1 );
+
+    const gfloat w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8 =
+      w_1_times_y_1_over_4 + x_1_times_y_1_over_8;
+    const gfloat x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8 =
+      x_1_times_z_1_over_4 + x_1_times_y_1_over_8;
+
+    newval[0] =
+      nohalo_step2 (w_1_times_z_1,
+                    x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8,
+                    w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8,
+                    x_1_times_y_1_over_8,
+                    NOHALO_SELECT_REFLECT( uno_two_0, uno_thr_0, qua_two_0, qua_thr_0 ),
+                    NOHALO_SELECT_REFLECT( uno_thr_0, uno_two_0, qua_thr_0, qua_two_0 ),
+                    NOHALO_SELECT_REFLECT( dos_one_0, dos_fou_0, tre_one_0, tre_fou_0 ),
+                    NOHALO_SELECT_REFLECT( dos_two_0, dos_thr_0, tre_two_0, tre_thr_0 ),
+                    NOHALO_SELECT_REFLECT( dos_thr_0, dos_two_0, tre_thr_0, tre_two_0 ),
+                    NOHALO_SELECT_REFLECT( dos_fou_0, dos_one_0, tre_fou_0, tre_one_0 ),
+                    NOHALO_SELECT_REFLECT( tre_one_0, tre_fou_0, dos_one_0, dos_fou_0 ),
+                    NOHALO_SELECT_REFLECT( tre_two_0, tre_thr_0, dos_two_0, dos_thr_0 ),
+                    NOHALO_SELECT_REFLECT( tre_thr_0, tre_two_0, dos_thr_0, dos_two_0 ),
+                    NOHALO_SELECT_REFLECT( tre_fou_0, tre_one_0, dos_fou_0, dos_one_0 ),
+                    NOHALO_SELECT_REFLECT( qua_two_0, qua_thr_0, uno_two_0, uno_thr_0 ),
+                    NOHALO_SELECT_REFLECT( qua_thr_0, qua_two_0, uno_thr_0, uno_two_0 ));
+
+    /*
+     * Second channel:
+     *
+     * Shift input pointer by one channel:
+     */
+    input_bptr++;
+
+    nohalo_step1 (input_bptr[ uno_thr_shift ],
+                  input_bptr[ uno_fou_shift ],
+                  input_bptr[ dos_two_shift ],
+                  input_bptr[ dos_thr_shift ],
+                  input_bptr[ dos_fou_shift ],
+                  input_bptr[ dos_fiv_shift ],
+                  input_bptr[ tre_one_shift ],
+                  input_bptr[ tre_two_shift ],
+                  input_bptr[ tre_thr_shift ],
+                  input_bptr[ tre_fou_shift ],
+                  input_bptr[ tre_fiv_shift ],
+                  input_bptr[ qua_one_shift ],
+                  input_bptr[ qua_two_shift ],
+                  input_bptr[ qua_thr_shift ],
+                  input_bptr[ qua_fou_shift ],
+                  input_bptr[ qua_fiv_shift ],
+                  input_bptr[ cin_two_shift ],
+                  input_bptr[ cin_thr_shift ],
+                  input_bptr[ cin_fou_shift ],
+                  &uno_two_1,
+                  &uno_thr_1,
+                  &dos_one_1,
+                  &dos_two_1,
+                  &dos_thr_1,
+                  &dos_fou_1,
+                  &tre_one_1,
+                  &tre_two_1,
+                  &tre_thr_1,
+                  &tre_fou_1,
+                  &qua_two_1,
+                  &qua_thr_1);
+
+    newval[1] =
+      nohalo_step2 (w_1_times_z_1,
+                    x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8,
+                    w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8,
+                    x_1_times_y_1_over_8,
+                    NOHALO_SELECT_REFLECT( uno_two_1, uno_thr_1, qua_two_1, qua_thr_1 ),
+                    NOHALO_SELECT_REFLECT( uno_thr_1, uno_two_1, qua_thr_1, qua_two_1 ),
+                    NOHALO_SELECT_REFLECT( dos_one_1, dos_fou_1, tre_one_1, tre_fou_1 ),
+                    NOHALO_SELECT_REFLECT( dos_two_1, dos_thr_1, tre_two_1, tre_thr_1 ),
+                    NOHALO_SELECT_REFLECT( dos_thr_1, dos_two_1, tre_thr_1, tre_two_1 ),
+                    NOHALO_SELECT_REFLECT( dos_fou_1, dos_one_1, tre_fou_1, tre_one_1 ),
+                    NOHALO_SELECT_REFLECT( tre_one_1, tre_fou_1, dos_one_1, dos_fou_1 ),
+                    NOHALO_SELECT_REFLECT( tre_two_1, tre_thr_1, dos_two_1, dos_thr_1 ),
+                    NOHALO_SELECT_REFLECT( tre_thr_1, tre_two_1, dos_thr_1, dos_two_1 ),
+                    NOHALO_SELECT_REFLECT( tre_fou_1, tre_one_1, dos_fou_1, dos_one_1 ),
+                    NOHALO_SELECT_REFLECT( qua_two_1, qua_thr_1, uno_two_1, uno_thr_1 ),
+                    NOHALO_SELECT_REFLECT( qua_thr_1, qua_two_1, uno_thr_1, uno_two_1 ));
+
+    input_bptr++;
+
+    nohalo_step1 (input_bptr[ uno_thr_shift ],
+                  input_bptr[ uno_fou_shift ],
+                  input_bptr[ dos_two_shift ],
+                  input_bptr[ dos_thr_shift ],
+                  input_bptr[ dos_fou_shift ],
+                  input_bptr[ dos_fiv_shift ],
+                  input_bptr[ tre_one_shift ],
+                  input_bptr[ tre_two_shift ],
+                  input_bptr[ tre_thr_shift ],
+                  input_bptr[ tre_fou_shift ],
+                  input_bptr[ tre_fiv_shift ],
+                  input_bptr[ qua_one_shift ],
+                  input_bptr[ qua_two_shift ],
+                  input_bptr[ qua_thr_shift ],
+                  input_bptr[ qua_fou_shift ],
+                  input_bptr[ qua_fiv_shift ],
+                  input_bptr[ cin_two_shift ],
+                  input_bptr[ cin_thr_shift ],
+                  input_bptr[ cin_fou_shift ],
+                  &uno_two_2,
+                  &uno_thr_2,
+                  &dos_one_2,
+                  &dos_two_2,
+                  &dos_thr_2,
+                  &dos_fou_2,
+                  &tre_one_2,
+                  &tre_two_2,
+                  &tre_thr_2,
+                  &tre_fou_2,
+                  &qua_two_2,
+                  &qua_thr_2);
+
+    newval[2] =
+      nohalo_step2 (w_1_times_z_1,
+                    x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8,
+                    w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8,
+                    x_1_times_y_1_over_8,
+                    NOHALO_SELECT_REFLECT( uno_two_2, uno_thr_2, qua_two_2, qua_thr_2 ),
+                    NOHALO_SELECT_REFLECT( uno_thr_2, uno_two_2, qua_thr_2, qua_two_2 ),
+                    NOHALO_SELECT_REFLECT( dos_one_2, dos_fou_2, tre_one_2, tre_fou_2 ),
+                    NOHALO_SELECT_REFLECT( dos_two_2, dos_thr_2, tre_two_2, tre_thr_2 ),
+                    NOHALO_SELECT_REFLECT( dos_thr_2, dos_two_2, tre_thr_2, tre_two_2 ),
+                    NOHALO_SELECT_REFLECT( dos_fou_2, dos_one_2, tre_fou_2, tre_one_2 ),
+                    NOHALO_SELECT_REFLECT( tre_one_2, tre_fou_2, dos_one_2, dos_fou_2 ),
+                    NOHALO_SELECT_REFLECT( tre_two_2, tre_thr_2, dos_two_2, dos_thr_2 ),
+                    NOHALO_SELECT_REFLECT( tre_thr_2, tre_two_2, dos_thr_2, dos_two_2 ),
+                    NOHALO_SELECT_REFLECT( tre_fou_2, tre_one_2, dos_fou_2, dos_one_2 ),
+                    NOHALO_SELECT_REFLECT( qua_two_2, qua_thr_2, uno_two_2, uno_thr_2 ),
+                    NOHALO_SELECT_REFLECT( qua_thr_2, qua_two_2, uno_thr_2, uno_two_2 ));
+
+    input_bptr++;
+
+    nohalo_step1 (input_bptr[ uno_thr_shift ],
+                  input_bptr[ uno_fou_shift ],
+                  input_bptr[ dos_two_shift ],
+                  input_bptr[ dos_thr_shift ],
+                  input_bptr[ dos_fou_shift ],
+                  input_bptr[ dos_fiv_shift ],
+                  input_bptr[ tre_one_shift ],
+                  input_bptr[ tre_two_shift ],
+                  input_bptr[ tre_thr_shift ],
+                  input_bptr[ tre_fou_shift ],
+                  input_bptr[ tre_fiv_shift ],
+                  input_bptr[ qua_one_shift ],
+                  input_bptr[ qua_two_shift ],
+                  input_bptr[ qua_thr_shift ],
+                  input_bptr[ qua_fou_shift ],
+                  input_bptr[ qua_fiv_shift ],
+                  input_bptr[ cin_two_shift ],
+                  input_bptr[ cin_thr_shift ],
+                  input_bptr[ cin_fou_shift ],
+                  &uno_two_3,
+                  &uno_thr_3,
+                  &dos_one_3,
+                  &dos_two_3,
+                  &dos_thr_3,
+                  &dos_fou_3,
+                  &tre_one_3,
+                  &tre_two_3,
+                  &tre_thr_3,
+                  &tre_fou_3,
+                  &qua_two_3,
+                  &qua_thr_3);
+
+    newval[3] =
+      nohalo_step2 (w_1_times_z_1,
+                    x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8,
+                    w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8,
+                    x_1_times_y_1_over_8,
+                    NOHALO_SELECT_REFLECT( uno_two_3, uno_thr_3, qua_two_3, qua_thr_3 ),
+                    NOHALO_SELECT_REFLECT( uno_thr_3, uno_two_3, qua_thr_3, qua_two_3 ),
+                    NOHALO_SELECT_REFLECT( dos_one_3, dos_fou_3, tre_one_3, tre_fou_3 ),
+                    NOHALO_SELECT_REFLECT( dos_two_3, dos_thr_3, tre_two_3, tre_thr_3 ),
+                    NOHALO_SELECT_REFLECT( dos_thr_3, dos_two_3, tre_thr_3, tre_two_3 ),
+                    NOHALO_SELECT_REFLECT( dos_fou_3, dos_one_3, tre_fou_3, tre_one_3 ),
+                    NOHALO_SELECT_REFLECT( tre_one_3, tre_fou_3, dos_one_3, dos_fou_3 ),
+                    NOHALO_SELECT_REFLECT( tre_two_3, tre_thr_3, dos_two_3, dos_thr_3 ),
+                    NOHALO_SELECT_REFLECT( tre_thr_3, tre_two_3, dos_thr_3, dos_two_3 ),
+                    NOHALO_SELECT_REFLECT( tre_fou_3, tre_one_3, dos_fou_3, dos_one_3 ),
+                    NOHALO_SELECT_REFLECT( qua_two_3, qua_thr_3, uno_two_3, uno_thr_3 ),
+                    NOHALO_SELECT_REFLECT( qua_thr_3, qua_two_3, uno_thr_3, uno_two_3 ));
+
+    /*
+     * Ship out the array of new pixel values:
+     */
+    babl_process (babl_fish (self->interpolate_format, self->format),
+                  newval, output, 1);
+  }
+}
+
+static void
+set_property (      GObject*    gobject,
+                    guint       property_id,
+              const GValue*     value,
+                    GParamSpec* pspec)
+{
+  /* G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); */
+}
+
+static void
+get_property (GObject*    gobject,
+              guint       property_id,
+              GValue*     value,
+              GParamSpec* pspec)
+{
+  /* G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); */
+}
diff --git a/gegl/buffer/gegl-sampler-upsharp.h b/gegl/buffer/gegl-sampler-upsharp.h
new file mode 100644
index 0000000..d483991
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-upsharp.h
@@ -0,0 +1,48 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __GEGL_SAMPLER_UPSHARP_H__
+#define __GEGL_SAMPLER_UPSHARP_H__
+
+#include "gegl-sampler.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_SAMPLER_UPSHARP            (gegl_sampler_upsharp_get_type ())
+#define GEGL_SAMPLER_UPSHARP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_SAMPLER_UPSHARP, GeglSamplerUpsharp))
+#define GEGL_SAMPLER_UPSHARP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GEGL_TYPE_SAMPLER_UPSHARP, GeglSamplerUpsharpClass))
+#define GEGL_IS_SAMPLER_UPSHARP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_SAMPLER_UPSHARP))
+#define GEGL_IS_SAMPLER_UPSHARP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GEGL_TYPE_SAMPLER_UPSHARP))
+#define GEGL_SAMPLER_UPSHARP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GEGL_TYPE_SAMPLER_UPSHARP, GeglSamplerUpsharpClass))
+
+typedef struct _GeglSamplerUpsharp      GeglSamplerUpsharp;
+typedef struct _GeglSamplerUpsharpClass GeglSamplerUpsharpClass;
+
+struct _GeglSamplerUpsharp
+{
+  GeglSampler parent_instance;
+};
+
+struct _GeglSamplerUpsharpClass
+{
+  GeglSamplerClass parent_class;
+};
+
+GType gegl_sampler_upsharp_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/gegl/buffer/gegl-sampler-upsize.c b/gegl/buffer/gegl-sampler-upsize.c
new file mode 100644
index 0000000..acf1913
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-upsize.c
@@ -0,0 +1,679 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 2009 (c) Eric Daoust, Nicolas Robidoux, Adam Turcotte and Ã?yvind
+ * Kolås.
+ */
+
+/*
+ * ==============
+ * UPSIZE SAMPLER
+ * ==============
+ *
+ * "Upsize" is the GEGL name of the symmetrized MP-quadratic
+ * (Monotonicity Preserving with derivative estimated by fitting a
+ * parabola (quadratic polynomial)) method, which essentially is
+ * Catmull-Rom with derivatives clamped so as to ensure monotonicity.
+ *
+ * 1D MP-quadratic (for curve, not surface, interpolation) is
+ * described in
+ *
+ * Accurate Monotone Cubic Interpolation, by Hung T. Huynh, published
+ * in the SIAM Journal on Numerical Analysis, Volume 30, Issue 1
+ * (February 1993), pages 57-100, 1993. ISSN:0036-1429.
+ *
+ * and in NASA technical memorandum 103789, which can be downloaded
+ * from http://
+ * ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19910011517_1991011517.pdf
+ *
+ * In order to ensure reflexion symmetry about diagonal lines, 1D
+ * MP-quadratic is performed two different ways---horizontally then
+ * vertically, and vertically then horizontally---and
+ * averaged. (Symmetry about 45 degree lines is not automatically
+ * respected because MP-quadratic is a nonlinear method: interpolating
+ * horizontally then vertically does not necessarily give the same as
+ * interpolating vertically then horizontally.)
+ */
+/*
+ * Acknowledgements: Eric Daoust and Adam Turcotte's GEGL programming
+ * funded by Google Summer of Code 2009.  Nicolas Robidoux thanks
+ * Chantal Racette, Ralf Meyer, Minglun Gong, John Cupitt, Geert
+ * Jordaens, �yvind Kolås and Sven Neumann for useful comments and
+ * code.
+ */
+
+#include "config.h"
+#include <glib-object.h>
+
+#include "gegl.h"
+#include "gegl-types-internal.h"
+#include "gegl-buffer-private.h"
+#include "gegl-sampler-upsize.h"
+
+/*
+ * FAST_MINMOD is an implementation of the minmod function which only
+ * needs two conditional moves. FAST_MINMOD(a,b,a_times_a,a_times_b)
+ * "returns" minmod(a,b). The parameter ("input") a_times_a is assumed
+ * to contain the square of a; a_times_b, the product of a and b.
+ *
+ * This version is most suitable for images with flat (constant)
+ * colour areas, since a, which is a pixel difference, will often be
+ * 0, in which case both forward branches are likely.
+ *
+ * For uncompressed natural images in high bit depth (images for which
+ * the slopes a and b are unlikely to be equal to zero or be equal to
+ * each other), we recommend using
+ *
+ * ( (a_times_b)>=0. ? 1. : 0. ) * ( (a_times_b)<(a_times_a) ? (b) : (a) )
+ *
+ * instead. With this second version, the forward branch of the second
+ * conditional move is taken when |b|>|a| and when a*b<0. However, the
+ * "else" branch is taken when a=0 (or when a=b), which is why the
+ * above version is not recommended for images with regions with
+ * constant pixel values (or regions with pixel values which vary
+ * bilinearly).
+ */
+#define FAST_MINMOD(a,b,a_times_a,a_times_b) \
+  ( (a_times_b)>=0.f ? 1.f : 0.f ) * ( (a_times_a)<=(a_times_b) ? (a) : (b) )
+
+/*
+ * FAST_PSEUDO_FLOOR is a floor replacement which has been found to be
+ * faster. It returns the floor of its argument unless the argument is
+ * a negative integer, in which case it returns one less than the
+ * floor. For example:
+ *
+ * FAST_PSEUDO_FLOOR(0.5) = 0
+ *
+ * FAST_PSEUDO_FLOOR(0.) = 0
+ *
+ * FAST_PSEUDO_FLOOR(-.5) = -1
+ *
+ * as expected, but
+ *
+ * FAST_PSEUDO_FLOOR(-1.) = -2
+ *
+ * The discontinuities of FAST_PSEUDO_FLOOR are on the right of
+ * negative numbers instead of on the left as is the case for floor.
+ */
+#define FAST_PSEUDO_FLOOR(x) ( (gint)(x) - ( (x) < 0. ) )
+
+/*
+ * Hack to get the restrict C99 keyword going at least some of the
+ * time:
+ */
+#ifndef restrict
+#ifdef __restrict
+#define restrict __restrict
+#else
+#ifdef __restrict__
+#define restrict __restrict__
+#else
+#define restrict
+#endif
+#endif
+#endif
+
+enum
+{
+  PROP_0,
+  PROP_LAST
+};
+
+static inline gfloat mp_quadratic (const gfloat one,
+                                   const gfloat two,
+                                   const gfloat thr,
+                                   const gfloat fou,
+                                   const gfloat coef1,
+                                   const gfloat coef2,
+                                   const gfloat coef3);
+
+static void gegl_sampler_upsize_get (      GeglSampler* restrict self,
+                                      const gdouble               absolute_x,
+                                      const gdouble               absolute_y,
+                                            void*        restrict output );
+
+static void set_property (      GObject*    gobject,
+                                guint       property_id,
+                          const GValue*     value,
+                                GParamSpec* pspec);
+
+static void get_property (GObject*    gobject,
+                          guint       property_id,
+                          GValue*     value,
+                          GParamSpec* pspec);
+
+G_DEFINE_TYPE (GeglSamplerUpsize, gegl_sampler_upsize, GEGL_TYPE_SAMPLER)
+
+static void
+gegl_sampler_upsize_class_init (GeglSamplerUpsizeClass *klass)
+{
+  GeglSamplerClass *sampler_class = GEGL_SAMPLER_CLASS (klass);
+  GObjectClass *object_class  = G_OBJECT_CLASS (klass);
+  object_class->set_property = set_property;
+  object_class->get_property = get_property;
+  sampler_class->get = gegl_sampler_upsize_get;
+ }
+
+static void
+gegl_sampler_upsize_init (GeglSamplerUpsize *self)
+{
+  GEGL_SAMPLER (self)->context_rect.x = -1;
+  GEGL_SAMPLER (self)->context_rect.y = -1;
+  GEGL_SAMPLER (self)->context_rect.width = 4;
+  GEGL_SAMPLER (self)->context_rect.height = 4;
+  GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
+}
+
+static inline gfloat mp_quadratic (const gfloat one,
+                                   const gfloat two,
+                                   const gfloat thr,
+                                   const gfloat fou,
+                                   const gfloat coef_thr_point,
+                                   const gfloat half_coef_two_slope,
+                                   const gfloat half_coef_thr_slope)
+{
+  /*
+   * Computation of the slopes and slope limiters:
+   *
+   * Differences:
+   */
+  const gfloat prem = two - one;
+  const gfloat deux = thr - two;
+  const gfloat troi = fou - thr;
+
+  const gfloat part = two + deux * coef_thr_point;
+
+  /*
+   * Products useful for the minmod computations:
+   */
+  const gfloat deux_prem = deux * prem;
+  const gfloat deux_deux = deux * deux;
+  const gfloat deux_troi = deux * troi;
+
+  /*
+   * Twice the horizontal limiter slopes (twice_lx) interwoven with
+   * twice the Catmull-Rom slopes (twice_sx).  Because we have twice
+   * the Catmull-Rom slope, we need to use 6 times the minmod slope
+   * instead of the usual 3 (specified by the cited article).
+   */
+  const gfloat twice_lx_two =
+    6.f * FAST_MINMOD (deux, prem, deux_deux, deux_prem);
+  const gfloat twice_sx_two = deux + prem;
+  const gfloat twice_lx_thr =
+    6.f * FAST_MINMOD (deux, troi, deux_deux, deux_troi);
+  const gfloat twice_sx_thr = deux + troi;
+
+  const gfloat sx_sx_two = twice_sx_two * twice_sx_two;
+  const gfloat sx_lx_two = twice_sx_two * twice_lx_two;
+  const gfloat sx_sx_thr = twice_sx_thr * twice_sx_thr;
+  const gfloat sx_lx_thr = twice_sx_thr * twice_lx_thr;
+
+  /*
+   * Result of the first interpolations along horizontal lines. Note
+   * that the Catmull-Rom slope almost always satisfies the
+   * monotonicity constraint, hence twice_sx is "likely" to be the one
+   * selected by minmod.
+   */
+  const gfloat newval =
+    part +
+    + half_coef_two_slope
+    * FAST_MINMOD (twice_sx_two, twice_lx_two, sx_sx_two, sx_lx_two)
+    + half_coef_thr_slope
+    * FAST_MINMOD (twice_sx_thr, twice_lx_thr, sx_sx_thr, sx_lx_thr);
+
+  return newval;
+}
+
+static inline gfloat
+symmetrized_monotone_catmull_rom (const gfloat coef_rite_point,
+                                  const gfloat coef_bot_point,
+                                  const gfloat half_coef_left_slope,
+                                  const gfloat half_coef_rite_slope,
+                                  const gfloat half_coef_top_slope,
+                                  const gfloat half_coef_bot_slope,
+                                  const gfloat uno_one,
+                                  const gfloat uno_two,
+                                  const gfloat uno_thr,
+                                  const gfloat uno_fou,
+                                  const gfloat dos_one,
+                                  const gfloat dos_two,
+                                  const gfloat dos_thr,
+                                  const gfloat dos_fou,
+                                  const gfloat tre_one,
+                                  const gfloat tre_two,
+                                  const gfloat tre_thr,
+                                  const gfloat tre_fou,
+                                  const gfloat qua_one,
+                                  const gfloat qua_two,
+                                  const gfloat qua_thr,
+                                  const gfloat qua_fou)
+{
+  /*
+   * STENCIL (FOOTPRINT) OF INPUT VALUES:
+   *
+   * The stencil of Symmetrized Monotone Catmull-Rom is the same as
+   * the standard Catmull-Rom's:
+   *
+   *  (ix-1,iy-1)  (ix,iy-1)    (ix+1,iy-1)  (ix+2,iy-1)
+   *  = uno_one    = uno_two    = uno_thr    = uno_fou
+   *
+   *  (ix-1,iy)    (ix,iy)      (ix+1,iy)    (ix+2,iy)
+   *  = dos_one    = dos_two    = dos_thr    = dos_fou
+   *                        X
+   *  (ix-1,iy+1)  (ix,iy+1)    (ix+1,iy+1)  (ix+2,iy+1)
+   *  = tre_one    = tre_two    = tre_thr    = tre_fou
+   *
+   *  (ix-1,iy+2)  (ix,iy+2)    (ix+1,iy+2)  (ix+2,iy+2)
+   *  = qua_one    = qua_two    = qua_thr    = qua_fou
+   *
+   * where ix is the (pseudo-)floor of the requested left-to-right
+   * location ("X"), and iy is the floor of the requested up-to-down
+   * location.
+   */
+  /*
+   * OUTLINE:
+   *
+   * First, four horizontal cubic Hermite interpolations are performed
+   * to get values on the vertical line which passes through X, and
+   * then these four values are used to perform cubic Hermite
+   * interpolation in the vertical direction to get one approximation
+   * of the pixel value at X,
+   *
+   * Then, four vertical cubic Hermite interpolations are performed to
+   * get values on the horizontal line which passes through X, and
+   * then these four values are used to perform cubic Hermite
+   * interpolation in the horizontal direction to get another
+   * approximation of the pixel value at X,
+   *
+   * These two interpolated pixel values are then averaged.
+   */
+
+  /*
+   * Computation of the slopes and slope limiters:
+   *
+   * Uno horizontal differences:
+   */
+  const gfloat uno = mp_quadratic (uno_one,
+                                   uno_two,
+                                   uno_thr,
+                                   uno_fou,
+                                   coef_rite_point,
+                                   half_coef_left_slope,
+                                   half_coef_rite_slope);
+  /*
+   * Do the same with the other three horizontal lines.
+   *
+   * Dos horizontal line:
+   */
+  const gfloat dos = mp_quadratic (dos_one,
+                                   dos_two,
+                                   dos_thr,
+                                   dos_fou,
+                                   coef_rite_point,
+                                   half_coef_left_slope,
+                                   half_coef_rite_slope);
+  /*
+   * Tre(s) horizontal line:
+   */
+  const gfloat tre = mp_quadratic (tre_one,
+                                   tre_two,
+                                   tre_thr,
+                                   tre_fou,
+                                   coef_rite_point,
+                                   half_coef_left_slope,
+                                   half_coef_rite_slope);
+  /*
+   * Qua(ttro) horizontal line:
+   */
+  const gfloat qua = mp_quadratic (qua_one,
+                                   qua_two,
+                                   qua_thr,
+                                   qua_fou,
+                                   coef_rite_point,
+                                   half_coef_left_slope,
+                                   half_coef_rite_slope);
+
+  /*
+   * Perform the interpolation along the one vertical line (filled
+   * with results obtained by interpolating along horizontal lines):
+   */
+  const gfloat partial_y = mp_quadratic(uno,
+                                        dos,
+                                        tre,
+                                        qua,
+                                        coef_bot_point,
+                                        half_coef_top_slope,
+                                        half_coef_bot_slope);
+
+  /*
+   * Redo with four vertical lines (and the corresponding horizontal
+   * one).
+   *
+   * One:
+   */
+  const gfloat one = mp_quadratic (uno_one,
+                                   dos_one,
+                                   tre_one,
+                                   qua_one,
+                                   coef_bot_point,
+                                   half_coef_top_slope,
+                                   half_coef_bot_slope);
+  /*
+   * Two:
+   */
+  const gfloat two = mp_quadratic (uno_two,
+                                   dos_two,
+                                   tre_two,
+                                   qua_two,
+                                   coef_bot_point,
+                                   half_coef_top_slope,
+                                   half_coef_bot_slope);
+  /*
+   * Thr(ee):
+   */
+  const gfloat thr = mp_quadratic (uno_thr,
+                                   dos_thr,
+                                   tre_thr,
+                                   qua_thr,
+                                   coef_bot_point,
+                                   half_coef_top_slope,
+                                   half_coef_bot_slope);
+  /*
+   * Fou(r):
+   */
+  const gfloat fou = mp_quadratic (uno_fou,
+                                   dos_fou,
+                                   tre_fou,
+                                   qua_fou,
+                                   coef_bot_point,
+                                   half_coef_top_slope,
+                                   half_coef_bot_slope);
+
+  /*
+   * Final horizontal line of vertical results:
+   */
+  const gfloat prem_x = two - one;
+  const gfloat deux_x = thr - two;
+  const gfloat troi_x = fou - thr;
+
+  const gfloat partial_newval = partial_y + two + coef_rite_point * deux_x;
+
+  const gfloat deux_prem_x = deux_x * prem_x;
+  const gfloat deux_deux_x = deux_x * deux_x;
+  const gfloat deux_troi_x = deux_x * troi_x;
+
+  const gfloat twice_l_two =
+    6.f * FAST_MINMOD (deux_x, prem_x, deux_deux_x, deux_prem_x);
+  const gfloat twice_s_two = deux_x + prem_x;
+  const gfloat twice_l_thr =
+    6.f * FAST_MINMOD (deux_x, troi_x, deux_deux_x, deux_troi_x);
+  const gfloat twice_s_thr = deux_x + troi_x;
+
+  const gfloat s_s_two = twice_s_two * twice_s_two;
+  const gfloat s_l_two = twice_s_two * twice_l_two;
+  const gfloat s_s_thr = twice_s_thr * twice_s_thr;
+  const gfloat s_l_thr = twice_s_thr * twice_l_thr;
+
+  const gfloat newval =
+    (
+      partial_newval +
+      + half_coef_left_slope * FAST_MINMOD (twice_s_two, twice_l_two,
+                                                s_s_two,     s_l_two)
+      + half_coef_rite_slope * FAST_MINMOD (twice_s_thr, twice_l_thr,
+                                                s_s_thr,     s_l_thr)
+    ) * .5f;
+
+  return newval;
+}
+
+static void
+gegl_sampler_upsize_get (      GeglSampler* restrict self,
+                          const gdouble               absolute_x,
+                          const gdouble               absolute_y,
+                                void*        restrict output)
+{
+  /*
+   * Needed constants related to the input pixel value pointer
+   * provided by gegl_sampler_get_ptr (self, ix, iy). pixels_per_row
+   * corresponds to fetch_rectangle.width in gegl_sampler_get_ptr.
+   */
+  const gint channels       = 4;
+  const gint pixels_per_row = 64;
+
+  /*
+   * Pointer shifts to access the values of the 4x4 footprint:
+   */
+  const gint pixel_skip = channels;
+  const gint row_skip   = channels * pixels_per_row;
+
+  const gint uno_one_shift = -row_skip - pixel_skip;
+  const gint uno_two_shift = -row_skip;
+  const gint uno_thr_shift = -row_skip + pixel_skip;
+  const gint uno_fou_shift = -row_skip + pixel_skip * 2;
+
+  const gint dos_one_shift = -pixel_skip;
+  const gint dos_two_shift = 0;
+  const gint dos_thr_shift = pixel_skip;
+  const gint dos_fou_shift = pixel_skip * 2;
+
+  const gint tre_one_shift = row_skip - pixel_skip;
+  const gint tre_two_shift = row_skip;
+  const gint tre_thr_shift = row_skip + pixel_skip;
+  const gint tre_fou_shift = row_skip + pixel_skip * 2;
+
+  const gint qua_one_shift = row_skip * 2 - pixel_skip;
+  const gint qua_two_shift = row_skip * 2;
+  const gint qua_thr_shift = row_skip * 2 + pixel_skip;
+  const gint qua_fou_shift = row_skip * 2 + pixel_skip * 2;
+
+  /*
+   * floor's surrogate FAST_PSEUDO_FLOOR is used to make sure that the
+   * transition through 0 is smooth. If it is known that absolute_x
+   * and absolute_y will never be less than 0, plain cast---that is,
+   * const gint ix = absolute_x---should be used instead.  Actually,
+   * any function which agrees with floor for non-integer values, and
+   * picks one of the two possibilities for integer values, can be
+   * used. FAST_PSEUDO_FLOOR fits the bill.
+   */
+  const gint ix = FAST_PSEUDO_FLOOR (absolute_x);
+  const gint iy = FAST_PSEUDO_FLOOR (absolute_y);
+
+  /*
+   * Move the pointer to (the first band of) the top/left pixel of the
+   * 2x2 group of pixel centers which contains the sampling location
+   * in its convex hull (this is dos_two below).
+   */
+  const gfloat* restrict input_bptr =
+    (gfloat*) gegl_sampler_get_ptr (self, ix, iy);
+
+  /*
+   * x is the x-coordinate of the sampling point relative to the
+   * position of top left corner of the convex hull of the 2x2 block
+   * of closest pixels. Similarly for y. Range of values: [0,1).  Note
+   * that the RHS is computed in double precision, which is good for
+   * round off because absolute_x and ix may both be large, even
+   * thought their difference may be small.
+   */
+  const gfloat x = absolute_x - ix;
+  const gfloat y = absolute_y - iy;
+
+  /*
+   * Hermite interpolation coefficients:
+   */
+  const gfloat x_squared = x * x;
+  const gfloat y_squared = y * y;
+  const gfloat twice_x   = x + x;
+  const gfloat twice_y   = y + y;
+  const gfloat half_x_squared_minus_x = .5f * ( x_squared - x );
+  const gfloat half_y_squared_minus_y = .5f * ( y_squared - y );
+
+  const gfloat coef_rite_point = x_squared * ( 3.f - twice_x );
+  const gfloat coef_bot_point  = y_squared * ( 3.f - twice_y );
+  /*
+   * We implicitly use
+   *
+   * coef_left_point = 1. - coef_rite_point;
+   * coef_top_point  = 1. - coef_bot_point;
+   *
+   * This is done using a difference (which is computed anyway) to
+   * account for the fact that plus and minus coef_rite/bot_point are
+   * used.
+   */
+  /*
+   * The "half" are because we later compute double the slope. In
+   * other words, this is an example of constant folding:
+   */
+  const gfloat half_coef_rite_slope = x * half_x_squared_minus_x;
+  const gfloat half_coef_bot_slope  = y * half_y_squared_minus_y;
+  const gfloat half_coef_left_slope =
+    half_coef_rite_slope - half_x_squared_minus_x;
+  const gfloat half_coef_top_slope  =
+    half_coef_bot_slope  - half_y_squared_minus_y;
+
+  /*
+   * Channel by channel computation of the new pixel values:
+   */
+
+  /*
+   * The newval array will contain one computed resampled value per
+   * channel:
+   */
+  gfloat newval[channels];
+
+  /*
+   * First channel:
+   */
+  newval[0] = symmetrized_monotone_catmull_rom (coef_rite_point,
+                                                coef_bot_point,
+                                                half_coef_left_slope,
+                                                half_coef_rite_slope,
+                                                half_coef_top_slope,
+                                                half_coef_bot_slope,
+                                                input_bptr[ uno_one_shift ],
+                                                input_bptr[ uno_two_shift ],
+                                                input_bptr[ uno_thr_shift ],
+                                                input_bptr[ uno_fou_shift ],
+                                                input_bptr[ dos_one_shift ],
+                                                input_bptr[ dos_two_shift ],
+                                                input_bptr[ dos_thr_shift ],
+                                                input_bptr[ dos_fou_shift ],
+                                                input_bptr[ tre_one_shift ],
+                                                input_bptr[ tre_two_shift ],
+                                                input_bptr[ tre_thr_shift ],
+                                                input_bptr[ tre_fou_shift ],
+                                                input_bptr[ qua_one_shift ],
+                                                input_bptr[ qua_two_shift ],
+                                                input_bptr[ qua_thr_shift ],
+                                                input_bptr[ qua_fou_shift ]);
+  /*
+   * Second channel:
+   */
+  newval[1] = symmetrized_monotone_catmull_rom (coef_rite_point,
+                                                coef_bot_point,
+                                                half_coef_left_slope,
+                                                half_coef_rite_slope,
+                                                half_coef_top_slope,
+                                                half_coef_bot_slope,
+                                                input_bptr[ uno_one_shift+1 ],
+                                                input_bptr[ uno_two_shift+1 ],
+                                                input_bptr[ uno_thr_shift+1 ],
+                                                input_bptr[ uno_fou_shift+1 ],
+                                                input_bptr[ dos_one_shift+1 ],
+                                                input_bptr[ dos_two_shift+1 ],
+                                                input_bptr[ dos_thr_shift+1 ],
+                                                input_bptr[ dos_fou_shift+1 ],
+                                                input_bptr[ tre_one_shift+1 ],
+                                                input_bptr[ tre_two_shift+1 ],
+                                                input_bptr[ tre_thr_shift+1 ],
+                                                input_bptr[ tre_fou_shift+1 ],
+                                                input_bptr[ qua_one_shift+1 ],
+                                                input_bptr[ qua_two_shift+1 ],
+                                                input_bptr[ qua_thr_shift+1 ],
+                                                input_bptr[ qua_fou_shift+1 ]);
+  /*
+   * Third channel:
+   */
+  newval[2] = symmetrized_monotone_catmull_rom (coef_rite_point,
+                                                coef_bot_point,
+                                                half_coef_left_slope,
+                                                half_coef_rite_slope,
+                                                half_coef_top_slope,
+                                                half_coef_bot_slope,
+                                                input_bptr[ uno_one_shift+2 ],
+                                                input_bptr[ uno_two_shift+2 ],
+                                                input_bptr[ uno_thr_shift+2 ],
+                                                input_bptr[ uno_fou_shift+2 ],
+                                                input_bptr[ dos_one_shift+2 ],
+                                                input_bptr[ dos_two_shift+2 ],
+                                                input_bptr[ dos_thr_shift+2 ],
+                                                input_bptr[ dos_fou_shift+2 ],
+                                                input_bptr[ tre_one_shift+2 ],
+                                                input_bptr[ tre_two_shift+2 ],
+                                                input_bptr[ tre_thr_shift+2 ],
+                                                input_bptr[ tre_fou_shift+2 ],
+                                                input_bptr[ qua_one_shift+2 ],
+                                                input_bptr[ qua_two_shift+2 ],
+                                                input_bptr[ qua_thr_shift+2 ],
+                                                input_bptr[ qua_fou_shift+2 ]);
+  /*
+   * Fourth channel:
+   */
+  newval[3] = symmetrized_monotone_catmull_rom (coef_rite_point,
+                                                coef_bot_point,
+                                                half_coef_left_slope,
+                                                half_coef_rite_slope,
+                                                half_coef_top_slope,
+                                                half_coef_bot_slope,
+                                                input_bptr[ uno_one_shift+3 ],
+                                                input_bptr[ uno_two_shift+3 ],
+                                                input_bptr[ uno_thr_shift+3 ],
+                                                input_bptr[ uno_fou_shift+3 ],
+                                                input_bptr[ dos_one_shift+3 ],
+                                                input_bptr[ dos_two_shift+3 ],
+                                                input_bptr[ dos_thr_shift+3 ],
+                                                input_bptr[ dos_fou_shift+3 ],
+                                                input_bptr[ tre_one_shift+3 ],
+                                                input_bptr[ tre_two_shift+3 ],
+                                                input_bptr[ tre_thr_shift+3 ],
+                                                input_bptr[ tre_fou_shift+3 ],
+                                                input_bptr[ qua_one_shift+3 ],
+                                                input_bptr[ qua_two_shift+3 ],
+                                                input_bptr[ qua_thr_shift+3 ],
+                                                input_bptr[ qua_fou_shift+3 ]);
+  /*
+   * Ship out newval:
+   */
+  babl_process (babl_fish (self->interpolate_format, self->format),
+                newval, output, 1);
+}
+
+static void
+set_property (      GObject*    gobject,
+                    guint       property_id,
+              const GValue*     value,
+                    GParamSpec* pspec)
+{
+  G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+}
+
+static void
+get_property (GObject*    gobject,
+              guint       property_id,
+              GValue*     value,
+              GParamSpec* pspec)
+{
+  G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+}
diff --git a/gegl/buffer/gegl-sampler-upsize.h b/gegl/buffer/gegl-sampler-upsize.h
new file mode 100644
index 0000000..8abe50f
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-upsize.h
@@ -0,0 +1,50 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __GEGL_SAMPLER_UPSIZE_H__
+#define __GEGL_SAMPLER_UPSIZE_H__
+
+#include "gegl-sampler.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_SAMPLER_UPSIZE            (gegl_sampler_upsize_get_type ())
+#define GEGL_SAMPLER_UPSIZE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_SAMPLER_UPSIZE, GeglSamplerUpsize))
+#define GEGL_SAMPLER_UPSIZE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GEGL_TYPE_SAMPLER_UPSIZE, GeglSamplerUpsizeClass))
+#define GEGL_IS_SAMPLER_UPSIZE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_SAMPLER_UPSIZE))
+#define GEGL_IS_SAMPLER_UPSIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GEGL_TYPE_SAMPLER_UPSIZE))
+#define GEGL_SAMPLER_UPSIZE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GEGL_TYPE_SAMPLER_UPSIZE, GeglSamplerUpsizeClass))
+
+typedef struct _GeglSamplerUpsize      GeglSamplerUpsize;
+typedef struct _GeglSamplerUpsizeClass GeglSamplerUpsizeClass;
+
+struct _GeglSamplerUpsize
+{
+  GeglSampler parent_instance;
+  /*< private >*/
+};
+
+struct _GeglSamplerUpsizeClass
+{
+  GeglSamplerClass parent_class;
+};
+
+GType gegl_sampler_upsize_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/gegl/buffer/gegl-sampler-upsmooth.c b/gegl/buffer/gegl-sampler-upsmooth.c
new file mode 100644
index 0000000..740c653
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-upsmooth.c
@@ -0,0 +1,1259 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 2009 (c) Adam Turcotte, Nicolas Robidoux, Eric Daoust, �yvind Kolås
+ * and Geert Jordaens.
+ */
+
+/*
+ * ================
+ * UPSMOOTH SAMPLER
+ * ================
+ *
+ * "Upsmooth" is the GEGL name of the Snohalo level 1.5 resampler with
+ * maximum reasonable smoothing.
+ *
+ * =========================================================================
+ * ONLY IMPLEMENTS THE SECOND LOWEST QUALITY SNOHALO RESAMPLER WITH MAX BLUR
+ * =========================================================================
+ *
+ * This code implements Snohalo for (quality) level = 1.5: the
+ * smoothing step is only performed once, and the Nohalo subdivision
+ * is performed twice. (Snohalo level 2 would be smooth -> subdivide
+ * -> smooth -> subdivide, for a total of two smoothing and two
+ * subdivision steps). For Snohalo level 1.5, we only do smooth ->
+ * subdivide -> subdivide. Although the smoothing step is only used
+ * once, the smoothing (= blur = antialiasing) parameter set to its
+ * maximum reasonable value.
+ *
+ * This sampler has quite strong antialiasing. For very smooth or
+ * blurry images, Nohalo level 2 (= Snohalo level 1.5 (with blur = 0)
+ * = Snohalo level 2 (with blur = 0), currently called
+ * gegl-sampler-upsharp.* in GEGL), or MP-quadratic (= monotone
+ * interpolatory cubic splines = Fritsch and Carlson, currently called
+ * gegl-sampler-upsize.* in GEGL) are probably better choices.
+ */
+
+/*
+ * Acknowledgements: Adam Turcotte and Eric Daoust's Snohalo
+ * programming funded by Google Summer of Code 2009.  Nicolas
+ * Robidoux's research on Nohalo funded in part by an NSERC (National
+ * Science and Engineering Research Council of Canada) Discovery
+ * Grant.
+ *
+ * Nicolas Robidoux thanks Minglun Gong, Ralf Meyer, John Cupitt and
+ * Sven Neumann for useful comments and code.
+ */
+
+#include "config.h"
+#include <glib-object.h>
+
+#include "gegl.h"
+#include "gegl-types-internal.h"
+#include "gegl-buffer-private.h"
+
+#include "gegl-sampler-upsmooth.h"
+
+/*
+ * FAST_MINMOD is an implementation of the minmod function which only
+ * needs two conditional moves. FAST_MINMOD(a,b,a_times_a,a_times_b)
+ * "returns" minmod(a,b). The parameter ("input") a_times_a is assumed
+ * to contain the square of a; a_times_b, the product of a and b.
+ *
+ * This version is most suitable for images with flat (constant)
+ * colour areas, since a, which is a pixel difference, will often be
+ * 0, in which case both forward branches are likely.
+ *
+ * For uncompressed natural images in high bit depth (images for which
+ * the slopes a and b are unlikely to be equal to zero or be equal to
+ * each other), we recommend using
+ *
+ * ( (a_times_b)>=0. ? 1. : 0. ) * ( (a_times_b)<(a_times_a) ? (b) : (a) )
+ *
+ * instead. With this second version, the forward branch of the second
+ * conditional move is taken when |b|>|a| and when a*b<0. However, the
+ * "else" branch is taken when a=0 (or when a=b), which is why the
+ * above version is not recommended for images with regions with
+ * constant pixel values (or regions with pixel values which vary
+ * bilinearly).
+ */
+#define FAST_MINMOD(a,b,a_times_a,a_times_b) \
+ ( (a_times_b)>=0.f ? 1.f : 0.f ) * ( (a_times_a)<=(a_times_b) ? (a) : (b) )
+
+/*
+ * FAST_PSEUDO_FLOOR is a floor replacement which has been found to be
+ * faster. It returns the floor of its argument unless the argument is
+ * a negative integer, in which case it returns one less than the
+ * floor. For example:
+ *
+ * FAST_PSEUDO_FLOOR(0.5) = 0
+ *
+ * FAST_PSEUDO_FLOOR(0.) = 0
+ *
+ * FAST_PSEUDO_FLOOR(-.5) = -1
+ *
+ * as expected, but
+ *
+ * FAST_PSEUDO_FLOOR(-1.) = -2
+ *
+ * The discontinuities of FAST_PSEUDO_FLOOR are on the right of
+ * negative numbers instead of on the left as is the case for floor.
+ */
+#define FAST_PSEUDO_FLOOR(x) ( (gint)(x) - ( (x) < 0. ) )
+
+/*
+ * Hack to get the restrict C99 keyword going at least some of the
+ * time:
+ */
+#ifndef restrict
+#ifdef __restrict
+#define restrict __restrict
+#else
+#ifdef __restrict__
+#define restrict __restrict__
+#else
+#define restrict
+#endif
+#endif
+#endif
+
+enum
+{
+  PROP_0,
+  PROP_LAST
+};
+
+static void gegl_sampler_upsmooth_get (      GeglSampler* restrict self,
+                                       const gdouble               absolute_x,
+                                       const gdouble               absolute_y,
+                                               void*      restrict output);
+
+static void set_property (      GObject*    gobject,
+                                guint       property_id,
+                          const GValue*     value,
+                                GParamSpec* pspec);
+
+static void get_property (GObject*    gobject,
+                          guint       property_id,
+                          GValue*     value,
+                          GParamSpec* pspec);
+
+G_DEFINE_TYPE (GeglSamplerUpsmooth, gegl_sampler_upsmooth, GEGL_TYPE_SAMPLER)
+
+static void
+gegl_sampler_upsmooth_class_init (GeglSamplerUpsmoothClass *klass)
+{
+  GeglSamplerClass *sampler_class = GEGL_SAMPLER_CLASS (klass);
+  GObjectClass *object_class  = G_OBJECT_CLASS (klass);
+  object_class->set_property = set_property;
+  object_class->get_property = get_property;
+  sampler_class->get = gegl_sampler_upsmooth_get;
+}
+
+static void
+gegl_sampler_upsmooth_init (GeglSamplerUpsmooth *self)
+{
+  GEGL_SAMPLER (self)->context_rect.x = -1;
+  GEGL_SAMPLER (self)->context_rect.y = -1;
+  GEGL_SAMPLER (self)->context_rect.width = 4;
+  GEGL_SAMPLER (self)->context_rect.height = 4;
+  GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
+}
+
+static void inline
+snohalo_step1 (const gfloat           cer_thr_in,
+               const gfloat           cer_fou_in,
+               const gfloat           uno_two_in,
+               const gfloat           uno_thr_in,
+               const gfloat           uno_fou_in,
+               const gfloat           uno_fiv_in,
+               const gfloat           dos_one_in,
+               const gfloat           dos_two_in,
+               const gfloat           dos_thr_in,
+               const gfloat           dos_fou_in,
+               const gfloat           dos_fiv_in,
+               const gfloat           dos_six_in,
+               const gfloat           tre_zer_in,
+               const gfloat           tre_one_in,
+               const gfloat           tre_two_in,
+               const gfloat           tre_thr_in,
+               const gfloat           tre_fou_in,
+               const gfloat           tre_fiv_in,
+               const gfloat           tre_six_in,
+               const gfloat           qua_zer_in,
+               const gfloat           qua_one_in,
+               const gfloat           qua_two_in,
+               const gfloat           qua_thr_in,
+               const gfloat           qua_fou_in,
+               const gfloat           qua_fiv_in,
+               const gfloat           qua_six_in,
+               const gfloat           cin_one_in,
+               const gfloat           cin_two_in,
+               const gfloat           cin_thr_in,
+               const gfloat           cin_fou_in,
+               const gfloat           cin_fiv_in,
+               const gfloat           sei_two_in,
+               const gfloat           sei_thr_in,
+               const gfloat           sei_fou_in,
+                     gfloat* restrict uno_two_1,
+                     gfloat* restrict uno_thr_1,
+                     gfloat* restrict dos_one_1,
+                     gfloat* restrict dos_two_1,
+                     gfloat* restrict dos_thr_1,
+                     gfloat* restrict dos_fou_1,
+                     gfloat* restrict tre_one_1,
+                     gfloat* restrict tre_two_1,
+                     gfloat* restrict tre_thr_1,
+                     gfloat* restrict tre_fou_1,
+                     gfloat* restrict qua_two_1,
+                     gfloat* restrict qua_thr_1)
+{
+  /*
+   * This function calculates the missing ten double density pixel
+   * values, and also returns the "already known" two, so that the
+   * twelve values which make up the stencil of snohalo level 1 are
+   * available. One level of snohalo subdivision is then applied to
+   * these 24 values, prior to applying bilinear interpolation.
+   */
+  /*
+   * THE STENCIL OF INPUT VALUES:
+   *
+   * Pointer arithmetic is used to implicitly reflect the input
+   * stencil about tre_thr---assumed closer to the sampling location
+   * than other pixels (ties are OK)---in such a way that after
+   * reflection the sampling point is to the bottom right of tre_thr.
+   *
+   * The following code and picture assumes that the stencil reflexion
+   * has already been performed.
+   *
+   *
+   *                                         (ix,iy-3)    (ix+1,iy-3)
+   *                                         = cer_thr    = cer_fou
+   *
+   *
+   *
+   *                            (ix-1,iy-2)  (ix,iy-2)    (ix+1,iy-2)  (ix+1,iy-3)
+   *                            = uno_two    = uno_thr    = uno_fou    = uno_fiv
+   *
+   *
+   *
+   *               (ix-2,iy-1)  (ix-1,iy-1)  (ix,iy-1)    (ix+1,iy-1)  (ix+2,iy-1)  (ix+3,iy-1)
+   *               = dos_one    = dos_two    = dos_thr    = dos_fou    = dos_fiv    = dos_six
+   *
+   *
+   *
+   *  (ix-3,iy)    (ix-2,iy)    (ix-1,iy)    (ix,iy)      (ix+1,iy)    (ix+2,iy)    (ix+3,iy)
+   *  = tre_zer    = tre_one    = tre_two    = tre_thr    = tre_fou    = tre_fiv    = tre_six
+   *                                                  X
+   *
+   *
+   *  (ix-3,iy)    (ix-2,iy)    (ix-1,iy+1)  (ix,iy+1)    (ix+1,iy+1)  (ix+2,iy+1)  (ix+3,iy+1)
+   *  = qua_zer    = qua_one    = qua_two    = qua_thr    = qua_fou    = qua_fiv    = qua_six
+   *
+   *
+   *
+   *               (ix-2,iy+2)  (ix-1,iy+2)  (ix,iy+2)    (ix+1,iy+2)  (ix+2,iy+2)
+   *               = cin_one    = cin_two    = cin_thr    = cin_fou    = cin_fiv
+   *
+   *
+   *
+   *                            (ix-1,iy+3)  (ix,iy+3)    (ix+1,iy+3)
+   *                            = sei_two    = sei_thr    = sei_fou
+   *
+   *
+   * The above input pixel values are the ones needed in order to make
+   * available to the second level the following first level values:
+   *
+   *                   uno_two_1 =  uno_thr_1 =
+   *                   (ix,iy-1/2)  (ix+1/2,iy-1/2)
+   *
+   *
+   *
+   *
+   *  dos_one_1 =      dos_two_1 =  dos_thr_1 =      dos_fou_1 =
+   *  (ix-1/2,iy)      (ix,iy)      (ix+1/2,iy)      (ix+1,iy)
+   *
+   *                             X
+   *
+   *
+   *  tre_one_1 =      tre_two_1 =  tre_thr_1 =      tre_fou_1 =
+   *  (ix-1/2,iy+1/2)  (ix,iy+1/2)  (ix+1/2,iy+1/2)  (ix+1,iy+1/2)
+   *
+   *
+   *
+   *
+   *                   qua_two_1 =  qua_thr_1 =
+   *                   (ix,iy+1)    (ix+1/2,iy+1)
+   *
+   *
+   * to which nohalo level 1 is applied by the caller.
+   */
+
+  /*
+   * Computation of the blurred input pixel values:
+   */
+  const gfloat uno_two_plus_cer_thr_in = uno_two_in + cer_thr_in;
+  const gfloat uno_thr_plus_cer_fou_in = uno_thr_in + cer_fou_in;
+
+  const gfloat dos_one_plus_uno_two_in = dos_one_in + uno_two_in;
+  const gfloat dos_two_plus_uno_thr_in = dos_two_in + uno_thr_in;
+  const gfloat dos_thr_plus_uno_fou_in = dos_thr_in + uno_fou_in;
+  const gfloat dos_fou_plus_uno_fiv_in = dos_fou_in + uno_fiv_in;
+
+  const gfloat tre_zer_plus_dos_one_in = tre_zer_in + dos_one_in;
+  const gfloat tre_one_plus_dos_two_in = tre_one_in + dos_two_in;
+  const gfloat tre_two_plus_dos_thr_in = tre_two_in + dos_thr_in;
+  const gfloat tre_thr_plus_dos_fou_in = tre_thr_in + dos_fou_in;
+  const gfloat tre_fou_plus_dos_fiv_in = tre_fou_in + dos_fiv_in;
+  const gfloat tre_fiv_plus_dos_six_in = tre_fiv_in + dos_six_in;
+
+  const gfloat qua_zer_plus_tre_one_in = qua_zer_in + tre_one_in;
+  const gfloat qua_one_plus_tre_two_in = qua_one_in + tre_two_in;
+  const gfloat qua_two_plus_tre_thr_in = qua_two_in + tre_thr_in;
+  const gfloat qua_thr_plus_tre_fou_in = qua_thr_in + tre_fou_in;
+  const gfloat qua_fou_plus_tre_fiv_in = qua_fou_in + tre_fiv_in;
+  const gfloat qua_fiv_plus_tre_six_in = qua_fiv_in + tre_six_in;
+
+  const gfloat cin_one_plus_qua_two_in = cin_one_in + qua_two_in;
+  const gfloat cin_two_plus_qua_thr_in = cin_two_in + qua_thr_in;
+  const gfloat cin_thr_plus_qua_fou_in = cin_thr_in + qua_fou_in;
+  const gfloat cin_fou_plus_qua_fiv_in = cin_fou_in + qua_fiv_in;
+  const gfloat cin_fiv_plus_qua_six_in = cin_fiv_in + qua_six_in;
+
+  const gfloat sei_two_plus_cin_thr_in = sei_two_in + cin_thr_in;
+  const gfloat sei_thr_plus_cin_fou_in = sei_thr_in + cin_fou_in;
+  const gfloat sei_fou_plus_cin_fiv_in = sei_fou_in + cin_fiv_in;
+
+  const gfloat uno_thr =
+    .125f * ( uno_two_plus_cer_thr_in + dos_thr_plus_uno_fou_in )
+    + .5f * uno_thr_in;
+  const gfloat uno_fou =
+    .125f * ( uno_thr_plus_cer_fou_in + dos_fou_plus_uno_fiv_in )
+    + .5f * uno_fou_in;
+
+  const gfloat dos_two =
+    .125f * ( dos_one_plus_uno_two_in + tre_two_plus_dos_thr_in )
+    + .5f * dos_two_in;
+  const gfloat dos_thr =
+    .125f * ( dos_two_plus_uno_thr_in + tre_thr_plus_dos_fou_in )
+    + .5f * dos_thr_in;
+  const gfloat dos_fou =
+    .125f * ( dos_thr_plus_uno_fou_in + tre_fou_plus_dos_fiv_in )
+    + .5f * dos_fou_in;
+  const gfloat dos_fiv =
+    .125f * ( dos_fou_plus_uno_fiv_in + tre_fiv_plus_dos_six_in )
+    + .5f * dos_fiv_in;
+
+  const gfloat tre_one =
+    .125f * ( tre_zer_plus_dos_one_in + qua_one_plus_tre_two_in )
+    + .5f * tre_one_in;
+  const gfloat tre_two =
+    .125f * ( tre_one_plus_dos_two_in + qua_two_plus_tre_thr_in )
+    + .5f * tre_two_in;
+  const gfloat tre_thr =
+    .125f * ( tre_two_plus_dos_thr_in + qua_thr_plus_tre_fou_in )
+    + .5f * tre_thr_in;
+  const gfloat tre_fou =
+    .125f * ( tre_thr_plus_dos_fou_in + qua_fou_plus_tre_fiv_in )
+    + .5f * tre_fou_in;
+  const gfloat tre_fiv =
+    .125f * ( tre_fou_plus_dos_fiv_in + qua_fiv_plus_tre_six_in )
+    + .5f * tre_fiv_in;
+
+  const gfloat qua_one =
+    .125f * ( qua_zer_plus_tre_one_in + cin_one_plus_qua_two_in )
+    + .5f * qua_one_in;
+  const gfloat qua_two =
+    .125f * ( qua_one_plus_tre_two_in + cin_two_plus_qua_thr_in )
+    + .5f * qua_two_in;
+  const gfloat qua_thr =
+    .125f * ( qua_two_plus_tre_thr_in + cin_thr_plus_qua_fou_in )
+    + .5f * qua_thr_in;
+  const gfloat qua_fou =
+    .125f * ( qua_thr_plus_tre_fou_in + cin_fou_plus_qua_fiv_in )
+    + .5f * qua_fou_in;
+  const gfloat qua_fiv =
+    .125f * ( qua_fou_plus_tre_fiv_in + cin_fiv_plus_qua_six_in )
+    + .5f * qua_fiv_in;
+
+  const gfloat cin_two =
+    .125f * ( cin_one_plus_qua_two_in + sei_two_plus_cin_thr_in )
+    + .5f * cin_two_in;
+  const gfloat cin_thr =
+    .125f * ( cin_two_plus_qua_thr_in + sei_thr_plus_cin_fou_in )
+    + .5f * cin_thr_in;
+  const gfloat cin_fou =
+    .125f * ( cin_thr_plus_qua_fou_in + sei_fou_plus_cin_fiv_in )
+    + .5f * cin_fou_in;
+
+  /*
+   * Computation of the nonlinear slopes: If two consecutive pixel
+   * value differences have the same sign, the smallest one (in
+   * absolute value) is taken to be the corresponding slope; if the
+   * two consecutive pixel value differences don't have the same sign,
+   * the corresponding slope is set to 0. In other words, apply minmod
+   * to consecutive differences.
+   */
+  /*
+   * Two vertical simple differences:
+   */
+  const gfloat d_dostre_two = tre_two - dos_two;
+  const gfloat d_trequa_two = qua_two - tre_two;
+  const gfloat d_quacin_two = cin_two - qua_two;
+  /*
+   * Thr(ee) vertical differences:
+   */
+  const gfloat d_unodos_thr = dos_thr - uno_thr;
+  const gfloat d_dostre_thr = tre_thr - dos_thr;
+  const gfloat d_trequa_thr = qua_thr - tre_thr;
+  const gfloat d_quacin_thr = cin_thr - qua_thr;
+  /*
+   * Fou(r) vertical differences:
+   */
+  const gfloat d_unodos_fou = dos_fou - uno_fou;
+  const gfloat d_dostre_fou = tre_fou - dos_fou;
+  const gfloat d_trequa_fou = qua_fou - tre_fou;
+  const gfloat d_quacin_fou = cin_fou - qua_fou;
+  /*
+   * Dos horizontal differences:
+   */
+  const gfloat d_dos_twothr = dos_thr - dos_two;
+  const gfloat d_dos_thrfou = dos_fou - dos_thr;
+  const gfloat d_dos_foufiv = dos_fiv - dos_fou;
+  /*
+   * Tre(s) horizontal differences:
+   */
+  const gfloat d_tre_onetwo = tre_two - tre_one;
+  const gfloat d_tre_twothr = tre_thr - tre_two;
+  const gfloat d_tre_thrfou = tre_fou - tre_thr;
+  const gfloat d_tre_foufiv = tre_fiv - tre_fou;
+  /*
+   * Qua(ttro) horizontal differences:
+   */
+  const gfloat d_qua_onetwo = qua_two - qua_one;
+  const gfloat d_qua_twothr = qua_thr - qua_two;
+  const gfloat d_qua_thrfou = qua_fou - qua_thr;
+  const gfloat d_qua_foufiv = qua_fiv - qua_fou;
+
+  /*
+   * Recyclable vertical products and squares:
+   */
+  const gfloat d_dostre_times_trequa_two = d_dostre_two * d_trequa_two;
+  const gfloat d_trequa_two_sq           = d_trequa_two * d_trequa_two;
+  const gfloat d_trequa_times_quacin_two = d_quacin_two * d_trequa_two;
+
+  const gfloat d_unodos_times_dostre_thr = d_unodos_thr * d_dostre_thr;
+  const gfloat d_dostre_thr_sq           = d_dostre_thr * d_dostre_thr;
+  const gfloat d_dostre_times_trequa_thr = d_trequa_thr * d_dostre_thr;
+  const gfloat d_trequa_times_quacin_thr = d_trequa_thr * d_quacin_thr;
+  const gfloat d_quacin_thr_sq           = d_quacin_thr * d_quacin_thr;
+
+  const gfloat d_unodos_times_dostre_fou = d_unodos_fou * d_dostre_fou;
+  const gfloat d_dostre_fou_sq           = d_dostre_fou * d_dostre_fou;
+  const gfloat d_dostre_times_trequa_fou = d_trequa_fou * d_dostre_fou;
+  const gfloat d_trequa_times_quacin_fou = d_trequa_fou * d_quacin_fou;
+  const gfloat d_quacin_fou_sq           = d_quacin_fou * d_quacin_fou;
+  /*
+   * Recyclable horizontal products and squares:
+   */
+  const gfloat d_dos_twothr_times_thrfou = d_dos_twothr * d_dos_thrfou;
+  const gfloat d_dos_thrfou_sq           = d_dos_thrfou * d_dos_thrfou;
+  const gfloat d_dos_thrfou_times_foufiv = d_dos_foufiv * d_dos_thrfou;
+
+  const gfloat d_tre_onetwo_times_twothr = d_tre_onetwo * d_tre_twothr;
+  const gfloat d_tre_twothr_sq           = d_tre_twothr * d_tre_twothr;
+  const gfloat d_tre_twothr_times_thrfou = d_tre_thrfou * d_tre_twothr;
+  const gfloat d_tre_thrfou_times_foufiv = d_tre_thrfou * d_tre_foufiv;
+  const gfloat d_tre_foufiv_sq           = d_tre_foufiv * d_tre_foufiv;
+
+  const gfloat d_qua_onetwo_times_twothr = d_qua_onetwo * d_qua_twothr;
+  const gfloat d_qua_twothr_sq           = d_qua_twothr * d_qua_twothr;
+  const gfloat d_qua_twothr_times_thrfou = d_qua_thrfou * d_qua_twothr;
+  const gfloat d_qua_thrfou_times_foufiv = d_qua_thrfou * d_qua_foufiv;
+  const gfloat d_qua_foufiv_sq           = d_qua_foufiv * d_qua_foufiv;
+
+  /*
+   * Minmod slopes and first level pixel values:
+   */
+  const gfloat dos_thr_y =
+    FAST_MINMOD( d_dostre_thr, d_unodos_thr,
+                 d_dostre_thr_sq,
+                 d_unodos_times_dostre_thr );
+  const gfloat tre_thr_y =
+    FAST_MINMOD( d_dostre_thr, d_trequa_thr,
+                 d_dostre_thr_sq,
+                 d_dostre_times_trequa_thr );
+
+  const gfloat val_uno_two_1 =
+    .5 * ( dos_thr + tre_thr )
+    +
+    .25 * ( dos_thr_y - tre_thr_y );
+
+  const gfloat qua_thr_y =
+    FAST_MINMOD( d_quacin_thr, d_trequa_thr,
+                 d_quacin_thr_sq,
+                 d_trequa_times_quacin_thr );
+
+  const gfloat val_tre_two_1 =
+    .5 * ( tre_thr + qua_thr )
+    +
+    .25 * ( tre_thr_y - qua_thr_y );
+
+  const gfloat tre_fou_y =
+    FAST_MINMOD( d_dostre_fou, d_trequa_fou,
+                 d_dostre_fou_sq,
+                 d_dostre_times_trequa_fou );
+  const gfloat qua_fou_y =
+    FAST_MINMOD( d_quacin_fou, d_trequa_fou,
+                 d_quacin_fou_sq,
+                 d_trequa_times_quacin_fou );
+
+  const gfloat val_tre_fou_1 =
+    .5 * ( tre_fou + qua_fou )
+    +
+    .25 * ( tre_fou_y - qua_fou_y );
+
+  const gfloat tre_two_x =
+    FAST_MINMOD( d_tre_twothr, d_tre_onetwo,
+                 d_tre_twothr_sq,
+                 d_tre_onetwo_times_twothr );
+  const gfloat tre_thr_x =
+    FAST_MINMOD( d_tre_twothr, d_tre_thrfou,
+                 d_tre_twothr_sq,
+                 d_tre_twothr_times_thrfou );
+
+  const gfloat val_dos_one_1 =
+    .5 * ( tre_two + tre_thr )
+    +
+    .25 * ( tre_two_x - tre_thr_x );
+
+  const gfloat tre_fou_x =
+    FAST_MINMOD( d_tre_foufiv, d_tre_thrfou,
+                 d_tre_foufiv_sq,
+                 d_tre_thrfou_times_foufiv );
+
+  const gfloat tre_thr_x_minus_tre_fou_x =
+    tre_thr_x - tre_fou_x;
+
+  const gfloat val_dos_thr_1 =
+    .5 * ( tre_thr + tre_fou )
+    +
+    .25 * tre_thr_x_minus_tre_fou_x;
+
+  const gfloat qua_thr_x =
+    FAST_MINMOD( d_qua_twothr, d_qua_thrfou,
+                 d_qua_twothr_sq,
+                 d_qua_twothr_times_thrfou );
+  const gfloat qua_fou_x =
+    FAST_MINMOD( d_qua_foufiv, d_qua_thrfou,
+                 d_qua_foufiv_sq,
+                 d_qua_thrfou_times_foufiv );
+
+  const gfloat qua_thr_x_minus_qua_fou_x =
+    qua_thr_x - qua_fou_x;
+
+  const gfloat val_qua_thr_1 =
+    .5 * ( qua_thr + qua_fou )
+    +
+    .25 * qua_thr_x_minus_qua_fou_x;
+  const gfloat val_tre_thr_1 =
+    .125 * ( tre_thr_x_minus_tre_fou_x + qua_thr_x_minus_qua_fou_x )
+    +
+    .5 * ( val_tre_two_1 + val_tre_fou_1 );
+
+  const gfloat dos_fou_y =
+    FAST_MINMOD( d_dostre_fou, d_unodos_fou,
+                 d_dostre_fou_sq,
+                 d_unodos_times_dostre_fou );
+  const gfloat dos_thr_x =
+    FAST_MINMOD( d_dos_thrfou, d_dos_twothr,
+                 d_dos_thrfou_sq,
+                 d_dos_twothr_times_thrfou );
+  const gfloat dos_fou_x =
+    FAST_MINMOD( d_dos_thrfou, d_dos_foufiv,
+                 d_dos_thrfou_sq,
+                 d_dos_thrfou_times_foufiv );
+
+  const gfloat val_uno_thr_1 =
+    .25 * ( dos_fou - tre_thr )
+    +
+    .125 * ( dos_fou_y - tre_fou_y + dos_thr_x - dos_fou_x )
+    +
+    .5 * ( val_uno_two_1 + val_dos_thr_1 );
+
+  const gfloat qua_two_x =
+    FAST_MINMOD( d_qua_twothr, d_qua_onetwo,
+                 d_qua_twothr_sq,
+                 d_qua_onetwo_times_twothr );
+  const gfloat tre_two_y =
+    FAST_MINMOD( d_trequa_two, d_dostre_two,
+                 d_trequa_two_sq,
+                 d_dostre_times_trequa_two );
+  const gfloat qua_two_y =
+    FAST_MINMOD( d_trequa_two, d_quacin_two,
+                 d_trequa_two_sq,
+                 d_trequa_times_quacin_two );
+
+  const gfloat val_tre_one_1 =
+    .25 * ( qua_two - tre_thr )
+    +
+    .125 * ( qua_two_x - qua_thr_x + tre_two_y - qua_two_y )
+    +
+    .5 * ( val_dos_one_1 + val_tre_two_1 );
+
+  /*
+   * Return level 1 stencil values:
+   */
+  *uno_two_1 = val_uno_two_1;
+  *uno_thr_1 = val_uno_thr_1;
+  *dos_one_1 = val_dos_one_1;
+  *dos_two_1 = tre_thr;
+  *dos_thr_1 = val_dos_thr_1;
+  *dos_fou_1 = tre_fou;
+  *tre_one_1 = val_tre_one_1;
+  *tre_two_1 = val_tre_two_1;
+  *tre_thr_1 = val_tre_thr_1;
+  *tre_fou_1 = val_tre_fou_1;
+  *qua_two_1 = qua_thr;
+  *qua_thr_1 = val_qua_thr_1;
+}
+
+static inline gfloat
+snohalo_step2 (const gfloat w_times_z,
+               const gfloat x_times_z_over_4_plus_x_times_y_over_8,
+               const gfloat w_times_y_over_4_plus_x_times_y_over_8,
+               const gfloat x_times_y_over_8,
+               const gfloat uno_two,
+               const gfloat uno_thr,
+               const gfloat dos_one,
+               const gfloat dos_two,
+               const gfloat dos_thr,
+               const gfloat dos_fou,
+               const gfloat tre_one,
+               const gfloat tre_two,
+               const gfloat tre_thr,
+               const gfloat tre_fou,
+               const gfloat qua_two,
+               const gfloat qua_thr)
+{
+  /*
+   * THE STENCIL OF INPUT VALUES:
+   *
+   * The footprint (stencil) of Nohalo level 1 is the same as, say,
+   * Catmull-Rom, with the exception that the four corner values are
+   * not used:
+   *
+   *               (ix,iy-1)    (ix+1,iy-1)
+   *               = uno_two    = uno_thr
+   *
+   *  (ix-1,iy)    (ix,iy)      (ix+1,iy)    (ix+2,iy)
+   *  = dos_one    = dos_two    = dos_thr    = dos_fou
+   *
+   *  (ix-1,iy+1)  (ix,iy+1)    (ix+1,iy+1)  (ix+2,iy+1)
+   *  = tre_one    = tre_two    = tre_thr    = tre_fou
+   *
+   *               (ix,iy+2)    (ix+1,iy+2)
+   *               = qua_two    = qua_thr
+   *
+   * Here, ix is the (pseudo-)floor of the requested left-to-right
+   * location, iy is the floor of the requested up-to-down location.
+   *
+   * Pointer arithmetic is used to implicitly reflect the input
+   * stencil so that the requested pixel location is closer to
+   * dos_two, The above consequently corresponds to the case in which
+   * absolute_x is closer to ix than ix+1, and absolute_y is closer to
+   * iy than iy+1. For example, if relative_x_is_rite = 1 but
+   * relative_y_is_down = 0 (see below), then dos_two corresponds to
+   * (ix+1,iy), dos_thr corresponds to (ix,iy) etc, and the three
+   * missing double density values are halfway between dos_two and
+   * dos_thr, halfway between dos_two and tre_two, and at the average
+   * of the four central positions.
+   *
+   * The following code assumes that the stencil has been suitably
+   * reflected.
+   */
+
+  /*
+   * Computation of the nonlinear slopes: If two consecutive pixel
+   * value differences have the same sign, the smallest one (in
+   * absolute value) is taken to be the corresponding slope; if the
+   * two consecutive pixel value differences don't have the same sign,
+   * the corresponding slope is set to 0. In other words, apply minmod
+   * to comsecutive differences.
+   *
+   * Dos(s) horizontal differences:
+   */
+  const gfloat prem_dos = dos_two - dos_one;
+  const gfloat deux_dos = dos_thr - dos_two;
+  const gfloat troi_dos = dos_fou - dos_thr;
+  /*
+   * Tre(s) horizontal differences:
+   */
+  const gfloat prem_tre = tre_two - tre_one;
+  const gfloat deux_tre = tre_thr - tre_two;
+  const gfloat troi_tre = tre_fou - tre_thr;
+  /*
+   * Two vertical differences:
+   */
+  const gfloat prem_two = dos_two - uno_two;
+  const gfloat deux_two = tre_two - dos_two;
+  const gfloat troi_two = qua_two - tre_two;
+  /*
+   * Thr(ee) vertical differences:
+   */
+  const gfloat prem_thr = dos_thr - uno_thr;
+  const gfloat deux_thr = tre_thr - dos_thr;
+  const gfloat troi_thr = qua_thr - tre_thr;
+
+  /*
+   * Products useful for minmod:
+   */
+  const gfloat deux_prem_dos = deux_dos * prem_dos;
+  const gfloat deux_deux_dos = deux_dos * deux_dos;
+  const gfloat deux_troi_dos = deux_dos * troi_dos;
+
+  const gfloat deux_prem_two = deux_two * prem_two;
+  const gfloat deux_deux_two = deux_two * deux_two;
+  const gfloat deux_troi_two = deux_two * troi_two;
+
+  const gfloat deux_prem_tre = deux_tre * prem_tre;
+  const gfloat deux_deux_tre = deux_tre * deux_tre;
+  const gfloat deux_troi_tre = deux_tre * troi_tre;
+
+  const gfloat deux_prem_thr = deux_thr * prem_thr;
+  const gfloat deux_deux_thr = deux_thr * deux_thr;
+  const gfloat deux_troi_thr = deux_thr * troi_thr;
+
+  /*
+   * Terms computed here to put space between the computation of key
+   * quantities and the related conditionals:
+   */
+  const gfloat twice_dos_two_plus_dos_thr = ( dos_two + dos_thr ) * 2.f;
+  const gfloat twice_dos_two_plus_tre_two = ( dos_two + tre_two ) * 2.f;
+  const gfloat twice_deux_thr_plus_deux_dos = ( deux_thr + deux_dos ) * 2.f;
+
+  /*
+   * Compute the needed "right" (at the boundary between one input
+   * pixel areas) double resolution pixel value:
+   */
+  const gfloat four_times_dos_twothr =
+    twice_dos_two_plus_dos_thr
+    +
+    FAST_MINMOD( deux_dos, prem_dos, deux_deux_dos, deux_prem_dos )
+    -
+    FAST_MINMOD( deux_dos, troi_dos, deux_deux_dos, deux_troi_dos );
+
+  /*
+   * Compute the needed "down" double resolution pixel value:
+   */
+  const gfloat four_times_dostre_two =
+    twice_dos_two_plus_tre_two
+    +
+    FAST_MINMOD( deux_two, prem_two, deux_deux_two, deux_prem_two )
+    -
+    FAST_MINMOD( deux_two, troi_two, deux_deux_two, deux_troi_two );
+
+  /*
+   * Compute the "diagonal" (at the boundary between four input pixel
+   * areas) double resolution pixel value:
+   */
+  const gfloat partial_eight_times_dostre_twothr =
+    twice_deux_thr_plus_deux_dos
+    +
+    FAST_MINMOD( deux_tre, prem_tre, deux_deux_tre, deux_prem_tre )
+    -
+    FAST_MINMOD( deux_tre, troi_tre, deux_deux_tre, deux_troi_tre )
+    +
+    FAST_MINMOD( deux_thr, prem_thr, deux_deux_thr, deux_prem_thr )
+    -
+    FAST_MINMOD( deux_thr, troi_thr, deux_deux_thr, deux_troi_thr );
+
+  /*
+   * Compute the output pixel value with bilinear applied to the
+   * reconstructed double density data:
+   */
+  const gfloat newval =
+    w_times_z * dos_two
+    +
+    x_times_z_over_4_plus_x_times_y_over_8 * four_times_dos_twothr
+    +
+    w_times_y_over_4_plus_x_times_y_over_8 * four_times_dostre_two
+    +
+    x_times_y_over_8 * partial_eight_times_dostre_twothr;
+
+  return newval;
+}
+
+#define SNOHALO_SELECT_REFLECT(tl,tr,bl,br) ( \
+  (                                           \
+    (tl) * is_top_left                        \
+    +                                         \
+    (tr) * is_top_rite                        \
+  )                                           \
+  +                                           \
+  (                                           \
+    (bl) * is_bot_left                        \
+    +                                         \
+    (br) * is_bot_rite )                      \
+  )
+
+static void
+gegl_sampler_upsmooth_get (      GeglSampler* restrict self,
+                           const gdouble               absolute_x,
+                           const gdouble               absolute_y,
+                                 void*        restrict output)
+{
+  /*
+   * Needed constants related to the input pixel value pointer
+   * provided by gegl_sampler_get_ptr (self, ix, iy). pixels_per_row
+   * corresponds to fetch_rectangle.width in gegl_sampler_get_ptr.
+   */
+  const gint channels  = 4;
+  const gint pixels_per_row = 64;
+  const gint row_skip = channels * pixels_per_row;
+
+  const gint ix_0 = FAST_PSEUDO_FLOOR (absolute_x + .5);
+  const gint iy_0 = FAST_PSEUDO_FLOOR (absolute_y + .5);
+
+  const gfloat* restrict input_bptr =
+    (gfloat*) gegl_sampler_get_ptr (self, ix_0, iy_0);
+
+  const gfloat x_0 = absolute_x - ix_0;
+  const gfloat y_0 = absolute_y - iy_0;
+
+  const gint sign_of_x_0 = 2 * ( x_0 >= 0. ) - 1;
+  const gint sign_of_y_0 = 2 * ( y_0 >= 0. ) - 1;
+
+  const gint shift_forw_1_pix = sign_of_x_0 * channels;
+  const gint shift_forw_1_row = sign_of_y_0 * row_skip;
+
+  const gint shift_back_1_pix = -shift_forw_1_pix;
+  const gint shift_back_1_row = -shift_forw_1_row;
+
+  const gint shift_back_2_pix = 2 * shift_back_1_pix;
+  const gint shift_back_2_row = 2 * shift_back_1_row;
+  const gint shift_forw_2_pix = 2 * shift_forw_1_pix;
+  const gint shift_forw_2_row = 2 * shift_forw_1_row;
+
+  const gint shift_back_3_pix = 3 * shift_back_1_pix;
+  const gint shift_back_3_row = 3 * shift_back_1_row;
+  const gint shift_forw_3_pix = 3 * shift_forw_1_pix;
+  const gint shift_forw_3_row = 3 * shift_forw_1_row;
+
+  const gint cer_thr_shift =                    shift_back_3_row;
+  const gint cer_fou_shift = shift_forw_1_pix + shift_back_3_row;
+
+  const gint uno_two_shift = shift_back_1_pix + shift_back_2_row;
+  const gint uno_thr_shift =                    shift_back_2_row;
+  const gint uno_fou_shift = shift_forw_1_pix + shift_back_2_row;
+  const gint uno_fiv_shift = shift_forw_2_pix + shift_back_2_row;
+
+  const gint dos_one_shift = shift_back_2_pix + shift_back_1_row;
+  const gint dos_two_shift = shift_back_1_pix + shift_back_1_row;
+  const gint dos_thr_shift =                    shift_back_1_row;
+  const gint dos_fou_shift = shift_forw_1_pix + shift_back_1_row;
+  const gint dos_fiv_shift = shift_forw_2_pix + shift_back_1_row;
+  const gint dos_six_shift = shift_forw_3_pix + shift_back_1_row;
+
+  const gint tre_zer_shift = shift_back_3_pix;
+  const gint tre_one_shift = shift_back_2_pix;
+  const gint tre_two_shift = shift_back_1_pix;
+  const gint tre_thr_shift = 0;
+  const gint tre_fou_shift = shift_forw_1_pix;
+  const gint tre_fiv_shift = shift_forw_2_pix;
+  const gint tre_six_shift = shift_forw_3_pix;
+
+  const gint qua_zer_shift = shift_back_3_pix + shift_forw_1_row;
+  const gint qua_one_shift = shift_back_2_pix + shift_forw_1_row;
+  const gint qua_two_shift = shift_back_1_pix + shift_forw_1_row;
+  const gint qua_thr_shift =                    shift_forw_1_row;
+  const gint qua_fou_shift = shift_forw_1_pix + shift_forw_1_row;
+  const gint qua_fiv_shift = shift_forw_2_pix + shift_forw_1_row;
+  const gint qua_six_shift = shift_forw_3_pix + shift_forw_1_row;
+
+  const gint cin_one_shift = shift_back_2_pix + shift_forw_2_row;
+  const gint cin_two_shift = shift_back_1_pix + shift_forw_2_row;
+  const gint cin_thr_shift =                    shift_forw_2_row;
+  const gint cin_fou_shift = shift_forw_1_pix + shift_forw_2_row;
+  const gint cin_fiv_shift = shift_forw_2_pix + shift_forw_2_row;
+
+  const gint sei_two_shift = shift_back_1_pix + shift_forw_3_row;
+  const gint sei_thr_shift =                    shift_forw_3_row;
+  const gint sei_fou_shift = shift_forw_1_pix + shift_forw_3_row;
+
+  /*
+   * Channel by channel computation of the new pixel values:
+   */
+  gfloat            uno_two_0, uno_thr_0;
+  gfloat dos_one_0, dos_two_0, dos_thr_0, dos_fou_0;
+  gfloat tre_one_0, tre_two_0, tre_thr_0, tre_fou_0;
+  gfloat            qua_two_0, qua_thr_0;
+
+  gfloat            uno_two_1, uno_thr_1;
+  gfloat dos_one_1, dos_two_1, dos_thr_1, dos_fou_1;
+  gfloat tre_one_1, tre_two_1, tre_thr_1, tre_fou_1;
+  gfloat            qua_two_1, qua_thr_1;
+
+  gfloat            uno_two_2, uno_thr_2;
+  gfloat dos_one_2, dos_two_2, dos_thr_2, dos_fou_2;
+  gfloat tre_one_2, tre_two_2, tre_thr_2, tre_fou_2;
+  gfloat            qua_two_2, qua_thr_2;
+
+  gfloat            uno_two_3, uno_thr_3;
+  gfloat dos_one_3, dos_two_3, dos_thr_3, dos_fou_3;
+  gfloat tre_one_3, tre_two_3, tre_thr_3, tre_fou_3;
+  gfloat            qua_two_3, qua_thr_3;
+
+  /*
+   * The newval array will contain one computed resampled value per
+   * channel:
+   */
+  gfloat newval[channels];
+
+  /*
+   * First channel:
+   */
+  snohalo_step1 (input_bptr[ cer_thr_shift ],
+                 input_bptr[ cer_fou_shift ],
+                 input_bptr[ uno_two_shift ],
+                 input_bptr[ uno_thr_shift ],
+                 input_bptr[ uno_fou_shift ],
+                 input_bptr[ uno_fiv_shift ],
+                 input_bptr[ dos_one_shift ],
+                 input_bptr[ dos_two_shift ],
+                 input_bptr[ dos_thr_shift ],
+                 input_bptr[ dos_fou_shift ],
+                 input_bptr[ dos_fiv_shift ],
+                 input_bptr[ dos_six_shift ],
+                 input_bptr[ tre_zer_shift ],
+                 input_bptr[ tre_one_shift ],
+                 input_bptr[ tre_two_shift ],
+                 input_bptr[ tre_thr_shift ],
+                 input_bptr[ tre_fou_shift ],
+                 input_bptr[ tre_fiv_shift ],
+                 input_bptr[ tre_six_shift ],
+                 input_bptr[ qua_zer_shift ],
+                 input_bptr[ qua_one_shift ],
+                 input_bptr[ qua_two_shift ],
+                 input_bptr[ qua_thr_shift ],
+                 input_bptr[ qua_fou_shift ],
+                 input_bptr[ qua_fiv_shift ],
+                 input_bptr[ qua_six_shift ],
+                 input_bptr[ cin_one_shift ],
+                 input_bptr[ cin_two_shift ],
+                 input_bptr[ cin_thr_shift ],
+                 input_bptr[ cin_fou_shift ],
+                 input_bptr[ cin_fiv_shift ],
+                 input_bptr[ sei_two_shift ],
+                 input_bptr[ sei_thr_shift ],
+                 input_bptr[ sei_fou_shift ],
+                 &uno_two_0,
+                 &uno_thr_0,
+                 &dos_one_0,
+                 &dos_two_0,
+                 &dos_thr_0,
+                 &dos_fou_0,
+                 &tre_one_0,
+                 &tre_two_0,
+                 &tre_thr_0,
+                 &tre_fou_0,
+                 &qua_two_0,
+                 &qua_thr_0);
+
+  {
+    /*
+     * Computation of the needed weights (coefficients).
+     */
+    const gfloat x = ( 2 * sign_of_x_0 ) * x_0 - .5;
+    const gfloat y = ( 2 * sign_of_y_0 ) * y_0 - .5;
+
+    const gint x_is_rite = ( x >= 0. );
+    const gint y_is_down = ( y >= 0. );
+    const gint x_is_left = !x_is_rite;
+    const gint y_is___up = !y_is_down;
+
+    const gint is_bot_rite = x_is_rite & y_is_down;
+    const gint is_bot_left = x_is_left & y_is_down;
+    const gint is_top_rite = x_is_rite & y_is___up;
+    const gint is_top_left = x_is_left & y_is___up;
+
+    const gint sign_of_x = 2 * x_is_rite - 1;
+    const gint sign_of_y = 2 * y_is_down - 1;
+
+    const gfloat w_1 = ( 2 * sign_of_x ) * x;
+    const gfloat z_1 = ( 2 * sign_of_y ) * y;
+    const gfloat x_1 = 1. - w_1;
+    const gfloat w_1_times_z_1 = w_1 * z_1;
+    const gfloat x_1_times_z_1 = x_1 * z_1;
+
+    const gfloat w_1_times_y_1_over_4 = .25  * ( w_1 - w_1_times_z_1 );
+    const gfloat x_1_times_z_1_over_4 = .25  * x_1_times_z_1;
+    const gfloat x_1_times_y_1_over_8 = .125 * ( x_1 - x_1_times_z_1 );
+
+    const gfloat w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8 =
+      w_1_times_y_1_over_4 + x_1_times_y_1_over_8;
+    const gfloat x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8 =
+      x_1_times_z_1_over_4 + x_1_times_y_1_over_8;
+
+    newval[0] =
+      snohalo_step2 (w_1_times_z_1,
+                     x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8,
+                     w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8,
+                     x_1_times_y_1_over_8,
+                     SNOHALO_SELECT_REFLECT( uno_two_0, uno_thr_0, qua_two_0, qua_thr_0 ),
+                     SNOHALO_SELECT_REFLECT( uno_thr_0, uno_two_0, qua_thr_0, qua_two_0 ),
+                     SNOHALO_SELECT_REFLECT( dos_one_0, dos_fou_0, tre_one_0, tre_fou_0 ),
+                     SNOHALO_SELECT_REFLECT( dos_two_0, dos_thr_0, tre_two_0, tre_thr_0 ),
+                     SNOHALO_SELECT_REFLECT( dos_thr_0, dos_two_0, tre_thr_0, tre_two_0 ),
+                     SNOHALO_SELECT_REFLECT( dos_fou_0, dos_one_0, tre_fou_0, tre_one_0 ),
+                     SNOHALO_SELECT_REFLECT( tre_one_0, tre_fou_0, dos_one_0, dos_fou_0 ),
+                     SNOHALO_SELECT_REFLECT( tre_two_0, tre_thr_0, dos_two_0, dos_thr_0 ),
+                     SNOHALO_SELECT_REFLECT( tre_thr_0, tre_two_0, dos_thr_0, dos_two_0 ),
+                     SNOHALO_SELECT_REFLECT( tre_fou_0, tre_one_0, dos_fou_0, dos_one_0 ),
+                     SNOHALO_SELECT_REFLECT( qua_two_0, qua_thr_0, uno_two_0, uno_thr_0 ),
+                     SNOHALO_SELECT_REFLECT( qua_thr_0, qua_two_0, uno_thr_0, uno_two_0 ));
+
+    /*
+     * Second channel:
+     *
+     * Shift input pointer by one channel:
+     */
+    input_bptr++;
+
+    snohalo_step1 (input_bptr[ cer_thr_shift ],
+                   input_bptr[ cer_fou_shift ],
+                   input_bptr[ uno_two_shift ],
+                   input_bptr[ uno_thr_shift ],
+                   input_bptr[ uno_fou_shift ],
+                   input_bptr[ uno_fiv_shift ],
+                   input_bptr[ dos_one_shift ],
+                   input_bptr[ dos_two_shift ],
+                   input_bptr[ dos_thr_shift ],
+                   input_bptr[ dos_fou_shift ],
+                   input_bptr[ dos_fiv_shift ],
+                   input_bptr[ dos_six_shift ],
+                   input_bptr[ tre_zer_shift ],
+                   input_bptr[ tre_one_shift ],
+                   input_bptr[ tre_two_shift ],
+                   input_bptr[ tre_thr_shift ],
+                   input_bptr[ tre_fou_shift ],
+                   input_bptr[ tre_fiv_shift ],
+                   input_bptr[ tre_six_shift ],
+                   input_bptr[ qua_zer_shift ],
+                   input_bptr[ qua_one_shift ],
+                   input_bptr[ qua_two_shift ],
+                   input_bptr[ qua_thr_shift ],
+                   input_bptr[ qua_fou_shift ],
+                   input_bptr[ qua_fiv_shift ],
+                   input_bptr[ qua_six_shift ],
+                   input_bptr[ cin_one_shift ],
+                   input_bptr[ cin_two_shift ],
+                   input_bptr[ cin_thr_shift ],
+                   input_bptr[ cin_fou_shift ],
+                   input_bptr[ cin_fiv_shift ],
+                   input_bptr[ sei_two_shift ],
+                   input_bptr[ sei_thr_shift ],
+                   input_bptr[ sei_fou_shift ],
+                   &uno_two_1,
+                   &uno_thr_1,
+                   &dos_one_1,
+                   &dos_two_1,
+                   &dos_thr_1,
+                   &dos_fou_1,
+                   &tre_one_1,
+                   &tre_two_1,
+                   &tre_thr_1,
+                   &tre_fou_1,
+                   &qua_two_1,
+                   &qua_thr_1);
+
+    newval[1] =
+      snohalo_step2 (w_1_times_z_1,
+                     x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8,
+                     w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8,
+                     x_1_times_y_1_over_8,
+                     SNOHALO_SELECT_REFLECT( uno_two_1, uno_thr_1, qua_two_1, qua_thr_1 ),
+                     SNOHALO_SELECT_REFLECT( uno_thr_1, uno_two_1, qua_thr_1, qua_two_1 ),
+                     SNOHALO_SELECT_REFLECT( dos_one_1, dos_fou_1, tre_one_1, tre_fou_1 ),
+                     SNOHALO_SELECT_REFLECT( dos_two_1, dos_thr_1, tre_two_1, tre_thr_1 ),
+                     SNOHALO_SELECT_REFLECT( dos_thr_1, dos_two_1, tre_thr_1, tre_two_1 ),
+                     SNOHALO_SELECT_REFLECT( dos_fou_1, dos_one_1, tre_fou_1, tre_one_1 ),
+                     SNOHALO_SELECT_REFLECT( tre_one_1, tre_fou_1, dos_one_1, dos_fou_1 ),
+                     SNOHALO_SELECT_REFLECT( tre_two_1, tre_thr_1, dos_two_1, dos_thr_1 ),
+                     SNOHALO_SELECT_REFLECT( tre_thr_1, tre_two_1, dos_thr_1, dos_two_1 ),
+                     SNOHALO_SELECT_REFLECT( tre_fou_1, tre_one_1, dos_fou_1, dos_one_1 ),
+                     SNOHALO_SELECT_REFLECT( qua_two_1, qua_thr_1, uno_two_1, uno_thr_1 ),
+                     SNOHALO_SELECT_REFLECT( qua_thr_1, qua_two_1, uno_thr_1, uno_two_1 ));
+
+    input_bptr++;
+
+    snohalo_step1 (input_bptr[ cer_thr_shift ],
+                   input_bptr[ cer_fou_shift ],
+                   input_bptr[ uno_two_shift ],
+                   input_bptr[ uno_thr_shift ],
+                   input_bptr[ uno_fou_shift ],
+                   input_bptr[ uno_fiv_shift ],
+                   input_bptr[ dos_one_shift ],
+                   input_bptr[ dos_two_shift ],
+                   input_bptr[ dos_thr_shift ],
+                   input_bptr[ dos_fou_shift ],
+                   input_bptr[ dos_fiv_shift ],
+                   input_bptr[ dos_six_shift ],
+                   input_bptr[ tre_zer_shift ],
+                   input_bptr[ tre_one_shift ],
+                   input_bptr[ tre_two_shift ],
+                   input_bptr[ tre_thr_shift ],
+                   input_bptr[ tre_fou_shift ],
+                   input_bptr[ tre_fiv_shift ],
+                   input_bptr[ tre_six_shift ],
+                   input_bptr[ qua_zer_shift ],
+                   input_bptr[ qua_one_shift ],
+                   input_bptr[ qua_two_shift ],
+                   input_bptr[ qua_thr_shift ],
+                   input_bptr[ qua_fou_shift ],
+                   input_bptr[ qua_fiv_shift ],
+                   input_bptr[ qua_six_shift ],
+                   input_bptr[ cin_one_shift ],
+                   input_bptr[ cin_two_shift ],
+                   input_bptr[ cin_thr_shift ],
+                   input_bptr[ cin_fou_shift ],
+                   input_bptr[ cin_fiv_shift ],
+                   input_bptr[ sei_two_shift ],
+                   input_bptr[ sei_thr_shift ],
+                   input_bptr[ sei_fou_shift ],
+                   &uno_two_2,
+                   &uno_thr_2,
+                   &dos_one_2,
+                   &dos_two_2,
+                   &dos_thr_2,
+                   &dos_fou_2,
+                   &tre_one_2,
+                   &tre_two_2,
+                   &tre_thr_2,
+                   &tre_fou_2,
+                   &qua_two_2,
+                   &qua_thr_2);
+
+    newval[2] =
+      snohalo_step2 (w_1_times_z_1,
+                     x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8,
+                     w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8,
+                     x_1_times_y_1_over_8,
+                     SNOHALO_SELECT_REFLECT( uno_two_2, uno_thr_2, qua_two_2, qua_thr_2 ),
+                     SNOHALO_SELECT_REFLECT( uno_thr_2, uno_two_2, qua_thr_2, qua_two_2 ),
+                     SNOHALO_SELECT_REFLECT( dos_one_2, dos_fou_2, tre_one_2, tre_fou_2 ),
+                     SNOHALO_SELECT_REFLECT( dos_two_2, dos_thr_2, tre_two_2, tre_thr_2 ),
+                     SNOHALO_SELECT_REFLECT( dos_thr_2, dos_two_2, tre_thr_2, tre_two_2 ),
+                     SNOHALO_SELECT_REFLECT( dos_fou_2, dos_one_2, tre_fou_2, tre_one_2 ),
+                     SNOHALO_SELECT_REFLECT( tre_one_2, tre_fou_2, dos_one_2, dos_fou_2 ),
+                     SNOHALO_SELECT_REFLECT( tre_two_2, tre_thr_2, dos_two_2, dos_thr_2 ),
+                     SNOHALO_SELECT_REFLECT( tre_thr_2, tre_two_2, dos_thr_2, dos_two_2 ),
+                     SNOHALO_SELECT_REFLECT( tre_fou_2, tre_one_2, dos_fou_2, dos_one_2 ),
+                     SNOHALO_SELECT_REFLECT( qua_two_2, qua_thr_2, uno_two_2, uno_thr_2 ),
+                     SNOHALO_SELECT_REFLECT( qua_thr_2, qua_two_2, uno_thr_2, uno_two_2 ));
+
+    input_bptr++;
+
+    snohalo_step1 (input_bptr[ cer_thr_shift ],
+                   input_bptr[ cer_fou_shift ],
+                   input_bptr[ uno_two_shift ],
+                   input_bptr[ uno_thr_shift ],
+                   input_bptr[ uno_fou_shift ],
+                   input_bptr[ uno_fiv_shift ],
+                   input_bptr[ dos_one_shift ],
+                   input_bptr[ dos_two_shift ],
+                   input_bptr[ dos_thr_shift ],
+                   input_bptr[ dos_fou_shift ],
+                   input_bptr[ dos_fiv_shift ],
+                   input_bptr[ dos_six_shift ],
+                   input_bptr[ tre_zer_shift ],
+                   input_bptr[ tre_one_shift ],
+                   input_bptr[ tre_two_shift ],
+                   input_bptr[ tre_thr_shift ],
+                   input_bptr[ tre_fou_shift ],
+                   input_bptr[ tre_fiv_shift ],
+                   input_bptr[ tre_six_shift ],
+                   input_bptr[ qua_zer_shift ],
+                   input_bptr[ qua_one_shift ],
+                   input_bptr[ qua_two_shift ],
+                   input_bptr[ qua_thr_shift ],
+                   input_bptr[ qua_fou_shift ],
+                   input_bptr[ qua_fiv_shift ],
+                   input_bptr[ qua_six_shift ],
+                   input_bptr[ cin_one_shift ],
+                   input_bptr[ cin_two_shift ],
+                   input_bptr[ cin_thr_shift ],
+                   input_bptr[ cin_fou_shift ],
+                   input_bptr[ cin_fiv_shift ],
+                   input_bptr[ sei_two_shift ],
+                   input_bptr[ sei_thr_shift ],
+                   input_bptr[ sei_fou_shift ],
+                   &uno_two_3,
+                   &uno_thr_3,
+                   &dos_one_3,
+                   &dos_two_3,
+                   &dos_thr_3,
+                   &dos_fou_3,
+                   &tre_one_3,
+                   &tre_two_3,
+                   &tre_thr_3,
+                   &tre_fou_3,
+                   &qua_two_3,
+                   &qua_thr_3);
+
+    newval[3] =
+      snohalo_step2 (w_1_times_z_1,
+                     x_1_times_z_1_over_4_plus_x_1_times_y_1_over_8,
+                     w_1_times_y_1_over_4_plus_x_1_times_y_1_over_8,
+                     x_1_times_y_1_over_8,
+                     SNOHALO_SELECT_REFLECT( uno_two_3, uno_thr_3, qua_two_3, qua_thr_3 ),
+                     SNOHALO_SELECT_REFLECT( uno_thr_3, uno_two_3, qua_thr_3, qua_two_3 ),
+                     SNOHALO_SELECT_REFLECT( dos_one_3, dos_fou_3, tre_one_3, tre_fou_3 ),
+                     SNOHALO_SELECT_REFLECT( dos_two_3, dos_thr_3, tre_two_3, tre_thr_3 ),
+                     SNOHALO_SELECT_REFLECT( dos_thr_3, dos_two_3, tre_thr_3, tre_two_3 ),
+                     SNOHALO_SELECT_REFLECT( dos_fou_3, dos_one_3, tre_fou_3, tre_one_3 ),
+                     SNOHALO_SELECT_REFLECT( tre_one_3, tre_fou_3, dos_one_3, dos_fou_3 ),
+                     SNOHALO_SELECT_REFLECT( tre_two_3, tre_thr_3, dos_two_3, dos_thr_3 ),
+                     SNOHALO_SELECT_REFLECT( tre_thr_3, tre_two_3, dos_thr_3, dos_two_3 ),
+                     SNOHALO_SELECT_REFLECT( tre_fou_3, tre_one_3, dos_fou_3, dos_one_3 ),
+                     SNOHALO_SELECT_REFLECT( qua_two_3, qua_thr_3, uno_two_3, uno_thr_3 ),
+                     SNOHALO_SELECT_REFLECT( qua_thr_3, qua_two_3, uno_thr_3, uno_two_3 ));
+
+    /*
+     * Ship out the array of new pixel values:
+     */
+    babl_process (babl_fish (self->interpolate_format, self->format),
+                  newval, output, 1);
+  }
+}
+
+static void
+set_property (      GObject*    gobject,
+                    guint       property_id,
+              const GValue*     value,
+                    GParamSpec* pspec)
+{
+  G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+}
+
+static void
+get_property (GObject*    gobject,
+              guint       property_id,
+              GValue*     value,
+              GParamSpec* pspec)
+{
+  G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+}
diff --git a/gegl/buffer/gegl-sampler-upsmooth.h b/gegl/buffer/gegl-sampler-upsmooth.h
new file mode 100644
index 0000000..6b16246
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-upsmooth.h
@@ -0,0 +1,48 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __GEGL_SAMPLER_UPSMOOTH_H__
+#define __GEGL_SAMPLER_UPSMOOTH_H__
+
+#include "gegl-sampler.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_SAMPLER_UPSMOOTH            (gegl_sampler_upsmooth_get_type ())
+#define GEGL_SAMPLER_UPSMOOTH(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_SAMPLER_UPSMOOTH, GeglSamplerUpsmooth))
+#define GEGL_SAMPLER_UPSMOOTH_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GEGL_TYPE_SAMPLER_UPSMOOTH, GeglSamplerUpsmoothClass))
+#define GEGL_IS_SAMPLER_UPSMOOTH(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_SAMPLER_UPSMOOTH))
+#define GEGL_IS_SAMPLER_UPSMOOTH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GEGL_TYPE_SAMPLER_UPSMOOTH))
+#define GEGL_SAMPLER_UPSMOOTH_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GEGL_TYPE_SAMPLER_UPSMOOTH, GeglSamplerUpsmoothClass))
+
+typedef struct _GeglSamplerUpsmooth      GeglSamplerUpsmooth;
+typedef struct _GeglSamplerUpsmoothClass GeglSamplerUpsmoothClass;
+
+struct _GeglSamplerUpsmooth
+{
+  GeglSampler parent_instance;
+};
+
+struct _GeglSamplerUpsmoothClass
+{
+  GeglSamplerClass parent_class;
+};
+
+GType gegl_sampler_upsmooth_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/gegl/buffer/gegl-sampler.c b/gegl/buffer/gegl-sampler.c
index 5778384..719d090 100644
--- a/gegl/buffer/gegl-sampler.c
+++ b/gegl/buffer/gegl-sampler.c
@@ -34,8 +34,9 @@
 #include "gegl-sampler-downsharp.h"
 #include "gegl-sampler-downsize.h"
 #include "gegl-sampler-downsmooth.h"
-#include "gegl-sampler-sharp.h"
-#include "gegl-sampler-yafr.h"
+#include "gegl-sampler-upsharp.h"
+#include "gegl-sampler-upsize.h"
+#include "gegl-sampler-upsmooth.h"
 
 enum
 {
@@ -464,15 +465,6 @@ gegl_buffer_interpolation_from_string (const gchar *string)
       g_str_equal (string, "bicubic"))
     return GEGL_INTERPOLATION_CUBIC;
 
-  if (g_str_equal (string, "sharp"))
-    return GEGL_INTERPOLATION_SHARP;
-
-  if (g_str_equal (string, "yafr"))
-    return GEGL_INTERPOLATION_YAFR;
-
-  if (g_str_equal (string, "lanczos"))
-    return GEGL_INTERPOLATION_LANCZOS;
-
   if (g_str_equal (string, "downsharp"))
     return GEGL_INTERPOLATION_DOWNSHARP;
 
@@ -482,6 +474,15 @@ gegl_buffer_interpolation_from_string (const gchar *string)
   if (g_str_equal (string, "downsmooth"))
     return GEGL_INTERPOLATION_DOWNSMOOTH;
 
+  if (g_str_equal (string, "upsharp"))
+    return GEGL_INTERPOLATION_UPSHARP;
+
+  if (g_str_equal (string, "upsize"))
+    return GEGL_INTERPOLATION_UPSIZE;
+
+  if (g_str_equal (string, "upsmooth"))
+    return GEGL_INTERPOLATION_UPSMOOTH;
+
   return GEGL_INTERPOLATION_NEAREST;
 }
 
@@ -496,10 +497,6 @@ gegl_sampler_type_from_interpolation (GeglInterpolation interpolation)
         return GEGL_TYPE_SAMPLER_LINEAR;
       case GEGL_INTERPOLATION_CUBIC:
         return GEGL_TYPE_SAMPLER_CUBIC;
-      case GEGL_INTERPOLATION_SHARP:
-        return GEGL_TYPE_SAMPLER_SHARP;
-      case GEGL_INTERPOLATION_YAFR:
-        return GEGL_TYPE_SAMPLER_YAFR;
       case GEGL_INTERPOLATION_LANCZOS:
         return GEGL_TYPE_SAMPLER_LANCZOS;
       case GEGL_INTERPOLATION_DOWNSHARP:
@@ -508,6 +505,12 @@ gegl_sampler_type_from_interpolation (GeglInterpolation interpolation)
         return GEGL_TYPE_SAMPLER_DOWNSIZE;
       case GEGL_INTERPOLATION_DOWNSMOOTH:
         return GEGL_TYPE_SAMPLER_DOWNSMOOTH;
+      case GEGL_INTERPOLATION_UPSHARP:
+        return GEGL_TYPE_SAMPLER_UPSHARP;
+      case GEGL_INTERPOLATION_UPSIZE:
+        return GEGL_TYPE_SAMPLER_UPSIZE;
+      case GEGL_INTERPOLATION_UPSMOOTH:
+        return GEGL_TYPE_SAMPLER_UPSMOOTH;
       default:
         return GEGL_TYPE_SAMPLER_LINEAR;
     }
diff --git a/operations/affine/affine.c b/operations/affine/affine.c
index 641cf12..47df3ba 100644
--- a/operations/affine/affine.c
+++ b/operations/affine/affine.c
@@ -252,7 +252,7 @@ op_affine_class_init (OpAffineClass *klass)
                                    g_param_spec_string (
                                      "filter",
                                      _("Filter"),
-                                     _("Filter type (nearest, linear, lanczos, cubic, downsharp, downsize, downsmooth)"),
+                                     _("Filter type (nearest, linear, lanczos, cubic, downsharp, downsize, downsmooth, upsharp, upsize, upsmooth)"),
                                      "linear",
                                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
   g_object_class_install_property (gobject_class, PROP_HARD_EDGES,



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