Index: ./app/base/base-enums.h
===================================================================
RCS file: /cvs/gnome/gimp/app/base/base-enums.h,v
retrieving revision 1.17
diff -u -p -r1.17 base-enums.h
--- ./app/base/base-enums.h	26 Oct 2004 17:50:50 -0000	1.17
+++ ./app/base/base-enums.h	5 Jan 2005 17:55:11 -0000
@@ -69,7 +69,8 @@ typedef enum
 {
   GIMP_INTERPOLATION_NONE,   /*< desc="None (Fastest)" >*/
   GIMP_INTERPOLATION_LINEAR, /*< desc="Linear"         >*/
-  GIMP_INTERPOLATION_CUBIC   /*< desc="Cubic (Best)"   >*/
+  GIMP_INTERPOLATION_CUBIC,  /*< desc="Cubic (Best)"   >*/
+  GIMP_INTERPOLATION_LANCZOS /*< desc="Lanczos (New)">*/
 } GimpInterpolationType;
 
 
Index: ./app/paint-funcs/paint-funcs.c
===================================================================
RCS file: /cvs/gnome/gimp/app/paint-funcs/paint-funcs.c,v
retrieving revision 1.168
diff -u -p -r1.168 paint-funcs.c
--- ./app/paint-funcs/paint-funcs.c	12 Dec 2004 14:01:07 -0000	1.168
+++ ./app/paint-funcs/paint-funcs.c	5 Jan 2005 17:55:18 -0000
@@ -42,7 +42,6 @@
 #define RANDOM_SEED   314159265
 #define EPSILON       0.0001
 
-
 typedef enum
 {
   MinifyX_MinifyY,
@@ -154,8 +153,6 @@ static void     apply_layer_mode_replace
 static inline void rotate_pointers       (guchar         **p,
                                           guint32          n);
 
-
-
 static void
 update_tile_rowhints (Tile *tile,
                       gint  ymin,
@@ -432,6 +429,7 @@ cubic (gdouble dx,
                      ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
 }
 
+
 /*********************/
 /*  FUNCTIONS        */
 /*********************/
@@ -2829,275 +2827,6 @@ gaussian_blur_region (PixelRegion *srcR,
   g_free (buf);
 }
 
-
-/* non-interpolating scale_region.  [adam]
- */
-static void
-scale_region_no_resample (PixelRegion *srcPR,
-                          PixelRegion *destPR)
-{
-  gint   *x_src_offsets;
-  gint   *y_src_offsets;
-  guchar *src;
-  guchar *dest;
-  gint    width, height, orig_width, orig_height;
-  gint    last_src_y;
-  gint    row_bytes;
-  gint    x, y, b;
-  gchar   bytes;
-
-  orig_width = srcPR->w;
-  orig_height = srcPR->h;
-
-  width = destPR->w;
-  height = destPR->h;
-
-  bytes = srcPR->bytes;
-
-  /*  the data pointers...  */
-  x_src_offsets = g_new (gint, width * bytes);
-  y_src_offsets = g_new (gint, height);
-  src  = g_new (guchar, orig_width * bytes);
-  dest = g_new (guchar, width * bytes);
-
-  /*  pre-calc the scale tables  */
-  for (b = 0; b < bytes; b++)
-    for (x = 0; x < width; x++)
-      x_src_offsets [b + x * bytes] =
-        b + bytes * ((x * orig_width + orig_width / 2) / width);
-
-  for (y = 0; y < height; y++)
-    y_src_offsets [y] = (y * orig_height + orig_height / 2) / height;
-
-  /*  do the scaling  */
-  row_bytes = width * bytes;
-  last_src_y = -1;
-  for (y = 0; y < height; y++)
-    {
-      /* if the source of this line was the same as the source
-       *  of the last line, there's no point in re-rescaling.
-       */
-      if (y_src_offsets[y] != last_src_y)
-        {
-          pixel_region_get_row (srcPR, 0, y_src_offsets[y], orig_width, src, 1);
-          for (x = 0; x < row_bytes ; x++)
-            {
-              dest[x] = src[x_src_offsets[x]];
-            }
-          last_src_y = y_src_offsets[y];
-        }
-
-      pixel_region_set_row (destPR, 0, y, width, dest);
-    }
-
-  g_free (x_src_offsets);
-  g_free (y_src_offsets);
-  g_free (src);
-  g_free (dest);
-}
-
-
-static void
-get_premultiplied_double_row (PixelRegion *srcPR,
-                              gint         x,
-                              gint         y,
-                              gint         w,
-                              gdouble     *row,
-                              guchar      *tmp_src,
-                              gint         n)
-{
-  gint b;
-  gint bytes = srcPR->bytes;
-
-  pixel_region_get_row (srcPR, x, y, w, tmp_src, n);
-
-  if (pixel_region_has_alpha (srcPR))
-    {
-      /* premultiply the alpha into the double array */
-      gdouble *irow  = row;
-      gint     alpha = bytes - 1;
-      gdouble  mod_alpha;
-
-      for (x = 0; x < w; x++)
-        {
-          mod_alpha = tmp_src[alpha] / 255.0;
-          for (b = 0; b < alpha; b++)
-            irow[b] = mod_alpha * tmp_src[b];
-          irow[b] = tmp_src[alpha];
-          irow += bytes;
-          tmp_src += bytes;
-        }
-    }
-  else /* no alpha */
-    {
-      for (x = 0; x < w * bytes; x++)
-        row[x] = tmp_src[x];
-    }
-
-  /* set the off edge pixels to their nearest neighbor */
-  for (b = 0; b < 2 * bytes; b++)
-    row[b - 2 * bytes] = row[b % bytes];
-  for (b = 0; b < bytes * 2; b++)
-    row[b + w * bytes] = row[(w - 1) * bytes + b % bytes];
-}
-
-
-static void
-expand_line (gdouble               *dest,
-             gdouble               *src,
-             gint                   bytes,
-             gint                   old_width,
-             gint                   width,
-             GimpInterpolationType  interp)
-{
-  gdouble  ratio;
-  gint     x,b;
-  gint     src_col;
-  gdouble  frac;
-  gdouble *s;
-
-  ratio = old_width / (gdouble) width;
-
-  /* we can overflow src's boundaries, so we expect our caller to have
-     allocated extra space for us to do so safely (see scale_region ()) */
-
-  /* this could be optimized much more by precalculating the coefficients for
-     each x */
-  switch(interp)
-    {
-    case GIMP_INTERPOLATION_CUBIC:
-      for (x = 0; x < width; x++)
-        {
-          src_col = ((int) (x * ratio + 2.0 - 0.5)) - 2;
-          /* +2, -2 is there because (int) rounds towards 0 and we need
-             to round down */
-          frac = (x * ratio - 0.5) - src_col;
-          s = &src[src_col * bytes];
-          for (b = 0; b < bytes; b++)
-            dest[b] = cubic (frac, s[b - bytes], s[b], s[b + bytes],
-                             s[b + bytes * 2]);
-          dest += bytes;
-        }
-
-      break;
-
-    case GIMP_INTERPOLATION_LINEAR:
-      for (x = 0; x < width; x++)
-        {
-          src_col = ((int) (x * ratio + 2.0 - 0.5)) - 2;
-          /* +2, -2 is there because (int) rounds towards 0 and we need
-             to round down */
-          frac = (x * ratio - 0.5) - src_col;
-          s = &src[src_col * bytes];
-          for (b = 0; b < bytes; b++)
-            dest[b] = ((s[b + bytes] - s[b]) * frac + s[b]);
-          dest += bytes;
-        }
-      break;
-
-    case GIMP_INTERPOLATION_NONE:
-      g_assert_not_reached ();
-      break;
-    }
-}
-
-
-static void
-shrink_line (gdouble               *dest,
-             gdouble               *src,
-             gint                   bytes,
-             gint                   old_width,
-             gint                   width,
-             GimpInterpolationType  interp)
-{
-  gint          x;
-  gint          b;
-  gdouble      *srcp;
-  gdouble      *destp;
-  gdouble       accum[4];
-  gdouble       slice;
-  const gdouble avg_ratio = (gdouble) width / old_width;
-  const gdouble inv_width = 1.0 / width;
-  gint          slicepos;      /* slice position relative to width */
-
-#if 0
-  g_printerr ("shrink_line bytes=%d old_width=%d width=%d interp=%d "
-              "avg_ratio=%f\n",
-              bytes, old_width, width, interp, avg_ratio);
-#endif
-
-  g_return_if_fail (bytes <= 4);
-
-  /* This algorithm calculates the weighted average of pixel data that
-     each output pixel must receive, taking into account that it always
-     scales down, i.e. there's always more than one input pixel per each
-     output pixel.  */
-
-  srcp = src;
-  destp = dest;
-
-  slicepos = 0;
-
-  /* Initialize accum to the first pixel slice.  As there is no partial
-     pixel at start, that value is 0.  The source data is interleaved, so
-     we maintain BYTES accumulators at the same time to deal with that
-     many channels simultaneously.  */
-  for (b = 0; b < bytes; b++)
-    accum[b] = 0.0;
-
-  for (x = 0; x < width; x++)
-    {
-      /* Accumulate whole pixels.  */
-      do
-        {
-          for (b = 0; b < bytes; b++)
-            accum[b] += *srcp++;
-
-          slicepos += width;
-        }
-      while (slicepos < old_width);
-      slicepos -= old_width;
-
-      if (! (slicepos < width))
-        g_warning ("Assertion (slicepos < width) failed. Please report.");
-
-      if (slicepos == 0)
-        {
-          /* Simplest case: we have reached a whole pixel boundary.  Store
-             the average value per channel and reset the accumulators for
-             the next round.
-
-             The main reason to treat this case separately is to avoid an
-             access to out-of-bounds memory for the first pixel.  */
-          for (b = 0; b < bytes; b++)
-            {
-              *destp++ = accum[b] * avg_ratio;
-              accum[b] = 0.0;
-            }
-        }
-      else
-        {
-          for (b = 0; b < bytes; b++)
-            {
-              /* We have accumulated a whole pixel per channel where just a
-                 slice of it was needed.  Subtract now the previous pixel's
-                 extra slice.  */
-              slice = srcp[- bytes + b] * slicepos * inv_width;
-              *destp++ = (accum[b] - slice) * avg_ratio;
-
-              /* That slice is the initial value for the next round.  */
-              accum[b] = slice;
-            }
-        }
-    }
-
-  /* Sanity check: srcp should point to the next-to-last position, and
-     slicepos should be zero.  */
-  if (! (srcp - src == old_width * bytes && slicepos == 0))
-    g_warning ("Assertion (srcp - src == old_width * bytes && slicepos == 0)"
-               " failed. Please report.");
-}
-
 static inline void
 rotate_pointers (guchar  **p,
                  guint32   n)
@@ -3113,421 +2842,6 @@ rotate_pointers (guchar  **p,
   p[i] = tmp;
 }
 
-static void
-get_scaled_row (gdouble              **src,
-                gint                   y,
-                gint                   new_width,
-                PixelRegion           *srcPR,
-                gdouble               *row,
-                guchar                *src_tmp,
-                GimpInterpolationType  interpolation_type)
-{
-  /* get the necesary lines from the source image, scale them,
-     and put them into src[] */
-  rotate_pointers ((gpointer) src, 4);
-  if (y < 0)
-    y = 0;
-  if (y < srcPR->h)
-    {
-      get_premultiplied_double_row (srcPR, 0, y, srcPR->w,
-                                    row, src_tmp, 1);
-      if (new_width > srcPR->w)
-        expand_line(src[3], row, srcPR->bytes,
-                    srcPR->w, new_width, interpolation_type);
-      else if (srcPR->w > new_width)
-        shrink_line(src[3], row, srcPR->bytes,
-                    srcPR->w, new_width, interpolation_type);
-      else /* no scailing needed */
-        memcpy(src[3], row, sizeof (gdouble) * new_width * srcPR->bytes);
-    }
-  else
-    memcpy(src[3], src[2], sizeof (gdouble) * new_width * srcPR->bytes);
-}
-
-void
-scale_region (PixelRegion           *srcPR,
-              PixelRegion           *destPR,
-              GimpInterpolationType  interpolation,
-              GimpProgressFunc       progress_callback,
-              gpointer               progress_data)
-{
-  gdouble *src[4];
-  guchar  *src_tmp;
-  guchar  *dest;
-  gdouble *row, *accum;
-  gint     bytes, b;
-  gint     width, height;
-  gint     orig_width, orig_height;
-  gdouble  y_rat;
-  gint     i;
-  gint     old_y = -4;
-  gint     new_y;
-  gint     x, y;
-
-  if (interpolation == GIMP_INTERPOLATION_NONE)
-    {
-      scale_region_no_resample (srcPR, destPR);
-      return;
-    }
-
-  orig_width = srcPR->w;
-  orig_height = srcPR->h;
-
-  width = destPR->w;
-  height = destPR->h;
-
-#if 0
-  g_printerr ("scale_region: (%d x %d) -> (%d x %d)\n",
-              orig_width, orig_height, width, height);
-#endif
-
-  /*  find the ratios of old y to new y  */
-  y_rat = (gdouble) orig_height / (gdouble) height;
-
-  bytes = destPR->bytes;
-
-  /*  the data pointers...  */
-  for (i = 0; i < 4; i++)
-    src[i] = g_new (gdouble, width * bytes);
-
-  dest = g_new (guchar, width * bytes);
-
-  src_tmp = g_new (guchar, orig_width * bytes);
-
-  /* offset the row pointer by 2*bytes so the range of the array
-     is [-2*bytes] to [(orig_width + 2)*bytes] */
-  row = g_new (gdouble, (orig_width + 2 * 2) * bytes);
-  row += bytes * 2;
-
-  accum = g_new (gdouble, width * bytes);
-
-  /*  Scale the selected region  */
-
-  for (y = 0; y < height; y++)
-    {
-      if (progress_callback && !(y & 0xf))
-        (* progress_callback) (0, height, y, progress_data);
-
-      if (height < orig_height)
-        {
-          gint          max;
-          gdouble       frac;
-          const gdouble inv_ratio = 1.0 / y_rat;
-
-          if (y == 0) /* load the first row if this is the first time through */
-            get_scaled_row (&src[0], 0, width, srcPR, row,
-                            src_tmp,
-                            interpolation);
-          new_y = (int) (y * y_rat);
-          frac = 1.0 - (y * y_rat - new_y);
-          for (x = 0; x < width * bytes; x++)
-            accum[x] = src[3][x] * frac;
-
-          max = (int) ((y + 1) * y_rat) - new_y - 1;
-
-          get_scaled_row (&src[0], ++new_y, width, srcPR, row,
-                          src_tmp,
-                          interpolation);
-
-          while (max > 0)
-            {
-              for (x = 0; x < width * bytes; x++)
-                accum[x] += src[3][x];
-              get_scaled_row (&src[0], ++new_y, width, srcPR, row,
-                              src_tmp,
-                              interpolation);
-              max--;
-            }
-          frac = (y + 1) * y_rat - ((int) ((y + 1) * y_rat));
-          for (x = 0; x < width * bytes; x++)
-            {
-              accum[x] += frac * src[3][x];
-              accum[x] *= inv_ratio;
-            }
-        }
-      else if (height > orig_height)
-        {
-          new_y = floor (y * y_rat - 0.5);
-
-          while (old_y <= new_y)
-            {
-              /* get the necesary lines from the source image, scale them,
-                 and put them into src[] */
-              get_scaled_row (&src[0], old_y + 2, width, srcPR, row,
-                              src_tmp,
-                              interpolation);
-              old_y++;
-            }
-
-          switch (interpolation)
-            {
-            case GIMP_INTERPOLATION_CUBIC:
-              {
-                gdouble p0, p1, p2, p3;
-                gdouble dy = (y * y_rat - 0.5) - new_y;
-
-                p0 = cubic (dy, 1, 0, 0, 0);
-                p1 = cubic (dy, 0, 1, 0, 0);
-                p2 = cubic (dy, 0, 0, 1, 0);
-                p3 = cubic (dy, 0, 0, 0, 1);
-                for (x = 0; x < width * bytes; x++)
-                  accum[x] = (p0 * src[0][x] + p1 * src[1][x] +
-                              p2 * src[2][x] + p3 * src[3][x]);
-              }
-
-              break;
-
-            case GIMP_INTERPOLATION_LINEAR:
-              {
-                gdouble idy = (y * y_rat - 0.5) - new_y;
-                gdouble dy = 1.0 - idy;
-
-                for (x = 0; x < width * bytes; x++)
-                  accum[x] = dy * src[1][x] + idy * src[2][x];
-              }
-
-              break;
-
-            case GIMP_INTERPOLATION_NONE:
-              g_assert_not_reached ();
-              break;
-            }
-        }
-      else /* height == orig_height */
-        {
-          get_scaled_row (&src[0], y, width, srcPR, row,
-                          src_tmp,
-                          interpolation);
-          memcpy (accum, src[3], sizeof (gdouble) * width * bytes);
-        }
-
-      if (pixel_region_has_alpha (srcPR))
-        {
-          /* unmultiply the alpha */
-          gdouble  inv_alpha;
-          gdouble *p = accum;
-          gint     alpha = bytes - 1;
-          gint     result;
-          guchar  *d = dest;
-
-          for (x = 0; x < width; x++)
-            {
-              if (p[alpha] > 0.001)
-                {
-                  inv_alpha = 255.0 / p[alpha];
-                  for (b = 0; b < alpha; b++)
-                    {
-                      result = RINT (inv_alpha * p[b]);
-                      if (result < 0)
-                        d[b] = 0;
-                      else if (result > 255)
-                        d[b] = 255;
-                      else
-                        d[b] = result;
-                    }
-                  result = RINT (p[alpha]);
-                  if (result > 255)
-                    d[alpha] = 255;
-                  else
-                    d[alpha] = result;
-                }
-              else /* alpha <= 0 */
-                for (b = 0; b <= alpha; b++)
-                  d[b] = 0;
-
-              d += bytes;
-              p += bytes;
-            }
-        }
-      else
-        {
-          gint w = width * bytes;
-
-          for (x = 0; x < w; x++)
-            {
-              if (accum[x] < 0.0)
-                dest[x] = 0;
-              else if (accum[x] > 255.0)
-                dest[x] = 255;
-              else
-                dest[x] = RINT (accum[x]);
-            }
-        }
-      pixel_region_set_row (destPR, 0, y, width, dest);
-    }
-
-  /*  free up temporary arrays  */
-  g_free (accum);
-  for (i = 0; i < 4; i++)
-    g_free (src[i]);
-  g_free (src_tmp);
-  g_free (dest);
-
-  row -= 2 * bytes;
-  g_free (row);
-}
-
-void
-subsample_region (PixelRegion *srcPR,
-                  PixelRegion *destPR,
-                  gint         subsample)
-{
-  guchar  *src,  *s;
-  guchar  *dest, *d;
-  gdouble *row,  *r;
-  gint destwidth;
-  gint src_row, src_col;
-  gint bytes, b;
-  gint width, height;
-  gint orig_width, orig_height;
-  gdouble x_rat, y_rat;
-  gdouble x_cum, y_cum;
-  gdouble x_last, y_last;
-  gdouble * x_frac, y_frac, tot_frac;
-  gint i, j;
-  gint frac;
-  gint advance_dest;
-
-  orig_width = srcPR->w / subsample;
-  orig_height = srcPR->h / subsample;
-  width = destPR->w;
-  height = destPR->h;
-
-#if 0
-  g_printerr ("subsample_region: (%d x %d) -> (%d x %d)\n",
-              orig_width, orig_height, width, height);
-#endif
-
-  /*  Some calculations...  */
-  bytes = destPR->bytes;
-  destwidth = destPR->rowstride;
-
-  /*  the data pointers...  */
-  src  = g_new (guchar, orig_width * bytes);
-  dest = destPR->data;
-
-  /*  find the ratios of old x to new x and old y to new y  */
-  x_rat = (gdouble) orig_width / (gdouble) width;
-  y_rat = (gdouble) orig_height / (gdouble) height;
-
-  /*  allocate an array to help with the calculations  */
-  row    = g_new (gdouble, width * bytes);
-  x_frac = g_new (gdouble, width + orig_width);
-
-  /*  initialize the pre-calculated pixel fraction array  */
-  src_col = 0;
-  x_cum = (gdouble) src_col;
-  x_last = x_cum;
-
-  for (i = 0; i < width + orig_width; i++)
-    {
-      if (x_cum + x_rat <= (src_col + 1 + EPSILON))
-        {
-          x_cum += x_rat;
-          x_frac[i] = x_cum - x_last;
-        }
-      else
-        {
-          src_col ++;
-          x_frac[i] = src_col - x_last;
-        }
-      x_last += x_frac[i];
-    }
-
-  /*  clear the "row" array  */
-  memset (row, 0, sizeof (gdouble) * width * bytes);
-
-  /*  counters...  */
-  src_row = 0;
-  y_cum = (gdouble) src_row;
-  y_last = y_cum;
-
-  pixel_region_get_row (srcPR, 0, src_row * subsample, orig_width * subsample, src, subsample);
-
-  /*  Scale the selected region  */
-  for (i = 0; i < height; )
-    {
-      src_col = 0;
-      x_cum = (gdouble) src_col;
-
-      /* determine the fraction of the src pixel we are using for y */
-      if (y_cum + y_rat <= (src_row + 1 + EPSILON))
-        {
-          y_cum += y_rat;
-          y_frac = y_cum - y_last;
-          advance_dest = TRUE;
-        }
-      else
-        {
-          src_row ++;
-          y_frac = src_row - y_last;
-          advance_dest = FALSE;
-        }
-
-      y_last += y_frac;
-
-      s = src;
-      r = row;
-
-      frac = 0;
-      j = width;
-
-      while (j)
-        {
-          tot_frac = x_frac[frac++] * y_frac;
-
-          for (b = 0; b < bytes; b++)
-            r[b] += s[b] * tot_frac;
-
-          /*  increment the destination  */
-          if (x_cum + x_rat <= (src_col + 1 + EPSILON))
-            {
-              r += bytes;
-              x_cum += x_rat;
-              j--;
-            }
-
-          /* increment the source */
-          else
-            {
-              s += bytes;
-              src_col++;
-            }
-        }
-
-      if (advance_dest)
-        {
-          tot_frac = 1.0 / (x_rat * y_rat);
-
-          /*  copy "row" to "dest"  */
-          d = dest;
-          r = row;
-
-          j = width;
-          while (j--)
-            {
-              b = bytes;
-              while (b--)
-                *d++ = (guchar) (*r++ * tot_frac + 0.5);
-            }
-
-          dest += destwidth;
-
-          /*  clear the "row" array  */
-          memset (row, 0, sizeof (gdouble) * destwidth);
-
-          i++;
-        }
-      else
-        pixel_region_get_row (srcPR, 0, src_row * subsample, orig_width * subsample, src, subsample);
-    }
-
-  /*  free up temporary arrays  */
-  g_free (row);
-  g_free (x_frac);
-  g_free (src);
-}
-
 
 gfloat
 shapeburst_region (PixelRegion      *srcPR,
Index: ./app/paint-funcs/paint-funcs.h
===================================================================
RCS file: /cvs/gnome/gimp/app/paint-funcs/paint-funcs.h,v
retrieving revision 1.48
diff -u -p -r1.48 paint-funcs.h
--- ./app/paint-funcs/paint-funcs.h	12 Dec 2004 14:01:07 -0000	1.48
+++ ./app/paint-funcs/paint-funcs.h	5 Jan 2005 17:55:20 -0000
@@ -369,12 +369,6 @@ void  border_region                     
                                            gint16       xradius,
                                            gint16       yradius);
 
-void  scale_region                        (PixelRegion           *srcPR,
-                                           PixelRegion           *destPR,
-                                           GimpInterpolationType  interpolation,
-                                           GimpProgressFunc       progress_callback,
-                                           gpointer               progress_data);
-
 void  subsample_region                    (PixelRegion *srcPR,
                                            PixelRegion *destPR,
                                            gint         subsample);
Index: ./app/paint-funcs/Makefile.am
===================================================================
RCS file: /cvs/gnome/gimp/app/paint-funcs/Makefile.am,v
retrieving revision 1.15
diff -u -p -r1.15 Makefile.am
--- ./app/paint-funcs/Makefile.am	14 Jul 2003 10:33:52 -0000	1.15
+++ ./app/paint-funcs/Makefile.am	5 Jan 2005 17:55:20 -0000
@@ -6,7 +6,9 @@ libapppaint_funcs_a_SOURCES = \
 	paint-funcs-types.h	\
 	paint-funcs.c		\
 	paint-funcs.h		\
-	paint-funcs-generic.h
+	paint-funcs-generic.h \
+	scale-funcs.c		\
+	scale-funcs.h
 
 INCLUDES = \
 	-I$(top_srcdir)		\
Index: ./app/core/gimpdrawable.c
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpdrawable.c,v
retrieving revision 1.176
diff -u -p -r1.176 gimpdrawable.c
--- ./app/core/gimpdrawable.c	26 Nov 2004 14:45:10 -0000	1.176
+++ ./app/core/gimpdrawable.c	5 Jan 2005 17:55:24 -0000
@@ -30,6 +30,7 @@
 #include "base/tile-manager.h"
 
 #include "paint-funcs/paint-funcs.h"
+#include "paint-funcs/scale-funcs.h"
 
 #include "gimp.h"
 #include "gimp-utils.h"
Index: ./app/core/gimpdrawable-transform.c
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpdrawable-transform.c,v
retrieving revision 1.107
diff -u -p -r1.107 gimpdrawable-transform.c
--- ./app/core/gimpdrawable-transform.c	16 Nov 2004 13:41:55 -0000	1.107
+++ ./app/core/gimpdrawable-transform.c	5 Jan 2005 17:55:25 -0000
@@ -32,6 +32,7 @@
 #include "base/tile.h"
 
 #include "paint-funcs/paint-funcs.h"
+#include "paint-funcs/scale-funcs.h"
 
 #include "gimp.h"
 #include "gimp-utils.h"
@@ -98,6 +99,33 @@ static void     sample_linear     (Pixel
                                    gint           bytes,
                                    gint           alpha);
 
+/* Lanczos */
+static inline gdouble     sinc           (gdouble   x);
+
+static        gdouble*    kernel_lanczos ();
+
+static void               sample_lanczos (gdouble  *kernel,
+                                          gint      su,
+                                          gint      sv,
+                                          guchar   *color,
+                                          guchar   *buffer,
+                                          gint      bytes,
+                                          gint      alpha);
+
+static inline gdouble    lanczos_sum       (guchar      *buffer,
+                                            gdouble     *l,
+                                            gint         row,
+                                            gint         bytes,
+                                            gint         byte);
+
+static inline gdouble    lanczos_sum_mul   (guchar      *buffer,
+                                            gdouble     *l,
+                                            gint         row,
+                                            gint         bytes,
+                                            gint         byte,
+                                            gint         alpha);
+
+/* Lanczos */
 
 /*  public functions  */
 
@@ -137,6 +165,11 @@ gimp_drawable_transform_tiles_affine (Gi
   gdouble      tu[5],tv[5],tw[5];     /* undivided source coordinates and
                                          divisor */
 
+  gdouble     *kernel=NULL;             /* Lanczos kernel                    */
+  gint         su, sv;                  /* Lanczos kernel position           */
+  guchar      *buffer=NULL;             /* Holds sliding window buffer       */
+
+
   gint         coords;
   gint         width;
   gint         alpha;
@@ -265,6 +298,12 @@ gimp_drawable_transform_tiles_affine (Gi
         }
     }
 
+/* Lanczos */
+  if ( x2-x1 <  LANCZOS_WIDTH2 || y2-y1 < LANCZOS_WIDTH2) 
+    /*  If the gimage is to small sitch to no interpolation  */
+    interpolation_type = GIMP_INTERPOLATION_NONE;
+/* Lanczos */
+   
   /*  Get the new temporary buffer for the transformed result  */
   new_tiles = tile_manager_new (x2 - x1, y2 - y1,
                                 tile_manager_bpp (orig_tiles));
@@ -272,6 +311,9 @@ gimp_drawable_transform_tiles_affine (Gi
                      0, 0, x2 - x1, y2 - y1, TRUE);
   tile_manager_set_offsets (new_tiles, x1, y1);
 
+  width  = tile_manager_width (new_tiles);
+  bytes  = tile_manager_bpp (new_tiles);
+
   /* initialise the pixel_surround and pixel_cache accessors */
   switch (interpolation_type)
     {
@@ -283,11 +325,16 @@ gimp_drawable_transform_tiles_affine (Gi
     case GIMP_INTERPOLATION_LINEAR:
       pixel_surround_init (&surround, orig_tiles, 2, 2, bg_color);
       break;
+  /* Lanczos */
+    case GIMP_INTERPOLATION_LANCZOS:
+      /* Calculate kernel */
+      kernel = kernel_lanczos();
+      /* Allocate buffer for source window */
+      buffer = g_new0(guchar, (LANCZOS_WIDTH2)*bytes);
+      break;
+  /* Lanczos */
     }
 
-  width  = tile_manager_width (new_tiles);
-  bytes  = tile_manager_bpp (new_tiles);
-
   dest = g_new (guchar, tile_manager_width (new_tiles) * bytes);
 
   uinc = m.coeff[0][0];
@@ -386,6 +433,49 @@ gimp_drawable_transform_tiles_affine (Gi
                     *d++ = bg_color[b];
                 }
             }
+/* Lanczos */
+          else if (interpolation_type == GIMP_INTERPOLATION_LANCZOS)
+            {
+              guchar color[MAX_CHANNELS];
+              gint   iu = (gint) u [0];
+              gint   iv = (gint) v [0];
+              gint   fu,fv;
+              gint   b;
+
+              if (iu >= u1 && iu < u2 &&
+                  iv >= v1 && iv < v2)
+                {
+                  /*  u, v coordinates into source tiles  */
+                  gint u = iu - u1;
+                  gint v = iv - v1;
+                  
+                  read_pixel_data (orig_tiles, 
+                                   u-LANCZOS_WIDTH+1, 
+                                   v-LANCZOS_WIDTH+1,
+                                   u+LANCZOS_WIDTH,
+                                   v+LANCZOS_WIDTH,
+                                   buffer,
+                                   bytes*LANCZOS_WIDTH2);
+
+                  fu = u-iu;
+                  su = (gint)( fu * LANCZOS_SPP );
+                  fv = v-iv;     
+                  sv = (gint)( fv * LANCZOS_SPP );
+              
+                  sample_lanczos (kernel, su, sv, color, buffer, bytes, alpha);
+
+                  for (b = 0; b < bytes; b++)
+                    *d++ = color[b];
+                }
+              else /* not in source range */
+                {
+                  /*  increment the destination pointers  */
+
+                  for (b = 0; b < bytes; b++)
+                    *d++ = bg_color[b];
+                }
+            }
+/* Lanczos */
           else
             {
               gint b;
@@ -454,6 +544,11 @@ gimp_drawable_transform_tiles_affine (Gi
   if (interpolation_type != GIMP_INTERPOLATION_NONE)
     pixel_surround_clear (&surround);
 
+/* Lanczos */
+  g_free(kernel);
+  g_free(buffer);
+/* Lanczos */
+
   g_free (dest);
 
   return new_tiles;
@@ -1611,3 +1706,130 @@ sample_cubic (PixelSurround *surround,
 
   pixel_surround_release (surround);
 }
+
+/* Lanczos */
+static inline gdouble 
+sinc (gdouble x)
+{
+  gdouble y=x*G_PI;
+  if (ABS(x) < EPSILON) return(1.0);
+  return(sin(y)/(y));
+}
+
+static gdouble *
+kernel_lanczos ()
+{
+   gint     i;
+   gdouble *kernel ;
+   gdouble  x = 0.0;
+   gdouble  dx = (gdouble)LANCZOS_WIDTH/(gdouble)(LANCZOS_SAMPLES-1);
+
+   kernel = (gdouble *) g_malloc(LANCZOS_SAMPLES * sizeof(gdouble)) ;
+   for ( i = 0 ; i < LANCZOS_SAMPLES ; i++ ) 
+     {
+       kernel[i] = (ABS(x) < LANCZOS_WIDTH) ? (sinc(x) * sinc(x/LANCZOS_WIDTH)): 0.0;
+       x+=dx;
+     }
+   return kernel;
+}
+
+static inline gdouble 
+lanczos_sum (guchar   *buffer,
+             gdouble  *l,
+             gint      row,
+             gint      bytes,
+             gint      byte)
+{
+  gdouble sum = 0;
+  gint j,k, p;
+  p = row*bytes*LANCZOS_WIDTH2;
+  for ( k = 0, j = 0 ; j < LANCZOS_WIDTH2 ; j++ , k++)
+    sum+=l[k]*(buffer+p)[j*bytes+byte];
+  return sum;
+}
+static inline gdouble
+lanczos_sum_mul (guchar   *buffer,
+                 gdouble  *l,
+                 gint      row,
+                 gint      bytes,
+                 gint      byte,
+                 gint      alpha)
+{
+  gdouble sum = 0;
+  gint j,k, p;
+  p = row*bytes*LANCZOS_WIDTH2;
+  for ( k = 0, j = 0 ; j < LANCZOS_WIDTH2 ; j++ , k++)
+    sum+=l[k]*(buffer+p)[j*bytes+byte]*(buffer+p)[j*bytes+alpha];
+  return sum;
+}
+
+static void
+sample_lanczos (gdouble  *kernel,
+                gint      su,
+                gint      sv,
+                guchar   *color,
+                guchar   *buffer,
+                gint      bytes,
+                gint      alpha)
+{
+
+  gdouble  lu[LANCZOS_WIDTH2],      /* Lanczos sample value              */
+           lv[LANCZOS_WIDTH2];      /* Lanczos sample value              */
+  gdouble  lusum, lvsum, weight;    /* Lanczos weighting vars            */
+  gint	   i,j,row, byte;           /* loop vars to fill source window   */
+
+  gdouble  aval, arecip;            /* Handle alpha values               */ 
+  gdouble  newval;                  /* New interpolated RGB value        */
+
+
+  for ( lusum = lvsum = i = 0, j = LANCZOS_WIDTH-1 ; j >= -LANCZOS_WIDTH ; j-- , i++)
+    {
+        lusum+=lu[i]=kernel[ ABS(j*LANCZOS_SPP+su) ];
+        lvsum+=lv[i]=kernel[ ABS(j*LANCZOS_SPP+sv) ];
+    }
+  weight = (lusum*lvsum);
+  
+  if (alpha != 0)
+    {
+       for ( aval = 0, row = 0 ; row < LANCZOS_WIDTH2 ; row ++ )
+          aval+=lanczos_sum(buffer, lu, row, bytes, alpha)*lv[row];
+
+       /* calculate alpha of result */  
+       aval/=weight;  
+
+       if ( aval <= 0.0 )
+         {
+           arecip = 0.0;
+           color[alpha] = 0;
+         }
+       else if ( aval > 255.0 )
+         {
+           arecip = 1.0 / aval;
+           color[alpha] = 255;
+         }
+       else
+         {
+           arecip = 1.0 / aval;
+           color[alpha] = RINT (aval);
+         }
+       for (byte = 0; byte < alpha; byte++)
+         {
+           for (newval=0, row = 0 ; row < LANCZOS_WIDTH2 ; row ++ )
+             newval+=lanczos_sum_mul(buffer, lu, row, bytes, byte, alpha)*lv[row];
+           newval*=arecip;
+           color[byte] = CLAMP (newval, 0, 255);
+         }
+    }
+  else
+    {
+      for (byte = 0; byte < bytes; byte++)
+        {
+          for (newval = 0, row = 0 ; row < LANCZOS_WIDTH2 ; row++ )
+            newval+=lanczos_sum(buffer, lu, row, bytes, byte)*lv[row];
+          newval/=weight;
+          color[byte] = CLAMP ((gint)newval, 0, 255);
+        }
+    }
+
+}
+/* Lanczos */
