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	3 Jan 2005 14:24:41 -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"        >*/
 } 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	3 Jan 2005 14:24:48 -0000
@@ -42,6 +42,12 @@
 #define RANDOM_SEED   314159265
 #define EPSILON       0.0001
 
+/* Lanczos */
+#define LANCZOS_SPP      (1000)
+#define LANCZOS_WIDTH    (2)
+#define LANCZOS_SAMPLES  (1+(int)(LANCZOS_SPP * LANCZOS_WIDTH))
+#define LANCZOS_WIDTH2   (LANCZOS_WIDTH*2)
+/* End Lanczos */
 
 typedef enum
 {
@@ -154,7 +160,32 @@ static void     apply_layer_mode_replace
 static inline void rotate_pointers       (guchar         **p,
                                           guint32          n);
 
+/* Lanczos */
+static inline gdouble    sinc                 (gdouble      x);
 
+static gboolean          inv_lin_trans        (gdouble     *t,
+                                               gdouble     *it);
+
+static void              scale_region_lanczos (PixelRegion *srcPR,
+                                               PixelRegion *dstPR);
+
+static gdouble *         kernel_lanczos       ();
+
+static inline gdouble    lanczos_sum          (guchar     **src,
+                                               gdouble     *l,
+                                               gint         row,
+                                               gint         col,
+                                               gint         bytes,
+                                               gint         byte);
+
+static inline gdouble    lanczos_sum_mul      (guchar     **src,
+                                               gdouble     *l,
+                                               gint         row,
+                                               gint         col,
+                                               gint         bytes,
+                                               gint         byte,
+                                               gint         alpha);
+/* Lanczos */
 
 static void
 update_tile_rowhints (Tile *tile,
@@ -432,6 +463,7 @@ cubic (gdouble dx,
                      ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
 }
 
+
 /*********************/
 /*  FUNCTIONS        */
 /*********************/
@@ -2998,6 +3030,11 @@ expand_line (gdouble               *dest
     case GIMP_INTERPOLATION_NONE:
       g_assert_not_reached ();
       break;
+/* Lanczos */
+    case GIMP_INTERPOLATION_LANCZOS:
+      g_assert_not_reached ();
+      break;
+/* Lanczos */
     }
 }
 
@@ -3169,6 +3206,13 @@ scale_region (PixelRegion           *src
       scale_region_no_resample (srcPR, destPR);
       return;
     }
+/* Lanczos */
+  else if (interpolation == GIMP_INTERPOLATION_LANCZOS)
+    {
+      scale_region_lanczos(srcPR, destPR);
+      return;
+    }
+/* Lanczos */
 
   orig_width = srcPR->w;
   orig_height = srcPR->h;
@@ -3291,6 +3335,11 @@ scale_region (PixelRegion           *src
             case GIMP_INTERPOLATION_NONE:
               g_assert_not_reached ();
               break;
+/* Lanczos */
+            case GIMP_INTERPOLATION_LANCZOS:
+              g_assert_not_reached ();
+              break;
+/* Lanczos */
             }
         }
       else /* height == orig_height */
@@ -5178,3 +5227,259 @@ apply_layer_mode_replace (guchar        
 {
   replace_pixels (src1, src2, dest, mask, length, opacity, affect, bytes1, bytes2);
 }
+
+/* Lanczos */
+static inline gdouble 
+sinc (gdouble x)
+{
+  gdouble y=x*G_PI;
+  if (ABS(x) < EPSILON) return(1.0);
+  return(sin(y)/(y));
+}
+
+static inline gdouble 
+lanczos_sum (guchar  **src,
+             gdouble  *l,
+             gint      row,
+             gint      col,
+             gint      bytes,
+             gint      byte)
+{
+  gdouble sum = 0;
+  gint j,k;
+  /* LANCZOS_WIDTH = 2
+     l[*] = kernel coefficients
+
+                / col =5
+     row = abc[defg]hij
+              |    \ col + LANCZOS_WIDTH
+              \ _____col - LANCZOS_WIDTH +1
+
+     sum = d.l[0] +e.l[1] + f.l[2] + g.l[3]
+  */ 
+  for ( k = 0, j = col-LANCZOS_WIDTH+1 ; j <= col+LANCZOS_WIDTH ; j++ , k++)
+    sum+=l[k]*src[row][j*bytes+byte];
+  return sum;
+}
+static inline gdouble
+lanczos_sum_mul (guchar  **src, 
+                 gdouble  *l,
+                 gint      row,
+                 gint      col,
+                 gint      bytes,
+                 gint      byte,
+                 gint      alpha)
+{
+  gdouble sum = 0;
+  gint j,k;
+  for ( k = 0, j = col-LANCZOS_WIDTH+1 ; j <= col+LANCZOS_WIDTH ; j++ , k++)
+    sum+=l[k]*src[row][j*bytes+byte]*src[row][j*bytes+alpha];
+  return sum;
+}
+ 
+static gboolean
+inv_lin_trans (gdouble *t, 
+               gdouble *it)
+{
+  gdouble d;  /* Determinant */
+  d = ( t[0] * t[4] ) - ( t[1] * t[3] );
+  if (fabs(d) < EPSILON )
+    {
+       return FALSE;
+    }
+  it[0] =    t[4] / d;
+  it[1] =   -t[1] / d;
+  it[2] = (( t[1] * t[5]) - (t[2] * t[4])) / d;
+  it[3] =   -t[3] / d;
+  it[4] =    t[0] / d;
+  it[5] = (( t[2] * t[3]) - (t[0] * t[5])) / d;
+  return TRUE;
+}
+
+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 void 
+scale_region_lanczos (PixelRegion *srcPR,
+                      PixelRegion *dstPR)
+{
+  gdouble     *kernel=NULL;             /* Lanczos kernel                    */
+  gdouble      lu[LANCZOS_WIDTH2],      /* Lanczos sample value              */
+               lv[LANCZOS_WIDTH2];      /* Lanczos sample value              */
+  gint         su, sv;                  /* Lanczos kernel position           */      
+  gdouble      lusum, lvsum, weight;    /* Lanczos weighting vars            */
+
+  gint         bytes, alpha, row;       /* Image properties                  */
+
+  gint         src_width, src_height;   /* Source width height               */
+  gint         src_rowstride;           /* Source rowstride (= dest)         */
+  gint         srcrow;                  /* counter for read src rows         */
+  guchar      *src_buf=NULL;            /* Holds sliding window buffer       */
+  guchar      *src[LANCZOS_WIDTH2];     /* Array for sliding window pointers */
+  guchar      *cur_buf=NULL;            /* Current line in sliding window    */
+
+  gint         dst_width, dst_height;   /* Destination width height          */
+  gint         dst_rowstride;           /* Destination rowstride             */
+  guchar      *dst_buf=NULL;            /* Pointers to image data            */     
+
+  gdouble      du ,dv;                  /* Pos in source image (double)      */
+  gdouble      fu ,fv;                  /* Pos in source image (fract.  part)*/
+  gint         u, v;                    /* Pos in source image (integer part)*/
+  gint         x, y;                    /* Position in destination image     */
+
+  gint	       i,j,pos,byte;            /* loop vars to fill source window   */
+
+  gdouble      sx,  sy;                 /* Scalefactor                       */
+  gdouble      trans[6],itrans[6];      /* Scale transformations             */
+  gdouble      aval, arecip;            /* Handle alpha values               */ 
+  gdouble      newval;                  /* New interpolated RGB value        */
+
+
+  /* Initialize variables */
+  dst_width  = dstPR->w;
+  dst_height = dstPR->h;
+  bytes      = dstPR->bytes;
+  src_width  = srcPR->w;
+  src_height = srcPR->h;
+
+  /* Pure scaling */
+  sx = (gdouble)dst_width/(gdouble)src_width;
+  sy = (gdouble)dst_height/(gdouble)src_height;
+  for ( i = 0 ; i < 6 ; i++ )
+    trans[i] = 0.0;
+  trans[0] = sx;
+  trans[4] = sy;
+  inv_lin_trans(trans, itrans);
+
+
+  /* Calculate kernel */
+  kernel = kernel_lanczos();
+  /* allocate buffer for 2*LANCZOS_WIDTH2+1 temp source rows 
+     LANCZOS_WIDTH2   : lines are sliding window buffer
+  */
+  src_rowstride = src_width*bytes;
+  src_buf = g_new0(guchar, (LANCZOS_WIDTH2)*src_rowstride);
+  for (i = 0 ; i < LANCZOS_WIDTH2 ; i++ )
+    src[i]=src_buf+i*src_rowstride;
+
+  /* allocate buffer for 1 destination row */
+  dst_rowstride = dst_width*bytes;
+  dst_buf = g_new0(guchar, dst_rowstride);
+  for ( srcrow = -1, y = 0 ; y < dst_height ; y ++ )
+    {
+      pixel_region_get_row (dstPR, 0, y, dst_width, dst_buf, 1);
+      for ( x = 0 ; x < dst_width ; x ++ )
+        {
+           du = itrans[0] * (gdouble)x + itrans[1] * (gdouble)y + itrans[2];
+           dv = itrans[3] * (gdouble)x + itrans[4] * (gdouble)y + itrans[5];
+           u = (gint)du;
+           v = (gint)dv;
+           /* make sure we have enough data available */
+           if ( srcrow < v+LANCZOS_WIDTH && srcrow < src_height-1 )
+             {               
+               for ( i = srcrow+1 ; i <= v+LANCZOS_WIDTH ; i++)
+                 {
+                   /* 2nd row in src buffer becomes first */
+                   rotate_pointers(src, LANCZOS_WIDTH2);
+                   /* Make sure we do not read past the end of image */
+                   srcrow = ( i < src_height ) ? i : src_height - 1;
+                   /* append row at the end src buffer*/
+                   pos = LANCZOS_WIDTH2-1;
+                   pixel_region_get_row (srcPR, 0, srcrow, src_width, src[pos], 1); 
+                 }
+                 /* current src(v) line in sliding window */
+                 cur_buf = src[LANCZOS_WIDTH-1];
+             }
+           /* check edge condition */
+           if (( u < LANCZOS_WIDTH-1           ) || 
+               ( u > src_width - LANCZOS_WIDTH ) ||
+               ( v < LANCZOS_WIDTH-1           ) ||
+               ( v > src_height - LANCZOS_WIDTH)  )
+            {
+              u = CLAMP (u, 0, src_width-1);
+              v = CLAMP (v, 0, src_height-1);
+	      for ( byte = 0 ; byte < bytes ; byte++ ) 
+                dst_buf[x*bytes+byte] = cur_buf[u*bytes+byte]; 
+            }
+          else
+            {
+              /* get weight for fractional error */
+              fu = du-u;
+              su = (gint)( fu * LANCZOS_SPP );
+              fv = dv-v;     
+              sv = (gint)( fv * LANCZOS_SPP );
+              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 (pixel_region_has_alpha (srcPR))
+                {
+                  alpha = bytes - 1;
+
+                  for (aval = 0, row = 0 ; row < LANCZOS_WIDTH2 ; row ++ )
+                    aval+=lanczos_sum(src, lu, row, u, bytes, alpha)*lv[row];
+	
+                  /* calculate alpha of result */  
+                  aval/=weight;
+  
+                  if (aval <= 0.0)
+                    {
+                      arecip = 0.0;
+                      dst_buf[x*bytes+alpha] = 0;
+                    }
+                  else if (aval > 255.0)
+                    {
+                      arecip = 1.0 / aval;
+                      dst_buf[x*bytes+alpha] = 255;
+                    }
+                  else
+                    {
+                      arecip = 1.0 / aval;
+                      dst_buf[x*bytes+alpha] = RINT (aval);
+                    }
+                  for (byte = 0; byte < alpha; byte++)
+                    {
+                      for (newval=0, row = 0 ; row < LANCZOS_WIDTH2 ; row ++ )
+                        newval+=lanczos_sum_mul(src, lu, row, u, bytes, byte, alpha)*lv[row];
+                      newval*=arecip;
+                      dst_buf[x*bytes+byte] = CLAMP (newval, 0, 255);
+                    }
+                }
+              else
+                {
+                  for (byte = 0; byte < bytes; byte++)
+                    {
+                      for (newval = 0, row = 0 ; row < LANCZOS_WIDTH2 ; row++ )
+                        newval+=lanczos_sum(src, lu, row, u, bytes, byte)*lv[row];
+                      newval/=weight;
+                      dst_buf[x*bytes+byte] = CLAMP ((gint)newval, 0, 255);
+                    }
+                }
+            }
+        }
+      pixel_region_set_row (dstPR, 0, y , dst_width, dst_buf);
+    } 
+  g_free (src_buf);
+  g_free (dst_buf);
+  g_free (kernel);
+}
+/* End Lanczos */
+
+
