Index: trunk/Ohana/src/kapa2/Makefile
===================================================================
--- trunk/Ohana/src/kapa2/Makefile	(revision 16010)
+++ trunk/Ohana/src/kapa2/Makefile	(revision 16011)
@@ -77,5 +77,7 @@
 $(SRC)/bDrawOverlay.$(ARCH).o             $(SRC)/ButtonFunctions.$(ARCH).o    \
 $(SRC)/PSimage.$(ARCH).o                  $(SRC)/PSPixmap.$(ARCH).o           \
-$(SRC)/PSOverlay.$(ARCH).o
+$(SRC)/PSOverlay.$(ARCH).o                $(SRC)/SetChannel.$(ARCH).o         \
+$(SRC)/SetColorScale.$(ARCH).o            $(SRC)/ColorCube.$(ARCH).o          \
+$(SRC)/ColorHistogram.$(ARCH).o           $(SRC)/sort.$(ARCH).o
 
 OBJ  =  $(KAPA)
Index: trunk/Ohana/src/kapa2/include/buttons.h
===================================================================
--- trunk/Ohana/src/kapa2/include/buttons.h	(revision 16010)
+++ trunk/Ohana/src/kapa2/include/buttons.h	(revision 16011)
@@ -47,7 +47,7 @@
    0x80, 0xef, 0x03, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00};
-#define puns_width 25
-#define puns_height 25
-static char puns_bits[] = {
+#define heat_width 25
+#define heat_height 25
+static char heat_bits[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xd8, 0x01,
    0x00, 0x0c, 0x37, 0x00, 0xf8, 0xc9, 0x6f, 0x00, 0x0c, 0xde, 0xf0, 0x00,
Index: trunk/Ohana/src/kapa2/include/constants.h
===================================================================
--- trunk/Ohana/src/kapa2/include/constants.h	(revision 16010)
+++ trunk/Ohana/src/kapa2/include/constants.h	(revision 16011)
@@ -9,4 +9,10 @@
  | StructureNotifyMask \
  | PointerMotionMask)
+
+# define NCHANNELS 3
+# define NPIXELS_DYNAMIC 128
+
+// XXX for the moment, this is set to match the values in SetColorScale3D_CC
+# define NPIXELS_STATIC 4600
 
 # define PAD1  3
@@ -27,13 +33,34 @@
 # define LABEL_MAXLEN 128
 
+typedef enum {
+    KAPA_SCALE_1D,
+    KAPA_SCALE_3D_RUFF,
+    KAPA_SCALE_3D_FULL
+} KapaColorScaleMode;
+
 /* label names */
-# define LABELX0 0
-# define LABELY0 1
-# define LABELX1 2
-# define LABELY1 3
-# define LABELUL 4
-# define LABELUR 5
-# define LABELLL 6
-# define LABELLR 7
+typedef enum {
+  LABELX0,
+  LABELY0,
+  LABELX1,
+  LABELY1,
+  LABELUL,
+  LABELUR,
+  LABELLL,
+  LABELLR
+} KapaLabelMode;
+
+typedef enum {
+  KAPA_CHANNEL_RED,
+  KAPA_CHANNEL_GREEN,
+  KAPA_CHANNEL_BLUE,
+} KapaChannels;
+
+// use an enum to identify the 3 dimensions:
+typedef enum {
+  CC_X,
+  CC_Y,
+  CC_Z,
+} CCDimen;
 
 /* EVENT_MASK consists of:
Index: trunk/Ohana/src/kapa2/include/prototypes.h
===================================================================
--- trunk/Ohana/src/kapa2/include/prototypes.h	(revision 16010)
+++ trunk/Ohana/src/kapa2/include/prototypes.h	(revision 16011)
@@ -71,4 +71,6 @@
 int           GetImageCoords      PROTO((int sock));
 int           GetImageRange       PROTO((int sock));
+int           SetChannel (int sock);
+int           SetColormapFromPipe (int sock);
 
 int           LoadVectorData      PROTO((int sock, KapaGraphWidget *graph, int N, char *type));
@@ -140,5 +142,8 @@
 
 int           Center              PROTO(());
-void          Remap               PROTO((Graphic *graphic, KapaImageWidget *image, Matrix *matrix));
+void          SetColorScale       PROTO((Graphic *graphic, KapaImageWidget *image));
+void          SetColorScale1D     PROTO((Graphic *graphic, KapaImageWidget *image));
+int           SetColorScale3D     PROTO((Graphic *graphic, KapaImageWidget *image));
+void          Remap               PROTO((Graphic *graphic, KapaImageWidget *image));
 void          Remap8              PROTO((Graphic *graphic, KapaImageWidget *image, Matrix *matrix));
 void          Remap16             PROTO((Graphic *graphic, KapaImageWidget *image, Matrix *matrix));
@@ -147,5 +152,6 @@
 int           LoadPicture         PROTO((int sock));
 
-KapaImageWidget *InitImage        PROTO(());
+KapaImageWidget *InitImageWidget  PROTO(());
+int           InitImageChannel    PROTO((KapaImageChannel *channel));
 void          FreeImage           PROTO((KapaImageWidget *image));
 void          SetImageSize        PROTO((Section *section));
@@ -179,5 +185,5 @@
 /* Button Functions */
 int           greycolors	  PROTO((Graphic *graphic, KapaImageWidget *image));
-int	      puns		  PROTO((Graphic *graphic, KapaImageWidget *image));
+int	      heat		  PROTO((Graphic *graphic, KapaImageWidget *image));
 int	      rainbow		  PROTO((Graphic *graphic, KapaImageWidget *image));
 int	      Recenter		  PROTO((Graphic *graphic, KapaImageWidget *image));
@@ -219,2 +225,22 @@
 void InvertButton (Graphic *graphic, Button *button);
 void bDrawOverlay (KapaImageWidget *image, int N);
+
+/* color cube tools */
+CCNode *CCNodeAlloc ();
+CCNode *CCFindChild (CCNode *node, float x, float y, float z);
+int CCSplitNode (CCNode *node);
+int CCSplitNodeIterate (CCNode *node, int current, int max);
+void CCNodeFree (CCNode *node);
+CCNode *CCFindBottom (CCNode *top, float x, float y, float z);
+int CCNodeExtractCounts (CCNode *node, float **values, int *nvalues, int *NVALUES);
+int CCNodeDivideLimit (CCNode *node, float minValue);
+int CCNodeInitCounts (CCNode *node, float value);
+
+/* 3D color histogram */
+void ColorHistogram (KapaImageWidget *image, CCNode *cube);
+void CCNodeSetColorPixels (KapaImageWidget *image, CCNode *cube);
+int CCNodeSetColorMap (CCNode *node, XColor *cmap, int Npixels, int *current);
+
+int SetColorScale3D_CC (Graphic *graphic, KapaImageWidget *image);
+
+void sort (float *value, int N);
Index: trunk/Ohana/src/kapa2/include/structures.h
===================================================================
--- trunk/Ohana/src/kapa2/include/structures.h	(revision 16010)
+++ trunk/Ohana/src/kapa2/include/structures.h	(revision 16011)
@@ -2,11 +2,11 @@
 /**************** Graphic carries X info around ****************/
 typedef struct {
-  Display       *display;
-  int            screen;
+  Display       *display;     // X display pointer
+  int            screen;      // X screen number
   int            depth;
   Window         window;
   Visual        *visual;
-  int            visualclass;
-  int            Nbits;
+  int            visualclass; // is visual dynamic? (XXX change name?)
+  int            Nbits;	      // pixel depth in bits (8, 16, 24, 32)
   GC             gc;
   XFontStruct   *font;
@@ -14,13 +14,21 @@
   int            x,  y;
   unsigned int   dx, dy;
-  XColor         cmap[256];
+  XColor        *cmap;
   Colormap       colormap;
-  unsigned long  fore;
-  unsigned long  back;
-  unsigned long  *color;
-  unsigned long  pixels[256];
-  unsigned long  overlay_color[NOVERLAYS];
-  int Npixels;
-  int Ncolors;
+  unsigned long *color;      // graph plotting colors
+  int            Ncolors;
+
+  unsigned long *pixels;      // image pixel colors
+  int Npixels;		      // number of pixels
+
+  int            ColorScaleMode; // single colormap for all images??
+  int nRed;
+  int nBlue;
+  int nGreen;
+
+  unsigned long  fore;	      // basic foreground color 
+  unsigned long  back;	      // basic background color
+
+  unsigned long  overlay_color[NOVERLAYS]; // image plotting colors 
 } Graphic;
 
@@ -58,4 +66,18 @@
 } TextBox;
 
+/*** 3C color cube histogram tree thingy ***/
+typedef struct CCNode {
+  // for the moment, this structure is specific to the color-histogram analysis.  if
+  // this were a void *pointer and we defined some additional apis, we could use this
+  // structure to track any 3D space
+  int count;    
+  int pixel;
+  char bottom;
+  float min[3]; // min value for each of the 3 dimensions for this node
+  float mid[3]; // mid-point for each of the 3 dimensions for this node
+  float max[3]; // max value for each of the 3 dimensions for this node
+  struct CCNode *sub[2][2][2];
+} CCNode;
+
 /**************** general structures ****************/
 typedef struct {
@@ -125,4 +147,15 @@
 } KapaGraphWidget;
 
+typedef struct {
+  // data associated with this image element
+  Matrix   matrix;         /* data for picture */
+  double   zero, range;    /* zero, range for picture to cmap */
+  double   max, min;       /* zero, range for data to z-value */
+  double   start, slope;   /* zero, range for cmap to pixels */
+  Coords   coords;
+  char     file[1024];     /* name of file */
+  char     name[1024];     /* name of buffer */
+} KapaImageChannel;
+
 // a single image in the display window
 typedef struct {
@@ -139,5 +172,5 @@
   Button   grey_button;
   Button   rainbow_button;
-  Button    puns_button;
+  Button   heat_button;
   Button   overlay_button[NOVERLAYS];
 
@@ -149,17 +182,16 @@
   int      DecimalDegrees;
 
-  // data associated with this image element
+  double   X, Y;           /* image pixel at screen center */
+  int      expand;         /* zoomscale */
+  double   x, y, z;        /* last pointer coords */
+
   Overlay  overlay[NOVERLAYS];
   Overlay  tickmarks;
-  Matrix   matrix;         /* data for picture */
-  double   X, Y;           /* image pixel at screen center */
-  int      expand;         /* zoomscale */
-  double   zero, range;    /* zero, range for picture to cmap */
-  double   max, min;       /* zero, range for data to z-value */
-  double   start, slope;   /* zero, range for cmap to pixels */
-  double   x, y, z;        /* last pointer coords */
-  Coords   coords;
-  char     file[1024];     /* name of file */
-  char     name[1024];  /* name of buffer */
+
+  unsigned short   *pixmap;   // lookup table for image pixel value to pixel index
+  int      nPixels;
+ 
+  KapaImageChannel *image;
+  KapaImageChannel channel[NCHANNELS];
 } KapaImageWidget;
 
Index: trunk/Ohana/src/kapa2/src/ButtonFunctions.c
===================================================================
--- trunk/Ohana/src/kapa2/src/ButtonFunctions.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/ButtonFunctions.c	(revision 16011)
@@ -2,5 +2,5 @@
 
 static char *GREY = "greyscale";
-static char *PUNS = "Puns";
+static char *HEAT = "Heat";
 static char *RAINBOW = "Rainbow";
 
@@ -18,5 +18,6 @@
   SetColormap (name);
   CreateColorbar (image, graphic);
-  Remap (graphic, image, &image[0].matrix);
+  SetColorScale (graphic, image);
+  Remap (graphic, image);
   CreateZoom (image, graphic, 0, 0); 
   Refresh ();
@@ -25,10 +26,11 @@
 }
 
-int puns (Graphic *graphic, KapaImageWidget *image) {
+int heat (Graphic *graphic, KapaImageWidget *image) {
   char *name;
-  name = PUNS;
-  SetColormap (name);
+  name = HEAT;
+  SetColormap ("ruffcolor");
   CreateColorbar (image, graphic);
-  Remap (graphic, image, &image[0].matrix);
+  SetColorScale (graphic, image);
+  Remap (graphic, image);
   CreateZoom (image, graphic, 0, 0); 
   Refresh ();
@@ -40,7 +42,8 @@
   char *name;
   name = RAINBOW;
-  SetColormap (name);
+  SetColormap ("fullcolor");
   CreateColorbar (image, graphic);
-  Remap (graphic, image, &image[0].matrix);
+  SetColorScale (graphic, image);
+  Remap (graphic, image);
   CreateZoom (image, graphic, 0, 0); 
   Refresh ();
@@ -54,5 +57,5 @@
   image[0].Y = 0;
  
-  Remap (graphic, image, &image[0].matrix);
+  Remap (graphic, image);
   Refresh ();
   FlushDisplay (graphic[0].display);
@@ -64,5 +67,5 @@
 
   image[0].expand = 1;
-  Remap (graphic, image, &image[0].matrix);
+  Remap (graphic, image);
   Refresh ();
   FlushDisplay (graphic[0].display);
@@ -77,5 +80,5 @@
   image[0].expand = 1;
  
-  Remap (graphic, image, &image[0].matrix);
+  Remap (graphic, image);
   Refresh ();
   FlushDisplay (graphic[0].display);
Index: trunk/Ohana/src/kapa2/src/CSaveOverlay.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CSaveOverlay.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CSaveOverlay.c	(revision 16011)
@@ -24,19 +24,19 @@
   for (i = 0; i < image[0].overlay[N].Nobjects; i++) {
     if (image[0].overlay[N].objects[i].type == KII_OVERLAY_LINE) {
-      XY_to_RD (&ra, &dec, image[0].overlay[N].objects[i].x, image[0].overlay[N].objects[i].y, &image[0].coords);
+      XY_to_RD (&ra, &dec, image[0].overlay[N].objects[i].x, image[0].overlay[N].objects[i].y, &image[0].image[0].coords);
       x1 = image[0].overlay[N].objects[i].x + image[0].overlay[N].objects[i].dx;
       y1 = image[0].overlay[N].objects[i].y + image[0].overlay[N].objects[i].dy;
-      XY_to_RD (&ra1, &dec1, x1, y1, &image[0].coords);
+      XY_to_RD (&ra1, &dec1, x1, y1, &image[0].image[0].coords);
       dra = (ra1 - ra);
       ddec = (dec1 - dec);
     } else {
-      XY_to_RD (&ra, &dec, image[0].overlay[N].objects[i].x, image[0].overlay[N].objects[i].y, &image[0].coords);
+      XY_to_RD (&ra, &dec, image[0].overlay[N].objects[i].x, image[0].overlay[N].objects[i].y, &image[0].image[0].coords);
       x1 = image[0].overlay[N].objects[i].x;
       y1 = image[0].overlay[N].objects[i].y + image[0].overlay[N].objects[i].dy;
-      XY_to_RD (&ra1, &dec1, x1, y1, &image[0].coords);
+      XY_to_RD (&ra1, &dec1, x1, y1, &image[0].image[0].coords);
       ddec = fabs (dec1 - dec);
       x1 = image[0].overlay[N].objects[i].x + image[0].overlay[N].objects[i].dx;
       y1 = image[0].overlay[N].objects[i].y;
-      XY_to_RD (&ra1, &dec1, x1, y1, &image[0].coords);
+      XY_to_RD (&ra1, &dec1, x1, y1, &image[0].image[0].coords);
       dra = cos (dec*RAD_DEG) * fabs (ra1 - ra);
     }
Index: trunk/Ohana/src/kapa2/src/Center.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Center.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/Center.c	(revision 16011)
@@ -16,6 +16,6 @@
   if (image == NULL) return (TRUE);
 
-  image[0].X = 0.5*image[0].matrix.Naxis[0] - X;
-  image[0].Y = 0.5*image[0].matrix.Naxis[1] - Y;
+  image[0].X = 0.5*image[0].image[0].matrix.Naxis[0] - X;
+  image[0].Y = 0.5*image[0].image[0].matrix.Naxis[1] - Y;
   if ((zoom != 0) && (zoom != -1)) {
     image[0].expand = zoom;
@@ -23,5 +23,5 @@
 
   if (USE_XWINDOW) {
-    Remap (graphic, image, &image[0].matrix);
+    Remap (graphic, image);
     Refresh ();
     XFlush (graphic[0].display);
Index: trunk/Ohana/src/kapa2/src/CheckButtons.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CheckButtons.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CheckButtons.c	(revision 16011)
@@ -1,7 +1,3 @@
 # include "Ximage.h"
-# define PAD_X 10
-# define PAD_Y 10
-# define NPLANES 1
-# define NPIXELS 255
 
 /******** Here we test the Buttons specific to this program  *******/
@@ -21,6 +17,6 @@
     button = &image[0].rainbow_button;
 
-  if (InButton (event, &image[0].puns_button)) 
-    button = &image[0].puns_button;
+  if (InButton (event, &image[0].heat_button)) 
+    button = &image[0].heat_button;
 
   if (InButton (event, &image[0].PS_button)) 
@@ -39,5 +35,4 @@
 }
 
-
 /* To define a button, you must:
 
Index: trunk/Ohana/src/kapa2/src/CheckPipe.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CheckPipe.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CheckPipe.c	(revision 16011)
@@ -268,4 +268,16 @@
   }
 
+  if (!strcmp (word, "CHAN")) {
+    status = SetChannel (sock);
+    KiiSendCommand (sock, 4, "DONE");
+    FINISHED (status);
+  }
+
+  if (!strcmp (word, "CMAP")) {
+    status = SetColormapFromPipe (sock);
+    KiiSendCommand (sock, 4, "DONE");
+    FINISHED (status);
+  }
+
   if (!strcmp (word, "SAVE")) {
     status = SaveOverlay (sock);
Index: trunk/Ohana/src/kapa2/src/CheckVisual.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CheckVisual.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CheckVisual.c	(revision 16011)
@@ -1,4 +1,3 @@
 # include "Ximage.h"
-# define NPIXELS 64
 
 /* DirectColor doesn't seem to work, even though it is available:
@@ -11,5 +10,5 @@
 
   int i, Nfound, N;
-  int col, def, dyn;
+  int isColor, isDefault, isDynamic;
   XVisualInfo *visual_list, visual_temp;
   unsigned long planes[3];
@@ -20,8 +19,8 @@
     fprintf (stderr, "DirectColor: %d\n", DirectColor);
     fprintf (stderr, "PseudoColor: %d\n", PseudoColor);
-    fprintf (stderr, "TrueColor: %d\n", TrueColor);
-    fprintf (stderr, "GrayScale: %d\n", GrayScale);
+    fprintf (stderr, "TrueColor:   %d\n", TrueColor);
+    fprintf (stderr, "GrayScale:   %d\n", GrayScale);
     fprintf (stderr, "StaticColor: %d\n", StaticColor);
-    fprintf (stderr, "StaticGray: %d\n", StaticGray);
+    fprintf (stderr, "StaticGray:  %d\n", StaticGray);
   }
 
@@ -42,86 +41,65 @@
   }
 
-  col = def = dyn = FALSE;
+  // set these based on selected visual
+  isColor = isDefault = isDynamic = FALSE;
+
+  // attempt to select the most desirable type of visual: Default as PseudoColor (XXX is it still true?)
   if (DEBUG) fprintf (stderr, "default visual class is %d\n", visual_list[i].class);
-  switch (visual_list[i].class) {
-  case PseudoColor:
-    col = def = dyn = TRUE;
+  if (visual_list[i].class == PseudoColor) {
+    isColor = isDefault = isDynamic = TRUE;
     graphic[0].visual = visual_list[i].visual;
     graphic[0].visualclass = TRUE;
     goto test_pixels;
-    break;
-  default:
-    break;
   }
 
-  for (i = 0; i < Nfound; i++) {
-    switch (visual_list[i].class) {
-    case PseudoColor:
-      if (DEBUG) fprintf (stderr, "selected visual class is %d\n", visual_list[i].class);
-      col = dyn = TRUE;
-      if (graphic[0].visual == visual_list[i].visual) {
-	def = TRUE;
-      } else {
-	graphic[0].visual = visual_list[i].visual;
-      }
-      graphic[0].visualclass = TRUE;
-      goto test_pixels;
-      break;
-    default:
-      break;
-    }
+  // attempt to select the most desirable type of visual: PseudoColor (XXX is it still true?)
+  for (i = 0; (i < Nfound) && (visual_list[i].class != PseudoColor); i++);
+  if (i != Nfound) {
+    isColor = isDynamic = TRUE;
+    if (DEBUG) fprintf (stderr, "selected visual class is %d\n", visual_list[i].class);
+    isDefault = (graphic[0].visual == visual_list[i].visual);
+    graphic[0].visual = visual_list[i].visual;
+    graphic[0].visualclass = TRUE;
+    goto test_pixels;
   }
 
-  for (i = 0; i < Nfound; i++) {
-    switch (visual_list[i].class) {
-    case GrayScale:
-      if (DEBUG) fprintf (stderr, "selected visual class is %d\n", visual_list[i].class);
-      dyn = TRUE;
-      if (graphic[0].visual == visual_list[i].visual) {
-	def = TRUE;
-      } else {
-	graphic[0].visual = visual_list[i].visual;
-      }
-      graphic[0].visualclass = TRUE;
-      goto test_pixels;
-      break;
-    default:
-      break;
-    }
+  // attempt to select the most desirable type of visual: GrayScale (XXX is it still true?)
+  for (i = 0; (i < Nfound) && (visual_list[i].class != GrayScale); i++);
+  if (i != Nfound) {
+    isDynamic = TRUE;
+    if (DEBUG) fprintf (stderr, "selected visual class is %d\n", visual_list[i].class);
+    isDefault = (graphic[0].visual == visual_list[i].visual);
+    graphic[0].visual = visual_list[i].visual;
+    graphic[0].visualclass = TRUE;
+    goto test_pixels;
   }
 
+  // attempt to select the most desirable type of visual: TrueColor (XXX is it still true?)
   for (i = 0; (i < Nfound) && (visual_list[i].class != TrueColor); i++);
   if (i != Nfound) {
-    col = TRUE;
+    isColor = TRUE;
     if (DEBUG) fprintf (stderr, "visual class is %d\n", visual_list[i].class);
-    if (graphic[0].visual == visual_list[i].visual) {
-      def = TRUE;
-    } else {
-      graphic[0].visual = visual_list[i].visual;
-    }
+    isDefault = (graphic[0].visual == visual_list[i].visual);
+    graphic[0].visual = visual_list[i].visual;
     graphic[0].visualclass = FALSE;
     goto test_pixels;
   }
 
+  // attempt to select the most desirable type of visual: TrueColor (XXX is it still true?)
   for (i = 0; (i < Nfound) && (visual_list[i].class != StaticColor); i++);
   if (i != Nfound) {
     if (DEBUG) fprintf (stderr, "visual class is %d\n", visual_list[i].class);
-    if (graphic[0].visual == visual_list[i].visual) {
-      def = TRUE;
-    } else {
-      graphic[0].visual = visual_list[i].visual;
-    }
+    isDefault = (graphic[0].visual == visual_list[i].visual);
+    graphic[0].visual = visual_list[i].visual;
     graphic[0].visualclass = FALSE;
     goto test_pixels;
   }
 
+  // attempt to select the most desirable type of visual: TrueColor (XXX is it still true?)
   for (i = 0; (i < Nfound) && (visual_list[i].class != StaticGray); i++);
   if (i != Nfound) {
     if (DEBUG) fprintf (stderr, "visual class is %d\n", visual_list[i].class);
-    if (graphic[0].visual == visual_list[i].visual) {
-      def = TRUE;
-    } else {
-      graphic[0].visual = visual_list[i].visual;
-    }
+    isDefault = (graphic[0].visual == visual_list[i].visual);
+    graphic[0].visual = visual_list[i].visual;
     graphic[0].visualclass = FALSE;
     goto test_pixels;
@@ -136,35 +114,45 @@
   /* NEED TO ADD A COUPLE LINES DEFINING THE VARIOUS HARD COLORS (BLACK, WHITE, AND THE OVERLAYS) */
 
+  // allow user to force a private colormap
   if ((N = get_argument (*argc, argv, "-private"))) {
     remove_argument(N, argc, argv);
-    def = FALSE;
+    isDefault = FALSE;
   } 
 
-  if (!def) {
+  // allocate a private colormap, if needed
+  if (!isDefault) {
     if (DEBUG) fprintf (stderr, "allocated private colormap\n");
     graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, AllocNone);
   }
 
-  if (dyn) {
-    /* allocate color cells  */
-    for (graphic[0].Npixels = NPIXELS;
-	 ((graphic[0].Npixels >= 16) && 
-	  !XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 1, graphic[0].pixels, graphic[0].Npixels));
-	 graphic[0].Npixels -= 4) {
+  if (isDynamic) {
+    /* allocate color cells */
+    ALLOCATE (graphic[0].pixels, unsigned long, NPIXELS_DYNAMIC);
+    ALLOCATE (graphic[0].cmap,   XColor,        NPIXELS_DYNAMIC);
+    for (graphic[0].Npixels = NPIXELS_DYNAMIC; graphic[0].Npixels >= 16; graphic[0].Npixels -= 4) {
       if (DEBUG) fprintf (stderr, "trying %d colors\n", (int) graphic[0].Npixels);
+      if (XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 1, graphic[0].pixels, graphic[0].Npixels)) {
+	break;
+      }
     }
 
+    /* insufficient cells, can we make a private colormap? */
+    if (graphic[0].Npixels < 16) {
+      if (!isDefault) {
+	fprintf (stderr, "can't allocate enough cells in private colormap\n");
+	exit (0);
+      }
+      if (DEBUG) fprintf (stderr, "can't allocate enough cells, using private colormap\n");
+      graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, AllocNone);
 
-    /* make private colormap  */
-    if (graphic[0].Npixels < 16) {
-      // fprintf (stderr, "can't allocate enough cells, using private colormap\n");
-      graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, AllocNone);
-      for (graphic[0].Npixels = NPIXELS;
-	   ((graphic[0].Npixels >= 16) && 
-	    !XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 1, graphic[0].pixels, graphic[0].Npixels));
-	   graphic[0].Npixels -= 4);
+      for (graphic[0].Npixels = NPIXELS_DYNAMIC; graphic[0].Npixels >= 16; graphic[0].Npixels -= 4) {
+	if (DEBUG) fprintf (stderr, "trying %d colors\n", (int) graphic[0].Npixels);
+	if (XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 1, graphic[0].pixels, graphic[0].Npixels)) {
+	  break;
+	}
+      }
 
       if ((N = get_argument (*argc, argv, "-colorcount"))) {
-	fprintf (stderr, "kii can grab %d colors\n", (int) graphic[0].Npixels);
+	fprintf (stderr, "kapa can grab %d colors\n", graphic[0].Npixels);
 	exit (0);
       } 
@@ -174,15 +162,13 @@
       }
     }
-  }
-
-  if (!dyn) {
-    graphic[0].Npixels = 256;
-    // fprintf (stderr, "can't use dynamic colors, color scrollbar inactive\n");
-    // fprintf (stderr, " this can be avoided by using a dynamic visual class\n");
-    // fprintf (stderr, " (see Kii help page for details)\n");
+  } else {
+    // XXX allocate the unsigned long *pixels here and above
+    ALLOCATE (graphic[0].pixels, unsigned long, NPIXELS_STATIC);
+    ALLOCATE (graphic[0].cmap,   XColor,        NPIXELS_STATIC);
+    graphic[0].Npixels = NPIXELS_STATIC;
   }
 
   if ((N = get_argument (*argc, argv, "-colorcount"))) {
-    fprintf (stderr, "kii can grab %d colors\n", (int) graphic[0].Npixels);
+    fprintf (stderr, "kii can grab %d colors\n", graphic[0].Npixels);
     exit (0);
   } 
Index: trunk/Ohana/src/kapa2/src/ColorCube.c
===================================================================
--- trunk/Ohana/src/kapa2/src/ColorCube.c	(revision 16011)
+++ trunk/Ohana/src/kapa2/src/ColorCube.c	(revision 16011)
@@ -0,0 +1,225 @@
+# include "Ximage.h"
+
+/* these functions are used to generate an appropriately-sampled color map for a given image.
+   we assume that only a limited number of colors can be allocated (start with, eg, 1024, grow to
+   64k or so).  the RGB image is constructed from the 32bit images, each with their own zero and
+   scale.  We want to allocate set of color cells which sample the actual colors available in the
+   image data.  We generate a 3D histogram of the actual data values.  The histogram is generated
+   using a k-d tree. */
+
+// the k-d tree is built of a bunch of nodes, each of which represents a cubic region in the 3D
+// color space.  each node may be occupied, or may point to a set of 8 children, subdividing the
+// cube into equal cubes.
+
+// NOTE : nothing in this file specifies a relationship between x,y,z and red,blue,green
+
+// set of operations needed:
+
+// allocate empty, bottom-level node
+CCNode *CCNodeAlloc () {
+
+  CCNode *node;
+  int ix, iy, iz;
+
+  ALLOCATE (node, CCNode, 1);
+  node->count = 0;
+  node->pixel = 0;
+  node->bottom = TRUE;
+  for (ix = 0; ix < 2; ix++) {
+    for (iy = 0; iy < 2; iy++) {
+      for (iz = 0; iz < 2; iz++) {
+	node->sub[ix][iy][iz] = NULL;
+      }
+    }
+  }
+  return node;
+}
+
+// given a coordinate and a containing node, find the corresponding child node (if any)
+CCNode *CCFindChild (CCNode *node, float x, float y, float z) {
+
+  int ix, iy, iz;
+
+  assert (x >= node->min[CC_X]);
+  assert (y >= node->min[CC_Y]);
+  assert (z >= node->min[CC_Z]);
+
+  assert (x <= node->max[CC_X]);
+  assert (y <= node->max[CC_Y]);
+  assert (z <= node->max[CC_Z]);
+
+  if (node->bottom) return NULL; // already at the bottom
+
+  ix = (x < node->mid[CC_X]) ? 0 : 1;
+  iy = (y < node->mid[CC_Y]) ? 0 : 1;
+  iz = (z < node->mid[CC_Z]) ? 0 : 1;
+  
+  return node->sub[ix][iy][iz];
+}
+
+// given a coordinate and a containing node, find the corresponding child node (if any)
+int CCSplitNode (CCNode *node) {
+
+  CCNode *child;
+  int ix, iy, iz;
+
+  // trying to split an already split node
+  if (!node->bottom) return FALSE;
+
+  node->bottom = FALSE;
+  for (ix = 0; ix < 2; ix++) {
+    for (iy = 0; iy < 2; iy++) {
+      for (iz = 0; iz < 2; iz++) {
+	child = CCNodeAlloc();
+	child->min[CC_X] = (ix == 0) ? node->min[CC_X] : node->mid[CC_X];
+	child->min[CC_Y] = (iy == 0) ? node->min[CC_Y] : node->mid[CC_Y];
+	child->min[CC_Z] = (iz == 0) ? node->min[CC_Z] : node->mid[CC_Z];
+	child->max[CC_X] = (ix == 0) ? node->mid[CC_X] : node->max[CC_X];
+	child->max[CC_Y] = (iy == 0) ? node->mid[CC_Y] : node->max[CC_Y];
+	child->max[CC_Z] = (iz == 0) ? node->mid[CC_Z] : node->max[CC_Z];
+
+	child->mid[CC_X] = 0.5*(child->min[CC_X] + child->max[CC_X]);
+	child->mid[CC_Y] = 0.5*(child->min[CC_Y] + child->max[CC_Y]);
+	child->mid[CC_Z] = 0.5*(child->min[CC_Z] + child->max[CC_Z]);
+
+	node->sub[ix][iy][iz] = child;
+      }
+    }
+  }
+  return TRUE;
+}
+
+int CCSplitNodeIterate (CCNode *node, int current, int max) {
+
+  int ix, iy, iz;
+
+  if (current == max) return;
+  current ++;
+
+  CCSplitNode (node);
+  for (ix = 0; ix < 2; ix++) {
+    for (iy = 0; iy < 2; iy++) {
+      for (iz = 0; iz < 2; iz++) {
+	CCSplitNodeIterate (node->sub[ix][iy][iz], current, max);
+      }
+    }
+  }
+  return;
+}
+
+// allocate empty, bottom-level node
+void CCNodeFree (CCNode *node) {
+
+  int ix, iy, iz;
+
+  for (ix = 0; ix < 2; ix++) {
+    for (iy = 0; iy < 2; iy++) {
+      for (iz = 0; iz < 2; iz++) {
+	if (node->sub[ix][iy][iz]) CCNodeFree (node->sub[ix][iy][iz]);
+      }
+    }
+  }
+  free (node);
+  return;
+}
+
+// given a coordinate and a containing node, find the corresponding child node (if any)
+CCNode *CCFindBottom (CCNode *top, float x, float y, float z) {
+
+  CCNode *node;
+  CCNode *next;
+
+  assert (x >= top->min[CC_X]);
+  assert (y >= top->min[CC_Y]);
+  assert (z >= top->min[CC_Z]);
+
+  assert (x <= top->max[CC_X]);
+  assert (y <= top->max[CC_Y]);
+  assert (z <= top->max[CC_Z]);
+
+  node = top;
+  next = CCFindChild (node, x, y, z);
+  while (next != NULL) {
+    node = next;
+    next = CCFindChild (node, x, y, z);
+  }
+
+  return node;
+}
+
+// iterate over the CCNode tree to generate a single, 1d vector of all data values
+// XXX this function is specific to the color histogram concept
+int CCNodeExtractCounts (CCNode *node, float **values, int *nvalues, int *NVALUES) {
+
+  int ix, iy, iz;
+
+  if (*values == NULL) {
+    nvalues[0] = 0;
+    NVALUES[0] = 32;
+    ALLOCATE (*values, float, NVALUES[0]);
+  }
+
+  if (node->bottom) {
+    values[0][nvalues[0]] = node->count;
+    nvalues[0] ++;
+    if (nvalues[0] >= NVALUES[0]) {
+      NVALUES[0] += 32;
+      REALLOCATE (*values, float, NVALUES[0]);
+    }
+    return TRUE;
+  }
+  
+  for (ix = 0; ix < 2; ix++) {
+    for (iy = 0; iy < 2; iy++) {
+      for (iz = 0; iz < 2; iz++) {
+	CCNodeExtractCounts (node->sub[ix][iy][iz], values, nvalues, NVALUES);
+      }
+    }
+  }
+  return TRUE;
+}
+
+// iterate over the CCNode tree and subdivide any bottom level nodes with value > minValue
+// XXX this function is specific to the color histogram concept
+int CCNodeDivideLimit (CCNode *node, float minValue) {
+
+  int ix, iy, iz;
+
+  if (node->bottom) {
+    if (node->count > minValue) {
+      CCSplitNode (node);
+    }
+    return TRUE;
+  }
+  
+  for (ix = 0; ix < 2; ix++) {
+    for (iy = 0; iy < 2; iy++) {
+      for (iz = 0; iz < 2; iz++) {
+	CCNodeDivideLimit (node->sub[ix][iy][iz], minValue);
+      }
+    }
+  }
+  return TRUE;
+}
+
+// iterate over the CCNode tree and subdivide any bottom level nodes with value > minValue
+// XXX this function is specific to the color histogram concept
+int CCNodeInitCounts (CCNode *node, float value) {
+
+  int ix, iy, iz;
+
+  if (node->bottom) {
+    node->count = value;
+    return TRUE;
+  }
+  
+  for (ix = 0; ix < 2; ix++) {
+    for (iy = 0; iy < 2; iy++) {
+      for (iz = 0; iz < 2; iz++) {
+	CCNodeInitCounts (node->sub[ix][iy][iz], value);
+      }
+    }
+  }
+  return TRUE;
+}
+
Index: trunk/Ohana/src/kapa2/src/ColorHistogram.c
===================================================================
--- trunk/Ohana/src/kapa2/src/ColorHistogram.c	(revision 16011)
+++ trunk/Ohana/src/kapa2/src/ColorHistogram.c	(revision 16011)
@@ -0,0 +1,188 @@
+# include "Ximage.h"
+
+// in 3D we use channels 0,1,2 to choose the pixel from the cube
+void ColorHistogram (KapaImageWidget *image, CCNode *cube) {
+
+  int i, j, DX, DY, value, nPixels;
+  float *rData, *bData, *gData, rValue, gValue, bValue;
+  float redSlope, blueSlope, greenSlope;
+  float redStart, blueStart, greenStart;
+  CCNode *node;
+
+  // Input images are scaled to 0.0 - 1.0 floating point range.  These values are accumulated in the
+  // 3d histogram.  Use the histogram to allocate colors or subdivide the top-populated histogram
+  // cells and re-evaluated.   
+
+  // set start & slope for red (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_RED].range != 0.0) {
+    redSlope = 1.0 / image[0].channel[KAPA_CHANNEL_RED].range;
+    redStart = image[0].channel[KAPA_CHANNEL_RED].zero / image[0].channel[KAPA_CHANNEL_RED].range;
+  } else {
+    redSlope = 1.0;
+    redStart = image[0].channel[KAPA_CHANNEL_RED].zero;
+  }
+  // set start & slope for blue (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_BLUE].range != 0.0) {
+    blueSlope = 1.0 / image[0].channel[KAPA_CHANNEL_BLUE].range;
+    blueStart = image[0].channel[KAPA_CHANNEL_BLUE].zero / image[0].channel[KAPA_CHANNEL_BLUE].range;
+  } else {
+    blueSlope = 1.0;
+    blueStart = image[0].channel[KAPA_CHANNEL_BLUE].zero;
+  }
+  // set start & slope for green (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_GREEN].range != 0.0) {
+    greenSlope = 1.0 / image[0].channel[KAPA_CHANNEL_GREEN].range;
+    greenStart = image[0].channel[KAPA_CHANNEL_GREEN].zero / image[0].channel[KAPA_CHANNEL_GREEN].range;
+  } else {
+    greenSlope = 1.0;
+    greenStart = image[0].channel[KAPA_CHANNEL_GREEN].zero;
+  }
+
+  DX = image[0].channel[KAPA_CHANNEL_GREEN].matrix.Naxis[0];
+  DY = image[0].channel[KAPA_CHANNEL_GREEN].matrix.Naxis[1];
+  // XXX check on equal size for all three channels
+
+  nPixels = DX*DY;
+
+  // loop over pixels, convert data values to range values (0.0 - 1.0), increment 3D histogram cell
+  rData = (float *) image[0].channel[KAPA_CHANNEL_RED].matrix.buffer;
+  bData = (float *) image[0].channel[KAPA_CHANNEL_BLUE].matrix.buffer;
+  gData = (float *) image[0].channel[KAPA_CHANNEL_GREEN].matrix.buffer;
+
+  // convert pixel data values to pixel index values (0 - Npixel)
+  for (i = 0; i < nPixels; i++, rData++, bData++, gData++) {
+    rValue = *rData * redSlope   - redStart;
+    if (rValue < 0.0) rValue = 0.0;
+    if (rValue > 1.0) rValue = 1.0;
+    if (isnan(rValue)) rValue = 0.0;
+    if (isinf(rValue)) rValue = 1.0;
+
+    bValue = *bData * blueSlope  - blueStart;
+    if (bValue < 0.0) bValue = 0.0;
+    if (bValue > 1.0) bValue = 1.0;
+    if (isnan(bValue)) bValue = 0.0;
+    if (isinf(bValue)) bValue = 1.0;
+
+    gValue = *gData * greenSlope - greenStart;
+    if (gValue < 0.0) gValue = 0.0;
+    if (gValue > 1.0) gValue = 1.0;
+    if (isnan(gValue)) gValue = 0.0;
+    if (isinf(gValue)) gValue = 1.0;
+
+    // XXX at the moment, we are saturating before supplying to this function
+    // NOTE : x,y,z = red,green,blue
+    node = CCFindBottom (cube, rValue, gValue, bValue);
+    node->count ++;
+  }
+}
+
+// in 3D we use channels 0,1,2 to choose the pixel from the cube
+void CCNodeSetColorPixels (KapaImageWidget *image, CCNode *cube) {
+
+  int i, j, DX, DY, value, nPixels;
+  float *rData, *bData, *gData, rValue, gValue, bValue;
+  unsigned short *oData;
+  float redSlope, blueSlope, greenSlope;
+  float redStart, blueStart, greenStart;
+  CCNode *node;
+
+  // Input images are scaled to 0.0 - 1.0 floating point range.  These values are accumulated in the
+  // 3d histogram.  Use the histogram to allocate colors or subdivide the top-populated histogram
+  // cells and re-evaluated.   
+
+  // set start & slope for red (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_RED].range != 0.0) {
+    redSlope = 1.0 / image[0].channel[KAPA_CHANNEL_RED].range;
+    redStart = image[0].channel[KAPA_CHANNEL_RED].zero / image[0].channel[KAPA_CHANNEL_RED].range;
+  } else {
+    redSlope = 1.0;
+    redStart = image[0].channel[KAPA_CHANNEL_RED].zero;
+  }
+  // set start & slope for blue (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_BLUE].range != 0.0) {
+    blueSlope = 1.0 / image[0].channel[KAPA_CHANNEL_BLUE].range;
+    blueStart = image[0].channel[KAPA_CHANNEL_BLUE].zero / image[0].channel[KAPA_CHANNEL_BLUE].range;
+  } else {
+    blueSlope = 1.0;
+    blueStart = image[0].channel[KAPA_CHANNEL_BLUE].zero;
+  }
+  // set start & slope for green (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_GREEN].range != 0.0) {
+    greenSlope = 1.0 / image[0].channel[KAPA_CHANNEL_GREEN].range;
+    greenStart = image[0].channel[KAPA_CHANNEL_GREEN].zero / image[0].channel[KAPA_CHANNEL_GREEN].range;
+  } else {
+    greenSlope = 1.0;
+    greenStart = image[0].channel[KAPA_CHANNEL_GREEN].zero;
+  }
+
+  DX = image[0].channel[KAPA_CHANNEL_GREEN].matrix.Naxis[0];
+  DY = image[0].channel[KAPA_CHANNEL_GREEN].matrix.Naxis[1];
+  // XXX check on equal size for all three channels
+
+  nPixels = DX*DY;
+  if (image[0].nPixels != nPixels) {
+    REALLOCATE (image[0].pixmap, unsigned short, nPixels);
+    image[0].nPixels = nPixels;
+  }
+
+  // loop over pixels, convert data values to range values (0.0 - 1.0), increment 3D histogram cell
+  rData = (float *) image[0].channel[KAPA_CHANNEL_RED].matrix.buffer;
+  bData = (float *) image[0].channel[KAPA_CHANNEL_BLUE].matrix.buffer;
+  gData = (float *) image[0].channel[KAPA_CHANNEL_GREEN].matrix.buffer;
+
+  oData = image[0].pixmap;
+
+  // convert pixel data values to pixel index values (0 - Npixel)
+  for (i = 0; i < nPixels; i++, rData++, bData++, gData++, oData++) {
+    rValue = *rData * redSlope   - redStart;
+    if (rValue < 0.0) rValue = 0.0;
+    if (rValue > 1.0) rValue = 1.0;
+    if (isnan(rValue)) rValue = 0.0;
+    if (isinf(rValue)) rValue = 1.0;
+
+    bValue = *bData * blueSlope  - blueStart;
+    if (bValue < 0.0) bValue = 0.0;
+    if (bValue > 1.0) bValue = 1.0;
+    if (isnan(bValue)) bValue = 0.0;
+    if (isinf(bValue)) bValue = 1.0;
+
+    gValue = *gData * greenSlope - greenStart;
+    if (gValue < 0.0) gValue = 0.0;
+    if (gValue > 1.0) gValue = 1.0;
+    if (isnan(gValue)) gValue = 0.0;
+    if (isinf(gValue)) gValue = 1.0;
+
+    // XXX at the moment, we are saturating before supplying to this function
+    // NOTE : x,y,z = red,green,blue 
+    node = CCFindBottom (cube, rValue, gValue, bValue);
+    *oData = node->pixel;
+  }
+}
+
+// iterate over the CCNode tree and subdivide any bottom level nodes with value > minValue
+// XXX this function is specific to the color histogram concept
+// NOTE : x,y,z = red,green,blue 
+int CCNodeSetColorMap (CCNode *node, XColor *cmap, int Npixels, int *current) {
+
+  int ix, iy, iz;
+
+  if (node->bottom) {
+    cmap[current[0]].red   = node->mid[CC_X]*0xffff;
+    cmap[current[0]].green = node->mid[CC_Y]*0xffff;
+    cmap[current[0]].blue  = node->mid[CC_Z]*0xffff;
+    cmap[current[0]].flags = DoRed | DoGreen | DoBlue;
+    node->pixel = current[0];
+    current[0] ++;
+    assert (current[0] <= Npixels);
+    return TRUE;
+  }
+  
+  for (ix = 0; ix < 2; ix++) {
+    for (iy = 0; iy < 2; iy++) {
+      for (iz = 0; iz < 2; iz++) {
+	CCNodeSetColorMap (node->sub[ix][iy][iz], cmap, Npixels, current);
+      }
+    }
+  }
+  return TRUE;
+}
Index: trunk/Ohana/src/kapa2/src/CreateZoom16.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CreateZoom16.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CreateZoom16.c	(revision 16011)
@@ -31,5 +31,5 @@
   dy = image[0].zoom.dy;
 
-  if (image[0].matrix.size == 0) {  /* create a test pattern */
+  if (image[0].image[0].matrix.size == 0) {  /* create a test pattern */
     REALLOCATE (image[0].zoom.data, char, 2*dy*dx);
     bzero (image[0].zoom.data, image[0].zoom.dx*image[0].zoom.dy);
@@ -48,10 +48,10 @@
   // define the color transform parameters
   MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
+  if (image[0].image[0].range != 0.0) {
+    slope = graphic[0].Npixels / image[0].image[0].range;
+    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
   } else {
     slope = 1.0;
-    start = image[0].zero;
+    start = image[0].image[0].zero;
   }
 
@@ -61,6 +61,6 @@
   expand_in  = 1;
 
-  DX = image[0].matrix.Naxis[0];
-  DY = image[0].matrix.Naxis[1];
+  DX = image[0].image[0].matrix.Naxis[0];
+  DY = image[0].image[0].matrix.Naxis[1];
   Rx = x - expand*(int)(0.5*(dx + 1)) + 1;
   Ry = y - expand*(int)(0.5*(dy + 1)) + 1;
@@ -74,5 +74,5 @@
 
   data = out_pix = (unsigned char *) image[0].zoom.data;
-  imdata  = (float *) image[0].matrix.buffer;
+  imdata  = (float *) image[0].image[0].matrix.buffer;
   in_pix  = &imdata[DX*(int)MAX(Ry,0) + (int)MAX(Rx,0)];
 
Index: trunk/Ohana/src/kapa2/src/CreateZoom24.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CreateZoom24.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CreateZoom24.c	(revision 16011)
@@ -32,5 +32,5 @@
   extra = 4 - (dx * 3) % 4;
 
-  if (image[0].matrix.size == 0) {  /* create a test pattern */
+  if (image[0].image[0].matrix.size == 0) {  /* create a test pattern */
     REALLOCATE (image[0].zoom.data, char, dy*(3*dx+extra));
     bzero (image[0].zoom.data, image[0].zoom.dx*image[0].zoom.dy);
@@ -52,10 +52,10 @@
   // define the color transform parameters
   MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
+  if (image[0].image[0].range != 0.0) {
+    slope = graphic[0].Npixels / image[0].image[0].range;
+    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
   } else {
     slope = 1.0;
-    start = image[0].zero;
+    start = image[0].image[0].zero;
   }
 
@@ -65,6 +65,6 @@
   expand_in  = 1;
 
-  DX = image[0].matrix.Naxis[0];
-  DY = image[0].matrix.Naxis[1];
+  DX = image[0].image[0].matrix.Naxis[0];
+  DY = image[0].image[0].matrix.Naxis[1];
   Rx = x - expand*(int)(0.5*(dx + 1)) + 1;
   Ry = y - expand*(int)(0.5*(dy + 1)) + 1;
@@ -78,5 +78,5 @@
 
   data = out_pix = (unsigned char *) image[0].zoom.data;
-  imdata  = (float *) image[0].matrix.buffer;
+  imdata  = (float *) image[0].image[0].matrix.buffer;
   in_pix  = &imdata[DX*(int)MAX(Ry,0) + (int)MAX(Rx,0)];
 
Index: trunk/Ohana/src/kapa2/src/CreateZoom32.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CreateZoom32.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CreateZoom32.c	(revision 16011)
@@ -1,15 +1,4 @@
 # include "Ximage.h"
 # define FRAC(a) ((a) - (int)(a))
-
-static float slope = 1.0;
-static float start = 0.0;
-static int MaxValue = 255;
-
-// XXX inline this if needed
-static int PixelLookup(float value) {
-  int out;
-  out = MIN (MAX (slope * value - start, 0), MaxValue);
-  return (out);
-}
 
 void CreateZoom32 (KapaImageWidget *image, Graphic *graphic, double x, double y) {
@@ -22,9 +11,9 @@
   int expand_in, expand_out;
   unsigned int *out_pix, *out_pix2;
-  float *imdata, *in_pix, *in_pix2;
-  unsigned long pixel[256], pixvalue;
+  unsigned short *in_pix, *in_pix2;
+  unsigned long *pixel, pixvalue;
   unsigned long back;
 
-  if (image[0].matrix.size == 0) {  /* create a test pattern */
+  if (image[0].image[0].matrix.size == 0) {  /* create a test pattern */
     REALLOCATE (image[0].zoom.data, char, 4*image[0].zoom.dx*image[0].zoom.dy);
     image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
@@ -33,18 +22,11 @@
   }
 
-  for (i = 0; i < 256; i++) { /* set up pixel array */
+  ALLOCATE (pixel, unsigned long, graphic[0].Npixels);
+
+  // local array for pixel values
+  for (i = 0; i < graphic[0].Npixels; i++) { 
     pixel[i] = graphic[0].cmap[i].pixel;
   }
   back = graphic[0].back;
-
-  // define the color transform parameters
-  MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
-  } else {
-    slope = 1.0;
-    start = image[0].zero;
-  }
 
   zoomscale = MAX (5, image[0].expand + 5);
@@ -55,6 +37,8 @@
   dx = image[0].zoom.dx;
   dy = image[0].zoom.dy;
-  DX = image[0].matrix.Naxis[0];
-  DY = image[0].matrix.Naxis[1];
+  DX = image[0].image[0].matrix.Naxis[0];
+  DY = image[0].image[0].matrix.Naxis[1];
+  
+  /* Rx,Ry are the screen coordinates of the first image pixel */
   Rx = x - expand*(int)(0.5*(dx + 1)) + 1;
   Ry = y - expand*(int)(0.5*(dy + 1)) + 1;
@@ -64,10 +48,10 @@
   i_end   = MAX (MIN ((DX-Rx) / expand, dx - expand_out + 1), 0);
   j_end   = MAX (MIN ((DY-Ry) / expand, dy - expand_out + 1), 0);
+
   dropback = expand_out - (i_end - i_start) % expand_out;
   if ((i_end - i_start) % expand_out == 0) dropback = 0;
 
   out_pix = (unsigned int *) image[0].zoom.data;
-  imdata  = (float *) image[0].matrix.buffer;
-  in_pix  = &imdata[DX*(int)MAX(Ry,0) + (int)MAX(Rx,0)];
+  in_pix  = &image[0].pixmap[DX*(int)MAX(Ry,0) + (int)MAX(Rx,0)];
 
   /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
@@ -78,9 +62,9 @@
     return;
   } 
-  
+ 
 
   /**** fill in bottom area ****/
   for (j = 0; j < dx*j_start; j++, out_pix++) {
-    out_pix[0] = back;
+    *out_pix = back;
   }
 
@@ -88,8 +72,8 @@
 
     /**** fill in area to the left of the picture ****/
-    for (jj = 0; jj < expand_out; jj++) { 
+    for (jj = 0; (i_start > 0) && (jj < expand_out); jj++) { 
       out_pix2 = out_pix + jj*dx;
       for (i = 0; i < i_start; i++, out_pix2++) {
-	out_pix[0] = back;
+	*out_pix2 = back;
       }
     }
@@ -100,16 +84,13 @@
     if (expand_out == 1) {
       for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix++) {
-	pixelN = PixelLookup(*in_pix2);
-	out_pix[0] = pixel[pixelN];
+	*out_pix = pixel[*in_pix2];
       }
-    }
-    else {
+    } else {
       for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= expand_out) { 
-	pixelN   = PixelLookup(*in_pix2);
-	pixvalue = pixel[pixelN];
+	pixvalue = pixel[*in_pix2];
 	out_pix2 = out_pix;
 	for (jj = 0; jj < expand_out; jj++, out_pix2+=(dx-expand_out)) {
 	  for (ii = 0; ii < expand_out; ii++, out_pix2++) {
-	    out_pix2[0] = pixvalue; 
+	    *out_pix2 = pixvalue; 
 	  }
 	}
@@ -117,5 +98,4 @@
     }
     out_pix -= dropback;
-
     
     /**** fill in area to the right of the picture ****/
@@ -123,5 +103,5 @@
       out_pix2 = out_pix + jj*dx;
       for (i = i_end; i < dx; i++, out_pix2++) {
-	out_pix2[0] = back;
+	*out_pix2 = back;
       }
     }
@@ -134,10 +114,10 @@
   /**** fill in top area ****/
   for (j = 0; (j < dx*(dy - j_end)) && (out_pix - (unsigned int *)image[0].zoom.data < dx*dy); j++, out_pix++) { 
-    out_pix[0] = back;
+    *out_pix = back;
   }
 
-  out_pix = (unsigned int *)image[0].zoom.data;
   image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
 					image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 32, 0);
   
+  free (pixel);
 }
Index: trunk/Ohana/src/kapa2/src/CreateZoom8.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CreateZoom8.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CreateZoom8.c	(revision 16011)
@@ -26,5 +26,5 @@
   unsigned long back;
 
-  if (image[0].matrix.size == 0) {  /* create a test pattern */
+  if (image[0].image[0].matrix.size == 0) {  /* create a test pattern */
     REALLOCATE (image[0].zoom.data, char, image[0].zoom.dx*image[0].zoom.dy);
     bzero (image[0].zoom.data, image[0].zoom.dx*image[0].zoom.dy);
@@ -41,10 +41,10 @@
   // define the color transform parameters
   MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
+  if (image[0].image[0].range != 0.0) {
+    slope = graphic[0].Npixels / image[0].image[0].range;
+    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
   } else {
     slope = 1.0;
-    start = image[0].zero;
+    start = image[0].image[0].zero;
   }
 
@@ -56,6 +56,6 @@
   dx = image[0].zoom.dx;
   dy = image[0].zoom.dy;
-  DX = image[0].matrix.Naxis[0];
-  DY = image[0].matrix.Naxis[1];
+  DX = image[0].image[0].matrix.Naxis[0];
+  DY = image[0].image[0].matrix.Naxis[1];
   Rx = x - expand*(int)(0.5*(dx + 1)) + 1;
   Ry = y - expand*(int)(0.5*(dy + 1)) + 1;
@@ -69,5 +69,5 @@
 
   out_pix = (unsigned char *) image[0].zoom.data;
-  imdata  = (float *) image[0].matrix.buffer;
+  imdata  = (float *) image[0].image[0].matrix.buffer;
   in_pix  = &imdata[DX*(int)MAX(Ry,0) + (int)MAX(Rx,0)];
 
Index: trunk/Ohana/src/kapa2/src/CursorOps.c
===================================================================
--- trunk/Ohana/src/kapa2/src/CursorOps.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/CursorOps.c	(revision 16011)
@@ -13,6 +13,6 @@
   }
   
-  *x1 = expand*(x2 - image[0].picture.x - 0.5*image[0].picture.dx) + 0.5*image[0].matrix.Naxis[0] - image[0].X;
-  *y1 = expand*(y2 - image[0].picture.y - 0.5*image[0].picture.dy) + 0.5*image[0].matrix.Naxis[1] - image[0].Y;
+  *x1 = expand*(x2 - image[0].picture.x - 0.5*image[0].picture.dx) + 0.5*image[0].image[0].matrix.Naxis[0] - image[0].X;
+  *y1 = expand*(y2 - image[0].picture.y - 0.5*image[0].picture.dy) + 0.5*image[0].image[0].matrix.Naxis[1] - image[0].Y;
   
 }
@@ -31,6 +31,6 @@
   }
   
-  *x1 = (x2 - 0.5*image[0].matrix.Naxis[0] + image[0].X) * expand + image[0].picture.x + 0.5*image[0].picture.dx;
-  *y1 = (y2 - 0.5*image[0].matrix.Naxis[1] + image[0].Y) * expand + image[0].picture.y + 0.5*image[0].picture.dy;
+  *x1 = (x2 - 0.5*image[0].image[0].matrix.Naxis[0] + image[0].X) * expand + image[0].picture.x + 0.5*image[0].picture.dx;
+  *y1 = (y2 - 0.5*image[0].image[0].matrix.Naxis[1] + image[0].Y) * expand + image[0].picture.y + 0.5*image[0].picture.dy;
   
 }
Index: trunk/Ohana/src/kapa2/src/DragColorbar.c
===================================================================
--- trunk/Ohana/src/kapa2/src/DragColorbar.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/DragColorbar.c	(revision 16011)
@@ -15,6 +15,6 @@
   Y = mouse_event[0].y;
   Npix = graphic[0].Npixels;
-  slope = image[0].slope;
-  start = image[0].start;
+  slope = image[0].image[0].slope;
+  start = image[0].image[0].start;
   oldfrac_x = oldfrac_y = 10;
   
@@ -63,6 +63,6 @@
       case ButtonPress:
       case ButtonRelease:
-	image[0].start = start;	
-	image[0].slope = slope;
+	image[0].image[0].start = start;	
+	image[0].image[0].slope = slope;
 	return;
 	break;
Index: trunk/Ohana/src/kapa2/src/Image.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Image.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/Image.c	(revision 16011)
@@ -2,6 +2,21 @@
 # include "buttons.h"
 
+int InitImageChannel (KapaImageChannel *channel) {
+
+  /** set up a bunch of default things **/
+  channel->zero = 0;
+  channel->range = 1;
+  channel->start = 0;
+  channel->slope = 1;
+
+  channel->coords.Npolyterms = 0;
+  channel->matrix.size = 0; /* a flag to show there is no data in the matrix */
+  ALLOCATE (channel->matrix.buffer, char, 1);  /* allocate so later free will not crash! */
+
+  return (TRUE);
+}
+
 /* initialization for things not specific to X */
-KapaImageWidget *InitImage () {
+KapaImageWidget *InitImageWidget () {
 
   int i;
@@ -14,14 +29,15 @@
   memset (image, 0, sizeof(KapaImageWidget));
 
-  /** set up a bunch of default things **/
-  image[0].X = image[0].Y = 0;
-  image[0].expand = 1;
-  image[0].zero = 0;
-  image[0].range = 1;
-  image[0].start = 0;
-  image[0].slope = 1;
-  image[0].location = 4;
+  for (i = 0; i < NCHANNELS; i++) {
+    InitImageChannel (&image[0].channel[i]);
+  }
+  image[0].image = &image[0].channel[0];
 
-  image[0].coords.Npolyterms = 0;
+  image[0].nPixels = 0;
+  ALLOCATE (image[0].pixmap, unsigned short, 1);  /* allocate so later free will not crash! */
+
+  // XXXX this has been moved to graphic, which may be wrong
+  // image[0].ColorScaleMode = KAPA_SCALE_1D;
+
   for (i = 0; i < NOVERLAYS; i++) {
     image[0].overlay[i].Nobjects = 0;
@@ -30,9 +46,12 @@
     image[0].overlay[i].color = graphic[0].overlay_color[i];
   }
-  image[0].matrix.size = 0; /* a flag to show there is no data in the matrix */
+
+  image[0].X = 0.0;
+  image[0].Y = 0.0;
+  image[0].expand = 1;
+  image[0].location = 4;
 
   image[0].MovePointer = TRUE;
   image[0].DecimalDegrees  = TRUE;
-  ALLOCATE (image[0].matrix.buffer, char, 1);  /* allocate so later free will not crash! */
   ALLOCATE (image[0].picture.data, char, 1);   /* allocate so later free will not crash! */
   ALLOCATE (image[0].cmapbar.data, char, 1);   /* allocate so later free will not crash! */
@@ -48,6 +67,6 @@
   InitButtonFunc (&image[0].rainbow_button, rainbow);
 
-  InitButtonSize (&image[0].puns_button, puns_width, puns_height, puns_bits);
-  InitButtonFunc (&image[0].puns_button, puns);
+  InitButtonSize (&image[0].heat_button, heat_width, heat_height, heat_bits);
+  InitButtonFunc (&image[0].heat_button, heat);
 
   InitButtonSize (&image[0].recenter_button, recenter_width, recenter_height, recenter_bits);
@@ -131,5 +150,5 @@
     DrawButton (graphic, &image[0].grey_button);
     DrawButton (graphic, &image[0].rainbow_button);
-    DrawButton (graphic, &image[0].puns_button);
+    DrawButton (graphic, &image[0].heat_button);
     DrawButton (graphic, &image[0].hms_button);
 
@@ -152,5 +171,8 @@
     free (image[0].overlay[i].objects);
   }
-  free (image[0].matrix.buffer);
+  for (i = 0; i < NCHANNELS; i++) {
+    free (image[0].channel[i].matrix.buffer);
+  }
+  free (image[0].pixmap);
   free (image[0].picture.data);
   free (image[0].cmapbar.data);
Index: trunk/Ohana/src/kapa2/src/InterpretKeys.c
===================================================================
--- trunk/Ohana/src/kapa2/src/InterpretKeys.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/InterpretKeys.c	(revision 16011)
@@ -61,8 +61,8 @@
       if (event[0].y > image[0].picture.y + image[0].picture.dy) goto skip_cursor;
       Screen_to_Image (&X, &Y, (double)event[0].x, (double)event[0].y, image);
-      XY_to_RD (&R, &D, X, Y, &image[0].coords);
+      XY_to_RD (&R, &D, X, Y, &image[0].image[0].coords);
 
-      DX = image[0].matrix.Naxis[0];
-      DY = image[0].matrix.Naxis[1];
+      DX = image[0].image[0].matrix.Naxis[0];
+      DY = image[0].image[0].matrix.Naxis[1];
 
       if (X < 0) goto off_image;
@@ -70,5 +70,5 @@
       if (X >= DX) goto off_image;
       if (Y >= DY) goto off_image;
-      imdata = (float *) image[0].matrix.buffer;
+      imdata = (float *) image[0].image[0].matrix.buffer;
       Z      = imdata[DX*(int)(Y) + (int)(X)];
     }
@@ -89,4 +89,19 @@
   switch (keysym) {
 
+    case XK_F1:
+      image[0].image = &image[0].channel[0];
+      Reorient (graphic, image, image[0].X, image[0].Y, 0);
+      break;
+
+    case XK_F2:
+      image[0].image = &image[0].channel[1];
+      Reorient (graphic, image, image[0].X, image[0].Y, 0);
+      break;
+
+    case XK_F3:
+      image[0].image = &image[0].channel[2];
+      Reorient (graphic, image, image[0].X, image[0].Y, 0);
+      break;
+
     case XK_KP_Home:
     case XK_Home:
@@ -103,6 +118,6 @@
     case XK_Return:
       Screen_to_Image (&X, &Y, (double)event[0].x, (double)event[0].y, image);
-      X = 0.5*image[0].matrix.Naxis[0] - X;
-      Y = 0.5*image[0].matrix.Naxis[1] - Y;
+      X = 0.5*image[0].image[0].matrix.Naxis[0] - X;
+      Y = 0.5*image[0].image[0].matrix.Naxis[1] - Y;
       Reorient (graphic, image, X, Y, 0);
       break;
@@ -132,4 +147,13 @@
       break;
 
+    case XK_KP_Add:
+      image[0].image[0].zero += 0.1*image[0].image[0].range;
+      Reorient (graphic, image, image[0].X, image[0].Y, 0);
+      break;
+    case XK_KP_Subtract:
+      image[0].image[0].zero -= 0.1*image[0].image[0].range;
+      Reorient (graphic, image, image[0].X, image[0].Y, 0);
+      break;
+
     case XK_Tab:
       image[0].MovePointer = image[0].MovePointer ^ TRUE;
Index: trunk/Ohana/src/kapa2/src/InterpretPresses.c
===================================================================
--- trunk/Ohana/src/kapa2/src/InterpretPresses.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/InterpretPresses.c	(revision 16011)
@@ -36,8 +36,8 @@
       Screen_to_Image (&X, &Y, (double)event[0].x, (double)event[0].y, image);
 
-      XY_to_RD (&R, &D, X, Y, &image[0].coords);
+      XY_to_RD (&R, &D, X, Y, &image[0].image[0].coords);
 
-      DX = image[0].matrix.Naxis[0];
-      DY = image[0].matrix.Naxis[1];
+      DX = image[0].image[0].matrix.Naxis[0];
+      DY = image[0].image[0].matrix.Naxis[1];
 
       if (X < 0) goto off_image;
@@ -45,5 +45,5 @@
       if (X >= DX) goto off_image;
       if (Y >= DY) goto off_image;
-      imdata = (float *) image[0].matrix.buffer;
+      imdata = (float *) image[0].image[0].matrix.buffer;
       Z      = imdata[DX*(int)(Y) + (int)(X)];
     }
@@ -102,6 +102,6 @@
 
   Screen_to_Image (&X, &Y, (double)mouse_event[0].x, (double)mouse_event[0].y, image);
-  X = 0.5*image[0].matrix.Naxis[0] - X;
-  Y = 0.5*image[0].matrix.Naxis[1] - Y;
+  X = 0.5*image[0].image[0].matrix.Naxis[0] - X;
+  Y = 0.5*image[0].image[0].matrix.Naxis[1] - Y;
 
   switch (mouse_event[0].button) {
Index: trunk/Ohana/src/kapa2/src/JPEGit24.c
===================================================================
--- trunk/Ohana/src/kapa2/src/JPEGit24.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/JPEGit24.c	(revision 16011)
@@ -37,6 +37,6 @@
   double expand, Rx, Ry, X, Y;
   unsigned char *out_pix;
-  float *imdata, *in_pix, *in_pix_ref;
-  unsigned char pixel1[256], pixel2[256], pixel3[256];
+  unsigned short *in_pix, *in_pix_ref;
+  unsigned char *pixel1, *pixel2, *pixel3;
   char filename[1024];
   FILE *f;
@@ -75,19 +75,13 @@
   jpeg_start_compress (&cinfo, TRUE);
 
+  ALLOCATE (pixel1, unsigned char, graphic[0].Npixels);
+  ALLOCATE (pixel2, unsigned char, graphic[0].Npixels);
+  ALLOCATE (pixel3, unsigned char, graphic[0].Npixels);
+
   /** cmap[i].pixel must be defined even if X is not used **/
-  for (i = 0; i < 256; i++) { /* set up pixel array */
+  for (i = 0; i < graphic[0].Npixels; i++) { /* set up pixel array */
     pixel1[i] = graphic[0].cmap[i].red >> 8;
     pixel2[i] = graphic[0].cmap[i].green >> 8;
     pixel3[i] = graphic[0].cmap[i].blue >> 8;
-  }
-
-  // define the color transform parameters
-  MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
-  } else {
-    slope = 1.0;
-    start = image[0].zero;
   }
 
@@ -108,6 +102,6 @@
   dx = image[0].picture.dx;
   dy = image[0].picture.dy;
-  DX = image[0].matrix.Naxis[0];
-  DY = image[0].matrix.Naxis[1];
+  DX = image[0].image[0].matrix.Naxis[0];
+  DY = image[0].image[0].matrix.Naxis[1];
 
   /* X,Y are the image coordinates of the first image pixel */
@@ -145,6 +139,5 @@
   ALLOCATE (line_buffer, JSAMPLE, 3*dx);
 
-  imdata = (float *) image[0].matrix.buffer;
-  in_pix_ref = &imdata[DX*(int)MAX(Y,0) + (int)MAX(X,0)];
+  in_pix_ref  = &image[0].pixmap[DX*(int)MAX(Y,0) + (int)MAX(X,0)];
 
   /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
@@ -177,9 +170,8 @@
     /*** fill in the picture region ***/
     for (i = i_start; i < i_end; i+=expand_out, in_pix+=expand_in) {
-      pixelN = PixelLookup(*in_pix);
       for (ii = 0; ii < expand_out; ii++, out_pix+=3) {
-	out_pix[0] = pixel1[pixelN];
-	out_pix[1] = pixel2[pixelN];
-	out_pix[2] = pixel3[pixelN];
+	out_pix[0] = pixel1[*in_pix];
+	out_pix[1] = pixel2[*in_pix];
+	out_pix[2] = pixel3[*in_pix];
       }
     }
Index: trunk/Ohana/src/kapa2/src/LoadOverlay.c
===================================================================
--- trunk/Ohana/src/kapa2/src/LoadOverlay.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/LoadOverlay.c	(revision 16011)
@@ -14,5 +14,5 @@
   section = GetActiveSection();
   if (section->image == NULL) {
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
     SetSectionSizes (section);
   }
Index: trunk/Ohana/src/kapa2/src/LoadPicture.c
===================================================================
--- trunk/Ohana/src/kapa2/src/LoadPicture.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/LoadPicture.c	(revision 16011)
@@ -13,5 +13,5 @@
   section = GetActiveSection();
   if (section->image == NULL) {
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
     SetSectionSizes (section);
   }
@@ -24,19 +24,19 @@
   KiiScanMessage (sock, "%d %d %d %d %lf %lf", &header.Naxis[0], &header.Naxis[1]);
   KiiScanMessage (sock, "%d %d %d %d %lf %lf", &header.bitpix, &header.unsign, &header.bzero, &header.bscale);
-  KiiScanMessage (sock, "%lf %lf %s %s",  &image[0].zero, &image[0].range, image[0].name, image[0].file);
-  KiiScanMessage (sock, "%lf %lf %d", &image[0].min,  &image[0].max, &header.size);
-  KiiScanMessage (sock, "%lf %f %f %f %f", &image[0].coords.crval1, &image[0].coords.crpix1, &image[0].coords.cdelt1, &image[0].coords.pc1_1, &image[0].coords.pc1_2);
-  KiiScanMessage (sock, "%lf %f %f %f %f", &image[0].coords.crval2, &image[0].coords.crpix2, &image[0].coords.cdelt2, &image[0].coords.pc2_1, &image[0].coords.pc2_2);
-  KiiScanMessage (sock, "%s", image[0].coords.ctype);
+  KiiScanMessage (sock, "%lf %lf %s %s",  &image[0].image[0].zero, &image[0].image[0].range, image[0].image[0].name, image[0].image[0].file);
+  KiiScanMessage (sock, "%lf %lf %d", &image[0].image[0].min,  &image[0].image[0].max, &header.size);
+  KiiScanMessage (sock, "%lf %f %f %f %f", &image[0].image[0].coords.crval1, &image[0].image[0].coords.crpix1, &image[0].image[0].coords.cdelt1, &image[0].image[0].coords.pc1_1, &image[0].image[0].coords.pc1_2);
+  KiiScanMessage (sock, "%lf %f %f %f %f", &image[0].image[0].coords.crval2, &image[0].image[0].coords.crpix2, &image[0].image[0].coords.cdelt2, &image[0].image[0].coords.pc2_1, &image[0].image[0].coords.pc2_2);
+  KiiScanMessage (sock, "%s", image[0].image[0].coords.ctype);
 
-  gfits_free_matrix (&image[0].matrix);
-  gfits_create_matrix (&header, &image[0].matrix);
+  gfits_free_matrix (&image[0].image[0].matrix);
+  gfits_create_matrix (&header, &image[0].image[0].matrix);
 
   fcntl (sock, F_SETFL, O_NONBLOCK);  
 
   status = 1;
-  buff = image[0].matrix.buffer;
+  buff = image[0].image[0].matrix.buffer;
   bytes_left = header.size;
-  image[0].matrix.size = 0;
+  image[0].image[0].matrix.size = 0;
   while (bytes_left > 0) {
     status = read (sock, buff, bytes_left);
@@ -46,5 +46,5 @@
     }
     if (status != -1) { /* pipe has data */
-      image[0].matrix.size += status;
+      image[0].image[0].matrix.size += status;
       bytes_left -= status;
       buff = (char *)(buff + status);
@@ -54,8 +54,8 @@
   fcntl (sock, F_SETFL, !O_NONBLOCK);  
 
-  if (DEBUG) fprintf (stderr, "read %d bytes\n", image[0].matrix.size);
+  if (DEBUG) fprintf (stderr, "read %d bytes\n", image[0].image[0].matrix.size);
   /* it it not obvious this condition should kill kii, but ... */
-  if (image[0].matrix.size != header.size) {  
-    fprintf (stderr, "error: expected %d bytes, but got only %d\n", header.size, image[0].matrix.size);
+  if (image[0].image[0].matrix.size != header.size) {  
+    fprintf (stderr, "error: expected %d bytes, but got only %d\n", header.size, image[0].image[0].matrix.size);
     return (FALSE);
   }
@@ -63,5 +63,6 @@
   if (!USE_XWINDOW) return (TRUE);
 
-  Remap (graphic, image, &image[0].matrix);
+  SetColorScale (graphic, image);
+  Remap (graphic, image);
   if (DEBUG) fprintf (stderr, "remapped image\n");
   Refresh ();
Index: trunk/Ohana/src/kapa2/src/LoadTickmarks.c
===================================================================
--- trunk/Ohana/src/kapa2/src/LoadTickmarks.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/LoadTickmarks.c	(revision 16011)
@@ -11,5 +11,5 @@
   section = GetActiveSection();
   if (section->image == NULL) {
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
     SetSectionSizes (section);
   }
Index: trunk/Ohana/src/kapa2/src/MakeColormap.c
===================================================================
--- trunk/Ohana/src/kapa2/src/MakeColormap.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/MakeColormap.c	(revision 16011)
@@ -1,4 +1,3 @@
 # include "Ximage.h"
-# define NPIXELS 64
 
 static char default_cmap[] = "grayscale";
Index: trunk/Ohana/src/kapa2/src/PSPixmap.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PSPixmap.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/PSPixmap.c	(revision 16011)
@@ -13,6 +13,6 @@
   /* start at the last line, print lines in decending order */
   buff = (unsigned char *)image[0].picture.data + image[0].picture.dx*(image[0].picture.dy - 1);
-  slope = image[0].slope;
-  start = image[0].start;
+  slope = image[0].image[0].slope;
+  start = image[0].image[0].start;
   back  = graphic[0].back;
 
@@ -46,6 +46,6 @@
   /* start at the last line, print lines in decending order */
   buff = (unsigned short *)image[0].picture.data + image[0].picture.dx*(image[0].picture.dy - 1);
-  slope = image[0].slope;
-  start = image[0].start;
+  slope = image[0].image[0].slope;
+  start = image[0].image[0].start;
   back  = graphic[0].back;
 
@@ -83,6 +83,6 @@
   /* start at the last line, print lines in decending order */
   buff = (unsigned char *)&image[0].picture.data[(dy - 1)*(3*dx + extra)];
-  slope = image[0].slope;
-  start = image[0].start;
+  slope = image[0].image[0].slope;
+  start = image[0].image[0].start;
   back  = graphic[0].back;
 
@@ -123,6 +123,6 @@
   /* start at the last line, print lines in decending order */
   buff = (unsigned int *)image[0].picture.data + image[0].picture.dx*(image[0].picture.dy - 1);
-  slope = image[0].slope;
-  start = image[0].start;
+  slope = image[0].image[0].slope;
+  start = image[0].image[0].start;
   back  = graphic[0].back;
 
@@ -143,2 +143,41 @@
   return;
 }
+
+# if (0)
+// XXX needs work!
+void PSPixmap32_RGB (Graphic *graphic, KapaImageWidget *image, FILE *f) {
+
+  int i, k, m, val;
+  double Nchar, Npix, start, slope, frac;
+  unsigned int *buff;
+  unsigned long back;
+  unsigned char 
+
+  ALLOCATE (pixelR, unsigned char, graphic[0].Npixels);
+  ALLOCATE (pixelG, unsigned char, graphic[0].Npixels);
+  ALLOCATE (pixelB, unsigned char, graphic[0].Npixels);
+
+  /** cmap[i].pixel must be defined even if X is not used **/
+  for (i = 0; i < graphic[0].Npixels; i++) { /* set up pixel array */
+    pixelR[i] = graphic[0].cmap[i].red >> 8;
+    pixelG[i] = graphic[0].cmap[i].green >> 8;
+    pixelB[i] = graphic[0].cmap[i].blue >> 8;
+  }
+
+  for (i = 0; i < image[0].picture.dy; i++) {
+    for (k = 0; k < image[0].picture.dx; k++, buff++) {
+      if (*buff == back) 
+	val = Nchar;
+      else {
+	for (m = 0; (graphic[0].cmap[m].pixel != *buff) && (m < Npix); m++);
+	val = Nchar - frac * MIN (MAX (start + m * slope, 0), Npix);
+      }
+      fprintf (f, "%02x", val);
+      if (!((k+1) % 40)) fprintf (f, "\n"); 
+    }
+    fprintf (f, "\n");
+    buff -= 2*image[0].picture.dx;
+  }
+  return;
+}
+# endif
Index: trunk/Ohana/src/kapa2/src/Remap.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Remap.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/Remap.c	(revision 16011)
@@ -1,18 +1,18 @@
 # include "Ximage.h"
 
-void Remap (Graphic *graphic, KapaImageWidget *image, Matrix *matrix) {
+void Remap (Graphic *graphic, KapaImageWidget *image) {
 
   switch (graphic[0].Nbits) {
   case 8:
-    Remap8 (graphic, image, matrix);
+    Remap8  (graphic, image, &image->image->matrix);
     break;
   case 16:
-    Remap16 (graphic, image, matrix);
+    Remap16 (graphic, image, &image->image->matrix);
     break;
   case 24:
-    Remap24 (graphic, image, matrix);
+    Remap24 (graphic, image, &image->image->matrix);
     break;
   case 32:
-    Remap32 (graphic, image, matrix);
+    Remap32 (graphic, image, &image->image->matrix);
     break;
   }
Index: trunk/Ohana/src/kapa2/src/Remap16.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Remap16.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/Remap16.c	(revision 16011)
@@ -38,10 +38,10 @@
   // define the color transform parameters
   MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
+  if (image[0].image[0].range != 0.0) {
+    slope = graphic[0].Npixels / image[0].image[0].range;
+    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
   } else {
     slope = 1.0;
-    start = image[0].zero;
+    start = image[0].image[0].zero;
   }
 
Index: trunk/Ohana/src/kapa2/src/Remap24.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Remap24.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/Remap24.c	(revision 16011)
@@ -40,10 +40,10 @@
   // define the color transform parameters
   MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
+  if (image[0].image[0].range != 0.0) {
+    slope = graphic[0].Npixels / image[0].image[0].range;
+    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
   } else {
     slope = 1.0;
-    start = image[0].zero;
+    start = image[0].image[0].zero;
   }
 
Index: trunk/Ohana/src/kapa2/src/Remap32.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Remap32.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/Remap32.c	(revision 16011)
@@ -1,14 +1,3 @@
 # include "Ximage.h"
-
-static float slope = 1.0;
-static float start = 0.0;
-static int MaxValue = 255;
-
-// XXX inline this if needed
-static int PixelLookup(float value) {
-  int out;
-  out = MIN (MAX (slope * value - start, 0), MaxValue);
-  return (out);
-}
 
 void Remap32 (Graphic *graphic, KapaImageWidget *image, Matrix *matrix) {
@@ -21,23 +10,15 @@
   int expand_in, expand_out;
   unsigned int *out_pix, *out_pix2;
-  float *imdata, *in_pix, *in_pix2;
-  unsigned long pixel[256], pixvalue;
+  unsigned short *in_pix, *in_pix2;
+  unsigned long *pixel, pixvalue;
   unsigned long back;
 
+  ALLOCATE (pixel, unsigned long, graphic[0].Npixels);
+
   // local array for pixel values
-  for (i = 0; i < 256; i++) { 
+  for (i = 0; i < graphic[0].Npixels; i++) { 
     pixel[i] = graphic[0].cmap[i].pixel;
   }
   back = graphic[0].back;
-
-  // define the color transform parameters
-  MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
-  } else {
-    slope = 1.0;
-    start = image[0].zero;
-  }
 
   // set up expansions
@@ -61,4 +42,5 @@
   DX = matrix[0].Naxis[0];
   DY = matrix[0].Naxis[1];
+
   /* X,Y are the image coordinates of the first image pixel */
   X = MAX(0.5*(DX - dx*expand) - image[0].X, 0);
@@ -92,12 +74,12 @@
 
   out_pix = (unsigned int *) image[0].picture.data;
-  imdata  = (float *) matrix[0].buffer;
-  in_pix  = &imdata[DX*(int)MAX(Y,0) + (int)MAX(X,0)];
+  in_pix  = &image[0].pixmap[DX*(int)MAX(Y,0) + (int)MAX(X,0)];
 
   /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
 
   /**** fill in bottom area ****/
-  for (j = 0; j < dx*j_start; j++, out_pix++) 
+  for (j = 0; j < dx*j_start; j++, out_pix++) {
     *out_pix = back;
+  }
   
   for (j = j_start; j < j_end; j+= expand_out, out_pix+=(expand_out-1)*dx, in_pix += expand_in*DX) {
@@ -116,12 +98,9 @@
     if (expand_out == 1) {
       for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix++) {
-	pixelN = PixelLookup(*in_pix2);
-	*out_pix = pixel[pixelN];
+	*out_pix = pixel[*in_pix2];
       }
-    }
-    else {
+    } else {
       for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= expand_out) { 
-	pixelN   = PixelLookup(*in_pix2);
-	pixvalue = pixel[pixelN];
+	pixvalue = pixel[*in_pix2];
 	out_pix2 = out_pix;
 	for (jj = 0; jj < expand_out; jj++, out_pix2+=(dx-expand_out)) {
@@ -142,5 +121,4 @@
     }
     out_pix += (dx - i_end);
-    
   } 
   
@@ -152,6 +130,8 @@
     *out_pix = back;
   }
+
   image[0].picture.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
 					image[0].picture.data, image[0].picture.dx, image[0].picture.dy, 32, 0);
+
+  free (pixel);
 }
-
Index: trunk/Ohana/src/kapa2/src/Remap8.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Remap8.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/Remap8.c	(revision 16011)
@@ -33,10 +33,10 @@
   // define the color transform parameters
   MaxValue = graphic[0].Npixels - 1;
-  if (image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].range;
-    start = graphic[0].Npixels * image[0].zero / image[0].range;
+  if (image[0].image[0].range != 0.0) {
+    slope = graphic[0].Npixels / image[0].image[0].range;
+    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
   } else {
     slope = 1.0;
-    start = image[0].zero;
+    start = image[0].image[0].zero;
   }
 
Index: trunk/Ohana/src/kapa2/src/Reorient.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Reorient.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/Reorient.c	(revision 16011)
@@ -4,4 +4,10 @@
 
   if (image[0].expand == 0) image[0].expand = 1;
+
+  if ((image[0].X == X) && (image[0].Y == Y) && (mode == 0)) {
+    Refresh ();
+    XFlush (graphic[0].display);
+    return;
+  }
 
   switch (mode) {
@@ -38,5 +44,5 @@
   }
 
-  Remap (graphic, image, &image[0].matrix);
+  Remap (graphic, image);
   Refresh ();
  
Index: trunk/Ohana/src/kapa2/src/Rescale.c
===================================================================
--- trunk/Ohana/src/kapa2/src/Rescale.c	(revision 16011)
+++ trunk/Ohana/src/kapa2/src/Rescale.c	(revision 16011)
@@ -0,0 +1,41 @@
+# include "Ximage.h"
+
+void Rescale (Graphic *graphic, KapaImageWidget *image, Matrix *matrix) {
+
+  int i, j, DX, DY, value;
+  float *iData;
+  unsigned short *oData;
+  float slope;
+  float start;
+  unsigned short MaxValue;
+
+  // define the color transform parameters
+  MaxValue = graphic[0].Npixels - 1;
+  if (image[0].image[0].range != 0.0) {
+    slope = graphic[0].Npixels / image[0].image[0].range;
+    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
+  } else {
+    slope = 1.0;
+    start = image[0].image[0].zero;
+  }
+
+  DX = matrix[0].Naxis[0];
+  DY = matrix[0].Naxis[1];
+
+  oData = graphic[0].pixmap;
+  iData = (float *) matrix[0].buffer;
+
+  // convert pixel data values to pixel index values (0 - Npixel)
+  for (i = 0; i < DX; i++) {
+    for (j = 0; j < DY; j++, iData++, oData++) {
+      value = slope * iData - start;
+      if (value < 0) value = 0;
+      if (value > MaxValue) value = MaxValue;
+      *oData = value;
+    }
+  }
+}
+
+/** in order to call this function, graphic[0].pixmap must be allocated to match the
+ * current matrix (current channel) 
+ */
Index: trunk/Ohana/src/kapa2/src/SetChannel.c
===================================================================
--- trunk/Ohana/src/kapa2/src/SetChannel.c	(revision 16011)
+++ trunk/Ohana/src/kapa2/src/SetChannel.c	(revision 16011)
@@ -0,0 +1,66 @@
+# include "Ximage.h"
+
+int SetChannel (int sock) {
+  
+  int Nchannel;
+  Graphic *graphic;
+  Section *section;
+  KapaImageWidget *image;
+
+  graphic = GetGraphic ();
+  section = GetActiveSection();
+  if (section->image == NULL) {
+    section->image = InitImageWidget ();
+    SetSectionSizes (section);
+  }
+  image = section->image;
+
+  KiiScanMessage (sock, "%d", &Nchannel);
+
+  if (Nchannel <  0) return (TRUE);
+  if (Nchannel >= NCHANNELS) return (TRUE);
+  
+  image[0].image = &image[0].channel[Nchannel];
+  SetColorScale (graphic, image);
+
+  if (!USE_XWINDOW) return (TRUE);
+
+  Remap (graphic, image);
+  if (DEBUG) fprintf (stderr, "remapped image\n");
+  Refresh ();
+  if (DEBUG) fprintf (stderr, "refreshed\n");
+  XFlush (graphic[0].display);
+
+  return (TRUE);
+}
+
+int SetColormapFromPipe (int sock) {
+  
+  Graphic *graphic;
+  Section *section;
+  KapaImageWidget *image;
+  char colormap[256];
+  int status;
+
+  graphic = GetGraphic ();
+  section = GetActiveSection();
+  if (section->image == NULL) {
+    section->image = InitImageWidget ();
+    SetSectionSizes (section);
+  }
+  image = section->image;
+
+  KiiScanMessage (sock, "%s", colormap);
+
+  status = SetColormap (colormap);
+  if (!status) fprintf (stderr, "unknown colormap %s\n", colormap);
+
+  SetColorScale (graphic, image);
+  if (!USE_XWINDOW) return (TRUE);
+
+  Remap (graphic, image);
+  Refresh ();
+  XFlush (graphic[0].display);
+
+  return (TRUE);
+}
Index: trunk/Ohana/src/kapa2/src/SetColorScale.c
===================================================================
--- trunk/Ohana/src/kapa2/src/SetColorScale.c	(revision 16011)
+++ trunk/Ohana/src/kapa2/src/SetColorScale.c	(revision 16011)
@@ -0,0 +1,219 @@
+# include "Ximage.h"
+
+void SetColorScale (Graphic *graphic, KapaImageWidget *image) {
+
+  switch (graphic[0].ColorScaleMode) {
+    case KAPA_SCALE_1D:
+      SetColorScale1D (graphic, image);
+      break;
+    case KAPA_SCALE_3D_RUFF:
+      // fall-back on 1D colors (ie, if images are mis-matched)
+      if (!SetColorScale3D (graphic, image)) {
+	graphic[0].ColorScaleMode = KAPA_SCALE_1D;
+	SetColorScale1D (graphic, image);
+      }
+      break;
+    case KAPA_SCALE_3D_FULL:
+      // fall-back on 1D colors (ie, if images are mis-matched)
+      if (!SetColorScale3D_CC (graphic, image)) {
+	graphic[0].ColorScaleMode = KAPA_SCALE_1D;
+	SetColorScale1D (graphic, image);
+      }
+      break;
+    default:
+      fprintf (stderr, "programming error in kapa: unknown color scale mode\n");
+      return;
+  }
+  return;
+}
+
+void SetColorScale1D (Graphic *graphic, KapaImageWidget *image) {
+  int i, j, DX, DY, value, nPixels;
+  float *iData;
+  unsigned short *oData;
+  float slope;
+  float start;
+  unsigned short MaxValue;
+  Matrix *matrix;
+
+  // define the color transform parameters
+  MaxValue = graphic[0].Npixels - 1;
+  if (image[0].image[0].range != 0.0) {
+    slope = graphic[0].Npixels / image[0].image[0].range;
+    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
+  } else {
+    slope = 1.0;
+    start = image[0].image[0].zero;
+  }
+
+  matrix = &image->image->matrix;
+
+  DX = matrix[0].Naxis[0];
+  DY = matrix[0].Naxis[1];
+
+  nPixels = DX*DY;
+  if (image[0].nPixels != nPixels) {
+    REALLOCATE (image[0].pixmap, unsigned short, nPixels);
+    image[0].nPixels = nPixels;
+  }
+
+  oData = image[0].pixmap;
+  iData = (float *) matrix[0].buffer;
+
+  // convert pixel data values to pixel index values (0 - Npixel)
+  for (i = 0; i < nPixels; i++, iData++, oData++) {
+    value = *iData * slope - start;
+    if (value < 0) value = 0;
+    if (value > MaxValue) value = MaxValue;
+    *oData = value;
+  }
+}
+
+// in 3D we use channels 0,1,2 to choose the pixel from the cube
+// XXX this uses a crude, uniform-spacing cube
+int SetColorScale3D (Graphic *graphic, KapaImageWidget *image) {
+  int i, j, DX, DY, value, nPixels, rValue, gValue, bValue;
+  float *rData, *bData, *gData;
+  unsigned short *oData;
+  float redSlope, blueSlope, greenSlope;
+  float redStart, blueStart, greenStart;
+
+  DX = image[0].channel[KAPA_CHANNEL_RED].matrix.Naxis[0];
+  DY = image[0].channel[KAPA_CHANNEL_RED].matrix.Naxis[1];
+
+  if (DX != image[0].channel[KAPA_CHANNEL_GREEN].matrix.Naxis[0]) return FALSE;
+  if (DY != image[0].channel[KAPA_CHANNEL_GREEN].matrix.Naxis[1]) return FALSE;
+  if (DX != image[0].channel[KAPA_CHANNEL_BLUE].matrix.Naxis[0]) return FALSE;
+  if (DY != image[0].channel[KAPA_CHANNEL_BLUE].matrix.Naxis[1]) return FALSE;
+
+  // define the color transform parameters
+  unsigned short maxRed = graphic[0].nRed - 1;
+  unsigned short maxBlue = graphic[0].nBlue - 1;
+  unsigned short maxGreen = graphic[0].nGreen - 1;
+
+  // set start & slope for red (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_RED].range != 0.0) {
+    redSlope = graphic[0].nRed / image[0].channel[KAPA_CHANNEL_RED].range;
+    redStart = graphic[0].nRed * image[0].channel[KAPA_CHANNEL_RED].zero / image[0].channel[KAPA_CHANNEL_RED].range;
+  } else {
+    redSlope = 1.0;
+    redStart = image[0].channel[KAPA_CHANNEL_RED].zero;
+  }
+  // set start & slope for blue (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_BLUE].range != 0.0) {
+    blueSlope = graphic[0].nBlue / image[0].channel[KAPA_CHANNEL_BLUE].range;
+    blueStart = graphic[0].nBlue * image[0].channel[KAPA_CHANNEL_BLUE].zero / image[0].channel[KAPA_CHANNEL_BLUE].range;
+  } else {
+    blueSlope = 1.0;
+    blueStart = image[0].channel[KAPA_CHANNEL_BLUE].zero;
+  }
+  // set start & slope for green (channel 0)
+  if (image[0].channel[KAPA_CHANNEL_GREEN].range != 0.0) {
+    greenSlope = graphic[0].nGreen / image[0].channel[KAPA_CHANNEL_GREEN].range;
+    greenStart = graphic[0].nGreen * image[0].channel[KAPA_CHANNEL_GREEN].zero / image[0].channel[KAPA_CHANNEL_GREEN].range;
+  } else {
+    greenSlope = 1.0;
+    greenStart = image[0].channel[KAPA_CHANNEL_GREEN].zero;
+  }
+
+  nPixels = DX*DY;
+  if (image[0].nPixels != nPixels) {
+    REALLOCATE (image[0].pixmap, unsigned short, nPixels);
+    image[0].nPixels = nPixels;
+  }
+
+  oData = image[0].pixmap;
+  rData = (float *) image[0].channel[KAPA_CHANNEL_RED].matrix.buffer;
+  bData = (float *) image[0].channel[KAPA_CHANNEL_BLUE].matrix.buffer;
+  gData = (float *) image[0].channel[KAPA_CHANNEL_GREEN].matrix.buffer;
+
+  // convert pixel data values to pixel index values (0 - Npixel)
+  for (i = 0; i < nPixels; i++, rData++, bData++, gData++, oData++) {
+    rValue = *rData * redSlope   - redStart;
+    if (rValue < 0) rValue = 0;
+    if (rValue > maxRed) rValue = maxRed;
+
+    bValue = *bData * blueSlope  - blueStart;
+    if (bValue < 0) bValue = 0;
+    if (bValue > maxBlue) bValue = maxBlue;
+
+    gValue = *gData * greenSlope - greenStart;
+    if (gValue < 0) gValue = 0;
+    if (gValue > maxGreen) gValue = maxGreen;
+
+    *oData = gValue + bValue * (maxGreen + 1) + rValue * (maxGreen + 1) * (maxBlue + 1);
+  }
+  return TRUE;
+}
+
+// in 3D we use channels 0,1,2 to choose the pixel from the cube
+int SetColorScale3D_CC (Graphic *graphic, KapaImageWidget *image) {
+
+  int i, DX, DY, Nvalues, NVALUES, Npixels, Nmin;
+  float *values, *colors;
+  CCNode *cube;
+
+  DX = image[0].channel[KAPA_CHANNEL_RED].matrix.Naxis[0];
+  DY = image[0].channel[KAPA_CHANNEL_RED].matrix.Naxis[1];
+  if (DX != image[0].channel[KAPA_CHANNEL_GREEN].matrix.Naxis[0]) return FALSE;
+  if (DY != image[0].channel[KAPA_CHANNEL_GREEN].matrix.Naxis[1]) return FALSE;
+  if (DX != image[0].channel[KAPA_CHANNEL_BLUE].matrix.Naxis[0]) return FALSE;
+  if (DY != image[0].channel[KAPA_CHANNEL_BLUE].matrix.Naxis[1]) return FALSE;
+
+  // create the top-level cube
+  cube = CCNodeAlloc();
+  cube->min[CC_X] = cube->min[CC_Y] = cube->min[CC_Z] = 0.0;
+  cube->max[CC_X] = cube->max[CC_Y] = cube->max[CC_Z] = 1.0;
+  cube->mid[CC_X] = cube->mid[CC_Y] = cube->mid[CC_Z] = 0.5;
+
+  // subdivide cube into first, uniform division (4x4x4)
+  CCSplitNodeIterate (cube, 0, 2);
+
+  // need to allocate at least 64 + NPASS*7*NSPLIT pixels (overestimate if 64 < NSPLIT)
+# define NPASS 5
+# define NSPLIT 128
+
+  for (i = 0; i < NPASS; i++) {
+    // generate histogram
+    ColorHistogram (image, cube);
+
+    // extract histogram values
+    values  = NULL;
+    Nvalues = 0;
+    NVALUES = 0;
+    CCNodeExtractCounts (cube, &values, &Nvalues, &NVALUES);
+  
+    // select top N cells
+    sort (values, Nvalues);
+
+    // split nodes with more than value[n]
+    Nmin = MAX (0, Nvalues - NSPLIT);
+    CCNodeDivideLimit (cube, values[Nmin]);
+    free (values);
+
+    CCNodeInitCounts (cube, 0.0);
+  }
+
+  // generate histogram
+  ColorHistogram (image, cube);
+  
+  // convert histogram 3D values to cmap colors
+  Npixels = 0;
+  CCNodeSetColorMap (cube, graphic[0].cmap, graphic[0].Npixels, &Npixels);
+
+  // store the colors
+  if (USE_XWINDOW) {
+    if (graphic[0].visualclass) {
+      XStoreColors(graphic[0].display, graphic[0].colormap, graphic[0].cmap, Npixels);
+    } else {
+      for (i = 0; i < Npixels; i++) {
+	if (XAllocColor (graphic[0].display, graphic[0].colormap, &graphic[0].cmap[i]) == 0) {
+	  fprintf (stderr, "error on %d\n", i);
+	}
+      }
+    }
+  }
+  CCNodeSetColorPixels (image, cube);
+  return TRUE;
+}
+
Index: trunk/Ohana/src/kapa2/src/SetColormap.c
===================================================================
--- trunk/Ohana/src/kapa2/src/SetColormap.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/SetColormap.c	(revision 16011)
@@ -1,20 +1,79 @@
 # include "Ximage.h"
 
-/*** this function uses only private colormaps.  it should try the standard colormap
-     first to get better control over the smooth greyscales ***/
+# define SETVALUE(VAR,VALUE,MINVAL,MAXVAL) { \
+  float tmp = (VALUE); \
+  if (tmp < MINVAL) { \
+    VAR = MINVAL; \
+  } else if (tmp > MAXVAL) { \
+    VAR = MAXVAL; \
+  } else { \
+    VAR = tmp; \
+  } }   
 
 int SetColormap (char *name) {
 
-  int i;
+  int i, red, blue, green;
+  float scale, blueRef, redRef, greenRef;
   Graphic *graphic;
 
   graphic = GetGraphic();
 
+  // the "fullcolor" colormap is uniquely defined for each image;
+  // defer to the 'SetColorScale' step
+  if (!strcasecmp (name, "fullcolor")) {
+    graphic[0].ColorScaleMode = KAPA_SCALE_3D_FULL;
+    return TRUE;
+  }
+
+  // very simple color model: evenly spaced cube 
+  if (!strcasecmp (name, "ruffcolor")) {
+      graphic[0].nRed  = pow (graphic[0].Npixels, 0.333);
+      graphic[0].nBlue = pow (graphic[0].Npixels, 0.333);
+      graphic[0].nGreen = graphic[0].Npixels / (graphic[0].nRed * graphic[0].nBlue);
+
+      // red,green,blue are values in range 0x0000 to 0xffff
+      float redScale = 0xffff / (graphic[0].nRed - 1);
+      float blueScale = 0xffff / (graphic[0].nBlue - 1);
+      float greenScale = 0xffff / (graphic[0].nGreen - 1);
+
+      i = 0;
+      for (red = 0; red < graphic[0].nRed; red++) {  
+	  for (blue = 0; blue < graphic[0].nBlue; blue++) {  
+	      for (green = 0; green < graphic[0].nGreen; green++, i++) {  
+		  SETVALUE (graphic[0].cmap[i].red,   red*redScale, 0, 0xffff);
+		  SETVALUE (graphic[0].cmap[i].blue,  blue*blueScale, 0, 0xffff);
+		  SETVALUE (graphic[0].cmap[i].green, green*greenScale, 0, 0xffff);
+		  graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
+	      }
+	  }
+      }
+
+      // all other modes are 1D: set the flag:
+      graphic[0].ColorScaleMode = KAPA_SCALE_3D_RUFF;
+      goto store_colors;
+  }
+
+  // all other modes are 1D: set the flag:
+  graphic[0].ColorScaleMode = KAPA_SCALE_1D;
+
+  // red,green,blue are values in range 0x0000 to 0xffff
+  scale = 0xffff / (graphic[0].Npixels - 1);
+
   /* greyscale */
-  if ((!strcmp (name, "grayscale")) || (!strcmp (name, "greyscale"))) {
+  if ((!strcasecmp (name, "grayscale")) || (!strcasecmp (name, "greyscale"))) {
     for (i = 0; i < graphic[0].Npixels; i++) {  
-      graphic[0].cmap[i].red = 256*(255 - 255*i/graphic[0].Npixels);
-      graphic[0].cmap[i].green = 256*(255 - 255*i/graphic[0].Npixels);
-      graphic[0].cmap[i].blue = 256*(255 - 255*i/graphic[0].Npixels);
+      SETVALUE (graphic[0].cmap[i].red,   0xffff - i*scale, 0, 0xffff);
+      SETVALUE (graphic[0].cmap[i].green, 0xffff - i*scale, 0, 0xffff);
+      SETVALUE (graphic[0].cmap[i].blue,  0xffff - i*scale, 0, 0xffff);
+      graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
+    }
+    goto store_colors;
+  }
+  /* -grayscale */
+  if ((!strcasecmp (name, "-grayscale")) || (!strcasecmp (name, "-greyscale"))) {
+    for (i = 0; i < graphic[0].Npixels; i++) {  
+      SETVALUE (graphic[0].cmap[i].red,   i*scale, 0, 0xffff);
+      SETVALUE (graphic[0].cmap[i].green, i*scale, 0, 0xffff);
+      SETVALUE (graphic[0].cmap[i].blue,  i*scale, 0, 0xffff);
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
@@ -22,37 +81,29 @@
   }
   /* heat */
-  if (!strcmp (name, "Puns")) {
+  if (!strcasecmp (name, "Heat")) {
+    greenRef = 0.25*graphic[0].Npixels*scale*2.0;
+    blueRef  = 0.50*graphic[0].Npixels*scale*2.0;
     for (i = 0; i < (int)(0.25*graphic[0].Npixels); i++) {  
+      SETVALUE (graphic[0].cmap[i].red,   2*i*scale, 0, 0xffff);
       graphic[0].cmap[i].green = 0;
-      graphic[0].cmap[i].blue = 0;
-      graphic[0].cmap[i].red = MIN (256*255, 256*255*2*i/(1.0*graphic[0].Npixels));  
+      graphic[0].cmap[i].blue  = 0;
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
-    for (i = (int)(0.25*graphic[0].Npixels); i < (int)(0.50*graphic[0].Npixels); i++) {  
-      graphic[0].cmap[i].red = MIN (256*255, 256*255*2*i/(1.0*graphic[0].Npixels));
-      graphic[0].cmap[i].green = MIN (256*255, 256*255*2*(i/(1.0*graphic[0].Npixels) - 0.25));
+    for (i = 0.25*graphic[0].Npixels; i < 0.50*graphic[0].Npixels; i++) {  
+      SETVALUE (graphic[0].cmap[i].red,   2*i*scale,            0, 0xffff);
+      SETVALUE (graphic[0].cmap[i].green, 2*i*scale - greenRef, 0, 0xffff);
       graphic[0].cmap[i].blue = 0;
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
     for (i = (int)(0.50*graphic[0].Npixels); i < (int)(0.75*graphic[0].Npixels); i++) {  
-      graphic[0].cmap[i].red = 256*255;
-      graphic[0].cmap[i].green = MIN (256*255, 256*255*2*(i/(1.0*graphic[0].Npixels) - 0.25));
-      graphic[0].cmap[i].blue = MIN (256*255, 256*255*2*(i/(1.0*graphic[0].Npixels) - 0.50));
+      graphic[0].cmap[i].red = 0xffff;
+      SETVALUE (graphic[0].cmap[i].green, 2*i*scale - greenRef, 0, 0xffff);
+      SETVALUE (graphic[0].cmap[i].blue,  2*i*scale - blueRef,  0, 0xffff);
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
     for (i = (int)(0.75*graphic[0].Npixels); i < graphic[0].Npixels; i++) {  
-      graphic[0].cmap[i].red = 256*255;
-      graphic[0].cmap[i].green = 256*255;
-      graphic[0].cmap[i].blue = MIN (256*255, 256*255*2*(i/(1.0*graphic[0].Npixels) - 0.50));
-      graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
-    }
-    goto store_colors;
-  }
-  /* -grayscale */
-  if ((!strcmp (name, "-grayscale")) || (!strcmp (name, "-greyscale"))) {
-    for (i = 0; i < graphic[0].Npixels; i++) {  
-      graphic[0].cmap[i].red = 256*(255*i/graphic[0].Npixels);
-      graphic[0].cmap[i].green = 256*(255*i/graphic[0].Npixels);
-      graphic[0].cmap[i].blue = 256*(255*i/graphic[0].Npixels);
+      graphic[0].cmap[i].red   = 0xffff;
+      graphic[0].cmap[i].green = 0xffff;
+      SETVALUE (graphic[0].cmap[i].blue,  2*i*scale - blueRef,  0, 0xffff);
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
@@ -60,27 +111,31 @@
   }
   /* rainbow */
-  if (!strcmp (name, "Rainbow")) {
+  if (!strcasecmp (name, "Rainbow")) {
+    redRef   = 0.25*graphic[0].Npixels*scale*4.0;
+    greenRef = 0.50*graphic[0].Npixels*scale*4.0;
+    blueRef  = 0.50*graphic[0].Npixels*scale*4.0;
     for (i = 0; i < (int)(0.25*graphic[0].Npixels); i++) {  
-      graphic[0].cmap[i].red = 0;
+      graphic[0].cmap[i].red   = 0;
       graphic[0].cmap[i].green = 0;
-      graphic[0].cmap[i].blue = 256*(255*4*(i/(1.0*graphic[0].Npixels)));  
+      SETVALUE (graphic[0].cmap[i].blue,  4*i*scale,           0, 0xffff);
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
     for (i = (int)(0.25*graphic[0].Npixels); i < (int)(0.50*graphic[0].Npixels); i++) {  
-      graphic[0].cmap[i].red = 256*(255*4*((i/(1.0*graphic[0].Npixels)) - 0.25));
+      SETVALUE (graphic[0].cmap[i].red,   4*i*scale - redRef,  0, 0xffff);
       graphic[0].cmap[i].green = 0;
-      graphic[0].cmap[i].blue = 256*(255*4*(0.50 - (i/(1.0*graphic[0].Npixels))));
+      SETVALUE (graphic[0].cmap[i].blue,  blueRef - 4*i*scale, 0, 0xffff);
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
     for (i = (int)(0.50*graphic[0].Npixels); i < (int)(0.75*graphic[0].Npixels); i++) {  
-      graphic[0].cmap[i].red = 256*255;
-      graphic[0].cmap[i].green = 256*(255*4*((i/(1.0*graphic[0].Npixels)) - 0.50));
+      graphic[0].cmap[i].red  = 0xffff;
+      SETVALUE (graphic[0].cmap[i].green,  4*i*scale - greenRef, 0, 0xffff);
       graphic[0].cmap[i].blue = 0;
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
+    blueRef  = 0.75*graphic[0].Npixels*scale*4.0;
     for (i = (int)(0.75*graphic[0].Npixels); i < graphic[0].Npixels; i++) {  
-      graphic[0].cmap[i].red = 256*255;
-      graphic[0].cmap[i].green = 256*255;
-      graphic[0].cmap[i].blue = 256*(255*4*((i/(1.0*graphic[0].Npixels)) - 0.75));
+      graphic[0].cmap[i].red   = 0xffff;
+      graphic[0].cmap[i].green = 0xffff;
+      SETVALUE (graphic[0].cmap[i].blue,  4*i*scale - blueRef, 0, 0xffff);
       graphic[0].cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
Index: trunk/Ohana/src/kapa2/src/SetGraphSize.c
===================================================================
--- trunk/Ohana/src/kapa2/src/SetGraphSize.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/SetGraphSize.c	(revision 16011)
@@ -41,5 +41,5 @@
   // if we are tied to an image, make mods as needed
   if (section->image) {
-    textpad = graphic[0].font[0].ascent;
+    textpad = USE_XWINDOW ? graphic[0].font[0].ascent : 10;
     textdY = 6*textpad + 7*PAD1;
     WdY = MAX (ZOOM_Y, textdY + 2*BUTTON_HEIGHT + PAD1);
Index: trunk/Ohana/src/kapa2/src/SetImageData.c
===================================================================
--- trunk/Ohana/src/kapa2/src/SetImageData.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/SetImageData.c	(revision 16011)
@@ -11,5 +11,5 @@
   section = GetActiveSection();
   if (section->image == NULL) {
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
     SetSectionSizes (section);
   }
@@ -18,8 +18,8 @@
   // get image data from client 
   KiiScanMessage (sock, "%lf %lf %s", 
-		  &image[0].zero, 
-		  &image[0].range, 
-		  image[0].name, 
-		  image[0].file);
+		  &image[0].image[0].zero, 
+		  &image[0].image[0].range, 
+		  image[0].image[0].name, 
+		  image[0].image[0].file);
 
   // XXX when we go to 32bit, this should remap the image
@@ -37,5 +37,5 @@
   section = GetActiveSection();
   if (section->image == NULL) {
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
     SetSectionSizes (section);
   }
@@ -43,8 +43,8 @@
 
   KiiSendMessage (sock, "%g %g %s %s", 
-		  image[0].zero,
-		  image[0].range,
-		  image[0].name,
-		  image[0].file);
+		  image[0].image[0].zero,
+		  image[0].image[0].range,
+		  image[0].image[0].name,
+		  image[0].image[0].file);
 
   return (TRUE);
@@ -61,5 +61,5 @@
   section = GetActiveSection();
   if (section->image == NULL) {
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
     SetSectionSizes (section);
   }
@@ -67,16 +67,16 @@
   
   KiiScanMessage (sock, "%f %f %f %f", 
-		  &image[0].coords.pc1_1, &image[0].coords.pc2_2,
-		  &image[0].coords.pc1_2, &image[0].coords.pc2_1);
+		  &image[0].image[0].coords.pc1_1, &image[0].image[0].coords.pc2_2,
+		  &image[0].image[0].coords.pc1_2, &image[0].image[0].coords.pc2_1);
 
-  KiiScanMessage (sock, "%s", image[0].coords.ctype);
+  KiiScanMessage (sock, "%s", image[0].image[0].coords.ctype);
 
   KiiScanMessage (sock, "%lf %lf %f %f %f %f", 
-		  &image[0].coords.crval1,
-		  &image[0].coords.crval2,
-		  &image[0].coords.crpix1,
-		  &image[0].coords.crpix2,
-		  &image[0].coords.cdelt1,
-		  &image[0].coords.cdelt2);
+		  &image[0].image[0].coords.crval1,
+		  &image[0].image[0].coords.crval2,
+		  &image[0].image[0].coords.crpix1,
+		  &image[0].image[0].coords.crpix2,
+		  &image[0].image[0].coords.cdelt1,
+		  &image[0].image[0].coords.cdelt2);
 
   return (TRUE);  
@@ -90,5 +90,5 @@
   section = GetActiveSection();
   if (section->image == NULL) {
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
     SetSectionSizes (section);
   }
@@ -96,16 +96,16 @@
 
   KiiSendMessage (sock, "%g %g %g %g", 
-		  image[0].coords.pc1_1, image[0].coords.pc2_2,
-		  image[0].coords.pc1_2, image[0].coords.pc2_1);
+		  image[0].image[0].coords.pc1_1, image[0].image[0].coords.pc2_2,
+		  image[0].image[0].coords.pc1_2, image[0].image[0].coords.pc2_1);
 
-  KiiSendMessage (sock, "%s", image[0].coords.ctype);
+  KiiSendMessage (sock, "%s", image[0].image[0].coords.ctype);
 
   KiiSendMessage (sock, "%g %g %g %g %g %g", 
-		  image[0].coords.crval1,
-		  image[0].coords.crval2,
-		  image[0].coords.crpix1,
-		  image[0].coords.crpix2,
-		  image[0].coords.cdelt1,
-		  image[0].coords.cdelt2);
+		  image[0].image[0].coords.crval1,
+		  image[0].image[0].coords.crval2,
+		  image[0].image[0].coords.crpix1,
+		  image[0].image[0].coords.crpix2,
+		  image[0].image[0].coords.cdelt1,
+		  image[0].image[0].coords.cdelt2);
 
   return (TRUE);
@@ -120,5 +120,5 @@
   section = GetActiveSection();
   if (section->image == NULL) {
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
     SetSectionSizes (section);
   }
Index: trunk/Ohana/src/kapa2/src/SetImageSize.c
===================================================================
--- trunk/Ohana/src/kapa2/src/SetImageSize.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/SetImageSize.c	(revision 16011)
@@ -40,9 +40,9 @@
       }
       if (USE_XWINDOW) CreatePicture (image, graphic);
-      Remap (graphic, image, &image[0].matrix);
+      Remap (graphic, image);
       return;
 
     case 1:
-      textpad = graphic[0].font[0].ascent;
+      textpad = USE_XWINDOW ? graphic[0].font[0].ascent : 10;
       textdY = 6*textpad + 7*PAD1;
       WdY = MAX (ZOOM_Y, textdY + 2*BUTTON_HEIGHT + PAD1);
@@ -104,13 +104,13 @@
       image[0].rainbow_button.y = image[0].PS_button.y;
 
-      image[0].puns_button.x = image[0].rainbow_button.x + image[0].rainbow_button.dx + PAD1;
-      image[0].puns_button.y = image[0].PS_button.y;
-
-      image[0].recenter_button.x = image[0].puns_button.x + image[0].puns_button.dx + PAD1;
+      image[0].heat_button.x = image[0].rainbow_button.x + image[0].rainbow_button.dx + PAD1;
+      image[0].heat_button.y = image[0].PS_button.y;
+
+      image[0].recenter_button.x = image[0].heat_button.x + image[0].heat_button.dx + PAD1;
       image[0].recenter_button.y = image[0].PS_button.y;
       break;
 
     case 3:
-      textpad = graphic[0].font[0].ascent;
+      textpad = USE_XWINDOW ? graphic[0].font[0].ascent : 10;
       textdY = 6*textpad + 7*PAD1;
       WdY = MAX (ZOOM_Y, textdY + 2*BUTTON_HEIGHT + PAD1);
@@ -172,8 +172,8 @@
       image[0].rainbow_button.y = image[0].PS_button.y;
 
-      image[0].puns_button.x = image[0].rainbow_button.x + image[0].rainbow_button.dx + PAD1;
-      image[0].puns_button.y = image[0].PS_button.y;
-
-      image[0].recenter_button.x = image[0].puns_button.x + image[0].puns_button.dx + PAD1;
+      image[0].heat_button.x = image[0].rainbow_button.x + image[0].rainbow_button.dx + PAD1;
+      image[0].heat_button.y = image[0].PS_button.y;
+
+      image[0].recenter_button.x = image[0].heat_button.x + image[0].heat_button.dx + PAD1;
       image[0].recenter_button.y = image[0].PS_button.y;
       break;
@@ -206,5 +206,5 @@
 
       /** everything below is tied in x-dir to the zoom box **/
-      textpad = graphic[0].font[0].ascent;
+      textpad = USE_XWINDOW ? graphic[0].font[0].ascent : 10;
       image[0].text_x = image[0].zoom.x;
       image[0].text_y = image[0].zoom.y + image[0].zoom.dy + PAD1;
@@ -238,8 +238,8 @@
       image[0].rainbow_button.y = image[0].PS_button.y;
 
-      image[0].puns_button.x = image[0].rainbow_button.x + image[0].rainbow_button.dx + PAD1;
-      image[0].puns_button.y = image[0].PS_button.y;
-
-      image[0].recenter_button.x = image[0].puns_button.x + image[0].puns_button.dx + PAD1;
+      image[0].heat_button.x = image[0].rainbow_button.x + image[0].rainbow_button.dx + PAD1;
+      image[0].heat_button.y = image[0].PS_button.y;
+
+      image[0].recenter_button.x = image[0].heat_button.x + image[0].heat_button.dx + PAD1;
       image[0].recenter_button.y = image[0].PS_button.y;
       break;
@@ -272,5 +272,5 @@
 
       /** everything below is tied in x-dir to the zoom box **/
-      textpad = graphic[0].font[0].ascent;
+      textpad = USE_XWINDOW ? graphic[0].font[0].ascent : 10;
       image[0].text_x = image[0].zoom.x;
       image[0].text_y = image[0].zoom.y + image[0].zoom.dy + PAD1;
@@ -304,8 +304,8 @@
       image[0].rainbow_button.y = image[0].PS_button.y;
 
-      image[0].puns_button.x = image[0].rainbow_button.x + image[0].rainbow_button.dx + PAD1;
-      image[0].puns_button.y = image[0].PS_button.y;
-
-      image[0].recenter_button.x = image[0].puns_button.x + image[0].puns_button.dx + PAD1;
+      image[0].heat_button.x = image[0].rainbow_button.x + image[0].rainbow_button.dx + PAD1;
+      image[0].heat_button.y = image[0].PS_button.y;
+
+      image[0].recenter_button.x = image[0].heat_button.x + image[0].heat_button.dx + PAD1;
       image[0].recenter_button.y = image[0].PS_button.y;
       break;
@@ -321,5 +321,5 @@
     CreateZoom (image, graphic, 0, 0); 
   }
-  Remap (graphic, image, &image[0].matrix);
+  Remap (graphic, image);
 
   return;
Index: trunk/Ohana/src/kapa2/src/SetToolbox.c
===================================================================
--- trunk/Ohana/src/kapa2/src/SetToolbox.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/SetToolbox.c	(revision 16011)
@@ -17,5 +17,5 @@
   section = GetActiveSection();
   if (section->image == NULL) { 
-    section->image = InitImage ();
+    section->image = InitImageWidget ();
   }
   section->image->location = location;
@@ -24,5 +24,5 @@
   if (!USE_XWINDOW) return;
 
-  Remap (graphic, section->image, &section->image->matrix);
+  Remap (graphic, section->image);
   if (DEBUG) fprintf (stderr, "remapped image\n");
   Refresh ();
Index: trunk/Ohana/src/kapa2/src/SetUpGraphic.c
===================================================================
--- trunk/Ohana/src/kapa2/src/SetUpGraphic.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/SetUpGraphic.c	(revision 16011)
@@ -17,5 +17,10 @@
   graphic->dy = 512; 
 
-  if (!USE_XWINDOW) return;
+  if (!USE_XWINDOW) {
+    ALLOCATE (graphic[0].pixels, unsigned long, NPIXELS_STATIC);
+    ALLOCATE (graphic[0].cmap,   XColor,        NPIXELS_STATIC);
+    graphic[0].Npixels = NPIXELS_STATIC;
+    return;
+  }
 
   name = CheckDisplayName (argc, argv);
Index: trunk/Ohana/src/kapa2/src/StatusBox.c
===================================================================
--- trunk/Ohana/src/kapa2/src/StatusBox.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/StatusBox.c	(revision 16011)
@@ -6,6 +6,6 @@
 
   if (image[0].MovePointer) {
-    x = 0.5*image[0].matrix.Naxis[0];
-    y = 0.5*image[0].matrix.Naxis[1];
+    x = 0.5*image[0].image[0].matrix.Naxis[0];
+    y = 0.5*image[0].image[0].matrix.Naxis[1];
     z = -1;
     image[0].x = x;
Index: trunk/Ohana/src/kapa2/src/UpdatePointer.c
===================================================================
--- trunk/Ohana/src/kapa2/src/UpdatePointer.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/UpdatePointer.c	(revision 16011)
@@ -19,13 +19,13 @@
   if (image[0].MovePointer && InPicture ((XButtonEvent *)event, &image[0].picture)) {
 
-    data = (float *) image[0].matrix.buffer;
+    data = (float *) image[0].image[0].matrix.buffer;
     Screen_to_Image (&x, &y, (double)event[0].x, (double)event[0].y, image);
 
     z = -1;
     if (x < 0) goto skip;
-    if (x >= image[0].matrix.Naxis[0]) goto skip;
+    if (x >= image[0].image[0].matrix.Naxis[0]) goto skip;
     if (y < 0) goto skip;
-    if (y >= image[0].matrix.Naxis[1]) goto skip;
-    z = data[(int)(y)*image[0].matrix.Naxis[0] + (int)(x)];
+    if (y >= image[0].image[0].matrix.Naxis[1]) goto skip;
+    z = data[(int)(y)*image[0].image[0].matrix.Naxis[0] + (int)(x)];
 
   skip:
@@ -47,5 +47,5 @@
   
   if (InPicture ((XButtonEvent *)event, &image[0].cmapbar)) {
-    z = image[0].zero  + image[0].range * (event[0].x - image[0].cmapbar.x) / image[0].cmapbar.dx;
+    z = image[0].image[0].zero  + image[0].image[0].range * (event[0].x - image[0].cmapbar.x) / image[0].cmapbar.dx;
     textpad = graphic[0].font[0].ascent;
     XSetForeground (graphic[0].display, graphic[0].gc, graphic[0].back);
Index: trunk/Ohana/src/kapa2/src/UpdateStatusBox.c
===================================================================
--- trunk/Ohana/src/kapa2/src/UpdateStatusBox.c	(revision 16010)
+++ trunk/Ohana/src/kapa2/src/UpdateStatusBox.c	(revision 16011)
@@ -7,5 +7,5 @@
   char line[100];
 
-  XY_to_RD (&ra, &dec, x, y, &image[0].coords);
+  XY_to_RD (&ra, &dec, x, y, &image[0].image[0].coords);
 
   textpad = graphic[0].font[0].ascent;
@@ -26,10 +26,10 @@
     
     bzero (line, 100);
-    sprintf (line, "%-25s", image[0].file); 
+    sprintf (line, "%-25s", image[0].image[0].file); 
     XDrawString (graphic[0].display, graphic[0].window, graphic[0].gc, 
 		 image[0].text_x + PAD1, image[0].text_y + 5*textpad + 5*PAD1, line, strlen(line));
     
     bzero (line, 100);
-    sprintf (line, "(%s)                                          ", image[0].name); 
+    sprintf (line, "(%s)                                          ", image[0].image[0].name); 
     XDrawString (graphic[0].display, graphic[0].window, graphic[0].gc, 
 		 image[0].text_x + PAD1, image[0].text_y + 6*textpad + 6*PAD1, line, 25);
Index: trunk/Ohana/src/kapa2/src/sort.c
===================================================================
--- trunk/Ohana/src/kapa2/src/sort.c	(revision 16011)
+++ trunk/Ohana/src/kapa2/src/sort.c	(revision 16011)
@@ -0,0 +1,36 @@
+# include "Ximage.h"
+
+void sort (float *value, int N) {
+
+  int l,j,ir,i;
+  float temp;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = value[--l];
+    }
+    else {
+      temp = value[ir];
+      value[ir] = value[0];
+      if (--ir == 0) {
+	value[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[j] < value[j+1]) ++j;
+      if (temp < value[j]) {
+	value[i]=value[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value[i] = temp;
+  }
+}
+
