diff --git a/src/modules/Image/colortable.c b/src/modules/Image/colortable.c
index fd887cf23df66a32815aa15b95b91141365fb240..f94c54ebc60ac39bb02bf924ae646d02b18fcdad 100644
--- a/src/modules/Image/colortable.c
+++ b/src/modules/Image/colortable.c
@@ -1,11 +1,11 @@
 #include <config.h>
 
-/* $Id: colortable.c,v 1.7 1997/10/18 11:55:26 mirar Exp $ */
+/* $Id: colortable.c,v 1.8 1997/10/21 18:37:01 mirar Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: colortable.c,v 1.7 1997/10/18 11:55:26 mirar Exp $<br>
+**!	$Id: colortable.c,v 1.8 1997/10/21 18:37:01 mirar Exp $<br>
 **! class colortable
 **!
 **!	This object keeps colortable information,
@@ -18,7 +18,7 @@
 #undef COLORTABLE_REDUCE_DEBUG
 
 #include "global.h"
-RCSID("$Id: colortable.c,v 1.7 1997/10/18 11:55:26 mirar Exp $");
+RCSID("$Id: colortable.c,v 1.8 1997/10/21 18:37:01 mirar Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -57,9 +57,18 @@ typedef unsigned long nct_weight_t;
 		 (COLORLOOKUPCACHEHASHB*(int)(b)))% \
 		COLORLOOKUPCACHEHASHSIZE) 
 
-#define SPACEFACTOR_R 8
-#define SPACEFACTOR_G 12
-#define SPACEFACTOR_B 4
+#define SPACEFACTOR_R 2
+#define SPACEFACTOR_G 3
+#define SPACEFACTOR_B 1
+
+#define CUBICLE_DEFAULT_R 4
+#define CUBICLE_DEFAULT_G 5
+#define CUBICLE_DEFAULT_B 4
+#define CUBICLE_DEFAULT_ACCUR 16
+
+#ifndef MAX
+#define MAX(X,Y) ((X)>(Y)?(X):(Y))
+#endif
 
 #define SQ(x) ((x)*(x))
 static INLINE int sq(int x) { return x*x; }
@@ -116,7 +125,7 @@ struct neo_colortable
    } u;
 
    rgbl_group spacefactor; 
-      /* rgb space factors, normally 87, 127 and 41 */
+      /* rgb space factors, normally 2,3,1 */
 
    struct lookupcache
    {
@@ -130,11 +139,13 @@ struct neo_colortable
       struct nctlu_cubicles
       {
 	 int r,g,b; /* size */
+	 int accur; /* accuracy, default 2 */
 	 struct nctlu_cubicle
 	 {
-	    int *index;
-	 } cubicles[1]; /* [r*g*b], index as [ri+(gi+bi*g)*r] */
-      } *cubicles;
+	    int n; 
+	    int *index; /* NULL if not initiated */
+	 } *cubicles; /* [r*g*b], index as [ri+(gi+bi*g)*r] */
+      } cubicles;
       struct nctlu_tree
       {
 	 struct nctlu_treenode
@@ -142,8 +153,8 @@ struct neo_colortable
 	    int splitvalue;
 	    enum { SPLIT_R,SPLIT_G,SPLIT_B,SPLIT_DONE } split_direction;
 	    int less,more;
-	 } nodes[1]; /* shoule be colors�2 */
-      } *tree;
+	 } *nodes; /* shoule be colors�2 */
+      } tree;
    } lu;
 };
 
@@ -158,17 +169,19 @@ static void colortable_free_lookup_stuff(struct neo_colortable *nct)
    switch (nct->lookup_mode)
    {
       case NCT_TREE: 
-         if (nct->lu.tree) free(nct->lu.tree);
-	 nct->lu.tree=NULL;
+         if (nct->lu.tree.nodes) free(nct->lu.tree.nodes);
+	 nct->lu.tree.nodes=NULL;
 	 break;
       case NCT_CUBICLES: 
-         if (nct->lu.cubicles)
+         if (nct->lu.cubicles.cubicles)
 	 {
-	    int i=nct->lu.cubicles->r*nct->lu.cubicles->g*nct->lu.cubicles->b;
-	    while (i--) free(nct->lu.cubicles->cubicles[i].index);
-	    free(nct->lu.cubicles);
+	    int i=nct->lu.cubicles.r*nct->lu.cubicles.g*nct->lu.cubicles.b;
+	    while (i--) 
+	       if (nct->lu.cubicles.cubicles[i].index)
+		  free(nct->lu.cubicles.cubicles[i].index);
+	    free(nct->lu.cubicles.cubicles);
 	 }
-	 nct->lu.cubicles=NULL;
+	 nct->lu.cubicles.cubicles=NULL;
 	 break;
       case NCT_FULL:
          break;
@@ -203,12 +216,17 @@ static void init_colortable_struct(struct object *o)
    int i;
    THIS->type=NCT_NONE;
    THIS->lookup_mode=NCT_CUBICLES;
-   THIS->lu.tree=NULL;
+   THIS->lu.cubicles.cubicles=NULL;
 
    THIS->spacefactor.r=SPACEFACTOR_R;
    THIS->spacefactor.g=SPACEFACTOR_G;
    THIS->spacefactor.b=SPACEFACTOR_B;
    
+   THIS->lu.cubicles.r=CUBICLE_DEFAULT_R;
+   THIS->lu.cubicles.g=CUBICLE_DEFAULT_G;
+   THIS->lu.cubicles.b=CUBICLE_DEFAULT_B;
+   THIS->lu.cubicles.accur=CUBICLE_DEFAULT_ACCUR;
+
    for (i=0; i<COLORLOOKUPCACHEHASHSIZE; i++)
       THIS->lookupcachehash[i].index=-1;
 }
@@ -220,7 +238,7 @@ static void exit_colortable_struct(struct object *obj)
 
 /***************** internal stuff ******************************/
 
-#if 1
+#if 0
 #include <sys/resource.h>
 #define CHRONO(X) chrono(X);
 
@@ -229,14 +247,14 @@ static void chrono(char *x)
    struct rusage r;
    static struct rusage rold;
    getrusage(RUSAGE_SELF,&r);
-   fprintf(stderr,"%s: %d.%06d - %d.%06d\n",x,
-	   r.ru_utime.tv_sec,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
-	   );
+   fprintf(stderr,"%s: %ld.%06ld - %ld.%06ld\n",x,
+	   (long)r.ru_utime.tv_sec,(long)r.ru_utime.tv_usec,
+	   
+	   (long)(((r.ru_utime.tv_usec-rold.ru_utime.tv_usec<0)?-1:0)
+		  +r.ru_utime.tv_sec-rold.ru_utime.tv_sec),
+	   (long)(((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;
 }
@@ -253,7 +271,13 @@ static void _img_copy_colortable(struct neo_colortable *dest,
       dest->lookupcachehash[i].index=-1;
 
    dest->lookup_mode=src->lookup_mode;
-   dest->lu.tree=NULL;
+   switch (dest->lookup_mode)
+   {
+      case NCT_TREE:     dest->lu.tree.nodes=NULL; break;
+      case NCT_CUBICLES: dest->lu.cubicles.cubicles=NULL; break;
+      case NCT_FULL:     break;
+   }
+
    switch (src->type)
    {
       case NCT_NONE:
@@ -527,7 +551,7 @@ static struct nct_flat _img_reduce_number_of_colors(struct nct_flat flat,
 						    unsigned long maxcols,
 						    rgbl_group sf)
 {
-   int i;
+   int i,j;
    struct nct_flat_entry *newe;
 
    newe=malloc(sizeof(struct nct_flat_entry)*flat.numentries);
@@ -540,6 +564,9 @@ static struct nct_flat _img_reduce_number_of_colors(struct nct_flat flat,
    flat.entries=realloc(newe,i*sizeof(struct nct_flat_entry));
    flat.numentries=i;
    if (!flat.entries) { free(newe); error("out of memory\n"); }
+
+   for (j=0; j<i; j++)
+      flat.entries[j].no=j;
    
    return flat;
 }
@@ -1480,11 +1507,11 @@ rerun_rehash_add_2:
 **! method void create(object(Image.image) image,int number,array(array(int)) needed)
 **! method void create(int r,int g,int b)
 **! method void create(int r,int g,int b, array(int) from1,array(int) to1,int steps1, ..., array(int) fromn,array(int) ton,int stepsn)
-**! method void add(array(array(int)) colors)
-**! method void add(object(Image.image) image,int number)
-**! method void add(object(Image.image) image,int number,array(array(int)) needed)
-**! method void add(int r,int g,int b)
-**! method void add(int r,int g,int b, array(int) from1,array(int) to1,int steps1, ..., array(int) fromn,array(int) ton,int stepsn)
+**! method object add(array(array(int)) colors)
+**! method object add(object(Image.image) image,int number)
+**! method object add(object(Image.image) image,int number,array(array(int)) needed)
+**! method object add(int r,int g,int b)
+**! method object add(int r,int g,int b, array(int) from1,array(int) to1,int steps1, ..., array(int) fromn,array(int) ton,int stepsn)
 **!
 **!	<ref>create</ref> initiates a colortable object. 
 **!	Default is that no colors are in the colortable. 
@@ -1554,7 +1581,12 @@ rerun_rehash_add_2:
 
 static void image_colortable_add(INT32 args)
 {
-   if (!args) error("Too few arguments to colortable->add|create()\n");
+   if (!args) 
+   {
+      pop_n_elems(args);
+      push_object(THISOBJ); THISOBJ->refs++;
+      return;
+   }
    
    if (THIS->type!=NCT_NONE)
    {
@@ -1567,6 +1599,10 @@ static void image_colortable_add(INT32 args)
 	    get_storage(sp[-args].u.object,image_colortable_program);
 	 if (ct2)
 	 {
+#ifdef COLORTABLE_DEBUG
+	    fprintf(stderr,"COLORTABLE added %lx and %lx to %lx (args=%d)\n",
+		           THIS,ct2,THIS,args);
+#endif
 	    _img_add_colortable(THIS,ct2);
 	    pop_n_elems(args);
 	    push_object(THISOBJ); THISOBJ->refs++;
@@ -1574,13 +1610,27 @@ static void image_colortable_add(INT32 args)
 	 }
       }
 
+#ifdef COLORTABLE_DEBUG
+      fprintf(stderr,
+	      "COLORTABLE %lx isn't empty; create new and add (args=%d)\n",
+	      THIS,args);
+#endif
       o=clone_object(image_colortable_program,args);
       push_object(o);
       image_colortable_add(1);
+
+#ifdef COLORTABLE_DEBUG
+      fprintf(stderr,
+	      "COLORTABLE done (%lx isn't empty...)\n",
+	      THIS,args);
+#endif
       return;
    }
 
    /* initiate */
+#ifdef COLORTABLE_DEBUG
+   fprintf(stderr,"COLORTABLE %lx created with %d args, sp-args=%lx\n",THIS,args,sp-args);
+#endif
 
    if (sp[-args].type==T_OBJECT)
    {
@@ -1627,6 +1677,7 @@ static void image_colortable_add(INT32 args)
 
 		  push_object(o);
 		  image_colortable_add(1);
+		  pop_n_elems(1);
 		  /* we will keep flat... */
 		  args=2;
 	       }
@@ -1664,11 +1715,17 @@ static void image_colortable_add(INT32 args)
    else error("Illegal argument(s) to Image.colortable->add|create\n");
    pop_n_elems(args);
    push_object(THISOBJ); THISOBJ->refs++;
+
+#ifdef COLORTABLE_DEBUG
+   fprintf(stderr,"COLORTABLE done (%lx created, %d args was left, sp-1=%lx)\n",THIS,args,sp-1);
+#endif
+
 }
 
 void image_colortable_create(INT32 args)
 {
-   if (args) image_colortable_add(args);
+   if (args)  /* optimize */
+      image_colortable_add(args); 
 }
 
 /*
@@ -1915,6 +1972,7 @@ void image_colortable_full(INT32 args)
 /*
 **! method object cubicles()
 **! method object cubicles(int r,int g,int b)
+**! method object cubicles(int r,int g,int b,int accuracy)
 **!	Set the colortable to use the cubicles algorithm to lookup
 **!     the closest color. This is a mostly very fast and very
 **!     accurate way to find the correct color, and the default
@@ -1935,6 +1993,14 @@ void image_colortable_full(INT32 args)
 **!     algorithm time: between O[m] and O[m * n], 
 **!	where n is numbers of colors and m is number of pixels
 **!
+**!	The arguments can be heavy trimmed for the usage
+**!	of your colortable; a large number (10�10�10 or bigger)
+**!	of cubicles is recommended when you use the colortable
+**!	repeatedly, since the calculation takes much
+**!	more time then usage.
+**!
+**!	In some cases, the <ref>full</ref> method is faster.
+**!
 **! returns the called object
 **!
 **! arg int r
@@ -1943,8 +2009,15 @@ void image_colortable_full(INT32 args)
 **!     Size, ie how much the colorspace is divided.
 **!     Note that the size of each cubicle is at least about 8b,
 **!     and that it takes time to calculate them. The number of
-**!     cubicles are <tt>r*g*b</tt>, and default is r=18, g=20, b=12,
-**!     ie 4320 cubicles.
+**!     cubicles are <tt>r*g*b</tt>, and default is 4,5,4,
+**!     ie 80 cubicles. This works good for 200�100 colors.
+**!
+**! arg int accuracy
+**!	Accuracy when checking sides of cubicles.
+**!	Default is 16. A value of 1 gives complete accuracy,
+**!	ie cubicle() method gives exactly the same result
+**!	as full(), but takes (in worst case) 16� the time
+**!	to calculate.
 **!
 **! note
 **!     this method doesn't figure out the cubicles, this is 
@@ -1960,6 +2033,31 @@ void image_colortable_cubicles(INT32 args)
       colortable_free_lookup_stuff(THIS);
       THIS->lookup_mode=NCT_CUBICLES;
    }
+   if (args)
+      if (args>=3 && 
+	  sp[-args].type==T_INT &&
+	  sp[2-args].type==T_INT &&
+	  sp[1-args].type==T_INT)
+      {
+	 THIS->lu.cubicles.r=MAX(sp[-args].u.integer,1);
+	 THIS->lu.cubicles.g=MAX(sp[1-args].u.integer,1);
+	 THIS->lu.cubicles.b=MAX(sp[2-args].u.integer,1);
+	 if (args>=4 &&
+	     sp[3-args].type==T_INT)
+	    THIS->lu.cubicles.accur=MAX(sp[3-args].u.integer,1);
+	 else
+	    THIS->lu.cubicles.accur=CUBICLE_DEFAULT_ACCUR;
+      }
+      else
+	 error("Illegal arguments to colortable->cubicles()\n");
+   else
+   {
+      THIS->lu.cubicles.r=CUBICLE_DEFAULT_R;
+      THIS->lu.cubicles.g=CUBICLE_DEFAULT_G;
+      THIS->lu.cubicles.b=CUBICLE_DEFAULT_B;
+      THIS->lu.cubicles.accur=CUBICLE_DEFAULT_ACCUR;
+   }
+
    pop_n_elems(args);
    push_object(THISOBJ); THISOBJ->refs++;
 }
@@ -2184,12 +2282,432 @@ static void _img_nct_map_to_flat_full(rgb_group *s,
    CHRONO("end flat/full map");
 }
 
+static  int _cub_find_2cub_add(int *i,int *p,
+			       int *p2,int n2,
+			       struct nct_flat_entry *fe,
+			       rgbl_group sf,
+			       int r,int g,int b)
+{
+   int mindist=256*256*100; /* max dist is 256�*3 */
+   int c=0;
+   int *p1=p;
+   int n=*i;
+   int k=1;
+
+   while (n--)
+   {
+      int dist=sf.r*SQ(fe[*p1].color.r-r)+
+	       sf.g*SQ(fe[*p1].color.g-g)+
+	       sf.b*SQ(fe[*p1].color.b-b);
+      
+      if (dist<mindist)
+      {
+	 c=*p1;
+	 mindist=dist;
+	 if (!dist) break;
+      }
+
+      p1++;
+   }
+   if (mindist) while (n2--)
+   {
+      int dist=sf.r*SQ(fe[*p2].color.r-r)+
+	       sf.g*SQ(fe[*p2].color.g-g)+
+	       sf.b*SQ(fe[*p2].color.b-b);
+      
+      if (dist<mindist)
+      {
+	 c=*p2;
+	 k=0;
+	 if (!dist) break;
+	 mindist=dist;
+      }
+
+      p2++;
+   }
+
+   if (!k)
+   {
+      n=*i;
+      while (n--)
+	 if (*p==c) return c; else p++;
+
+      *p=c;
+      (*i)++;
+   }
+
+   return c;
+}
+
+static void _cub_add_cs_2cub_recur(int *i,int *p,
+				   int *p2,int n2,
+				   struct nct_flat_entry *fe,
+				   int rp,int gp,int bp,
+				   int rd1,int gd1,int bd1,
+				   int rd2,int gd2,int bd2,
+				   int *a,int *b,int *c,int *d,
+				   rgbl_group sf,
+				   int accur)
+{
+
+/* a-h-b -> 2
+ | |   |
+ v e f g
+ 1 |   |
+   c-j-d */
+
+   int e=-1,f=-1,g=-1,h=-1,j=-1;
+   int rm1,gm1,bm1;
+   int rm2,gm2,bm2;
+
+   if (*a==-1) *a=_cub_find_2cub_add(i,p,p2,n2,fe,sf, rp,gp,bp); /* 0,0 */   
+   if (*b==-1) *b=_cub_find_2cub_add(i,p,p2,n2,fe,sf,
+                		     rp+rd2,gp+gd2,bp+bd2); /* 0,1 */
+   if (*c==-1) *c=_cub_find_2cub_add(i,p,p2,n2,fe,sf,
+                		     rp+rd1,gp+gd1,bp+bd1); /* 1,0 */
+   if (*d==-1) *d=_cub_find_2cub_add(i,p,p2,n2,fe,sf,
+				   rp+rd2+rd1,gp+gd2+gd1,bp+bd2+bd1); /* 1,1 */
+
+   if (rd1+gd1+bd1<=accur && rd2+gd2+bd2<=accur) return;
+
+   if (*a==*b) h=*a;
+   if (*c==*d) j=*c;
+
+   if (h!=-1 && h==j) return; /* all done */
+
+   if (*a==*c) e=*a;
+   if (*b==*d) g=*b;
+   if (*a==*d) f=*a;
+   if (*b==*c) f=*b;
+
+   rm1=rd1-(rd1>>1); rd1>>=1;
+   gm1=gd1-(gd1>>1); gd1>>=1;
+   bm1=bd1-(bd1>>1); bd1>>=1;
+   rm2=rd2-(rd2>>1); rd2>>=1;
+   gm2=gd2-(gd2>>1); gd2>>=1;
+   bm2=bd2-(bd2>>1); bd2>>=1;
+
+   _cub_add_cs_2cub_recur(i,p,p2,n2,fe, rp,gp,bp, rd1,gd1,bd1, rd2,gd2,bd2, a,&h,&e,&f,sf,accur);
+   _cub_add_cs_2cub_recur(i,p,p2,n2,fe, rp+rd2,gp+gd2,bp+bd2, rd2?rm1:rd1,gd2?gm1:gd1,bd2?bm1:bd1, rd2?rm2:rd2,gd2?gm2:gd2,bd2?bm2:bd2, &h,b,&f,&g,sf,accur);
+   _cub_add_cs_2cub_recur(i,p,p2,n2,fe, rp+rd1,gp+gd1,bp+bd1, rd1?rm1:rd1,gd1?gm1:gd1,bd1?bm1:bd1, rd1?rm2:rd2,gd1?gm2:gd2,bd1?bm2:bd2, &e,&f,c,&j,sf,accur);
+   _cub_add_cs_2cub_recur(i,p,p2,n2,fe, rp+rd2+rd1,gp+gd2+gd1,bp+bd2+bd1, rm1,gm1,bm1, rm2,gm2,bm2, &f,&g,&j,d,sf,accur);
+}
+
+static INLINE int _cub_find_full_add(int **pp,int *i,int *p,int n,
+				     struct nct_flat_entry *fe,
+				     int r,int g,int b,
+				     rgbl_group sf)
+{
+   int mindist=256*256*100; /* max dist is 256�*3 */
+   int c=0;
+
+   while (n--)
+   {
+      int dist=sf.r*SQ(fe->color.r-r)+
+	       sf.g*SQ(fe->color.g-g)+
+	       sf.b*SQ(fe->color.b-b);
+      
+      if (dist<mindist)
+      {
+	 c=fe->no;
+	 if (!dist) break;
+	 mindist=dist;
+      }
+
+      fe++;
+   }
+
+   n=*i;
+   while (n--)
+      if (*p==c) return c; else p++;
+
+   *p=c;
+   (*i)++;
+   (*pp)++;
+
+   return c;
+}
+
+static void _cub_add_cs_full_recur(int **pp,int *i,int *p,
+				   int n,struct nct_flat_entry *fe,
+				   int rp,int gp,int bp,
+				   int rd1,int gd1,int bd1,
+				   int rd2,int gd2,int bd2,
+				   int *a,int *b,int *c,int *d,
+				   rgbl_group sf,
+				   int accur)
+{
+
+/*
+   a-h-b -> 2
+ | |   |
+ v e f g
+ 1 |   |
+   c-i-d
+ */
+
+   int e,f,g,h,j;
+   int rm1,gm1,bm1;
+   int rm2,gm2,bm2;
+
+#if 0
+   fprintf(stderr,"%*s_cub_add_cs_full_recur #%02x%02x%02x, %d,%d,%d, %d,%d,%d %d,%d,%d,%d->",
+	   rlvl,"",
+	   rp,gp,bp,rd1,gd1,bd1,rd2,gd2,bd2,*a,*b,*c,*d);
+#endif
+
+   if (*a==-1) *a=_cub_find_full_add(pp,i,p,n,fe,rp,gp,bp,sf); /* 0,0 */   
+   if (*b==-1) *b=_cub_find_full_add(pp,i,p,n,fe,rp+rd2,gp+gd2,bp+bd2,sf); /* 0,1 */
+   if (*c==-1) *c=_cub_find_full_add(pp,i,p,n,fe,rp+rd1,gp+gd1,bp+bd1,sf); /* 1,0 */
+   if (*d==-1) *d=_cub_find_full_add(pp,i,p,n,fe,rp+rd2+rd1, gp+gd2+gd1,bp+bd2+bd1,sf); /* 1,1 */
+
+#if 0
+   fprintf(stderr,"%d,%d,%d,%d\n",*a,*b,*c,*d);
+#endif
+
+   if (rd1+gd1+bd1<=accur && rd2+gd2+bd2<=accur) return;
+
+   if (*a==*b) h=*a; else h=-1;
+   if (*c==*d) j=*c; else j=-1;
+
+   if (h!=-1 && h==j) return; /* all done */
+
+   if (*a==*c) e=*a; else e=-1;
+   if (*b==*d) g=*b; else g=-1;
+   if (*a==*d) f=*a;
+   else if (*b==*c) f=*b;
+   else f=-1;
+
+   rm1=rd1>>1; rd1-=rm1;
+   gm1=gd1>>1; gd1-=gm1;
+   bm1=bd1>>1; bd1-=bm1;
+   rm2=rd2>>1; rd2-=rm2;
+   gm2=gd2>>1; gd2-=gm2;
+   bm2=bd2>>1; bd2-=bm2;
+   
+   _cub_add_cs_full_recur(pp,i,p,n,fe, rp,gp,bp, rd1,gd1,bd1, rd2,gd2,bd2, a,&h,&e,&f,sf,accur);
+   _cub_add_cs_full_recur(pp,i,p,n,fe, rp+rd2,gp+gd2,bp+bd2, rd2?rm1:rd1,gd2?gm1:gd1,bd2?bm1:bd1, rd2?rm2:rd2,gd2?gm2:gd2,bd2?bm2:bd2, &h,b,&f,&g,sf,accur);
+   _cub_add_cs_full_recur(pp,i,p,n,fe, rp+rd1,gp+gd1,bp+bd1, rd1?rm1:rd1,gd1?gm1:gd1,bd1?bm1:bd1, rd1?rm2:rd2,gd1?gm2:gd2,bd1?bm2:bd2, &e,&f,c,&j,sf,accur);
+   _cub_add_cs_full_recur(pp,i,p,n,fe, rp+rd2+rd1,gp+gd2+gd1,bp+bd2+bd1, rm1,gm1,bm1, rm2,gm2,bm2, &f,&g,&j,d,sf,accur);
+}
+
+static INLINE void _cub_add_cs(struct neo_colortable *nct,
+			       struct nctlu_cubicle *cub,
+			       int **pp,int *i,int *p,
+			       int ri,int gi,int bi,
+			       int red,int green,int blue,
+			       int rp,int gp,int bp,
+			       int rd1,int gd1,int bd1,
+			       int rd2,int gd2,int bd2)
+{
+   int a=-1,b=-1,c=-1,d=-1;
+#if 0
+   fprintf(stderr,
+	   " _cub_add_cs %d,%d,%d %d,%d,%d, %d,%d,%d, %d,%d,%d, %d,%d,%d\n",
+	   ri,gi,bi,red,green,blue,rp,gp,bp,rd1,gd1,bd1,rd2,gd2,bd2);
+#endif
+
+   if (ri<0||gi<0||bi<0||ri>=red||gi>=green||bi>=blue) 
+      return; /* no, colorspace ends here */
+
+#if 0
+   if (nct->lu.cubicles.cubicles[ri+gi*red+bi*red*green].index) 
+      /* use the fact that the cube besides is known */
+      _cub_add_cs_2cub_recur(i,p,
+			     nct->lu.cubicles.cubicles[ri+gi*red+bi*red*green].index,
+			     nct->lu.cubicles.cubicles[ri+gi*red+bi*red*green].n,
+			     nct->u.flat.entries,
+			     rp,gp,bp, rd1,gd1,bd1, rd2,gd2,bd2,
+			     &a,&b,&c,&d,
+			     nct->spacefactor,
+			     nct->lu.cubicles.accur);
+   else
+#endif
+      _cub_add_cs_full_recur(pp,i,p,
+			     nct->u.flat.numentries,
+			     nct->u.flat.entries,
+			     rp,gp,bp, rd1,gd1,bd1, rd2,gd2,bd2,
+			     &a,&b,&c,&d,
+			     nct->spacefactor,
+			     nct->lu.cubicles.accur);
+}
+
+static INLINE void _build_cubicle(struct neo_colortable *nct,
+				  int r,int g,int b,
+				  int red,int green,int blue,
+				  struct nctlu_cubicle *cub)
+{
+   int rmin,rmax;
+   int gmin,gmax;
+   int bmin,bmax;
+
+   struct nct_flat_entry *fe=nct->u.flat.entries;
+   int n=nct->u.flat.numentries;
+
+   int i=0;
+   int *p=malloc(n*sizeof(struct nctlu_cubicle));
+   int *pp,*pi; /* write, read */
+
+   if (!p) error("out of memory (kablamm, typ) in _build_cubicle in colortable->map()\n");
+
+   rmin=(r*256)/red;   rmax=((r+1)*256)/red-1;
+   gmin=(g*256)/green; gmax=((g+1)*256)/green-1;
+   bmin=(b*256)/blue;  bmax=((b+1)*256)/blue-1;
+
+#if 0
+   fprintf(stderr,"build cubicle %d,%d,%d #%02x%02x%02x-#%02x%02x%02x...",
+	   r,g,b,rmin,gmin,bmin,rmax-1,gmax-1,bmax-1);
+#endif
+
+   pp=p;
+
+   while (n--)
+   {
+      if (fe->color.r>=rmin && fe->color.r<=rmax &&
+	  fe->color.g>=gmin && fe->color.g<=gmax &&
+	  fe->color.b>=bmin && fe->color.b<=bmax)
+      {
+	 *pp=fe->no;
+	 pp++; i++;
+      }
+
+      fe++;
+   }
+
+   /* add closest to sides */
+   _cub_add_cs(nct,cub,&pp,&i,p,r-1,g,b,red,green,blue,rmin,gmin,bmin,0,gmax-gmin,0,0,0,bmax-bmin);
+   _cub_add_cs(nct,cub,&pp,&i,p,r,g-1,b,red,green,blue,rmin,gmin,bmin,rmax-rmin,0,0,0,0,bmax-bmin);
+   _cub_add_cs(nct,cub,&pp,&i,p,r,g,b-1,red,green,blue,rmin,gmin,bmin,rmax-rmin,0,0,0,gmax-gmin,0);
+   _cub_add_cs(nct,cub,&pp,&i,p,r+1,g,b,red,green,blue,rmax,gmin,bmin,0,gmax-gmin,0,0,0,bmax-bmin);
+   _cub_add_cs(nct,cub,&pp,&i,p,r,g+1,b,red,green,blue,rmin,gmax,bmin,rmax-rmin,0,0,0,0,bmax-bmin);
+   _cub_add_cs(nct,cub,&pp,&i,p,r,g,b+1,red,green,blue,rmin,gmin,bmax,rmax-rmin,0,0,0,gmax-gmin,0);
+
+#if 0
+   fprintf(stderr," size=%d\n",i);
+
+   do
+   {
+      int j;
+      for (j=0; j<i; j++)
+	 fprintf(stderr,"#%02x%02x%02x,",
+		 nct->u.flat.entries[p[j]].color.r,
+		 nct->u.flat.entries[p[j]].color.g,
+		 nct->u.flat.entries[p[j]].color.b);
+      fprintf(stderr,"\n");
+   } 
+   while (0);
+#endif
+
+   cub->n=i;
+   cub->index=realloc(p,i*sizeof(struct nctlu_cubicle));
+
+   if (!cub->index) 
+      cub->index=p; /* out of memory, or wierd */
+}
+
 static void _img_nct_map_to_flat_cubicles(rgb_group *s,
 					  rgb_group *d,
 					  int n,
 					  struct neo_colortable *nct)
 {
-   error("colortable->map(): map to flat/cubicles not implemented\n");   
+   struct nctlu_cubicles *cubs;
+   struct nctlu_cubicle *cub;
+   int red,green,blue;
+   int hred,hgreen,hblue;
+   int redgreen;
+   struct nct_flat_entry *fe=nct->u.flat.entries;
+   int mindist;
+   rgbl_group sf=nct->spacefactor;
+
+
+   cubs=&(nct->lu.cubicles);
+   if (!(cubs->cubicles))
+   {
+      int n=cubs->r*cubs->g*cubs->b;
+
+CHRONO("init flat/cubicles");
+
+      cub=cubs->cubicles=malloc(sizeof(struct nctlu_cubicle)*n);
+      
+      if (!cub) error("out of memory\n");
+
+      while (n--) /* initiate all to empty */
+      {
+	 cub->n=0;
+	 cub->index=NULL;
+	 cub++;
+      } /* yes, could be faster with a memset... */
+   }
+
+CHRONO("begin flat/cubicles");
+
+   red=cubs->r;   hred=red/2;
+   green=cubs->g; hgreen=green/2;
+   blue=cubs->b;  hblue=blue/2;
+   redgreen=red*green;
+
+   while (n--)
+   {
+      int rgbr,rgbg,rgbb;
+      int r,g,b;
+      struct lookupcache *lc;
+      int m;
+      int *ci;
+
+      rgbr=s->r;
+      rgbg=s->g;
+      rgbb=s->b;
+      
+      lc=nct->lookupcachehash+COLORLOOKUPCACHEHASHVALUE(rgbr,rgbg,rgbb);
+      if (lc->index!=-1 &&
+	  lc->src.r==rgbr &&
+	  lc->src.g==rgbg &&
+	  lc->src.b==rgbb)
+      {
+	 *(d++)=lc->dest;
+	 s++;
+	 continue;
+      }
+
+      lc->src=*s;
+      
+      r=((rgbr*red+hred)>>8);
+      g=((rgbg*green+hgreen)>>8);
+      b=((rgbb*blue+hblue)>>8);
+
+      cub=cubs->cubicles+r+g*red+b*redgreen;
+      
+      if (!cub->index) /* need to build that cubicle */
+	 _build_cubicle(nct,r,g,b,red,green,blue,cub);
+
+      /* now, compare with the colors in that cubicle */
+
+      m=cub->n;
+      ci=cub->index;
+
+      mindist=256*256*100; /* max dist is 256�*3 */
+      
+      while (m--)
+      {
+	 int dist=sf.r*SQ(fe[*ci].color.r-rgbr)+
+	          sf.g*SQ(fe[*ci].color.g-rgbg)+
+	          sf.b*SQ(fe[*ci].color.b-rgbb);
+	 
+	 if (dist<mindist)
+	 {
+	    lc->dest=*d=fe[*ci].color;
+	    mindist=dist;
+	    lc->index=*ci;
+	 }
+	 
+	 ci++;
+      }
+      
+      d++;
+      s++;
+   }
+
+CHRONO("end flat/cubicles");
 }
 
 static void _img_nct_map_to_flat_tree(rgb_group *s,
@@ -2266,7 +2784,7 @@ void image_colortable_map(INT32 args)
 **!	distance factors. This is used when comparing distances
 **!	in the colorspace and comparing grey levels.
 **!
-**!	Default factors are 8, 12 and 4; blue is much 
+**!	Default factors are 2, 3 and 1; blue is much 
 **!	darker than green. Compare with <ref>Image.image::grey</ref>().
 **!
 **! returns the called object