diff --git a/src/modules/Image/encodings/gif.c b/src/modules/Image/encodings/gif.c
index 61ded9f443e03e9a7ed76519854fdc41054c1399..1af9fd57a97f6bfa82a2b44e8bc20a6d76742243 100644
--- a/src/modules/Image/encodings/gif.c
+++ b/src/modules/Image/encodings/gif.c
@@ -1,9 +1,9 @@
-/* $Id: gif.c,v 1.42 1998/04/16 23:47:54 hubbe Exp $ */
+/* $Id: gif.c,v 1.43 1998/04/29 01:27:20 mirar Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: gif.c,v 1.42 1998/04/16 23:47:54 hubbe Exp $
+**!	$Id: gif.c,v 1.43 1998/04/29 01:27:20 mirar Exp $
 **! submodule GIF
 **!
 **!	This submodule keep the GIF encode/decode capabilities
@@ -31,7 +31,7 @@
 #include <ctype.h>
 
 #include "stralloc.h"
-RCSID("$Id: gif.c,v 1.42 1998/04/16 23:47:54 hubbe Exp $");
+RCSID("$Id: gif.c,v 1.43 1998/04/29 01:27:20 mirar Exp $");
 #include "pike_macros.h"
 #include "object.h"
 #include "constants.h"
@@ -1595,13 +1595,6 @@ static void _gif_decode_lzw(unsigned char *s,
 {
    struct neo_colortable *nct;
 
-   struct lzwc
-   {
-      unsigned short prev;
-      unsigned short len;
-      unsigned short c;
-   } *c;
-
    rgb_group white={255,255,255},black={0,0,0};
 
    int bit=0,bits=obits+1;
@@ -1647,7 +1640,7 @@ fprintf(stderr,"_gif_decode_lzw(%lx,%lu,%d,%lx,%lx,%lx,%lu,%d)\n",
       bit-=bits; 
 
 #ifdef GIF_DEBUG
-      if (debug) fprintf(stderr,"code=%d 0x%x bits=%d\n",n,n,bits);
+      if (debug) fprintf(stderr,"code=%d 0x%02x bits=%d\n",n,n,bits);
 #endif
 
       if (n==m) 
@@ -2292,6 +2285,244 @@ void image_gif__encode(INT32 args)
    f_add(n); /* add the strings */
 }
 
+/** lzw stuff ***************************************************/
+
+static void image_gif_lzw_encode(INT32 args)
+{
+   struct gif_lzw lzw;
+
+   if (!args || sp[-args].type!=T_STRING)
+      error("Image.GIF.lzw_encode(): illegal argument\n");
+
+   image_gif_lzw_init(&lzw,8);
+   if (lzw.broken) error("out of memory\n");
+
+   if (args>=2 && !IS_ZERO(sp+1-args))
+      lzw.earlychange=1;
+
+   if (args>=3 && !IS_ZERO(sp+2-args))
+      lzw.reversebits=1;
+   
+   image_gif_lzw_add(&lzw,
+		     (unsigned char *)sp[-args].u.string->str,
+		     sp[-args].u.string->len);
+
+   image_gif_lzw_finish(&lzw);
+   
+   if (lzw.broken) error("out of memory\n");
+
+   pop_n_elems(args);
+   push_string(make_shared_binary_string((char*)lzw.out,lzw.outpos));
+}
+
+static void image_gif_lzw_decode(INT32 args)
+{
+   unsigned char *s,*dest0,*dest;
+   int earlychange=0;
+   unsigned long len,n;
+   signed long clearcode,endcode,last,q,bit,m,dlen,dlen0;
+   unsigned int mask;
+   struct lzwc *c;
+   signed long bits,obits=8;
+   signed long maxcode;
+   int reversebits=0;
+
+   if (!args || sp[-args].type!=T_STRING)
+      error("Image.GIF.lzw_encode(): illegal argument\n");
+
+   s=(unsigned char*)sp[-args].u.string->str;
+   len=(unsigned long)sp[-args].u.string->len;
+
+   if (args>=2 && !IS_ZERO(sp+1-args))
+      earlychange=1;
+   if (args>=3 && !IS_ZERO(sp+2-args))
+      reversebits=1;
+
+   if (len<1)
+   {
+      pop_n_elems(args);
+      push_string(make_shared_binary_string("",0));
+      return;
+   }
+
+   clearcode=(1<<obits);
+   endcode=clearcode+1;
+   bits=obits+1;
+   mask=(unsigned short)((1<<bits)-1);
+   m=endcode;
+   maxcode=(1<<bits);
+
+   last=clearcode;
+
+   c=(struct lzwc*)xalloc(sizeof(struct lzwc)*MAX_GIF_CODE);
+
+   dest0=(unsigned char*)malloc(dlen0=len*4);
+   if (!dest0)
+   {
+      free(c);
+      error("Image.GIF.lzw_decode: out of memory\n");
+   }
+   dest=dest0; dlen=dlen0;
+
+   for (n=0; n<clearcode; n++)
+      c[n].prev=0xffff,c[n].len=1,c[n].c=n;
+   c[clearcode].len=0; 
+   c[endcode].len=0;   
+
+   if (len>1)
+   {
+      if (reversebits) q=s[1]|(s[0]<<8);
+      else q=s[0]|(s[1]<<8);
+      bit=16;
+      s+=2; len-=2;
+   }
+   else
+   {
+      q=s[0];
+      bit=8;
+      s+=1; len-=1;
+   }
+
+   while (bit>0)
+   {
+      /* get next code */
+
+#ifdef GIF_DEBUG
+      fprintf(stderr,"q=0x%04x bit=%2d bits=%2d ... ",q,bit,bits);
+#endif
+
+      if (reversebits)
+	 n=(q>>(bit-bits))&mask; 
+      else
+      {
+	 n=q&mask; 
+	 q>>=bits;
+      }
+      bit-=bits; 
+
+#ifdef GIF_DEBUG
+      fprintf(stderr,"code=%3d 0x%02x bits=%d bit=%2d *s=0x%02x len=%d\n",n,n,bits,bit,*s,len);
+#endif
+
+      if (n==m) 
+      {
+	 c[n].prev=last;
+	 c[n].c=c[last].c;
+	 c[n].len=c[last].len+1;
+      }
+      else if (n>=m) 
+      {
+#ifdef GIF_DEBUG
+	 fprintf(stderr,"cancel; illegal code, %d>=%d at %lx\n",n,m,s);
+#endif
+	 break; /* illegal code */
+      }
+      if (!c[n].len) 
+	 if (n==clearcode) 
+	 {
+	    bits=obits+1;
+	    mask=(1<<bits)-1;
+	    m=endcode;
+	    last=clearcode;
+	    maxcode=1<<bits;
+	 }
+	 else 
+	 {
+	    /* endcode */
+#ifdef GIF_DEBUG
+	    fprintf(stderr,"endcode at %lx\n",s);
+#endif
+	    break; 
+	 }
+      else 
+      {
+	 struct lzwc *myc;
+	 unsigned char *d;
+	 unsigned short lc;
+	 myc=c+n;
+	 
+	 if (myc->len>dlen) 
+	 {
+	    signed long p;
+	    p=(dest-dest0);
+
+#ifdef GIF_DEBUG
+	    fprintf(stderr,"increase at dlen left=%lu p=%ld dlen0=%d\n",dlen,p,dlen0);
+#endif
+	    dest=realloc(dest0,dlen0*2);
+	    if (!dest)
+	    {
+	       dest=dest0+p;
+	       break; /* out of memory */
+	    }
+	    dest0=dest;
+	    dest=dest0+p;
+	    dlen+=dlen0;
+	    dlen0+=dlen0;
+
+#ifdef GIF_DEBUG
+	    fprintf(stderr,"increase at dlen left=%lu p=%ld dlen0=%d\n",dlen,dest-dest0,dlen0);
+#endif
+	 }
+
+	 d=(dest+=myc->len);
+	 dlen-=myc->len;
+	 
+	 for (;;)
+	 {
+	    lc=myc->c;
+	    *(--d)=(unsigned char)lc;
+	    if (myc->prev==0xffff) break;
+	    myc=c+myc->prev;
+	 }
+
+	 if (last!=clearcode)
+	 {
+	    c[m].prev=last;
+	    c[m].len=c[last].len+1;
+	    c[m].c=lc;
+	 }
+	 last=n;
+
+	 m++;
+	 if (m>=maxcode - earlychange) 
+	    if (m==MAX_GIF_CODE - earlychange)
+	    {
+#ifdef GIF_DEBUG
+	       fprintf(stderr,"too many codes at %lx\n",s);
+#endif
+	       m--;
+	       bits=12;
+	    }
+	    else 
+	    { 
+	       bits++; 
+	       mask=(1<<bits)-1;
+	       maxcode<<=1; 
+	       if (maxcode>MAX_GIF_CODE) 
+	       {
+#ifdef GIF_DEBUG
+		  fprintf(stderr,"cancel; gif codes=%ld m=%ld\n",maxcode,m);
+#endif
+		  break; /* error! too much codes */
+	       }
+	    }
+      }
+
+      if (reversebits)
+	 while (bit<bits && len) 
+	    q=(q<<8)|(*s),bit+=8,s++,len--;
+      else
+	 while (bit<bits && len) 
+	    q|=((*s)<<bit),bit+=8,s++,len--;
+   }
+   free(c);
+
+   pop_n_elems(args);
+   push_string(make_shared_binary_string((char*)dest0,dest-dest0));
+   free(dest0);
+}
+
 /** module *******************************************/
 
 struct program *image_encoding_gif_program=NULL;
@@ -2334,6 +2565,11 @@ void init_image_gif(void)
    add_function("_encode_extension",image_gif__encode_extension,
 		"function(array:string)",0);
 
+   add_function("lzw_encode",image_gif_lzw_encode,
+		"function(string,void|int,void|int:string)",0);
+   add_function("lzw_decode",image_gif_lzw_decode,
+		"function(string,void|int,void|int:string)",0);
+
    /** constants **/
 
    add_integer_constant("RENDER",GIF_RENDER,0);
diff --git a/src/modules/Image/encodings/gif_lzw.c b/src/modules/Image/encodings/gif_lzw.c
index 916e8ef62c0557023322d2bef61bd24b3e85c833..13ffa228307d986ae68acd254c227295851e6f76 100644
--- a/src/modules/Image/encodings/gif_lzw.c
+++ b/src/modules/Image/encodings/gif_lzw.c
@@ -1,7 +1,7 @@
 /*
 **! module Image
 **! note
-**!	$Id: gif_lzw.c,v 1.4 1997/11/05 03:42:50 mirar Exp $
+**!	$Id: gif_lzw.c,v 1.5 1998/04/29 01:27:22 mirar Exp $
 */
 
 #include "global.h"
@@ -12,9 +12,6 @@
 
 static INLINE void lzw_output(struct gif_lzw *lzw,lzwcode_t codeno)
 {
-   int bits,bitp;
-   unsigned char c;
-
    if (lzw->outpos+4>=lzw->outlen)
    {
       unsigned char *new;
@@ -23,31 +20,60 @@ static INLINE void lzw_output(struct gif_lzw *lzw,lzwcode_t codeno)
       lzw->out=new;
    }
 
-   bitp=lzw->outbit;
-   c=lzw->lastout;
-   bits=lzw->codebits;
-   if (bits>12) bits=12;
-
-   while (bits)
+   if (!lzw->reversebits)
    {
-      c|=(codeno<<bitp);
-      if (bits+bitp>=8)
+      int bits,bitp;
+      unsigned char c;
+
+      bitp=lzw->outbit;
+      c=(unsigned char)lzw->lastout;
+      bits=lzw->codebits;
+      if (bits>12) bits=12;
+
+      while (bits)
       {
-	 bits-=8-bitp;
-	 codeno>>=8-bitp;
-	 bitp=0;
-	 lzw->out[lzw->outpos++]=c;
-	 c=0;
+	 c|=(codeno<<bitp);
+	 if (bits+bitp>=8)
+	 {
+	    bits-=8-bitp;
+	    codeno>>=8-bitp;
+	    bitp=0;
+	    lzw->out[lzw->outpos++]=c;
+	    c=0;
+	 }
+	 else
+	 {
+	    lzw->outbit=bitp+bits;
+	    lzw->lastout=c;
+	    return;
+	 }
       }
-      else
+      lzw->lastout=0;
+      lzw->outbit=0;
+   }
+   else
+   {
+#ifdef GIF_DEBUG
+      fprintf(stderr,"codeno=%x lastout=%x outbit=%d codebits=%d\n",
+	      codeno,lzw->lastout,lzw->outbit,lzw->codebits);
+#endif
+      lzw->lastout=(lzw->lastout<<lzw->codebits)|codeno;
+      lzw->outbit+=lzw->codebits;
+#ifdef GIF_DEBUG
+      fprintf(stderr,"-> codeno=%x lastout=%x outbit=%d codebits=%d\n",
+	      codeno,lzw->lastout,lzw->outbit,lzw->codebits);
+#endif
+      while (lzw->outbit>8)
       {
-	 lzw->outbit=bitp+bits;
-	 lzw->lastout=c;
-	 return;
+	 lzw->out[lzw->outpos++] =
+	    (unsigned char)(lzw->lastout>>(lzw->outbit-8));
+	 lzw->outbit-=8;
+#ifdef GIF_DEBUG
+      fprintf(stderr,"(shiftout) codeno=%x lastout=%x outbit=%d codebits=%d\n",
+	      codeno,lzw->lastout,lzw->outbit,lzw->codebits);
+#endif
       }
    }
-   lzw->lastout=0;
-   lzw->outbit=0;
 }
 
 static INLINE void lzw_add(struct gif_lzw *lzw,int c)
@@ -103,7 +129,8 @@ static INLINE void lzw_add(struct gif_lzw *lzw,int c)
    lzw->code[lzw->current].firstchild=lno2;
 
    lzw->codes++;
-   if (lzw->codes>(unsigned long)(1L<<lzw->codebits)) lzw->codebits++;
+   if (lzw->codes+lzw->earlychange>(unsigned long)(1L<<lzw->codebits)) 
+      lzw->codebits++;
 
    lzw->current=c;
 }
@@ -134,6 +161,8 @@ void image_gif_lzw_init(struct gif_lzw *lzw,int bits)
    lzw->current=LZWCNULL;
    lzw->outbit=0;
    lzw->lastout=0;
+   lzw->earlychange=0;
+   lzw->reversebits=0;
    lzw_output(lzw,1L<<bits);
 }
 
@@ -143,7 +172,12 @@ void image_gif_lzw_finish(struct gif_lzw *lzw)
       lzw_output(lzw,lzw->current);
    lzw_output( lzw, (1L<<lzw->bits)+1 ); /* GIF end code */
    if (lzw->outbit)
-      lzw->out[lzw->outpos++]=lzw->lastout;
+   {
+      if (lzw->reversebits)
+	 lzw->out[lzw->outpos++]=lzw->lastout<<(8-lzw->outbit);
+      else
+	 lzw->out[lzw->outpos++]=lzw->lastout;
+   }
 }
 
 void image_gif_lzw_free(struct gif_lzw *lzw)
diff --git a/src/modules/Image/encodings/gif_lzw.h b/src/modules/Image/encodings/gif_lzw.h
index b50e2f3ea3f7c2bed5ff3dc1d4449f95fb584937..7555d1ada98698aad0c3fd5408f470d7628e9c71 100644
--- a/src/modules/Image/encodings/gif_lzw.h
+++ b/src/modules/Image/encodings/gif_lzw.h
@@ -1,19 +1,29 @@
 /*
 **! module Image
 **! note
-**!	$Id: gif_lzw.h,v 1.4 1997/11/02 03:44:51 mirar Exp $
+**!	$Id: gif_lzw.h,v 1.5 1998/04/29 01:27:23 mirar Exp $
 */
 
 typedef unsigned short lzwcode_t; /* no more than 12 bits used */
 #define LZWCNULL ((lzwcode_t)(~0))
 
+struct lzwc
+{
+   unsigned short prev;
+   unsigned short len;
+   unsigned short c;
+} *c;
+
 struct gif_lzw
 {
    int broken; /* lzw failed, out of memory */
 
-   unsigned char *out,lastout;
-   unsigned long outlen;
+   unsigned char *out;
+   unsigned long outlen,lastout;
 
+   int earlychange;
+   int reversebits;
+   
    unsigned long codes;
    unsigned long bits; /* initial encoding bits */
    unsigned long codebits; /* current encoding bits */