diff --git a/src/modules/_Image_XFace/image_xface.c b/src/modules/_Image_XFace/image_xface.c
index 056b001de466762455f6da85958dc72e0f675dfd..55c4a8d3c10e832724728b9a5a2ebcb3db2afa96 100644
--- a/src/modules/_Image_XFace/image_xface.c
+++ b/src/modules/_Image_XFace/image_xface.c
@@ -1,5 +1,5 @@
 #include "global.h"
-RCSID("$Id: image_xface.c,v 1.3 1998/04/05 21:14:10 mirar Exp $");
+RCSID("$Id: image_xface.c,v 1.4 1998/04/09 00:44:08 marcus Exp $");
 
 #include "config.h"
 
@@ -24,6 +24,8 @@ RCSID("$Id: image_xface.c,v 1.3 1998/04/05 21:14:10 mirar Exp $");
 #include "error.h"
 #include "stralloc.h"
 #include "dynamic_buffer.h"
+#include "operators.h"
+#include "builtin_functions.h"
 
 #ifdef HAVE_GMP_H
 
@@ -182,6 +184,20 @@ static int pop(mpz_t val, unsigned int *p)
   return r;
 }
 
+static void push(mpz_t val, unsigned int *p, int r)
+{
+  unsigned long int n;
+  mpz_t dum;
+
+  p += r<<1;
+  mpz_init(dum);
+  n = mpz_fdiv_qr_ui(val, dum, val, p[0]);
+  mpz_clear(dum);
+
+  mpz_mul_ui(val, val, 256);
+  mpz_add_ui(val, val, n+p[1]);
+}
+
 static void popg(mpz_t val, unsigned char *face, int s)
 {
   if(s>=4) {
@@ -199,6 +215,19 @@ static void popg(mpz_t val, unsigned char *face, int s)
   }
 }
 
+static void pushg(mpz_t val, unsigned char *face, int s)
+{
+  if(s>=4) {
+    s>>=1;
+    pushg(val, face+s*49, s);
+    pushg(val, face+s*48, s);
+    pushg(val, face+s, s);
+    pushg(val, face, s);    
+  } else
+    push(val, botprob,
+	 (face[0])|((face[1])<<1)|((face[48])<<2)|((face[49])<<3));
+}
+
 static void uncomp(mpz_t val, unsigned char *face, int s, int l)
 {
   switch(pop(val, topprob[l])) {
@@ -216,6 +245,46 @@ static void uncomp(mpz_t val, unsigned char *face, int s, int l)
   }
 }
 
+static int all_white(unsigned char *face, int s)
+{
+  int i, j;
+  for(i=0; i<s; i++) {
+    for(j=0; j<s; j++)
+      if(face[j])
+	return 0;
+    face += 48;
+  }
+  return 1;
+}
+
+static int all_black(unsigned char *face, int s)
+{
+  if(s>=4) {
+    s>>=1;
+    return all_black(face, s) && all_black(face+s, s) &&
+      all_black(face+s*48, s) && all_black(face+s*49, s);
+  } else
+    return face[0] || face[1] || face[48] || face[49];
+}
+
+static void comp(mpz_t val, unsigned char *face, int s, int l)
+{
+  if(all_white(face, s))
+    push(val, topprob[l], 2);
+  else if(all_black(face, s)) {
+    pushg(val, face, s);
+    push(val, topprob[l], 0);
+  } else {
+    s>>=1;
+    l++;
+    comp(val, face+s*49, s, l);
+    comp(val, face+s*48, s, l);
+    comp(val, face+s, s, l);
+    comp(val, face, s, l);
+    push(val, topprob[l-1], 1);
+  }
+}
+
 static void decodeface(char *data, INT32 len, rgb_group *out)
 {
   unsigned char face[48][48];
@@ -235,6 +304,7 @@ static void decodeface(char *data, INT32 len, rgb_group *out)
     for(j=0; j<3; j++)
       uncomp(val, &face[i*16][j*16], 16, 0);
   mpz_clear(val);
+
   xform((unsigned char *)face, (unsigned char *)face);
   for(i=0; i<48; i++)
     for(j=0; j<48; j++) {
@@ -246,6 +316,46 @@ static void decodeface(char *data, INT32 len, rgb_group *out)
     }
 }
 
+static struct pike_string *encodeface(rgb_group *in)
+{
+  unsigned char face[48][48], newface[48][48];
+  int i, j;
+  unsigned long int n;
+  mpz_t val, dum;
+  dynamic_buffer buf;
+
+  for(i=0; i<48; i++)
+    for(j=0; j<48; j++) {
+      if(in->r || in->g || in->b)
+	face[i][j] = 0;
+      else
+	face[i][j] = 1;
+      in++;
+    }
+  memcpy(newface, face, sizeof(face));
+  xform((unsigned char *)face, (unsigned char *)newface);
+  mpz_init(val);
+  mpz_set_ui(val, 0);
+  for(i=2; i>=0; --i)
+    for(j=2; j>=0; --j)
+      comp(val, &newface[i*16][j*16], 16, 0);
+  buf.s.str = NULL;
+  initialize_buf( &buf );
+  mpz_init(dum);
+  i = 0;
+  while(mpz_cmp_ui(val, 0)) {
+    n = mpz_fdiv_qr_ui(val, dum, val, 94);
+    low_my_putchar( n+'!', &buf );
+    i++;
+  }
+  if (i==0)
+    low_my_putchar( '!', &buf );
+  mpz_clear(dum);
+  mpz_clear(val);
+  return low_free_buf( &buf );
+}
+
+
 /*
 **! method object decode(string data)
 **! method object decode(string data, mapping options)
@@ -279,6 +389,49 @@ static void image_xface_decode(INT32 args)
   push_object(o);
 }
 
+
+/*
+**! method string encode(object img)
+**! method string encode(object img, mapping options)
+**! 	Encodes an X-Face image. 
+**!
+**!     The <tt>img</tt> argument must be an image of the dimensions
+**!     48 by 48 pixels.  All non-black pixels will be considered white.
+**!
+**!     The <tt>options</tt> argument may be a mapping
+**!	containing zero options.
+**!
+*/
+
+static void image_xface_encode(INT32 args)
+{
+  struct image *img;
+  struct pike_string *res;
+
+  if (args<1 
+      || sp[-args].type!=T_OBJECT
+      || !(img=(struct image*)
+	   get_storage(sp[-args].u.object,image_program))
+      || (args>1 && sp[1-args].type!=T_MAPPING))
+    error("Image.XFace.encode: Illegal arguments\n");
+  
+  if (!img->img)
+    error("Image.XFace.encode: Given image is empty.\n");
+  
+  if (img->xsize != 48 || img->ysize != 48)
+    error("Image.XFace.encode: Wrong image dimensions (must be 48 by 48).\n");
+
+  res = encodeface(img->img);
+
+  pop_n_elems(args);
+  if (res == NULL)
+    push_int(0);
+  else {
+    push_string(res);
+    f_reverse(1);
+  }
+}
+
 #endif /* HAVE_GMP_H */
 
 /*** module init & exit & stuff *****************************************/
@@ -307,6 +460,8 @@ void pike_module_init(void)
    {
       add_function("decode",image_xface_decode,
 		   "function(string,void|mapping(string:int):object)",0);
+      add_function("encode",image_xface_encode,
+		   "function(object,void|mapping(string:int):string)",0);
    }
 
 #endif /* HAVE_GMP_H */