diff --git a/src/modules/image/image.c b/src/modules/image/image.c
index 2041a5bf4e1ae1414329807979d6b306074c1cd1..ccf795823b9918141ea9feaed0610d61e970b035 100644
--- a/src/modules/image/image.c
+++ b/src/modules/image/image.c
@@ -1,4 +1,4 @@
-/* $Id: image.c,v 1.27 1996/11/23 07:24:03 law Exp $ */
+/* $Id: image.c,v 1.28 1996/11/30 13:14:35 law Exp $ */
 
 #include "global.h"
 
@@ -7,7 +7,7 @@
 
 #include "stralloc.h"
 #include "global.h"
-RCSID("$Id: image.c,v 1.27 1996/11/23 07:24:03 law Exp $");
+RCSID("$Id: image.c,v 1.28 1996/11/30 13:14:35 law Exp $");
 #include "types.h"
 #include "macros.h"
 #include "object.h"
@@ -436,6 +436,58 @@ void image_copy(INT32 args)
    push_object(o);
 }
 
+static void image_change_color(INT32 args)
+
+{
+   /* ->change_color([int from-r,g,b,] int to-r,g,b); */
+   rgb_group from,to,*s,*d;
+   INT32 left;
+   struct object *o;
+   struct image *img;
+
+   if (!THIS->img) error("no image\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()");
+      from=THIS->rgb;
+   }
+   else
+   {
+      getrgb(THIS,0,args,"image->change_color()");
+      from=THIS->rgb;
+      getrgb(THIS,3,args,"image->change_color()");
+      to=THIS->rgb;
+   }
+   
+   o=clone(image_program,0);
+   img=(struct image*)(o->storage);
+   *img=*THIS;
+
+   if (!(img->img=malloc(sizeof(rgb_group)*img->xsize*img->ysize +1)))
+   {
+      free_object(o);
+      error("out of memory\n");
+   }
+
+   left=THIS->xsize*THIS->ysize;
+   s=THIS->img;
+   d=img->img;
+   while (left--)
+   {
+      if (s->r==from.r && s->g==from.g && s->b==from.b)
+         *d=to;
+      else
+         *d=*s;
+      d++; s++;
+   }
+
+   pop_n_elems(args);
+   push_object(o);
+}
+
 static INLINE int try_autocrop_vertical(INT32 x,INT32 y,INT32 y2,
 					INT32 rgb_set,rgb_group *rgb)
 {
@@ -1096,7 +1148,7 @@ void image_select_from(INT32 args)
 {
    struct object *o;
    struct image *img;
-   INT32 low_limit;
+   INT32 low_limit=0;
 
    if (!THIS->img) error("no image\n");
 
@@ -1490,6 +1542,10 @@ void init_image_programs()
 		"function(:object)",0);
    add_function("scale",image_scale,
 		"function(int|float,int|float|void:object)",0);
+   add_function("translate",image_translate,
+		"function(int|float,int|float:object)",0);
+   add_function("translate_expand",image_translate_expand,
+		"function(int|float,int|float:object)",0);
 
    add_function("paste",image_paste,
 		"function(object,int|void,int|void:object)",0);
@@ -1519,6 +1575,8 @@ void init_image_programs()
 		"function("RGB_TYPE":object)",0);
    add_function("color",image_color,
 		"function("RGB_TYPE":object)",0);
+   add_function("change_color",image_change_color,
+		"function(int,int,int,"RGB_TYPE":object)",0);
    add_function("invert",image_invert,
 		"function("RGB_TYPE":object)",0);
    add_function("threshold",image_threshold,
diff --git a/src/modules/image/image.h b/src/modules/image/image.h
index 9c2eedbe7d07bc471b7ad17e452d46e065f731a1..486179a6be1c3005d16be53e2263f096e2a7010f 100644
--- a/src/modules/image/image.h
+++ b/src/modules/image/image.h
@@ -1,4 +1,4 @@
-/* $Id: image.h,v 1.10 1996/11/23 07:24:04 law Exp $ */
+/* $Id: image.h,v 1.11 1996/11/30 13:14:37 law Exp $ */
 
 #define MAX_NUMCOL 32768
 #define QUANT_MAP_BITS 4
@@ -104,6 +104,8 @@ void image_paste_alpha_color(INT32 args);
 /* matrix.c */
 
 void image_scale(INT32 args);
+void image_translate(INT32 args);
+void image_translate_expand(INT32 args);
 void image_skewx(INT32 args);
 void image_skewy(INT32 args);
 void image_skewx_expand(INT32 args);
diff --git a/src/modules/image/matrix.c b/src/modules/image/matrix.c
index 434755a6d3cf78cff0cdbc29c7779e7afcb52dae..0275b8cb77fa8d8a352e540f62c29eb27c8ebc26 100644
--- a/src/modules/image/matrix.c
+++ b/src/modules/image/matrix.c
@@ -1,4 +1,4 @@
-/* $Id: matrix.c,v 1.4 1996/11/23 07:24:05 law Exp $ */
+/* $Id: matrix.c,v 1.5 1996/11/30 13:14:39 law Exp $ */
 
 #include "global.h"
 
@@ -25,20 +25,25 @@ struct program *image_program;
 #define min(a,b) ((a)<(b)?(a):(b))
 #define max(a,b) ((a)<(b)?(b):(a))
 
-#undef MATRIX_CHRONO
-#ifdef MATRIX_CHRONO
+#if 0
 #include <sys/resource.h>
 #define CHRONO(X) chrono(X)
 
-void chrono(char *x)
+static void chrono(char *x)
 {
    struct rusage r;
+   static struct rusage rold;
    getrusage(RUSAGE_SELF,&r);
-   fprintf(stderr,"%s: %ld.%06ld %ld.%06ld %ld.%06ld\n",x,
+   fprintf(stderr,"%s: %ld.%06ld - %ld.%06ld\n",x,
 	   r.ru_utime.tv_sec,r.ru_utime.tv_usec,
-	   r.ru_stime.tv_sec,r.ru_stime.tv_usec,
-	   r.ru_stime.tv_sec+r.ru_utime.tv_sec,
-	   r.ru_stime.tv_usec+r.ru_utime.tv_usec);
+
+	   ((r.ru_utime.tv_usec-rold.ru_utime.tv_usec<0)?-1:0)
+	   +r.ru_utime.tv_sec-rold.ru_utime.tv_sec,
+           ((r.ru_utime.tv_usec-rold.ru_utime.tv_usec<0)?1000000:0)
+           + r.ru_utime.tv_usec-rold.ru_utime.tv_usec
+	   );
+
+   rold=r;
 }
 #else
 #define CHRONO(X)
@@ -105,30 +110,42 @@ static INLINE int getrgbl(rgbl_group *rgb,INT32 args_start,INT32 args,char *name
 #define decimals(x) ((x)-(int)(x))
 #define testrange(x) max(min((x),255),0)
 #define _scale_add_rgb(dest,src,factor) \
-   ((dest).r=testrange((dest).r+(int)((src).r*(factor)+0.5)), \
-    (dest).g=testrange((dest).g+(int)((src).g*(factor)+0.5)), \
-    (dest).b=testrange((dest).b+(int)((src).b*(factor)+0.5))) 
-#define scale_add_pixel(dest,dx,dy,dxw,src,sx,sy,sxw,factor) \
-   _scale_add_rgb(dest[(dx)+(dy)*(dxw)],src[(sx)+(sy)*(sxw)],factor)
+   ((dest)->r+=(src)->r*(factor), \
+    (dest)->g+=(src)->g*(factor), \
+    (dest)->b+=(src)->b*(factor)) 
+#define scale_add_pixel(dest,dx,src,sx,factor) \
+   _scale_add_rgb(dest,src,factor)
 
-static INLINE void scale_add_line(rgb_group *new,INT32 yn,INT32 newx,
+typedef struct
+{
+   double r,g,b;
+} rgbd_group;
+
+static INLINE void scale_add_line(rgbd_group *new,INT32 yn,INT32 newx,
 				  rgb_group *img,INT32 y,INT32 xsize,
 				  double py,double dx)
 {
    INT32 x,xd;
-   double xn;
-   for (x=0,xn=0; x<THIS->xsize; x++,xn+=dx)
+   double xn,xndxd;
+   new=new+yn*newx;
+   img=img+y*xsize;
+   for (x=0,xn=0; x<xsize; img++,x++,xn+=dx)
    {
       if ((INT32)xn<(INT32)(xn+dx))
       {
-         scale_add_pixel(new,(INT32)xn,yn,newx,img,x,y,xsize,py*(1.0-decimals(xn)));
-	 if ((xd=(INT32)(xn+dx)-(INT32)(xn))>1) 
+	 xndxd=py*(1.0-decimals(xn));
+	 if (xndxd)
+	    scale_add_pixel(new,(INT32)xn,img,x,xndxd);
+	 if (dx>=1.0 && (xd=(INT32)(xn+dx)-(INT32)(xn))>1) 
             while (--xd)
-               scale_add_pixel(new,(INT32)xn+xd,yn,newx,img,x,y,xsize,py);
-	 scale_add_pixel(new,(INT32)(xn+dx),yn,newx,img,x,y,xsize,py*decimals(xn+dx));
+               scale_add_pixel(new,(INT32)(xn+xd),img,x,py);
+	 xndxd=py*decimals(xn+dx);
+	 new++;
+	 if (xndxd)
+	    scale_add_pixel(new,(INT32)(xn+dx),img,x,xndxd);
       }
       else
-         scale_add_pixel(new,(int)xn,yn,newx,img,x,y,xsize,py*dx);
+         scale_add_pixel(new,(int)xn,img,x,py*dx);
    }
 }
 
@@ -136,17 +153,21 @@ void img_scale(struct image *dest,
 	       struct image *source,
 	       INT32 newx,INT32 newy)
 {
-   rgb_group *new;
+   rgbd_group *new,*s;
+   rgb_group *d;
    INT32 y,yd;
    double yn,dx,dy;
 
+CHRONO("scale begin");
+
    if (dest->img) { free(dest->img); dest->img=NULL; }
 
    if (!THIS->img || newx<=0 || newy<=0) return; /* no way */
-   new=malloc(newx*newy*sizeof(rgb_group) +1);
+   new=malloc(newx*newy*sizeof(rgbd_group) +1);
    if (!new) error("Out of memory!\n");
 
-   MEMSET(new,0,newx*newy*sizeof(rgb_group));
+   for (y=0; y<newx*newy; y++) 
+      new[y].r=new[y].g=new[y].b=0.0;
    
    dx=((double)newx-0.000001)/source->xsize; 
    dy=((double)newy-0.000001)/source->ysize; 
@@ -155,23 +176,41 @@ void img_scale(struct image *dest,
    {
       if ((INT32)yn<(INT32)(yn+dy))
       {
-	 scale_add_line(new,(INT32)(yn),newx,source->img,y,source->xsize,
-			(1.0-decimals(yn)),dx);
+	 if (1.0-decimals(yn))
+	    scale_add_line(new,(INT32)(yn),newx,source->img,y,source->xsize,
+			   (1.0-decimals(yn)),dx);
 	 if ((yd=(INT32)(yn+dy)-(INT32)(yn))>1) 
             while (--yd)
    	       scale_add_line(new,(INT32)yn+yd,newx,source->img,y,source->xsize,
 			      1.0,dx);
-	 scale_add_line(new,(INT32)(yn+dy),newx,source->img,y,source->xsize,
-			(decimals(yn+dy)),dx);
+	 if (decimals(yn+dy))
+	    scale_add_line(new,(INT32)(yn+dy),newx,source->img,y,source->xsize,
+			   (decimals(yn+dy)),dx);
       }
       else
 	 scale_add_line(new,(INT32)yn,newx,source->img,y,source->xsize,
 			dy,dx);
    }
 
-   dest->img=new;
+   dest->img=d=malloc(newx*newy*sizeof(rgb_group) +1);
+   if (!d) error("Out of memory!\n");
+
+CHRONO("transfer begin");
+
+   s=new;
+   y=newx*newy;
+   while (y--)
+   {
+      d->r=min((int)(s->r+0.5),255);
+      d->g=min((int)(s->g+0.5),255);
+      d->b=min((int)(s->b+0.5),255);
+      d++; s++;
+   }
+
    dest->xsize=newx;
    dest->ysize=newy;
+
+CHRONO("scale end");
 }
 
 /* Special, faster, case for scale=1/2 */
@@ -787,3 +826,125 @@ void image_rotate_expand(INT32 args)
    img_rotate(args,1);
 }
 
+void img_translate(INT32 args,int expand)
+{
+   float xt,yt;
+   int y,x;
+   struct object *o;
+   struct image *img;
+   rgb_group *s,*d;
+
+   if (args<2) error("illegal number of arguments to image->translate()\n");
+   
+   if (sp[-args].type==T_FLOAT) xt=sp[-args].u.float_number;
+   else if (sp[-args].type==T_INT) xt=sp[-args].u.integer;
+   else error("illegal argument 1 to image->translate()\n");
+
+   if (sp[1-args].type==T_FLOAT) yt=sp[1-args].u.float_number;
+   else if (sp[1-args].type==T_INT) yt=sp[1-args].u.integer;
+   else error("illegal argument 2 to image->translate()\n");
+
+   getrgb(THIS,2,args,"image->translate()\n");
+
+   xt-=floor(xt);
+   yt-=floor(yt);
+   
+   o=clone(image_program,0);
+   img=(struct image*)o->storage;
+
+   img->xsize=THIS->xsize+(xt!=0);
+   img->ysize=THIS->ysize+(xt!=0);
+
+   if (!(img->img=malloc(sizeof(rgb_group)*img->xsize*img->ysize+1)))
+   {
+      free_object(o);
+      error("Out of memory\n");
+   }
+
+   if (!xt)
+   {
+      memcpy(img->img,THIS->img,sizeof(rgb_group)*THIS->xsize*THIS->ysize);
+   }
+   else
+   {
+      float xn=1-xt;
+
+      d=img->img;
+      s=THIS->img;
+
+      for (y=0; y<img->ysize; y++)
+      {
+	 x=THIS->xsize-1;
+	 if (!expand)
+	    d->r=ROUND(THIS->rgb.r*xt+s->r*xn),
+	    d->g=ROUND(THIS->rgb.g*xt+s->g*xn),
+	    d->b=ROUND(THIS->rgb.b*xt+s->b*xn);
+	 else
+	    d->r=s->r, d->g=s->g, d->b=s->b;
+	 d++; s++;
+	 while (x--)
+	 {
+	    d->r=ROUND(s->r*xn+s[1].r*xt),
+	    d->g=ROUND(s->g*xn+s[1].g*xt),
+	    d->b=ROUND(s->b*xn+s[1].b*xt);
+	    d++; s++;
+	 }
+	 if (!expand)
+	    d->r=ROUND(s->r*xn+THIS->rgb.r*xt),
+	    d->g=ROUND(s->g*xn+THIS->rgb.g*xt),
+	    d->b=ROUND(s->b*xn+THIS->rgb.b*xt);
+	 else
+	    d->r=s->r, d->g=s->g, d->b=s->b;
+	 d++;
+      }
+   }
+
+   if (yt)
+   {
+      float yn=1-yt;
+      int xsz=img->xsize;
+
+      d=s=img->img;
+
+      for (x=0; x<img->xsize; x++)
+      {
+	 y=THIS->ysize-1;
+	 if (!expand)
+	    d->r=ROUND(THIS->rgb.r*yt+s->r*yn),
+	    d->g=ROUND(THIS->rgb.g*yt+s->g*yn),
+	    d->b=ROUND(THIS->rgb.b*yt+s->b*yn);
+	 else
+	    d->r=s->r, d->g=s->g, d->b=s->b;
+	 d+=xsz; s+=xsz;
+	 while (y--)
+	 {
+	    d->r=ROUND(s->r*yn+s[xsz].r*yt),
+	    d->g=ROUND(s->g*yn+s[xsz].g*yt),
+	    d->b=ROUND(s->b*yn+s[xsz].b*yt);
+	    d+=xsz; s+=xsz;
+	 }
+	 if (!expand)
+	    d->r=ROUND(s->r*yn+THIS->rgb.r*yt),
+	    d->g=ROUND(s->g*yn+THIS->rgb.g*yt),
+	    d->b=ROUND(s->b*yn+THIS->rgb.b*yt);
+	 else
+	    d->r=s->r, d->g=s->g, d->b=s->b;
+	 d-=xsz*(img->ysize-1)-1;
+	 s-=xsz*THIS->ysize-1;
+      }
+   }
+
+   pop_n_elems(args);
+   push_object(o);
+}
+
+
+void image_translate_expand(INT32 args)
+{
+   img_translate(args,1);
+}
+
+void image_translate(INT32 args)
+{
+   img_translate(args,0);
+}
diff --git a/src/modules/image/togif.c b/src/modules/image/togif.c
index 9256516fa39a0875f29c08f047032f8d8a9a2e82..18b32ac4afa0174fbe6cf30bd4e35485575f6eec 100644
--- a/src/modules/image/togif.c
+++ b/src/modules/image/togif.c
@@ -1,4 +1,4 @@
-/* $Id: togif.c,v 1.17 1996/11/23 11:53:36 law Exp $ */
+/* $Id: togif.c,v 1.18 1996/11/30 13:14:41 law Exp $ */
 /*
 
 togif 
@@ -599,7 +599,7 @@ void image_gif_netscape_loop(INT32 args)
 
 static void img_gif_add(INT32 args,int fs,int lm)
 {
-   INT32 x,y,i;
+   INT32 x=0,y=0,i;
    struct lzw lzw;
    rgb_group *rgb;
    struct colortable *ct=NULL;
@@ -629,13 +629,15 @@ CHRONO("gif add init");
 
    if (args>2+!!ct)
    {
-      unsigned short delay;
+      unsigned short delay=0;
       if (sp[2+!!ct-args].type==T_INT) 
 	 delay=sp[2+!!ct-args].u.integer;
       else if (sp[2+!!ct-args].type==T_FLOAT) 
 	 delay=(unsigned short)(sp[2+!!ct-args].u.float_number*100);
       else 
-	 error("Illegal argument 3 to image->gif_add()\n");
+	 error("Illegal argument %d to image->gif_add()\n",3+!!ct);
+
+fprintf(stderr,"delay: %d\n",delay);
 
       low_my_putchar( '!', &buf ); /* extension block */
       low_my_putchar( 0xf9, &buf ); /* graphics control */
@@ -646,11 +648,14 @@ CHRONO("gif add init");
       low_my_putchar( 0, &buf ); /* terminate block */
    }
 
-   if (!ct) ct=colortable_quant(THIS,256);
+   ct=colortable_quant(THIS,256);
 
    colors=4; bpp=2;
    while (colors<ct->numcol) { colors<<=1; bpp++; }
 
+      
+
+
    low_my_putchar( ',', &buf ); /* image separator */
 
    buf_word(x,&buf); /* leftofs */