diff --git a/src/modules/Image/image.c b/src/modules/Image/image.c
index 55428f00696de6e6bb7260633c2819d26293ded3..903478014bdae38de3edd30d860d9dab5c4c2b5e 100644
--- a/src/modules/Image/image.c
+++ b/src/modules/Image/image.c
@@ -1,4 +1,9 @@
-/* $Id: image.c,v 1.17 1997/03/24 20:41:06 mirar Exp $ */
+/* $Id: image.c,v 1.18 1997/03/25 06:13:41 mirar Exp $ */
+
+/*
+**! module Image
+**! class image
+*/
 
 #include "global.h"
 
@@ -7,7 +12,7 @@
 
 #include "stralloc.h"
 #include "global.h"
-RCSID("$Id: image.c,v 1.17 1997/03/24 20:41:06 mirar Exp $");
+RCSID("$Id: image.c,v 1.18 1997/03/25 06:13:41 mirar Exp $");
 #include "types.h"
 #include "pike_macros.h"
 #include "object.h"
@@ -76,6 +81,8 @@ static void init_image_struct(struct object *obj)
   THIS->rgb.r=0;
   THIS->rgb.g=0;
   THIS->rgb.b=0;
+  THIS->xsize=THIS->ysize=0;
+  THIS->alpha=0;
 /*  fprintf(stderr,"init %lx (%d)\n",obj,++obj_counter);*/
 }
 
@@ -250,7 +257,7 @@ void img_apply_matrix(struct image *dest,
    rgb_group *d,*ip,*dp;
    rgbd_group *mp;
    int i,j,x,y,bx,by,ex,ey,xp,yp;
-   int sumr,sumg,sumb;
+   double sumr,sumg,sumb;
    double qr,qg,qb;
    register double r=0,g=0,b=0;
 
@@ -349,14 +356,33 @@ THREADS_DISALLOW();
 
 /***************** methods *************************************/
 
+/*
+**! method void create()
+**! method void create(int xsize,int ysize)
+**! method void create(int xsize,int ysize,int r,int g,int b)
+**! method void create(int xsize,int ysize,int r,int g,int b,int alpha)
+**! 	Initializes a new image object.
+**! arg int xsize
+**! arg int ysize
+**! 	size of (new) image in pixels
+**! arg int r
+**! arg int g
+**! arg int b
+**!     background color (will also be current color),
+**!     default color is black
+**! arg int alpha
+**! 	default alpha channel value
+**! see also: copy, clone, Image.image
+*/
+
 void image_create(INT32 args)
 {
    if (args<2) return;
    if (sp[-args].type!=T_INT||
        sp[1-args].type!=T_INT)
-      error("Illegal arguments to image->clone()\n");
+      error("Illegal arguments to image::create()\n");
 
-   getrgb(THIS,2,args,"image->create()"); 
+   getrgb(THIS,2,args,"image::create()"); 
 
    if (THIS->img) free(THIS->img);
 	
@@ -374,6 +400,29 @@ void image_create(INT32 args)
    pop_n_elems(args);
 }
 
+/*
+**! method object clone()
+**! method object clone(int xsize,int ysize)
+**! method object clone(int xsize,int ysize,int r,int g,int b)
+**! method object clone(int xsize,int ysize,int r,int g,int b,int alpha)
+**! 	Copies to or initialize a new image object.
+**! returns the new object
+**! arg int xsize
+**! arg int ysize
+**! 	size of (new) image in pixels, called image
+**!     is cropped to that size
+**! arg int r
+**! arg int g
+**! arg int b
+**!     current color of the new image, 
+**!     default is black. 
+**!     Will also be the background color if the cloned image
+**!     is empty (no drawing area made).
+**! arg int alpha
+**! 	new default alpha channel value
+**! see also: copy, create
+*/
+
 void image_clone(INT32 args)
 {
    struct object *o;
@@ -383,7 +432,7 @@ void image_clone(INT32 args)
       if (args<2||
 	  sp[-args].type!=T_INT||
 	  sp[1-args].type!=T_INT)
-	 error("Illegal arguments to image->clone()\n");
+	 error("Illegal arguments to image::clone()\n");
 
    o=clone_object(image_program,0);
    img=(struct image*)(o->storage);
@@ -393,12 +442,12 @@ void image_clone(INT32 args)
    {
       if(sp[-args].u.integer < 0 ||
 	 sp[1-args].u.integer < 0)
-	 error("Illegal size to image->clone()\n");
+	 error("Illegal size to image::clone()\n");
       img->xsize=sp[-args].u.integer;
       img->ysize=sp[1-args].u.integer;
    }
 
-   getrgb(img,2,args,"image->clone()"); 
+   getrgb(img,2,args,"image::clone()"); 
 
    if (img->xsize<0) img->xsize=1;
    if (img->ysize<0) img->ysize=1;
@@ -426,6 +475,21 @@ void image_clone(INT32 args)
    push_object(o);
 }
 
+
+/*
+**! method void clear()
+**! method void clear(int r,int g,int b)
+**! method void clear(int r,int g,int b,int alpha)
+**! 	gives a new, cleared image with the same size of drawing area
+**! arg int r
+**! arg int g
+**! arg int b
+**!     color of the new image
+**! arg int alpha
+**! 	new default alpha channel value
+**! see also: copy, clone
+*/
+
 void image_clear(INT32 args)
 {
    struct object *o;
@@ -435,7 +499,7 @@ void image_clear(INT32 args)
    img=(struct image*)(o->storage);
    *img=*THIS;
 
-   getrgb(img,0,args,"image->clear()"); 
+   getrgb(img,0,args,"image::clear()"); 
 
    img->img=malloc(sizeof(rgb_group)*img->xsize*img->ysize +1);
    if (!img->img)
@@ -450,6 +514,35 @@ void image_clear(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object copy()
+**! method object copy(int x1,int y1,int x2,int y2)
+**! method object copy(int x1,int y1,int x2,int y2,int r,int g,int b)
+**! method object copy(int x1,int y1,int x2,int y2,int r,int g,int b,int alpha)
+**! 	Copies this part of the image. The requested area can
+**!	be smaller, giving a cropped image, or bigger - 
+**!	the new area will be filled with the given or current color.
+**!
+**! returns a new image object
+**!
+**! note
+**! 	<ref>clone</ref>(void) and <ref>copy</ref>(void) does the same 
+**!	operation
+**!
+**! arg int x1
+**! arg int y1
+**! arg int x2
+**! arg int y2
+**!	The requested new area. Default is the old image size.
+**! arg int r
+**! arg int g
+**! arg int b
+**!     color of the new image
+**! arg int alpha
+**! 	new default alpha channel value
+**! see also: clone, autocrop
+*/
+
 void image_copy(INT32 args)
 {
    struct object *o;
@@ -468,11 +561,11 @@ void image_copy(INT32 args)
        sp[1-args].type!=T_INT||
        sp[2-args].type!=T_INT||
        sp[3-args].type!=T_INT)
-      error("illegal arguments to image->copy()\n");
+      error("illegal arguments to image::copy()\n");
 
    if (!THIS->img) error("no image\n");
 
-   getrgb(THIS,2,args,"image->crop()"); 
+   getrgb(THIS,4,args,"image::copy()"); 
 
    o=clone_object(image_program,0);
    img=(struct image*)(o->storage);
@@ -485,6 +578,24 @@ void image_copy(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object change_color(int tor,int tog,int tob)
+**! method object change_color(int fromr,int fromg,int fromb, int tor,int tog,int tob)
+**! 	Changes one color (exakt match) to another.
+**!	If non-exakt-match is preferred, check <ref>distancesq</ref>
+**!	and <ref>paste_alpha_color</ref>.
+**! returns a new (the destination) image object
+**!
+**! arg int tor
+**! arg int tog
+**! arg int tob
+**!     destination color and next current color
+**! arg int fromr
+**! arg int fromg
+**! arg int fromb
+**!     source color, default is current color
+*/
+
 static void image_change_color(INT32 args)
 
 {
@@ -495,19 +606,19 @@ static void image_change_color(INT32 args)
    struct image *img;
 
    if (!THIS->img) error("no image\n");
-   if (args<3) error("too few arguments to image->change_color()\n");
+   if (args<3) error("too few arguments to image::change_color()\n");
 
    if (args<6)
    {
       to=THIS->rgb;   
-      getrgb(THIS,0,args,"image->change_color()");
+      getrgb(THIS,0,args,"image::change_color()");
       from=THIS->rgb;
    }
    else
    {
-      getrgb(THIS,0,args,"image->change_color()");
+      getrgb(THIS,0,args,"image::change_color()");
       from=THIS->rgb;
-      getrgb(THIS,3,args,"image->change_color()");
+      getrgb(THIS,3,args,"image::change_color()");
       to=THIS->rgb;
    }
    
@@ -559,6 +670,40 @@ static INLINE int try_autocrop_horisontal(INT32 y,INT32 x,INT32 x2,
    return 1;
 }
 
+/*
+**! method object autocrop()
+**! method object autocrop(int border)
+**! method object autocrop(int border,int r,int g,int b)
+**! method object autocrop(int border,int left,int right,int top,int bottom)
+**! method object autocrop(int border,int left,int right,int top,int bottom,int r,int g,int b)
+**! 	Removes "unneccesary" borders around the image, adds one of
+**!	its own if wanted to, in selected directions.
+**!
+**!	"Unneccesary" is all pixels that are equal -- ie if all the same pixels
+**!	to the left are the same color, that column of pixels are removed.
+**!
+**! returns the new image object
+**!
+**! arg int border
+**!     added border size in pixels
+**! arg int r
+**! arg int g
+**! arg int b
+**!     color of the new border
+**! arg int left
+**! arg int right
+**! arg int top
+**! arg int bottom
+**!	which borders to scan and cut the image; 
+**!	a typical example is removing the top and bottom unneccesary
+**!	pixels:
+**! example
+**!	img=img->autocrop(0, 0,0,1,1);
+**! end example
+**! see also: copy
+*/
+
+
 void image_autocrop(INT32 args)
 {
    INT32 border=0,x1,y1,x2,y2;
@@ -570,7 +715,7 @@ void image_autocrop(INT32 args)
 
    if (args)
       if (sp[-args].type!=T_INT)
-         error("Illegal argument to image->autocrop()\n");
+         error("Illegal argument to image::autocrop()\n");
       else
          border=sp[-args].u.integer; 
 
@@ -580,9 +725,9 @@ void image_autocrop(INT32 args)
       right=!(sp[2-args].type==T_INT && sp[2-args].u.integer==0);
       top=!(sp[3-args].type==T_INT && sp[3-args].u.integer==0);
       bottom=!(sp[4-args].type==T_INT && sp[4-args].u.integer==0);
-      getrgb(THIS,5,args,"image->autocrop()"); 
+      getrgb(THIS,5,args,"image::autocrop()"); 
    }
-   else getrgb(THIS,1,args,"image->autocrop()"); 
+   else getrgb(THIS,1,args,"image::autocrop()"); 
 
    if (!THIS->img)
    {
@@ -620,24 +765,55 @@ void image_autocrop(INT32 args)
 }
 
 
+/*
+**! method object setcolor(int r,int g,int b)
+**! method object setcolor(int r,int g,int b,int alpha)
+**!    set the current color
+**!
+**! returns the object called
+**!
+**! arg int r
+**! arg int g
+**! arg int b
+**!     new color
+**! arg int alpha
+**!     new alpha value
+*/
 void image_setcolor(INT32 args)
 {
    if (args<3)
-      error("illegal arguments to image->setcolor()\n");
-   getrgb(THIS,0,args,"image->setcolor()");
+      error("illegal arguments to image::setcolor()\n");
+   getrgb(THIS,0,args,"image::setcolor()");
    pop_n_elems(args);
    THISOBJ->refs++;
    push_object(THISOBJ);
 }
 
+/*
+**! method object setpixel(int x,int y)
+**! method object setpixel(int x,int y,int r,int g,int b)
+**! method object setpixel(int x,int y,int r,int g,int b,int alpha)
+**!    
+**! returns the object called
+**!
+**! arg int x
+**! arg int y
+**!	position of the pixel
+**! arg int r
+**! arg int g
+**! arg int b
+**!     color
+**! arg int alpha
+**!     alpha value
+*/
 void image_setpixel(INT32 args)
 {
    INT32 x,y;
    if (args<2||
        sp[-args].type!=T_INT||
        sp[1-args].type!=T_INT)
-      error("Illegal arguments to image->setpixel()\n");
-   getrgb(THIS,2,args,"image->setpixel()");   
+      error("Illegal arguments to image::setpixel()\n");
+   getrgb(THIS,2,args,"image::setpixel()");   
    if (!THIS->img) return;
    x=sp[-args].u.integer;
    y=sp[1-args].u.integer;
@@ -648,6 +824,15 @@ void image_setpixel(INT32 args)
    push_object(THISOBJ);
 }
 
+/*
+**! method array(int) getpixel(int x,int y)
+**!    
+**! returns color of the requested pixel -- ({int red,int green,int blue})
+**!
+**! arg int x
+**! arg int y
+**!	position of the pixel
+*/
 void image_getpixel(INT32 args)
 {
    INT32 x,y;
@@ -656,7 +841,7 @@ void image_getpixel(INT32 args)
    if (args<2||
        sp[-args].type!=T_INT||
        sp[1-args].type!=T_INT)
-      error("Illegal arguments to image->getpixel()\n");
+      error("Illegal arguments to image::getpixel()\n");
 
    if (!THIS->img) error("No image.\n");
 
@@ -675,6 +860,26 @@ void image_getpixel(INT32 args)
    f_aggregate(3);
 }
 
+/*
+**! method object line(int x1,int y1,int x2,int y2)
+**! method object line(int x1,int y1,int x2,int y2,int r,int g,int b)
+**! method object line(int x1,int y1,int x2,int y2,int r,int g,int b,int alpha)
+**! 	Draws a line on the image. The line is <i>not</i> antialiased.
+**! 
+**! returns the object called
+**!
+**! arg int x1
+**! arg int y1
+**! arg int x2
+**! arg int y2
+**!	line endpoints
+**! arg int r
+**! arg int g
+**! arg int b
+**!     color
+**! arg int alpha
+**!     alpha value
+*/
 void image_line(INT32 args)
 {
    if (args<4||
@@ -682,8 +887,8 @@ void image_line(INT32 args)
        sp[1-args].type!=T_INT||
        sp[2-args].type!=T_INT||
        sp[3-args].type!=T_INT)
-      error("Illegal arguments to image->line()\n");
-   getrgb(THIS,4,args,"image->line()");
+      error("Illegal arguments to image::line()\n");
+   getrgb(THIS,4,args,"image::line()");
    if (!THIS->img) return;
 
    img_line(sp[-args].u.integer,
@@ -695,6 +900,26 @@ void image_line(INT32 args)
    push_object(THISOBJ);
 }
 
+/*
+**! method object box(int x1,int y1,int x2,int y2)
+**! method object box(int x1,int y1,int x2,int y2,int r,int g,int b)
+**! method object box(int x1,int y1,int x2,int y2,int r,int g,int b,int alpha)
+**! 	Draws a filled rectangle on the image. 
+**! 
+**! returns the object called
+**!
+**! arg int x1
+**! arg int y1
+**! arg int x2
+**! arg int y2
+**!	box corners
+**! arg int r
+**! arg int g
+**! arg int b
+**!     color of the box
+**! arg int alpha
+**!     alpha value 
+*/
 void image_box(INT32 args)
 {
    if (args<4||
@@ -702,8 +927,8 @@ void image_box(INT32 args)
        sp[1-args].type!=T_INT||
        sp[2-args].type!=T_INT||
        sp[3-args].type!=T_INT)
-      error("Illegal arguments to image->box()\n");
-   getrgb(THIS,4,args,"image->box()");
+      error("Illegal arguments to image::box()\n");
+   getrgb(THIS,4,args,"image::box()");
    if (!THIS->img) return;
 
    img_box(sp[-args].u.integer,
@@ -715,6 +940,27 @@ void image_box(INT32 args)
    push_object(THISOBJ);
 }
 
+/*
+**! method object circle(int x,int y,int rx,int ry)
+**! method object circle(int x,int y,int rx,int ry,int r,int g,int b)
+**! method object circle(int x,int y,int rx,int ry,int r,int g,int b,int alpha)
+**! 	Draws a line on the image. The line is <i>not</i> antialiased.
+**! 
+**! returns the object called
+**!
+**! arg int x
+**! arg int y
+**!     circle center
+**! arg int rx
+**! arg int ry
+**!	circle radius in pixels
+**! arg int r
+**! arg int g
+**! arg int b
+**!     color
+**! arg int alpha
+**!     alpha value
+*/
 void image_circle(INT32 args)
 {
    INT32 x,y,rx,ry;
@@ -725,8 +971,8 @@ void image_circle(INT32 args)
        sp[1-args].type!=T_INT||
        sp[2-args].type!=T_INT||
        sp[3-args].type!=T_INT)
-      error("illegal arguments to image->circle()\n");
-   getrgb(THIS,4,args,"image->circle()");
+      error("illegal arguments to image::circle()\n");
+   getrgb(THIS,4,args,"image::circle()");
    if (!THIS->img) return;
 
    x=sp[-args].u.integer;
@@ -793,6 +1039,34 @@ static INLINE void
    sum->b=testrange(sum->b+(INT32)(rgba.b*factor+0.5));
 }
 
+/*
+**! method object tuned_box(int x1,int y1,int x2,int y2,array(array(int)) corner_color)
+**! 	Draws a filled rectangle with colors (and alpha values) tuned
+**!	between the corners.
+**!
+**!	Tuning function is (1.0-x/xw)*(1.0-y/yw) where x and y is
+**!	the distance to the corner and xw and yw are the sides of the
+**!	rectangle.
+**!
+**! returns the object called
+**!
+**! arg int x1
+**! arg int y1
+**! arg int x2
+**! arg int y2
+**!	rectangle corners
+**! arg array(array(int)) corner_color
+**!     colors of the corners:
+**!
+**!	({x1y1,x2y1,x1y2,x2y2})
+**!
+**!	each of these is an array of integeres:
+**!
+**!	({r,g,b}) or ({r,g,b,alpha})
+**!
+**!	Default alpha channel value is 0 (opaque).
+*/
+
 void image_tuned_box(INT32 args)
 {
    INT32 x1,y1,x2,y2,xw,yw,x,y;
@@ -807,7 +1081,7 @@ void image_tuned_box(INT32 args)
        sp[3-args].type!=T_INT||
        sp[4-args].type!=T_ARRAY||
        sp[4-args].u.array->size<4)
-      error("Illegal number of arguments to image->tuned_box()\n");
+      error("Illegal number of arguments to image::tuned_box()\n");
 
    if (!THIS->img)
       error("no image\n");
@@ -838,10 +1112,11 @@ void image_tuned_box(INT32 args)
 
    for (x=max(0,-x1); x<=xw && x+x1<THIS->xsize; x++)
    {
-#define tune_factor(a,aw) (1.0-((float)(a)/(aw)))
+#define tune_factor(a,aw) (1.0-((float)(a)*(aw)))
       INT32 ymax;
-      float tfx1=tune_factor(x,xw);
-      float tfx2=tune_factor(xw-x,xw);
+      float dyw=1/yw;
+      float tfx1=tune_factor(x,1/xw);
+      float tfx2=tune_factor(xw-x,1/xw);
 
       ymax=min(yw,this->ysize-y1);
       img=this->img+x+x1+this->xsize*max(0,y1);
@@ -851,9 +1126,9 @@ void image_tuned_box(INT32 args)
 	    float tfy;
 	    sum=sumzero;
 
-	    add_to_rgba_sum_with_factor(&sum,topleft,(tfy=tune_factor(y,yw))*tfx1);
+	    add_to_rgba_sum_with_factor(&sum,topleft,(tfy=tune_factor(y,dyw))*tfx1);
 	    add_to_rgba_sum_with_factor(&sum,topright,tfy*tfx2);
-	    add_to_rgba_sum_with_factor(&sum,bottomleft,(tfy=tune_factor(yw-y,yw))*tfx1);
+	    add_to_rgba_sum_with_factor(&sum,bottomleft,(tfy=tune_factor(yw-y,dyw))*tfx1);
 	    add_to_rgba_sum_with_factor(&sum,bottomright,tfy*tfx2);
 
 	    set_rgb_group_alpha(*img, sum,sum.alpha);
@@ -865,9 +1140,9 @@ void image_tuned_box(INT32 args)
 	    float tfy;
 	    rgb_group sum={0,0,0};
 
-	    add_to_rgb_sum_with_factor(&sum,topleft,(tfy=tune_factor(y,yw))*tfx1);
+	    add_to_rgb_sum_with_factor(&sum,topleft,(tfy=tune_factor(y,dyw))*tfx1);
 	    add_to_rgb_sum_with_factor(&sum,topright,tfy*tfx2);
-	    add_to_rgb_sum_with_factor(&sum,bottomleft,(tfy=tune_factor(yw-y,yw))*tfx1);
+	    add_to_rgb_sum_with_factor(&sum,bottomleft,(tfy=tune_factor(yw-y,dyw))*tfx1);
 	    add_to_rgb_sum_with_factor(&sum,bottomright,tfy*tfx2);
 
 	    *img=sum;
@@ -882,19 +1157,45 @@ void image_tuned_box(INT32 args)
    push_object(THISOBJ);
 }
 
+/*
+**! method int xsize()
+**! returns the width of the image
+*/
+
 void image_xsize(INT32 args)
 {
    pop_n_elems(args);
    if (THIS->img) push_int(THIS->xsize); else push_int(0);
 }
 
+/*
+**! method int ysize()
+**! returns the height of the image
+*/
+
 void image_ysize(INT32 args)
 {
    pop_n_elems(args);
    if (THIS->img) push_int(THIS->ysize); else push_int(0);
 }
 
-void image_gray(INT32 args)
+/*
+**! method object grey()
+**! method object grey(int r,int g,int b)
+**!    Makes a grey-scale image (with weighted values).
+**!
+**! returns the new image object
+**!
+**! arg int r
+**! arg int g
+**! arg int b
+**!     weight of color, default is r=87,g=127,b=41,
+**!	which should be pretty accurate of what the eyes see...
+**!
+**! see also: color, `*, modify_by_intensity
+*/
+
+void image_grey(INT32 args)
 {
    INT32 x,y,div;
    rgbl_group rgb;
@@ -909,7 +1210,7 @@ void image_gray(INT32 args)
       rgb.b=41;
    }
    else
-      getrgbl(&rgb,0,args,"image->gray()");
+      getrgbl(&rgb,0,args,"image::grey()");
    div=rgb.r+rgb.g+rgb.b;
 
    o=clone_object(image_program,0);
@@ -939,6 +1240,31 @@ void image_gray(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object color()
+**! method object color(int value)
+**! method object color(int r,int g,int b)
+**!    Colorize an image. 
+**!
+**!    The red, green and blue values of the pixels are multiplied
+**!    with the given value(s). This works best on a grey image...
+**!
+**!    The result is divided by 255, giving correct pixel values.
+**!
+**!    If no arguments are given, the current color is used as factors.
+**!
+**! returns the new image object
+**!
+**! arg int r
+**! arg int g
+**! arg int b
+**!	red, green, blue factors
+**! arg int value
+**!	factor
+**!
+**! see also: grey, `*, modify_by_intensity
+*/
+
 void image_color(INT32 args)
 {
    INT32 x,y;
@@ -958,7 +1284,7 @@ void image_color(INT32 args)
 	 rgb.b=THIS->rgb.b;
    }
    else
-      getrgbl(&rgb,0,args,"image->color()");
+      getrgbl(&rgb,0,args,"image::color()");
 
    o=clone_object(image_program,0);
    img=(struct image*)o->storage;
@@ -989,6 +1315,14 @@ void image_color(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object invert()
+**!    Invert an image. Each pixel value gets to be 255-x, where x 
+**!    is the old value.
+**!
+**! returns the new image object
+*/
+
 void image_invert(INT32 args)
 {
    INT32 x,y;
@@ -1026,6 +1360,31 @@ void image_invert(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object treshold()
+**! method object treshold(int r,int g,int b)
+**! 	Makes a black-white image. 
+**!
+**! 	If all red, green, blue parts of a pixel
+**!    	is larger or equal then the given value, the pixel will become
+**!	white, else black.
+**!
+**!	This method works fine with the grey method.
+**!
+**!	If no arguments are given, the current color is used 
+**!	for treshold values.
+**!
+**! returns the new image object
+**!
+**! arg int r
+**! arg int g
+**! arg int b
+**! 	red, green, blue threshold values
+**!
+**! see also: grey
+*/
+
+
 void image_threshold(INT32 args)
 {
    INT32 x,y;
@@ -1035,7 +1394,7 @@ void image_threshold(INT32 args)
 
    if (!THIS->img) error("no image\n");
 
-   getrgb(THIS,0,args,"image->threshold()");
+   getrgb(THIS,0,args,"image::threshold()");
 
    o=clone_object(image_program,0);
    img=(struct image*)o->storage;
@@ -1070,6 +1429,34 @@ void image_threshold(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object distancesq()
+**! method object distancesq(int r,int g,int b)
+**!    Makes an grey-scale image, for alpha-channel use.
+**!    
+**!    The given value (or current color) are used for coordinates
+**!    in the color cube. Each resulting pixel is the 
+**!    distance from this point to the source pixel color,
+**!    in the color cube, squared, rightshifted 8 steps:
+**!
+**!    <pre>
+**!    p = pixel color
+**!    o = given color
+**!    d = destination pixel
+**!    d.red=d.blue=d.green=
+**!	   ((o.red-p.red)�+(o.green-p.green)�+(o.blue-p.blue)�)>>8
+**!    </pre>
+**!
+**! returns the new image object
+**!
+**! arg int r
+**! arg int g
+**! arg int b
+**!	red, green, blue coordinates
+**!
+**! see also: select_from
+*/
+
 void image_distancesq(INT32 args)
 {
    INT32 i;
@@ -1079,7 +1466,7 @@ void image_distancesq(INT32 args)
 
    if (!THIS->img) error("no image\n");
 
-   getrgb(THIS,0,args,"image->distancesq()");
+   getrgb(THIS,0,args,"image::distancesq()");
 
    o=clone_object(image_program,0);
    img=(struct image*)o->storage;
@@ -1201,7 +1588,7 @@ fprintf(stderr," %d,%d,%d)\n",src[x+y*xsize].r,src[x+y*xsize].g,src[x+y*xsize].b
 	 while (++x<=x2)
 	    if ( (j=DISTANCE(rgb,src[x+y*xsize])) <=low_limit) break;
 	 xr=x;
-/*	 x++; hokuspokus /law */
+/*	 x++; hokuspokus /mirar */
 /*       n�n dag ska jag f�rs�ka begripa varf�r... */
 	 if (x>x2) return;
 	 continue;
@@ -1214,6 +1601,32 @@ fprintf(stderr," %d,%d,%d)\n",src[x+y*xsize].r,src[x+y*xsize].g,src[x+y*xsize].b
 	       xr,x-1,y,src,dest,xsize,ysize,rgb,reclvl+1);
 }
 
+/*
+**! method object select_from(int x,int y)
+**! method object select_from(int x,int y,int edge_value)
+**!    Makes an grey-scale image, for alpha-channel use.
+**!    
+**!    This is very close to a floodfill.
+**!    
+**!    The image is scanned from the given pixel,
+**!    filled with 255 if the color is the same,
+**!    or 255 minus distance in the colorcube, squared, rightshifted
+**!    8 steps (see <ref>distancesq</ref>).
+**!
+**!    When the edge distance is reached, the scan is stopped.
+**!    Default edge value is 30.
+**!    This value is squared and compared with the square of the 
+**!    distance above.
+**!
+**! returns the new image object
+**!
+**! arg int x
+**! arg int y
+**!    originating pixel in the image
+**!
+**! see also: distancesq
+*/
+
 void image_select_from(INT32 args)
 {
    struct object *o;
@@ -1225,11 +1638,11 @@ void image_select_from(INT32 args)
    if (args<2 
        || sp[-args].type!=T_INT
        || sp[1-args].type!=T_INT)
-      error("Illegal argument(s) to image->select_from()\n");
+      error("Illegal argument(s) to image::select_from()\n");
 
    if (args>=3)
       if (sp[2-args].type!=T_INT)
-	 error("Illegal argument 3 (edge type) to image->select_from()\n");
+	 error("Illegal argument 3 (edge value) to image::select_from()\n");
       else
 	 low_limit=max(0,sp[2-args].u.integer);
    else
@@ -1249,6 +1662,7 @@ void image_select_from(INT32 args)
    if (sp[-args].u.integer>=0 && sp[-args].u.integer<img->xsize 
        && sp[1-args].u.integer>=0 && sp[1-args].u.integer<img->ysize)
    {
+      MARK_DISTANCE(pixel(THIS,sp[-args].u.integer,sp[1-args].u.integer),0);
       isf_seek(ISF_LEFT|ISF_RIGHT,1,low_limit,
 	       sp[-args].u.integer,sp[-args].u.integer,
 	       sp[1-args].u.integer,
@@ -1265,6 +1679,67 @@ void image_select_from(INT32 args)
    push_object(o);
 }
 
+
+/*
+**! method object apply_matrix(array(array(int|array(int))) matrix)
+**! method object apply_matrix(array(array(int|array(int))) matrix,int r,int g,int b)
+**! method object apply_matrix(array(array(int|array(int))) matrix,int r,int g,int b,int|float div)
+**!     Applies a pixel-transform matrix, or filter, to the image.
+**!    
+**!	<pre>
+**!                            2   2
+**!	pixel(x,y)= base+ k ( sum sum pixel(x+k-1,y+l-1)*matrix(k,l) ) 
+**!                           k=0 l=0 
+**!     </pre>
+**!	
+**!	1/k is sum of matrix, or sum of matrix multiplied with div.
+**!	base is given by r,g,b and is normally black.
+**!
+**!     blur (ie a 2d gauss function):
+**!	<pre>
+**!	({({1,2,1}),
+**!	  ({2,5,2}),
+**!	  ({1,2,1})})
+**!	</pre>
+**!	
+**!     sharpen (k>8, preferably 12 or 16):
+**!	<pre>
+**!	({({-1,-1,-1}),
+**!	  ({-1, k,-1}),
+**!	  ({-1,-1,-1})})
+**!	</pre>
+**!
+**!     edge detect:
+**!	<pre>
+**!	({({1, 1,1}),
+**!	  ({1,-8,1}),
+**!	  ({1, 1,1})})
+**!	</pre>
+**!
+**!     horisontal edge detect (get the idea):
+**!	<pre>
+**!	({({0, 0,0})
+**!	  ({1,-8,1}),
+**!	  ({0, 0,0})})
+**!	</pre>
+**!
+**!     emboss (might prefer to begin with a <ref>grey</ref> image):
+**!	<pre>
+**!	({({2, 1, 0})
+**!	  ({1, 0,-1}),
+**!	  ({0,-1, 2})}), 128,128,128, 5
+**!	</pre>
+**!
+**! returns the new image object
+**!
+**! arg array(array(int|array(int)))
+**!     the matrix; innermost is a value or an array with red, green, blue
+**!     values for red, green, blue separation.
+**!	
+**!	
+*/
+
+
 void image_apply_matrix(INT32 args)
 {
    int width,height,i,j;
@@ -1277,13 +1752,13 @@ CHRONO("apply_matrix");
 
    if (args<1 ||
        sp[-args].type!=T_ARRAY)
-      error("Illegal arguments to image->apply_matrix()\n");
+      error("Illegal arguments to image::apply_matrix()\n");
 
    if (args>3)
       if (sp[1-args].type!=T_INT ||
 	  sp[2-args].type!=T_INT ||
 	  sp[3-args].type!=T_INT)
-	 error("Illegal argument(s) (2,3,4) to image->apply_matrix()\n");
+	 error("Illegal argument(s) (2,3,4) to image::apply_matrix()\n");
       else
       {
 	 default_rgb.r=sp[1-args].u.integer;
@@ -1318,12 +1793,12 @@ CHRONO("apply_matrix");
       struct svalue s;
       array_index_no_free(&s,sp[-args].u.array,i);
       if (s.type!=T_ARRAY) 
-	 error("Illegal contents of (root) array (image->apply_matrix)\n");
+	 error("Illegal contents of (root) array (image::apply_matrix)\n");
       if (width==-1)
 	 width=s.u.array->size;
       else
 	 if (width!=s.u.array->size)
-	    error("Arrays has different size (image->apply_matrix)\n");
+	    error("Arrays has different size (image::apply_matrix)\n");
       free_svalue(&s);
    }
    if (width==-1) width=0;
@@ -1381,6 +1856,31 @@ CHRONO("apply_matrix, end");
    push_object(o);
 }
 
+/*
+**! method object modify_by_intensity(int r,int g,int b,int|array(int) v1,...,int|array(int) vn)
+**!    Recolor an image from intensity values.
+**!
+**!    For each color an intensity is calculated, from r, g and b factors
+**!    (see <ref>grey</ref>), this gives a value between 0 and max.
+**!
+**!    The color is then calculated from the values given, v1 representing
+**!    the intensity value of 0, vn representing max, and colors between
+**!    representing intensity values between, linear.
+**!
+**! returns the new image object
+**!
+**! arg int r
+**! arg int g
+**! arg int b
+**!	red, green, blue intensity factors
+**! arg int|array(int) v1
+**! arg int|array(int) vn
+**!	destination color
+**!
+**! see also: grey, `*, color
+*/
+
+
 void image_modify_by_intensity(INT32 args)
 {
    INT32 x,y,i;
@@ -1393,9 +1893,9 @@ void image_modify_by_intensity(INT32 args)
 
    if (!THIS->img) error("no image\n");
    if (args<5) 
-      error("too few arguments to image->modify_by_intensity()\n");
+      error("too few arguments to image::modify_by_intensity()\n");
    
-   getrgbl(&rgb,0,args,"image->modify_by_intensity()");
+   getrgbl(&rgb,0,args,"image::modify_by_intensity()");
    div=rgb.r+rgb.g+rgb.b;
    if (!div) div=1;
 
@@ -1478,6 +1978,24 @@ void image_modify_by_intensity(INT32 args)
    push_object(o);
 }
 
+
+/*
+**! method object map_closest(array(array(int)) colors)
+**!    Maps all pixel colors to the colors given.
+**!
+**!    Method to find the correct color is linear search
+**!    over the colors given, selecting the nearest in the
+**!    color cube. Slow...
+**!
+**! returns the new image object
+**!
+**! arg array(array(int)) color
+**!    list of destination (available) colors
+**!
+**! see also: map_fast, select_colors, map_fs
+*/
+
+
 static void image_map_closest(INT32 args)
 {
    struct colortable *ct;
@@ -1488,13 +2006,13 @@ static void image_map_closest(INT32 args)
    if (!THIS->img) error("no image\n");
    if (args<1
        || sp[-args].type!=T_ARRAY)
-      error("illegal argument to image->map_closest()\n");
+      error("illegal argument to image::map_closest()\n");
 
    push_int(THIS->xsize);
    push_int(THIS->ysize);
    o=clone_object(image_program,2);
       
-   ct=colortable_from_array(sp[-args].u.array,"image->map_closest()\n");
+   ct=colortable_from_array(sp[-args].u.array,"image::map_closest()\n");
    pop_n_elems(args);
 
    i=THIS->xsize*THIS->ysize;
@@ -1512,6 +2030,24 @@ static void image_map_closest(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object map_fast(array(array(int)) colors)
+**!    Maps all pixel colors to the colors given.
+**!
+**!    Method to find the correct color is to branch
+**!    in a binary space partitioning tree in the 
+**!    colorcube. This is fast, but in some cases
+**!    it gives the wrong color (mostly when few colors
+**!    are available).
+**!
+**! returns the new image object
+**!
+**! arg array(array(int)) color
+**!    list of destination (available) colors
+**!
+**! see also: map_fast, select_colors
+*/
+
 static void image_map_fast(INT32 args)
 {
    struct colortable *ct;
@@ -1522,13 +2058,13 @@ static void image_map_fast(INT32 args)
    if (!THIS->img) error("no image\n");
    if (args<1
        || sp[-args].type!=T_ARRAY)
-      error("illegal argument to image->map_closest()\n");
+      error("illegal argument to image::map_closest()\n");
 
    push_int(THIS->xsize);
    push_int(THIS->ysize);
    o=clone_object(image_program,2);
       
-   ct=colortable_from_array(sp[-args].u.array,"image->map_closest()\n");
+   ct=colortable_from_array(sp[-args].u.array,"image::map_closest()\n");
    pop_n_elems(args);
 
    i=THIS->xsize*THIS->ysize;
@@ -1546,6 +2082,25 @@ static void image_map_fast(INT32 args)
    push_object(o);
 }
 
+/*
+**! method object map_closest(array(array(int)) colors)
+**!    Maps all pixel colors to the colors given.
+**!
+**!    Method to find the correct color is linear search
+**!    over the colors given, selecting the nearest in the
+**!    color cube. Slow...
+**!
+**!    Floyd-steinberg error correction is added to create
+**!    a better-looking image, in many cases, anyway.
+**!
+**! returns the new image object
+**!
+**! arg array(array(int)) color
+**!    list of destination (available) colors
+**!
+**! see also: map_fast, select_colors, map_closest
+*/
+
 static void image_map_fs(INT32 args)
 {
    struct colortable *ct;
@@ -1558,7 +2113,7 @@ static void image_map_fs(INT32 args)
    if (!THIS->img) error("no image\n");
    if (args<1
        || sp[-args].type!=T_ARRAY)
-      error("illegal argument to image->map_fs()\n");
+      error("illegal argument to image::map_fs()\n");
 
    push_int(THIS->xsize);
    push_int(THIS->ysize);
@@ -1567,7 +2122,7 @@ static void image_map_fs(INT32 args)
    res=(int*)xalloc(sizeof(int)*THIS->xsize);
    errb=(rgbl_group*)xalloc(sizeof(rgbl_group)*THIS->xsize);
       
-   ct=colortable_from_array(sp[-args].u.array,"image->map_closest()\n");
+   ct=colortable_from_array(sp[-args].u.array,"image::map_closest()\n");
    pop_n_elems(args);
 
    for (i=0; i<THIS->xsize; i++)
@@ -1596,6 +2151,18 @@ static void image_map_fs(INT32 args)
    push_object(o);
 }
 
+/*
+**! method array(array(int)) map_closest(int num_colors)
+**!    	Selects the best colors to represent the image.
+**!
+**! returns an array of colors
+**!
+**! arg int num_colors
+**!	number of colors to return
+**!
+**! see also: map_fast, select_colors
+*/
+
 void image_select_colors(INT32 args)
 {
    struct colortable *ct;
@@ -1603,7 +2170,7 @@ void image_select_colors(INT32 args)
 
    if (args<1
       || sp[-args].type!=T_INT)
-      error("Illegal argument to image->select_colors()\n");
+      error("Illegal argument to image::select_colors()\n");
 
    colors=sp[-args].u.integer;
    pop_n_elems(args);
@@ -1728,7 +2295,9 @@ void pike_module_init()
    add_function("tuned_box",image_tuned_box,
 		"function(int,int,int,int,array:object)",0);
 
-   add_function("gray",image_gray,
+   add_function("gray",image_grey,
+		"function("RGB_TYPE":object)",0);
+   add_function("grey",image_grey,
 		"function("RGB_TYPE":object)",0);
    add_function("color",image_color,
 		"function("RGB_TYPE":object)",0);
diff --git a/src/modules/Image/image_autodoc_foo b/src/modules/Image/image_autodoc_foo
index e51171785fa5f52cc431abac3f6424326f155580..7d59485733c402ccc5ac389b3a60e6cf56bc6d13 100644
--- a/src/modules/Image/image_autodoc_foo
+++ b/src/modules/Image/image_autodoc_foo
@@ -1,24 +1,26 @@
 pike-object-documentation:
 
 /*
-//! module <module_name>
-//! class <class_name>
-//!  
-//! method <return_type> <pike_function>(<args-declaration>)     - multiple
-//! <description>
-//! returns <returns>
-//!
-//! arg <type> <name>     - multiple for a method
-//! <description>         /
-//!
-//! example
-//! <example>
-//! end example
-//!
-//! note
-//! <note>
-//! 
-//! see also: <references separated by comma and whitespace>
+**! module <module_name>
+**! <description>�        
+**! class <class_name>
+**! <description>�        
+**!  
+**! method <return_type> <pike_function>(<args-declaration>)     - multiple
+**! <description>�
+**! returns <returns>
+**!
+**! arg <type> <name>     - multiple for a method
+**! <description>�        /
+**!
+**! example
+**! <example>
+**! end example
+**!
+**! note
+**! <note>
+**! 
+**! see also: <references separated by comma and whitespace>
 */
 
-� multiple
\ No newline at end of file
+� double newline is treated as new paragraph, <ref> and <pre> are allowed
\ No newline at end of file
diff --git a/src/modules/Image/operator.c b/src/modules/Image/operator.c
index cb752958dcdd0d7f84f0ef71528d21906d4ea75d..add1015620322c4a0a399f5add206229350d8de1 100644
--- a/src/modules/Image/operator.c
+++ b/src/modules/Image/operator.c
@@ -1,4 +1,4 @@
-/* $Id: operator.c,v 1.3 1997/03/17 03:08:01 hubbe Exp $ */
+/* $Id: operator.c,v 1.4 1997/03/25 06:13:48 mirar Exp $ */
 #include "global.h"
 
 #include <math.h>
@@ -103,17 +103,17 @@ void image_operator_plus(INT32 args)
 STANDARD_OPERATOR_HEADER("'+")
    while (i--)
    {
-      d->r=max(s1->r+s2->r,255);
-      d->g=max(s1->g+s2->g,255);
-      d->b=max(s1->b+s2->b,255);
+      d->r=min(s1->r+s2->r,255);
+      d->g=min(s1->g+s2->g,255);
+      d->b=min(s1->b+s2->b,255);
       s1++; s2++; d++; 
    }
    else
    while (i--)
    {
-      d->r=max(s1->r+rgb.r,255);
-      d->g=max(s1->g+rgb.g,255);
-      d->b=max(s1->b+rgb.b,255);
+      d->r=min(s1->r+rgb.r,255);
+      d->g=min(s1->g+rgb.g,255);
+      d->b=min(s1->b+rgb.b,255);
       s1++; d++;
    }
    THREADS_DISALLOW();
@@ -125,17 +125,17 @@ void image_operator_multiply(INT32 args)
 STANDARD_OPERATOR_HEADER("'+")
    while (i--)
    {
-      d->r=floor(s1->r*s2->r*q+0.5);
-      d->g=floor(s1->g*s2->g*q+0.5);
-      d->b=floor(s1->b*s2->b*q+0.5);
+      d->r=floor(s1->r*q*s2->r+0.5);
+      d->g=floor(s1->g*q*s2->g+0.5);
+      d->b=floor(s1->b*q*s2->b+0.5);
       s1++; s2++; d++; 
    }
    else
    while (i--)
    {
-      d->r=floor(s1->r*rgb.r*q+0.5);
-      d->g=floor(s1->g*rgb.g*q+0.5);
-      d->b=floor(s1->b*rgb.b*q+0.5);
+      d->r=floor(s1->r*q*rgb.r+0.5);
+      d->g=floor(s1->g*q*rgb.g+0.5);
+      d->b=floor(s1->b*q*rgb.b+0.5);
       s1++; d++; 
    }
    THREADS_DISALLOW();