[gegl/samplers] Added nohalo sampler (VSQBS).



commit cfbbf7a2b2e81fe76c20e72a0a32921c4d1b4092
Author: Adam Turcotte <aturcotte src gnome org>
Date:   Sun Jul 31 20:33:28 2011 -0400

    Added nohalo sampler (VSQBS).

 gegl/buffer/Makefile.am           |    2 +
 gegl/buffer/gegl-buffer-access.c  |    1 +
 gegl/buffer/gegl-buffer.c         |    1 +
 gegl/buffer/gegl-buffer.h         |    3 +-
 gegl/buffer/gegl-sampler-nohalo.c |  628 +++++++++++++++++++++++++++++++++++++
 gegl/buffer/gegl-sampler-nohalo.h |   48 +++
 gegl/buffer/gegl-sampler.c        |    6 +
 operations/affine/affine.c        |    2 +-
 8 files changed, 689 insertions(+), 2 deletions(-)
---
diff --git a/gegl/buffer/Makefile.am b/gegl/buffer/Makefile.am
index 72f3e43..b813ca4 100644
--- a/gegl/buffer/Makefile.am
+++ b/gegl/buffer/Makefile.am
@@ -28,6 +28,7 @@ libbuffer_la_SOURCES = \
     gegl-sampler-linear.c	\
     gegl-sampler-nearest.c	\
     gegl-sampler-lohalo.c       \
+    gegl-sampler-nohalo.c       \
     gegl-region-generic.c	\
     gegl-tile.c			\
     gegl-tile-source.c		\
@@ -56,6 +57,7 @@ libbuffer_la_SOURCES = \
     gegl-sampler-linear.h	\
     gegl-sampler-nearest.h	\
     gegl-sampler-lohalo.h       \
+    gegl-sampler-nohalo.h       \
     gegl-region.h		\
     gegl-region-generic.h	\
     gegl-tile.h			\
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 50b301e..d5dfb57 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -36,6 +36,7 @@
 #include "gegl-sampler-cubic.h"
 #include "gegl-sampler-lanczos.h"
 #include "gegl-sampler-lohalo.h"
+#include "gegl-sampler-nohalo.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 08056bb..0b15602 100644
--- a/gegl/buffer/gegl-buffer.c
+++ b/gegl/buffer/gegl-buffer.c
@@ -63,6 +63,7 @@
 #include "gegl-sampler-cubic.h"
 #include "gegl-sampler-lanczos.h"
 #include "gegl-sampler-lohalo.h"
+#include "gegl-sampler-nohalo.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 f303f52..7043b5d 100644
--- a/gegl/buffer/gegl-buffer.h
+++ b/gegl/buffer/gegl-buffer.h
@@ -312,7 +312,8 @@ typedef enum {
   GEGL_INTERPOLATION_LINEAR,
   GEGL_INTERPOLATION_CUBIC,
   GEGL_INTERPOLATION_LANCZOS,
-  GEGL_INTERPOLATION_LOHALO
+  GEGL_INTERPOLATION_LOHALO,
+  GEGL_INTERPOLATION_NOHALO
 } GeglInterpolation;
 
 /**
diff --git a/gegl/buffer/gegl-sampler-nohalo.c b/gegl/buffer/gegl-sampler-nohalo.c
new file mode 100644
index 0000000..740e408
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-nohalo.c
@@ -0,0 +1,628 @@
+/* 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) Nicolas Robidoux, Chantal Racette, Adam Turcotte, Ãyvind
+ * KolÃs, Eric Daoust and Geert Jordaens.
+ */
+
+/*
+ * ================
+ * NOHALO SAMPLER
+ * ================
+ *
+ * Vertex-Split Quadratic B-Splines (VSQBS) is a brand new method
+ * which consists of vertex-split subdivision, a subdivision method
+ * with the (as yet unknown?) property that data which is (locally)
+ * constant on diagonals is subdivided into data which is (locally)
+ * constant on diagonals, followed by quadratic B-Spline smoothing.
+ * Because both methods are linear, their combination can be
+ * implemented as if there is no subdivision.
+ *
+ * At high enlargement ratios, VSQBS is very effective at "masking"
+ * that that the original has pixels uniformly distributed on a
+ * grid. In particular, VSQBS produces resamples with only very mild
+ * staircasing. Like cubic B-Spline smoothing, however, VSQBS is not
+ * an interpolatory method. For example, using VSQBS to perform the
+ * identity geometric transformation (enlargement by a scaling factor
+ * equal to 1) on an image does not return the original: VSQBS
+ * effectively smooths out the image with the convolution mask
+ *
+ *     1/8
+ * 1/8 1/2 1/8
+ *     1/8
+ *
+ * which is a fairly moderate blur (although the checkerboard mode is
+ * in its nullspace).
+ *
+ * In the nohalo sampler, VSQBS is blended with bilinear when all
+ * the singular values of the Jacobian matrix of the transformation
+ * which calls the sampler are in the interval (-1/2,2).
+ *
+ * Blending VSQBS with an interpolatory method (here, bilinear) in a
+ * Jacobian adaptive way ensures that resampling is interpolatory for
+ * rotations (that is, the above blur is not active when the
+ * transformation is a rotation). In particular, resampling for the
+ * identity geometric transformation is equivalent to the
+ * identity.
+ *
+ * An article on VSQBS is forthcoming.
+ */
+
+/*
+ * 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 "math.h"
+#include "gegl-matrix.h"
+#include <glib-object.h>
+
+#include "gegl.h"
+#include "gegl-types-internal.h"
+#include "gegl-buffer-private.h"
+
+#include "gegl-sampler-nohalo.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) ( (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_nohalo_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 (GeglSamplerNohalo, gegl_sampler_nohalo, GEGL_TYPE_SAMPLER)
+
+static void
+gegl_sampler_nohalo_class_init (GeglSamplerNohaloClass *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_nohalo_get;
+}
+
+static void
+gegl_sampler_nohalo_init (GeglSamplerNohalo *self)
+{
+  GEGL_SAMPLER (self)->context_rect.x = -1;
+  GEGL_SAMPLER (self)->context_rect.y = -1;
+  GEGL_SAMPLER (self)->context_rect.width = 3;
+  GEGL_SAMPLER (self)->context_rect.height = 3;
+  GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
+}
+
+/*
+ * THE STENCIL OF INPUT VALUES:
+ *
+ * Pointer arithmetic is used to implicitly reflect the input stencil
+ * about dos_two---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 dos_two.
+ *
+ * The following code and picture assumes that the stencil reflexion
+ * has already been performed. (X is the sampling location.)
+ *
+ *
+ *               (ix,iy-1)    (ix+1,iy-1)
+ *               = uno_two    = uno_thr
+ *
+ *
+ *
+ *  (ix-1,iy)    (ix,iy)      (ix+1,iy)
+ *  = dos_one    = dos_two    = dos_thr
+ *                       X
+ *
+ *
+ *  (ix-1,iy+1)  (ix,iy+1)    (ix+1,iy+1)
+ *  = tre_one    = tre_two    = tre_thr
+ *
+ *
+ * The above input pixel values are the ones needed in order to
+ * IMPLICITLY make available the following values, needed by quadratic
+ * B-Splines, which is performed on (shifted) double density data:
+ *
+ *
+ *  uno_one_1 =      uno_two_1 =      uno_thr_1 =
+ *  (ix-1/4,iy-1/4)  (ix+1/4,iy-1/4)  (ix+3/4,iy-1/4)
+ *
+ *
+ *
+ *                 X            or X
+ *  dos_one_1 =      dos_two_1 =      dos_thr_1 =
+ *  (ix-1/4,iy+1/4)  (ix+1/4,iy+1/4)  (ix+3/4,iy+1/4)
+ *              or X            or X
+ *
+ *
+ *
+ *  tre_one_1 =      tre_two_1 =      tre_thr_1 =
+ *  (ix-1/4,iy+3/4)  (ix+1/4,iy+3/4)  (ix+3/4,iy+3/4)
+ *
+ *
+ * In the coefficient computations, we fix things so that coordinates
+ * are relative to dos_two_1, and so that distances are rescaled so
+ * that double density pixel locations are at a distance of 1.
+ *
+ * As far as the bilinear component of the sampler is concerned, the
+ * sampling position is normalized so that X is in the convex hull of
+ * dos_two, dos_thr, tre_two and tre_thr.
+ */
+
+static inline gfloat
+vsqbs_bilinear_mix (const gdouble four_c_uno_two,
+                    const gdouble four_c_uno_thr,
+                    const gdouble four_c_dos_one,
+                    const gdouble four_c_dos_two,
+                    const gdouble four_c_dos_thr,
+                    const gdouble four_c_tre_one,
+                    const gdouble four_c_tre_two,
+                    const gdouble four_c_tre_thr,
+                    const gdouble c_bot_rite,
+                    const gdouble c_bot_left,
+                    const gdouble c_top_left,
+                    const gdouble c_top_rite,
+                    const gdouble theta,
+                    const gdouble uno_two,
+                    const gdouble uno_thr,
+                    const gdouble dos_one,
+                    const gdouble dos_two,
+                    const gdouble dos_thr,
+                    const gdouble tre_one,
+                    const gdouble tre_two,
+                    const gdouble tre_thr)
+{
+  const gdouble vsqbs = ( four_c_uno_two * uno_two +
+                          four_c_uno_thr * uno_thr +
+                          four_c_dos_one * dos_one +
+                          four_c_dos_two * dos_two +
+                          four_c_dos_thr * dos_thr +
+                          four_c_tre_one * tre_one +
+                          four_c_tre_two * tre_two +
+                          four_c_tre_thr * tre_thr ) * 0.25;
+
+  const gdouble bilinear = c_bot_rite * tre_thr +
+                           c_bot_left * tre_two +
+                           c_top_rite * dos_thr +
+                           c_top_left * dos_two;
+
+  const gfloat newval = bilinear + theta * ( vsqbs - bilinear );
+
+  return newval;
+}
+
+static void
+gegl_sampler_nohalo_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;
+
+  /*
+   * epsilon determines how far from 1 the singular values can be
+   * before we switch out of pure bilinear. It should be strictly
+   * positive but reasonably close to 0. 3/255 ensures that using
+   * bilinear when, in theory, we should not, leads to pixel value
+   * differences of at most 1 when dealing with 8 bit images. (Some
+   * differences of 1 are unavoidable because of rounding.)
+   */
+  const gdouble epsilon = 3./255.;
+
+  /*
+   * The newval array will contain one computed resampled value per
+   * channel:
+   */
+  gfloat newval[channels];
+
+  /*
+   * Calculate the blending parameter from the squares of the singular
+   * values of the inverse Jacobian matrix:
+   */
+  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];
+
+  const gdouble Jinv_11_sq = Jinv_11 * Jinv_11;
+  const gdouble Jinv_12_sq = Jinv_12 * Jinv_12;
+  const gdouble Jinv_21_sq = Jinv_21 * Jinv_21;
+  const gdouble Jinv_22_sq = Jinv_22 * Jinv_22;
+
+  const gdouble sum_all_sq = Jinv_11_sq + Jinv_12_sq + Jinv_21_sq + Jinv_22_sq;
+  const gdouble det        = Jinv_11 * Jinv_22 - Jinv_12 * Jinv_21;
+  const gdouble twice_det  = det + det;
+
+  const gdouble discr_prod_1 = sum_all_sq + twice_det;
+  const gdouble discr_prod_2 = sum_all_sq - twice_det;
+  const gdouble discr        = discr_prod_1 * discr_prod_2;
+  const gdouble discr_sqrt = sqrt (discr);
+
+  const gdouble sigma1_sq          = ( sum_all_sq + discr_sqrt ) * 0.5;
+  const gdouble twice_sigma2_sq    = sum_all_sq - discr_sqrt;
+  const gdouble one_over_sigma2_sq = 2. / twice_sigma2_sq;
+
+  /*
+   * Take the largest of the two singular values and their two
+   * reciprocals:
+   */
+  const gdouble t =
+    ( sigma1_sq>=one_over_sigma2_sq ? sigma1_sq : one_over_sigma2_sq );
+
+  if ( t <= 1. + epsilon ) /* Pure bilinear */
+    {
+      const gint ix = FAST_PSEUDO_FLOOR (absolute_x);
+      const gint iy = FAST_PSEUDO_FLOOR (absolute_y);
+
+      const gfloat* restrict input_bptr =
+        (gfloat*) gegl_sampler_get_ptr (self, ix, iy);
+
+      const gfloat x = absolute_x - ix;
+      const gfloat y = absolute_y - iy;
+
+      /*
+       * Bilinear weights (Note: w = 1-x and z = 1-y):
+       */
+      const gfloat x_times_y = x * y;
+      const gfloat w_times_y = y - x_times_y;
+      const gfloat x_times_z = x - x_times_y;
+      const gfloat w_times_z = 1.f - ( x + w_times_y );
+
+      gfloat newval0, newval1, newval2, newval3;
+      gfloat newval0i, newval1i, newval2i, newval3i;
+
+      newval0 = *input_bptr++;
+      newval1 = *input_bptr++;
+      newval2 = *input_bptr++;
+      newval3 = *input_bptr++;
+
+      newval0i = *input_bptr++;
+      newval1i = *input_bptr++;
+      newval2i = *input_bptr++;
+      newval3i = *input_bptr;
+
+      input_bptr += 1 + row_skip - 2 * channels;
+
+      newval0 *= w_times_z;
+      newval1 *= w_times_z;
+      newval2 *= w_times_z;
+      newval3 *= w_times_z;
+
+      newval0i *= x_times_z;
+      newval1i *= x_times_z;
+      newval2i *= x_times_z;
+      newval3i *= x_times_z;
+
+      newval0 += w_times_y * *input_bptr++;
+      newval1 += w_times_y * *input_bptr++;
+      newval2 += w_times_y * *input_bptr++;
+      newval3 += w_times_y * *input_bptr++;
+
+      newval0i += x_times_y * *input_bptr++;
+      newval1i += x_times_y * *input_bptr++;
+      newval2i += x_times_y * *input_bptr++;
+      newval3i += x_times_y * *input_bptr;
+
+      newval[0] = newval0 + newval0i;
+      newval[1] = newval1 + newval1i;
+      newval[2] = newval2 + newval2i;
+      newval[3] = newval3 + newval3i;
+    }
+  else /* Pure VSQBS or VSQBS blended with bilinear */
+    {
+      /*
+       * Calculate the needed shifts:
+       */
+      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 gdouble x_0 = absolute_x - ix_0;
+      const gdouble 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 uno_two_shift =                    shift_back_1_row;
+      const gint uno_thr_shift = shift_forw_1_pix + shift_back_1_row;
+
+      const gint dos_one_shift = shift_back_1_pix;
+      const gint dos_two_shift = 0;
+      const gint dos_thr_shift = shift_forw_1_pix;
+
+      const gint tre_one_shift = shift_back_1_pix + shift_forw_1_row;
+      const gint tre_two_shift =                    shift_forw_1_row;
+      const gint tre_thr_shift = shift_forw_1_pix + shift_forw_1_row;
+
+      const gdouble abs_x_0       = sign_of_x_0 * x_0;
+      const gdouble abs_y_0       = sign_of_y_0 * y_0;
+      const gdouble twice_abs_x_0 = abs_x_0 + abs_x_0;
+      const gdouble twice_abs_y_0 = abs_y_0 + abs_y_0;
+      const gdouble x             = twice_abs_x_0 + -0.5;
+      const gdouble y             = twice_abs_y_0 + -0.5;
+      const gdouble cent          = 0.75 - x * x;
+      const gdouble mid           = 0.75 - y * y;
+      const gdouble left          = -0.5 * ( x + cent ) + 0.5;
+      const gdouble top           = -0.5 * ( y + mid  ) + 0.5;
+      const gdouble left_p_cent   = left + cent;
+      const gdouble top_p_mid     = top  + mid;
+      const gdouble cent_p_rite   = 1.0 - left;
+      const gdouble mid_p_bot     = 1.0 - top;
+      const gdouble rite          = 1.0 - left_p_cent;
+      const gdouble bot           = 1.0 - top_p_mid;
+
+      const gdouble four_c_uno_two = top  * left_p_cent;
+      const gdouble four_c_dos_one = left *  top_p_mid;
+      const gdouble four_c_dos_two = left_p_cent + top_p_mid;
+      const gdouble four_c_dos_thr = cent_p_rite * top_p_mid + rite;
+      const gdouble four_c_tre_two = mid_p_bot * left_p_cent + bot;
+      const gdouble four_c_tre_thr = mid_p_bot * rite + bot * cent_p_rite;
+      const gdouble four_c_uno_thr = top  - four_c_uno_two;
+      const gdouble four_c_tre_one = left - four_c_dos_one;
+
+      if ( t>=4. ) /* Pure VSQBS */
+        {
+          /*
+           * First channel:
+           */
+          newval[0] = ( four_c_uno_two * input_bptr[ uno_two_shift ] +
+                        four_c_uno_thr * input_bptr[ uno_thr_shift ] +
+                        four_c_dos_one * input_bptr[ dos_one_shift ] +
+                        four_c_dos_two * input_bptr[ dos_two_shift ] +
+                        four_c_dos_thr * input_bptr[ dos_thr_shift ] +
+                        four_c_tre_one * input_bptr[ tre_one_shift ] +
+                        four_c_tre_two * input_bptr[ tre_two_shift ] +
+                        four_c_tre_thr * input_bptr[ tre_thr_shift ] ) * 0.25;
+          /*
+           * Shift input pointer by one channel:
+           */
+          input_bptr++;
+          /*
+           * Compute the second channel result:
+           */
+          newval[1] = ( four_c_uno_two * input_bptr[ uno_two_shift ] +
+                        four_c_uno_thr * input_bptr[ uno_thr_shift ] +
+                        four_c_dos_one * input_bptr[ dos_one_shift ] +
+                        four_c_dos_two * input_bptr[ dos_two_shift ] +
+                        four_c_dos_thr * input_bptr[ dos_thr_shift ] +
+                        four_c_tre_one * input_bptr[ tre_one_shift ] +
+                        four_c_tre_two * input_bptr[ tre_two_shift ] +
+                        four_c_tre_thr * input_bptr[ tre_thr_shift ] ) * 0.25;
+          input_bptr++;
+          newval[2] = ( four_c_uno_two * input_bptr[ uno_two_shift ] +
+                        four_c_uno_thr * input_bptr[ uno_thr_shift ] +
+                        four_c_dos_one * input_bptr[ dos_one_shift ] +
+                        four_c_dos_two * input_bptr[ dos_two_shift ] +
+                        four_c_dos_thr * input_bptr[ dos_thr_shift ] +
+                        four_c_tre_one * input_bptr[ tre_one_shift ] +
+                        four_c_tre_two * input_bptr[ tre_two_shift ] +
+                        four_c_tre_thr * input_bptr[ tre_thr_shift ] ) * 0.25;
+          input_bptr++;
+          newval[3] = ( four_c_uno_two * input_bptr[ uno_two_shift ] +
+                        four_c_uno_thr * input_bptr[ uno_thr_shift ] +
+                        four_c_dos_one * input_bptr[ dos_one_shift ] +
+                        four_c_dos_two * input_bptr[ dos_two_shift ] +
+                        four_c_dos_thr * input_bptr[ dos_thr_shift ] +
+                        four_c_tre_one * input_bptr[ tre_one_shift ] +
+                        four_c_tre_two * input_bptr[ tre_two_shift ] +
+                        four_c_tre_thr * input_bptr[ tre_thr_shift ] ) * 0.25;
+        }
+      else /* Blend VSQBS with bilinear */
+        {
+          /*
+           * Bilinear weights (Note: w = 1-x and z = 1-y):
+           */
+          const gdouble x_times_y = abs_x_0 * abs_y_0;
+          const gdouble w_times_y = abs_y_0 - x_times_y;
+          const gdouble x_times_z = abs_x_0 - x_times_y;
+          const gdouble w_times_z = 1. - ( abs_x_0 + w_times_y );
+
+          /*
+           * Blending coefficient:
+           */
+          const gdouble theta = (1./3.)*(t-1.);
+
+          /*
+           * Channel by channel computation of the vsqbs/bilinear blend:
+           */
+          newval[0] = vsqbs_bilinear_mix (four_c_uno_two,
+                                          four_c_uno_thr,
+                                          four_c_dos_one,
+                                          four_c_dos_two,
+                                          four_c_dos_thr,
+                                          four_c_tre_one,
+                                          four_c_tre_two,
+                                          four_c_tre_thr,
+                                          x_times_y,
+                                          w_times_y,
+                                          x_times_z,
+                                          w_times_z,
+                                          theta,
+                                          input_bptr[ uno_two_shift ],
+                                          input_bptr[ uno_thr_shift ],
+                                          input_bptr[ dos_one_shift ],
+                                          input_bptr[ dos_two_shift ],
+                                          input_bptr[ dos_thr_shift ],
+                                          input_bptr[ tre_one_shift ],
+                                          input_bptr[ tre_two_shift ],
+                                          input_bptr[ tre_thr_shift ]);
+          input_bptr++;
+          newval[1] = vsqbs_bilinear_mix (four_c_uno_two,
+                                          four_c_uno_thr,
+                                          four_c_dos_one,
+                                          four_c_dos_two,
+                                          four_c_dos_thr,
+                                          four_c_tre_one,
+                                          four_c_tre_two,
+                                          four_c_tre_thr,
+                                          x_times_y,
+                                          w_times_y,
+                                          x_times_z,
+                                          w_times_z,
+                                          theta,
+                                          input_bptr[ uno_two_shift ],
+                                          input_bptr[ uno_thr_shift ],
+                                          input_bptr[ dos_one_shift ],
+                                          input_bptr[ dos_two_shift ],
+                                          input_bptr[ dos_thr_shift ],
+                                          input_bptr[ tre_one_shift ],
+                                          input_bptr[ tre_two_shift ],
+                                          input_bptr[ tre_thr_shift ]);
+          input_bptr++;
+          newval[2] = vsqbs_bilinear_mix (four_c_uno_two,
+                                          four_c_uno_thr,
+                                          four_c_dos_one,
+                                          four_c_dos_two,
+                                          four_c_dos_thr,
+                                          four_c_tre_one,
+                                          four_c_tre_two,
+                                          four_c_tre_thr,
+                                          x_times_y,
+                                          w_times_y,
+                                          x_times_z,
+                                          w_times_z,
+                                          theta,
+                                          input_bptr[ uno_two_shift ],
+                                          input_bptr[ uno_thr_shift ],
+                                          input_bptr[ dos_one_shift ],
+                                          input_bptr[ dos_two_shift ],
+                                          input_bptr[ dos_thr_shift ],
+                                          input_bptr[ tre_one_shift ],
+                                          input_bptr[ tre_two_shift ],
+                                          input_bptr[ tre_thr_shift ]);
+          input_bptr++;
+          newval[3] = vsqbs_bilinear_mix (four_c_uno_two,
+                                          four_c_uno_thr,
+                                          four_c_dos_one,
+                                          four_c_dos_two,
+                                          four_c_dos_thr,
+                                          four_c_tre_one,
+                                          four_c_tre_two,
+                                          four_c_tre_thr,
+                                          x_times_y,
+                                          w_times_y,
+                                          x_times_z,
+                                          w_times_z,
+                                          theta,
+                                          input_bptr[ uno_two_shift ],
+                                          input_bptr[ uno_thr_shift ],
+                                          input_bptr[ dos_one_shift ],
+                                          input_bptr[ dos_two_shift ],
+                                          input_bptr[ dos_thr_shift ],
+                                          input_bptr[ tre_one_shift ],
+                                          input_bptr[ tre_two_shift ],
+                                          input_bptr[ tre_thr_shift ]);
+        }
+    }
+
+  /*
+   * 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-nohalo.h b/gegl/buffer/gegl-sampler-nohalo.h
new file mode 100644
index 0000000..491cdf1
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-nohalo.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_NOHALO_H__
+#define __GEGL_SAMPLER_NOHALO_H__
+
+#include "gegl-sampler.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_SAMPLER_NOHALO            (gegl_sampler_nohalo_get_type ())
+#define GEGL_SAMPLER_NOHALO(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_SAMPLER_NOHALO, GeglSamplerNohalo))
+#define GEGL_SAMPLER_NOHALO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GEGL_TYPE_SAMPLER_NOHALO, GeglSamplerNohaloClass))
+#define GEGL_IS_SAMPLER_NOHALO(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_SAMPLER_NOHALO))
+#define GEGL_IS_SAMPLER_NOHALO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GEGL_TYPE_SAMPLER_NOHALO))
+#define GEGL_SAMPLER_NOHALO_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GEGL_TYPE_SAMPLER_NOHALO, GeglSamplerNohaloClass))
+
+typedef struct _GeglSamplerNohalo      GeglSamplerNohalo;
+typedef struct _GeglSamplerNohaloClass GeglSamplerNohaloClass;
+
+struct _GeglSamplerNohalo
+{
+  GeglSampler parent_instance;
+};
+
+struct _GeglSamplerNohaloClass
+{
+  GeglSamplerClass parent_class;
+};
+
+GType gegl_sampler_nohalo_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 24a1de9..eaa5990 100644
--- a/gegl/buffer/gegl-sampler.c
+++ b/gegl/buffer/gegl-sampler.c
@@ -35,6 +35,7 @@
 #include "gegl-sampler-cubic.h"
 #include "gegl-sampler-lanczos.h"
 #include "gegl-sampler-lohalo.h"
+#include "gegl-sampler-nohalo.h"
 
 enum
 {
@@ -568,6 +569,9 @@ gegl_buffer_interpolation_from_string (const gchar *string)
   if (g_str_equal (string, "lohalo"))
     return GEGL_INTERPOLATION_LOHALO;
 
+  if (g_str_equal (string, "nohalo"))
+    return GEGL_INTERPOLATION_NOHALO;
+
   return GEGL_INTERPOLATION_NEAREST;
 }
 
@@ -586,6 +590,8 @@ gegl_sampler_type_from_interpolation (GeglInterpolation interpolation)
         return GEGL_TYPE_SAMPLER_LANCZOS;
       case GEGL_INTERPOLATION_LOHALO:
         return GEGL_TYPE_SAMPLER_LOHALO;
+      case GEGL_INTERPOLATION_NOHALO:
+        return GEGL_TYPE_SAMPLER_NOHALO;
       default:
         return GEGL_TYPE_SAMPLER_LINEAR;
     }
diff --git a/operations/affine/affine.c b/operations/affine/affine.c
index 71f68d5..f849b3b 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, lohalo)"),
+                                     _("Filter type (nearest, linear, lanczos, cubic, lohalo, nohalo)"),
                                      "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]