diff --git a/src/modules/image/Makefile.src b/src/modules/image/Makefile.src
index d8c5f3ca9e5c09e43cec2c78035a13b7e38e555f..5e719c90641b52a407033483bcf47a6cf9cc4e8c 100644
--- a/src/modules/image/Makefile.src
+++ b/src/modules/image/Makefile.src
@@ -3,7 +3,8 @@ VPATH=@srcdir@:@srcdir@/../..:../..
 PREFLAGS=$(DEFINES) -I$(SRCDIR) -I$(SRCDIR)/../.. -I../..
 CFLAGS=$(PREFLAGS) $(OTHERFLAGS) @DEFS@
 
-FILES=image.o font.o quant.o lzw.o togif.o matrix.o pnm.o blit.o
+FILES =	image.o font.o quant.o lzw.o togif.o matrix.o pnm.o blit.o \
+	pattern.o
 
 image.a: $(FILES)
 	-rm -f image.a
diff --git a/src/modules/image/blit.c b/src/modules/image/blit.c
index 6c2988a3a8ed5a11656c762766485675179b6905..9d33009f0bd19e5bfa80be78c4a0c49d23ef1060 100644
--- a/src/modules/image/blit.c
+++ b/src/modules/image/blit.c
@@ -49,6 +49,8 @@ void chrono(char *x)
 
 /***************** internals ***********************************/
 
+#define testrange(x) max(min((x),255),0)
+
 #define apply_alpha(x,y,alpha) \
    ((unsigned char)((y*(255L-(alpha))+x*(alpha))/255L))
 
@@ -427,3 +429,5 @@ void img_box(INT32 x1,INT32 y1,INT32 x2,INT32 y2)
    img_box_nocheck(max(x1,0),max(y1,0),min(x2,THIS->xsize-1),min(y2,THIS->ysize-1));
 }
 
+
+
diff --git a/src/modules/image/image.c b/src/modules/image/image.c
index f9229b05d6033af77c2545b28527a217f31c31a4..09ceeff7a9534bd5a14e2725f7a7509df34e45e4 100644
--- a/src/modules/image/image.c
+++ b/src/modules/image/image.c
@@ -390,59 +390,6 @@ void image_clear(INT32 args)
    push_object(o);
 }
 
-
-void image_fromgif(INT32 args)
-{
-   if (sp[-args].type!=T_STRING)
-      error("Illegal argument to image->fromgif()\n");
-
-   if (THIS->img) free(THIS->img);
-   THIS->img=NULL;
-
-   image_decode_gif(THIS,NULL,sp[-args].u.string->str,sp[-args].u.string->len);
-
-   pop_n_elems(args);
-   THISOBJ->refs++;
-   push_object(THISOBJ);
-}
-
-void image_togif(INT32 args)
-{
-   rgb_group *transparent=NULL;
-   struct colortable *ct;
-
-   if (args>=3)
-   {
-      getrgb(THIS,0,args,"image->togif() (transparency)");
-      transparent=&(THIS->rgb);
-   }
-
-   pop_n_elems(args);
-   if (!THIS->img) { error("no image\n");  return; }
-   ct=colortable_quant(THIS,256);
-   push_string( image_encode_gif( THIS,ct, transparent, 0) );
-   colortable_free(ct);
-}
-
-void image_togif_fs(INT32 args)
-{
-   rgb_group *transparent=NULL;
-   struct colortable *ct;
-
-   if (args>=3)
-   {
-      getrgb(THIS,0,args,"image->togif_fs() (transparency)");
-      transparent=&(THIS->rgb);
-   }
-
-   pop_n_elems(args);
-   if (!THIS->img) { error("no image\n");  return; }
-   ct=colortable_quant(THIS,256);
-   push_string( image_encode_gif( THIS,ct, transparent, 1) );
-   colortable_free(ct);
-}
-
-
 void image_copy(INT32 args)
 {
    struct object *o;
@@ -881,9 +828,12 @@ void image_color(INT32 args)
    if (!THIS->img) error("no image\n");
    if (args<3)
    {
-      rgb.r=255;
-      rgb.g=255;
-      rgb.b=255;
+      if (args>0 && sp[-args].type==T_INT)
+	 rgb.r=rgb.b=rgb.g=sp[-args].u.integer;
+      else 
+	 rgb.r=THIS->rgb.r,
+	 rgb.g=THIS->rgb.g,
+	 rgb.b=THIS->rgb.b;
    }
    else
       getrgbl(&rgb,0,args,"image->color()");
@@ -1483,6 +1433,8 @@ void init_image_programs()
 {
    int i;
 
+   image_noise_init();
+
    start_new_program();
    add_storage(sizeof(struct image));
 
@@ -1506,6 +1458,17 @@ void init_image_programs()
 		"function(:string)",0);
    add_function("togif_fs",image_togif_fs,
 		"function(:string)",0);
+   add_function("gif_begin",image_gif_begin,
+		"function(int:string)",0);
+   add_function("gif_add",image_gif_add,
+		"function(int|void,int|void:string)",0);
+   add_function("gif_add_fs",image_gif_add_fs,
+		"function(int|void,int|void:string)",0);
+   add_function("gif_end",image_gif_end,
+		"function(:string)",0);
+   add_function("gif_netscape_loop",image_gif_netscape_loop,
+		"function(:string)",0);
+
    add_function("copy",image_copy,
 		"function(void|int,void|int,void|int,void|int,"RGB_TYPE":object)",0);
    add_function("autocrop",image_autocrop,
@@ -1588,6 +1551,11 @@ void init_image_programs()
                 "function(:object)",0);
    add_function("select_colors",image_select_colors,
                 "function(int:array(array(int)))",0);
+
+   add_function("noise",image_noise,
+                "function(array(float|int|array(int)),float|void,float|void,float|void,float|void:object)",0);
+   add_function("turbulence",image_turbulence,
+                "function(array(float|int|array(int)),int|void,float|void,float|void,float|void,float|void:object)",0);
 		
    set_init_callback(init_image_struct);
    set_exit_callback(exit_image_struct);
diff --git a/src/modules/image/image.h b/src/modules/image/image.h
index c577f5d54762a20b65519234542a7c186f5d1cf2..67245c199f030d0268b0f88b712d5cfb777a32a8 100644
--- a/src/modules/image/image.h
+++ b/src/modules/image/image.h
@@ -72,6 +72,15 @@ void image_floyd_steinberg(rgb_group *rgb,int xsize,
 int image_decode_gif(struct image *dest,struct image *dest_alpha,
 		     unsigned char *src,unsigned long len);
 
+void image_togif(INT32 args);
+void image_togif_fs(INT32 args);
+void image_fromgif(INT32 args);
+void image_gif_begin(INT32 args);
+void image_gif_add(INT32 args);
+void image_gif_add_fs(INT32 args);
+void image_gif_end(INT32 args);
+void image_gif_netscape_loop(INT32 args);
+
 /* blit.c */
 
 void img_clear(rgb_group *dest,rgb_group rgb,INT32 size);
@@ -108,3 +117,9 @@ void image_mirrory(INT32 args);
 
 void image_toppm(INT32 args);
 void image_frompnm(INT32 args);
+ 
+/* pattern.c */
+
+void image_noise(INT32 args);
+void image_turbulence(INT32 args);
+void image_noise_init(void);
diff --git a/src/modules/image/togif.c b/src/modules/image/togif.c
index 185430022b125004fd0f2bc66d6dff767155915c..e5c93e1b1ca1f3aa5d2904bb979e3126308fb52e 100644
--- a/src/modules/image/togif.c
+++ b/src/modules/image/togif.c
@@ -6,11 +6,21 @@ Pontus Hagland, law@infovav.se
 
 */
 
-#include <stdlib.h>
+#include "global.h"
+
+#include <math.h>
+#include <ctype.h>
 
 #include "stralloc.h"
 #include "global.h"
 #include "types.h"
+#include "macros.h"
+#include "object.h"
+#include "constants.h"
+#include "interpret.h"
+#include "svalue.h"
+#include "array.h"
+#include "error.h"
 #include "dynamic_buffer.h"
 
 #include "image.h"
@@ -18,6 +28,9 @@ Pontus Hagland, law@infovav.se
 
 #define INITIAL_BUF_LEN 8192
 
+#define THIS ((struct image *)(fp->current_storage))
+#define THISOBJ (fp->current_object)
+
 
 #define min(a,b) ((a)<(b)?(a):(b))
 #define max(a,b) ((a)<(b)?(b):(a))
@@ -378,3 +391,246 @@ int image_decode_gif(struct image *dest,struct image *dest_alpha,
    return 1; /* ok */
 }
 
+
+
+void image_fromgif(INT32 args)
+{
+   if (sp[-args].type!=T_STRING)
+      error("Illegal argument to image->fromgif()\n");
+
+   if (THIS->img) free(THIS->img);
+   THIS->img=NULL;
+
+   image_decode_gif(THIS,NULL,sp[-args].u.string->str,sp[-args].u.string->len);
+
+   pop_n_elems(args);
+   THISOBJ->refs++;
+   push_object(THISOBJ);
+}
+
+static INLINE void getrgb(struct image *img,
+			  INT32 args_start,INT32 args,char *name)
+{
+   INT32 i;
+   if (args-args_start<3) return;
+   for (i=0; i<3; i++)
+      if (sp[-args+i+args_start].type!=T_INT)
+         error("Illegal r,g,b argument to %s\n",name);
+   img->rgb.r=(unsigned char)sp[-args+args_start].u.integer;
+   img->rgb.g=(unsigned char)sp[1-args+args_start].u.integer;
+   img->rgb.b=(unsigned char)sp[2-args+args_start].u.integer;
+   if (args-args_start>=4)
+      if (sp[3-args+args_start].type!=T_INT)
+         error("Illegal alpha argument to %s\n",name);
+      else
+         img->alpha=sp[3-args+args_start].u.integer;
+   else
+      img->alpha=0;
+}
+
+void image_togif(INT32 args)
+{
+   rgb_group *transparent=NULL;
+   struct colortable *ct;
+
+   if (args>=3)
+   {
+      getrgb(THIS,0,args,"image->togif() (transparency)");
+      transparent=&(THIS->rgb);
+   }
+
+   pop_n_elems(args);
+   if (!THIS->img) { error("no image\n");  return; }
+   ct=colortable_quant(THIS,256);
+   push_string( image_encode_gif( THIS,ct, transparent, 0) );
+   colortable_free(ct);
+}
+
+void image_togif_fs(INT32 args)
+{
+   rgb_group *transparent=NULL;
+   struct colortable *ct;
+
+   if (args>=3)
+   {
+      getrgb(THIS,0,args,"image->togif_fs() (transparency)");
+      transparent=&(THIS->rgb);
+   }
+
+   pop_n_elems(args);
+   if (!THIS->img) { error("no image\n");  return; }
+   ct=colortable_quant(THIS,256);
+   push_string( image_encode_gif( THIS,ct, transparent, 1) );
+   colortable_free(ct);
+}
+
+void image_gif_begin(INT32 args)
+{
+   dynamic_buffer buf;
+   long i;
+
+   pop_n_elems(args);
+
+   buf.s.str=NULL;
+   low_init_buf(&buf);
+
+   low_my_binary_strcat("GIF89a",6,&buf);
+   buf_word((unsigned short)THIS->xsize,&buf);
+   buf_word((unsigned short)THIS->ysize,&buf);
+   low_my_putchar( (char)(0x77), &buf);
+   /* 7 is bpp - 1   7 is "no" global colormap + resolution (??!) */
+
+   low_my_putchar( 0, &buf ); /* background color */
+   low_my_putchar( 0, &buf ); /* just zero */
+
+   push_string(low_free_buf(&buf));
+}
+
+void image_gif_end(INT32 args)
+{
+   pop_n_elems(args);
+   push_string(make_shared_binary_string(";",1));
+}
+
+void image_gif_netscape_loop(INT32 args)
+{
+   unsigned short loops;
+   char buf[30];
+   if (args)
+      if (sp[-args].type!=T_INT) 
+	 error("Illegal argument to image->gif_netscape_loop()\n");
+      else
+	 loops=sp[-args].u.integer;
+   else
+      loops=65535;
+   pop_n_elems(args);
+
+   sprintf(buf,"%c%c%cNETSCAPE2.0%c%c%c%c%c",
+	   33,255,11,3,1,loops&255,(loops>>8)&255,0);
+
+   push_string(make_shared_binary_string(buf,19));
+}
+
+static void img_gif_add(INT32 args,int fs)
+{
+   INT32 x,y,i;
+   struct lzw lzw;
+   rgb_group *rgb;
+   struct colortable *ct;
+   dynamic_buffer buf;
+
+   buf.s.str=NULL;
+   low_init_buf(&buf);
+
+   if (args==0) x=y=0;
+   else if (sp[-args].type!=T_INT
+	    || sp[1-args].type!=T_INT)
+      error("Illegal argument(s) to image->gif_add()\n");
+   else 
+   {
+      x=sp[-args].u.integer;
+      y=sp[1-args].u.integer;
+   }
+
+   if (args>2)
+   {
+      unsigned short delay;
+      if (sp[2-args].type==T_INT) 
+	 delay=sp[2-args].u.integer;
+      else if (sp[2-args].type==T_FLOAT) 
+	 delay=(unsigned short)(sp[2-args].u.float_number*100);
+      else 
+	 error("Illegal argument 3 to image->gif_add()\n");
+
+      low_my_putchar( '!', &buf ); /* extension block */
+      low_my_putchar( 0xf9, &buf ); /* graphics control */
+      low_my_putchar( 4, &buf ); /* block size */
+      low_my_putchar( 0, &buf ); /* disposal, transparency, blabla */
+      buf_word( delay, &buf ); /* delay in centiseconds */
+      low_my_putchar( 0, &buf ); /* (transparency index) */
+      low_my_putchar( 0, &buf ); /* terminate block */
+   }
+
+   ct=colortable_quant(THIS,256);
+
+   low_my_putchar( ',', &buf ); /* image separator */
+
+   buf_word(x,&buf); /* leftofs */
+   buf_word(y,&buf); /* topofs */
+   buf_word(THIS->xsize,&buf); /* width */
+   buf_word(THIS->ysize,&buf); /* height */
+
+   low_my_putchar(0x80|7, &buf); 
+      /* not interlaced (interlaced == 0x40) */
+      /* local colormap ( == 0x80) */
+      /* 8 bpp in map ( == 0x07)   */
+
+   for (i=0; i<256; i++)
+   {
+      low_my_putchar(ct->clut[i].r,&buf);
+      low_my_putchar(ct->clut[i].g,&buf);
+      low_my_putchar(ct->clut[i].b,&buf);
+   }
+
+   low_my_putchar( 8, &buf ); /* bits per pixel , or min 2 */
+   
+   i=THIS->xsize*THIS->ysize;
+   rgb=THIS->img;
+
+   lzw_init(&lzw,8);
+   if (!fs)
+      while (i--) lzw_add(&lzw,colortable_rgb(ct,*(rgb++)));
+   else
+   {
+      rgbl_group *errb;
+      rgb_group corgb;
+      int w,*cres,j;
+      errb=(rgbl_group*)xalloc(sizeof(rgbl_group)*THIS->xsize);
+      cres=(int*)xalloc(sizeof(int)*THIS->xsize);
+      for (i=0; i<THIS->xsize; i++)
+	errb[i].r=(rand()%(FS_SCALE*2+1))-FS_SCALE,
+	errb[i].g=(rand()%(FS_SCALE*2+1))-FS_SCALE,
+	errb[i].b=(rand()%(FS_SCALE*2+1))-FS_SCALE;
+
+      w=0;
+      i=THIS->ysize;
+      while (i--)
+      {
+	 image_floyd_steinberg(rgb,THIS->xsize,errb,w=!w,cres,ct);
+	 for (j=0; j<THIS->xsize; j++)
+	    lzw_add(&lzw,cres[j]);
+	 rgb+=THIS->xsize;
+      }
+
+      free(errb);
+      free(cres);
+   }
+
+   lzw_write_last(&lzw);
+
+   for (i=0; i<(int)lzw.outpos; i+=254)
+   {
+      int wr;
+      if (i+254>(int)lzw.outpos) wr=lzw.outpos-i;
+      else wr=254;
+      low_my_putchar( (unsigned char)wr, &buf ); /* bytes in chunk */
+      low_my_binary_strcat( (char *) lzw.out+i, wr, &buf );
+   }
+   low_my_putchar( 0, &buf ); /* terminate stream */
+
+   lzw_quit(&lzw);
+
+   pop_n_elems(args);
+   push_string(low_free_buf(&buf));
+}
+
+void image_gif_add(INT32 args)
+{
+   img_gif_add(args,0);
+}
+
+void image_gif_add_fs(INT32 args)
+{
+   img_gif_add(args,1);
+}
+
diff --git a/src/pike_types.c b/src/pike_types.c
index cbfcee4a0dfd9f6d5c6e300348e436592aafabd3..83af7551098d67e63d90a84974b06b90b95b6862 100644
--- a/src/pike_types.c
+++ b/src/pike_types.c
@@ -70,6 +70,7 @@ void init_types()
 static int type_length(char *t)
 {
   char *q=t;
+
   switch(EXTRACT_UCHAR(t++))
   {
   default:
@@ -1027,6 +1028,11 @@ struct pike_string *get_type_of_svalue(struct svalue *s)
     push_type(T_MAPPING);
     return pop_type();
 
+  case T_OBJECT:
+    push_type_int(0);
+    push_type(T_OBJECT);
+    return pop_type();
+
   default:
     push_type(s->type);
     return pop_type();