diff --git a/src/modules/Image/image.c b/src/modules/Image/image.c
index fe75cb832da27c386492305c6f0b922b5027be03..fbc073926a1abd157d324ea8ae050c6c05634713 100644
--- a/src/modules/Image/image.c
+++ b/src/modules/Image/image.c
@@ -1,9 +1,9 @@
-/* $Id: image.c,v 1.164 2000/07/07 13:56:45 grubba Exp $ */
+/* $Id: image.c,v 1.165 2000/07/27 03:45:48 per Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: image.c,v 1.164 2000/07/07 13:56:45 grubba Exp $
+**!	$Id: image.c,v 1.165 2000/07/27 03:45:48 per Exp $
 **! class Image
 **!
 **!	The main object of the <ref>Image</ref> module, this object
@@ -98,7 +98,7 @@
 
 #include "stralloc.h"
 #include "global.h"
-RCSID("$Id: image.c,v 1.164 2000/07/07 13:56:45 grubba Exp $");
+RCSID("$Id: image.c,v 1.165 2000/07/27 03:45:48 per Exp $");
 #include "pike_macros.h"
 #include "object.h"
 #include "constants.h"
@@ -3604,6 +3604,224 @@ void image_modify_by_intensity(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object apply_curve( array(int(0..255)) curve_r, array(int(0..255)) curve_g, array(int(0..255)) curve_b )
+**! method object apply_curve( array(int(0..255)) curve )
+**! method object apply_curve( string channel, array(int(0..255)) curve )
+**!
+**!  Apply a lookup-table on all pixels in an image.
+**!  If only one curve is passed, use the same curve for red, green and blue.
+**!  If 'channel' is specified, the curve is only applied to the
+**!  specified channel.
+**! 
+**!  returns a new image object
+**! 
+**!  arg array(int(0..255)) curve_r
+**!  arg array(int(0..255)) curve_g
+**!  arg array(int(0..255)) curve_b
+**!  arg array(int(0..255)) curve
+**!      An array with 256 elements, each between 0 and 255.
+**!      It is used as a look-up table, if the pixel value is 2 and
+**!      curve[2] is 10, the new pixel value will be 10.
+**!
+**!  arg string channel
+**!      one of "red", "green", "blue", "value", "saturation" and "hue".
+**!
+**!  see also: gamma, `*, modify_by_intensity
+*/
+
+static void image_apply_curve_3( unsigned char curve[3][256] )
+{
+  int j, i;
+  struct object *o;
+  rgb_group *s = THIS->img, *d;
+  push_int( THIS->xsize );
+  push_int( THIS->ysize );
+  o = clone_object( image_program, 2 );
+  d = ((struct image *)get_storage( o, image_program ))->img;
+  i = THIS->xsize*THIS->ysize;
+  
+  THREADS_ALLOW();
+  for( ; i>0; i-- )
+  {
+    d->r = curve[0][s->r];
+    d->g = curve[1][s->g];
+    (d++)->b = curve[2][(s++)->b];
+  }
+  THREADS_DISALLOW();
+
+  push_object( o );
+}
+
+static void image_apply_curve_1( unsigned char curve[256] )
+{
+  int j, i;
+  struct object *o;
+  rgb_group *s = THIS->img, *d;
+  push_int( THIS->xsize );
+  push_int( THIS->ysize );
+  o = clone_object( image_program, 2 );
+  d = ((struct image *)get_storage( o, image_program ))->img;
+  i = THIS->xsize*THIS->ysize;
+  THREADS_ALLOW();
+  for( ; i>0; i-- )
+  {
+    d->r = curve[s->r];
+    d->g = curve[s->g];
+    (d++)->b = curve[(s++)->b];
+  }
+  THREADS_DISALLOW();
+  push_object( o );
+}
+
+
+static void image_apply_curve_2( struct object *o, 
+                                 int channel, 
+                                 unsigned char curve[256] )
+{
+  int j, i;
+  rgb_group *d;
+  d = ((struct image *)get_storage(o,image_program))->img;
+  i = THIS->xsize*THIS->ysize;
+
+  THREADS_ALLOW();
+  switch( channel ) 
+  {
+   case 0: for( ; i>0; i-- ) d->r = curve[(d++)->r]; break;
+   case 1: for( ; i>0; i-- ) d->g = curve[(d++)->g]; break;
+   case 2: for( ; i>0; i-- ) d->b = curve[(d++)->b]; break;
+  }
+  THREADS_DISALLOW();
+
+  push_object( o );
+}
+
+
+static void image_apply_curve( INT32 args )
+{
+  int i, j;
+  switch( args )
+  {
+   case 3:
+     {
+       unsigned char curve[3][256];
+       for( i = 0; i<3; i++ )
+         if( sp[-args+i].type != T_ARRAY ||
+             sp[-args+i].u.array->size != 256 )
+           bad_arg_error("Image.Image->apply_curve", 
+                         sp-args, args, 0, "", sp-args,
+                         "Bad arguments to apply_curve()\n");
+         else
+           for( j = 0; j<256; j++ )
+             if( sp[-args+i].u.array->item[j].type == T_INT )
+               curve[i][j]=MINIMUM(sp[-args+i].u.array->item[j].u.integer,255);
+       pop_n_elems( args );
+       image_apply_curve_3( curve );
+       return;
+     }
+   case 2:
+     {
+       struct pike_string *s_red, *s_green, *s_blue;
+       struct pike_string *s_saturation, *s_value, *s_hue;
+       unsigned char curve[256];
+       int chan = 0, co = 0;
+       struct object *o;
+       MAKE_CONSTANT_SHARED_STRING(s_red,"red");
+       MAKE_CONSTANT_SHARED_STRING(s_green,"green");
+       MAKE_CONSTANT_SHARED_STRING(s_blue,"blue");
+       MAKE_CONSTANT_SHARED_STRING(s_saturation,"saturation");
+       MAKE_CONSTANT_SHARED_STRING(s_value,"value");
+       MAKE_CONSTANT_SHARED_STRING(s_hue,"hue");
+
+       if( sp[-args].type != T_STRING )
+         bad_arg_error("Image.Image->apply_curve", 
+                       sp-args, args, 0, "", sp-args,
+                       "Bad arguments to apply_curve()\n" );
+       if( sp[-args+1].type != T_ARRAY ||
+           sp[-args+1].u.array->size != 256 )
+         bad_arg_error("Image.Image->apply_curve", 
+                       sp-args, args, 0, "", sp-args,
+                       "Bad arguments to apply_curve()\n" );
+       else
+         for( j = 0; j<256; j++ )
+           if( sp[-args+1].u.array->item[j].type == T_INT )
+             curve[j] = MINIMUM(sp[-args+1].u.array->item[j].u.integer,255);
+
+       if( sp[-args].u.string == s_red )
+       {
+         co = 1;
+         chan = 0;
+       }
+       else if( sp[-args].u.string == s_green )
+       {
+         co = 1;
+         chan = 1;
+       }
+       else if( sp[-args].u.string == s_blue )
+       {
+         co = 1;
+         chan = 2;
+       }
+       else if( sp[-args].u.string == s_hue )
+       {
+         chan = 0;
+         co = 0;
+       }
+       else if( sp[-args].u.string == s_saturation )
+       {
+         chan = 1;
+         co = 0;
+       }
+       else if( sp[-args].u.string == s_value )
+       {
+         chan = 2;
+         co = 0;
+       }
+
+       if( co )
+       { 
+         push_int( THIS->xsize );
+         push_int( THIS->ysize );
+         o = clone_object( image_program, 2 );
+         MEMCPY( ((struct image *)get_storage(o,image_program))->img, 
+                 THIS->img, 
+                 THIS->xsize*THIS->ysize*sizeof(rgb_group) );
+       }
+       else
+       {
+         image_rgb_to_hsv( 0 );
+         o = sp[-1].u.object;
+         sp--;
+       }
+       image_apply_curve_2( o, chan, curve );
+       if( !co )
+       {
+         apply( sp[-1].u.object, "hsv_to_rgb", 0 );
+         stack_swap();
+         pop_stack();
+       }
+       return;
+     }
+   case 1:
+     {
+       unsigned char curve[256];
+       if( sp[-args].type != T_ARRAY ||
+           sp[-args].u.array->size != 256 )
+         bad_arg_error("Image.Image->apply_curve", 
+                       sp-args, args, 0, "", sp-args,
+                       "Bad arguments to apply_curve()\n" );
+       else
+         for( j = 0; j<256; j++ )
+           if( sp[-args].u.array->item[j].type == T_INT )
+             curve[j] = MINIMUM(sp[-args].u.array->item[j].u.integer,255);
+       pop_n_elems( args );
+       image_apply_curve_1( curve );
+       return;
+     }
+  }
+}
+
+
 /*
 **! method object gamma(float g)
 **! method object gamma(float gred,ggreen,gblue)
@@ -4185,6 +4403,11 @@ void init_image_image(void)
 		tOr(tFunc(tOr(tFlt,tInt),tObj),
 		    tFunc(tOr(tFlt,tInt) tOr(tFlt,tInt) tOr(tFlt,tInt),tObj)),0);
 
+   ADD_FUNCTION("apply_curve",image_apply_curve,
+                tOr3( tFunc(tArr(tInt) tArr(tInt) tArr(tInt),tObj),
+                      tFunc(tArr(tInt),tObj),
+                      tFunc(tString tArr(tInt),tObj) ), 0);
+
    ADD_FUNCTION("rotate_ccw",image_ccw,
 		tFunc(tNone,tObj),0);
    ADD_FUNCTION("rotate_cw",image_cw,