OSDN Git Service

mrcImageOpticalFlow & mrcImageLucasKanade & mrcImageHornSchunckの変更
[eos/base.git] / util / src / TclTk / blt2.5 / generic / bltColor.c
diff --git a/util/src/TclTk/blt2.5/generic/bltColor.c b/util/src/TclTk/blt2.5/generic/bltColor.c
new file mode 100644 (file)
index 0000000..3b94220
--- /dev/null
@@ -0,0 +1,981 @@
+
+/*
+ * bltColor.c --
+ *
+ *     This module contains routines for color allocation strategies
+ *     used with color images in the BLT toolkit.
+ *
+ * Copyright 1997-1998 Lucent Technologies, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Lucent Technologies disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness.  In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ */
+
+/*
+ * Color strategies of 8-bit visuals:
+ *
+ * Try to "best" represent an N-color image into 8-bit (256 color)
+ * colormap.  The simplest method is use the high bits of each RGB
+ * value (3 bits for red and green, 2 bits for blue).  But this
+ * produces lots of contouring since the distribution of colors tends
+ * to be clustered.  Other problems: probably can't allocate even 256
+ * colors. Other applications will have already taken some color
+ * slots.  Furthermore, we might be displaying several images, and we
+ * can't assume that all images are representative of the colors used.
+ *
+ * If we use a private colormap, we may want to allocate some number
+ * of colors from the default colormap to prevent flashing when
+ * colormaps are switched.
+ *
+ * Switches:
+ *
+ *     -exact boolean          Try to match the colors of the image rather
+ *                             then generating a "best" color ramp.
+ *
+ *     -threshold value        Maximum average error. Indicates how far
+ *                             to reduce the quantized color palette.
+ *
+ *     -tolerance value        Allow colors within this distance to match.
+ *                             This will weight allocation towards harder
+ *                             to match colors, rather than the most
+ *                             frequent.
+ *
+ *     -mincolors number       Minimum number of reduced quantized colors.
+ *                             or color ramp.
+ *
+ *     -dither boolean         Turn on/off Floyd-Steinberg dithering.
+ *
+ *     -keep number            Hint to keep the first N colors in the
+ *                             in the default colormap.  This only applies to
+ *                             private colormaps.
+ *
+ *     -ramp number            Number of colors to use in a linear ramp.
+ *
+ */
+
+#include "bltInt.h"
+
+#ifndef WIN32
+
+#include "bltHash.h"
+#include "bltImage.h"
+
+#define NCOLORS                256
+
+
+static void
+GetPaletteSizes(nColors, nRedsPtr, nGreensPtr, nBluesPtr)
+    int nColors;               /* Number of colors requested. */
+    unsigned int *nRedsPtr;    /* (out) Number of red components. */
+    unsigned int *nGreensPtr;  /* (out) Number of green components. */
+    unsigned int *nBluesPtr;   /* (out) Number of blue components. */
+{
+    unsigned int nBlues, nReds, nGreens;
+
+    assert(nColors > 1); 
+    nBlues = nReds = nGreens = 0;
+    while ((nBlues * nBlues * nBlues) <= nColors) {
+       nBlues++;
+    }
+    nBlues--;
+    while ((nReds * nReds * nBlues) <= nColors) {
+       nReds++;
+    }
+    nReds--;
+    nGreens = nColors / (nBlues * nReds);
+
+    *nRedsPtr = nReds;
+    *nGreensPtr = nGreens;
+    *nBluesPtr = nBlues;
+}
+
+static void
+BuildColorRamp(palettePtr, nColors)
+    Pix32 *palettePtr;
+    int nColors;
+{
+    register unsigned int r, g, b;
+    unsigned int short red, green, blue;
+    unsigned int nReds, nGreens, nBlues;
+
+    GetPaletteSizes(nColors, &nReds, &nGreens, &nBlues);
+    for (r = 0; r < nReds; r++) {
+       red = (r * USHRT_MAX) / (nReds - 1);
+       for (g = 0; g < nGreens; g++) {
+           green = (g * USHRT_MAX) / (nGreens - 1);
+           for (b = 0; b < nBlues; b++) {
+               blue = (b * USHRT_MAX) / (nBlues - 1);
+               palettePtr->Red = red;
+               palettePtr->Green = green;
+               palettePtr->Blue = blue;
+               palettePtr++;
+           }
+       }
+    }
+
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * QueryColormap --
+ *
+ *     This is for psuedo-color displays only.  Fills an array or
+ *     XColors with the color values (RGB and pixel) currently
+ *     allocated in the colormap.
+ *
+ * Results:
+ *     The number of colors allocated is returned. The array "colorArr"
+ *     will contain the XColor values of each color in the colormap.
+ *
+ *---------------------------------------------------------------------- 
+ */
+
+static int
+QueryColormap(display, colorMap, mapColors, numMapColorsPtr)
+    Display *display;
+    Colormap colorMap;
+    XColor mapColors[];
+    int *numMapColorsPtr;
+{
+    unsigned long int pixelValues[NCOLORS];
+    int numAvail, numMapColors;
+    register int i;
+    register XColor *colorPtr;
+    register unsigned long *indexPtr;
+    int inUse[NCOLORS];
+
+    /* Initially, we assume all color cells are allocated. */
+    memset((char *)inUse, 0, sizeof(int) * NCOLORS);
+
+    /*
+     * Start allocating color cells.  This will tell us which color cells
+     * haven't already been allocated in the colormap.  We'll release the
+     * cells as soon as we find out how many there are.
+     */
+    numAvail = 0;
+    for (indexPtr = pixelValues, i = 0; i < NCOLORS; i++, indexPtr++) {
+       if (!XAllocColorCells(display, colorMap, False, NULL, 0, indexPtr, 1)) {
+           break;
+       }
+       inUse[*indexPtr] = TRUE;/* Indicate the cell is unallocated */
+       numAvail++;
+    }
+    XFreeColors(display, colorMap, pixelValues, numAvail, 0);
+
+    /*
+     * Put the indices of the cells already allocated into a color array.
+     * We'll use the array to query the RGB values of the allocated colors.
+     */
+    numMapColors = 0;
+    colorPtr = mapColors;
+    for (i = 0; i < NCOLORS; i++) {
+       if (!inUse[i]) {
+           colorPtr->pixel = i;
+           colorPtr->flags = (DoRed | DoGreen | DoBlue);
+           colorPtr++, numMapColors++;
+       }
+    }
+    XQueryColors(display, colorMap, mapColors, numMapColors);
+    *numMapColorsPtr = numMapColors;
+#ifdef notdef
+    fprintf(stderr, "Number of colors (allocated/free) %d/%d\n", numMapColors,
+       numAvail);
+#endif
+    return numAvail;
+}
+
+static void
+FindClosestColor(colorPtr, mapColors, numMapColors)
+    ColorInfo *colorPtr;
+    XColor mapColors[];
+    int numMapColors;
+{
+    double r, g, b;
+    register int i;
+    double dist, min;
+    XColor *lastMatch;
+    register XColor *mapColorPtr;
+
+    min = DBL_MAX;     /* Any color is closer. */
+    lastMatch = NULL;
+
+    /* Linear search of color */
+
+    mapColorPtr = mapColors;
+    for (i = 0; i < numMapColors; i++, mapColorPtr++) {
+       r = (double)mapColorPtr->red - (double)colorPtr->exact.red;
+       g = (double)mapColorPtr->green - (double)colorPtr->exact.green;
+       b = (double)mapColorPtr->blue - (double)colorPtr->exact.blue;
+
+       dist = (r * r) + (b * b) + (g * g);
+       if (dist < min) {
+           min = dist;
+           lastMatch = mapColorPtr;
+       }
+    }
+    colorPtr->best = *lastMatch;
+    colorPtr->best.flags = (DoRed | DoGreen | DoBlue);
+    colorPtr->error = (float)sqrt(min);
+}
+
+static int
+CompareColors(a, b)
+    void *a, *b;
+{
+    ColorInfo *i1Ptr, *i2Ptr;
+
+    i1Ptr = *(ColorInfo **) a;
+    i2Ptr = *(ColorInfo **) b;
+    if (i2Ptr->error > i1Ptr->error) {
+       return 1;
+    } else if (i2Ptr->error < i1Ptr->error) {
+       return -1;
+    }
+    return 0;
+}
+
+static float
+MatchColors(colorTabPtr, rgbPtr, numColors, numAvailColors, numMapColors,
+    mapColors)
+    struct ColorTableStruct *colorTabPtr;
+    Pix32 *rgbPtr;
+    int numColors;
+    int numAvailColors;
+    int numMapColors;
+    XColor mapColors[NCOLORS];
+{
+    int numMatched;
+    float sum;
+    register int i;
+    register ColorInfo *colorPtr;
+
+    /*
+     * For each quantized color, compute and store the error (i.e
+     * the distance from a color that's already been allocated).
+     * We'll use this information to sort the colors based upon how
+     * badly they match and their frequency to the color image.
+     */
+    colorPtr = colorTabPtr->colorInfo;
+    for (i = 0; i < numColors; i++, colorPtr++, rgbPtr++) {
+       colorPtr->index = i;
+       colorTabPtr->sortedColors[i] = colorPtr;
+       colorPtr->exact.red = rgbPtr->Red;
+       colorPtr->exact.green = rgbPtr->Green;
+       colorPtr->exact.blue = rgbPtr->Blue;
+       colorPtr->exact.flags = (DoRed | DoGreen | DoBlue);
+       FindClosestColor(colorPtr, mapColors, numMapColors);
+    }
+
+    /* Sort the colors, first by frequency (most to least), then by
+     * matching error (worst to best).
+     */
+    qsort(colorTabPtr->sortedColors, numColors, sizeof(ColorInfo *),
+       (QSortCompareProc *)CompareColors);
+
+    for (i = 0; i < numColors; i++) {
+       colorPtr = colorTabPtr->sortedColors[i];
+       fprintf(stderr, "%d. %04x%04x%04x / %04x%04x%04x = %f (%d)\n", i,
+           colorPtr->exact.red, colorPtr->exact.green, colorPtr->exact.blue,
+           colorPtr->best.red, colorPtr->best.green, colorPtr->best.blue,
+           colorPtr->error, colorPtr->freq);
+    }
+    sum = 0.0;
+    numMatched = 0;
+    for (i = numAvailColors; i < numColors; i++) {
+       colorPtr = colorTabPtr->sortedColors[i];
+       sum += colorPtr->error;
+       numMatched++;
+    }
+    if (numMatched > 0) {
+       sum /= numMatched;
+    }
+    return sum;
+}
+
+    
+static int
+AllocateColors(nImageColors, colorTabPtr, matchOnly)
+    int nImageColors;
+    struct ColorTableStruct *colorTabPtr;
+    int matchOnly;
+{
+    register int i;
+    register ColorInfo *colorPtr;
+    unsigned long int pixelValue;
+
+    for (i = 0; i < nImageColors; i++) {
+       colorPtr = colorTabPtr->sortedColors[i];
+       if (matchOnly) {
+           XAllocColor(colorTabPtr->display, colorTabPtr->colorMap,
+               &colorPtr->best);
+           pixelValue = colorPtr->best.pixel;
+       } else {
+           colorPtr->allocated = XAllocColor(colorTabPtr->display,
+               colorTabPtr->colorMap, &colorPtr->exact);
+
+           if (colorPtr->allocated) {
+               pixelValue = colorPtr->exact.pixel;
+           } else {
+               XAllocColor(colorTabPtr->display, colorTabPtr->colorMap,
+                   &colorPtr->best);
+               pixelValue = colorPtr->best.pixel;
+           }
+       }
+       colorTabPtr->pixelValues[colorPtr->index] = pixelValue;
+    }
+    colorTabPtr->nPixels = nImageColors;
+    return 1;
+}
+
+ColorTable
+Blt_CreateColorTable(tkwin)
+    Tk_Window tkwin;
+{
+    XVisualInfo visualInfo, *visualInfoPtr;
+    int nVisuals;
+    Visual *visualPtr;
+    Display *display;
+    struct ColorTableStruct *colorTabPtr;
+
+    display = Tk_Display(tkwin);
+    visualPtr = Tk_Visual(tkwin);
+
+    colorTabPtr = Blt_Calloc(1, sizeof(struct ColorTableStruct));
+    assert(colorTabPtr);
+    colorTabPtr->display = Tk_Display(tkwin);
+    colorTabPtr->colorMap = Tk_Colormap(tkwin);
+
+    visualInfo.screen = Tk_ScreenNumber(tkwin);
+    visualInfo.visualid = XVisualIDFromVisual(visualPtr);
+    visualInfoPtr = XGetVisualInfo(display, VisualScreenMask | VisualIDMask,
+       &visualInfo, &nVisuals);
+
+    colorTabPtr->visualInfo = *visualInfoPtr;
+    XFree(visualInfoPtr);
+
+    return colorTabPtr;
+}
+
+void
+Blt_FreeColorTable(colorTabPtr)
+    struct ColorTableStruct *colorTabPtr;
+{
+    if (colorTabPtr == NULL) {
+       return;
+    }
+    if (colorTabPtr->nPixels > 0) {
+       XFreeColors(colorTabPtr->display, colorTabPtr->colorMap,
+           colorTabPtr->pixelValues, colorTabPtr->nPixels, 0);
+    }
+    Blt_Free(colorTabPtr);
+}
+
+extern int redAdjust, greenAdjust, blueAdjust;
+extern int redMaskShift, greenMaskShift, blueMaskShift;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Blt_DirectColorTable --
+ *
+ *     Creates a color table using the DirectColor visual.  We try
+ *     to allocate colors across the color spectrum.
+ *
+ * Results:
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+ColorTable
+Blt_DirectColorTable(interp, tkwin, image)
+    Tcl_Interp *interp;
+    Tk_Window tkwin;
+    Blt_ColorImage image;
+{
+    struct ColorTableStruct *colorTabPtr;
+    Visual *visualPtr;
+    Display *display;
+    XColor color;
+    int nr, ng, nb;
+    int rBand, gBand, bBand;
+    int rLast, gLast, bLast;
+    unsigned int r, g, b;
+    unsigned int value;
+    register int i;
+
+    display = Tk_Display(tkwin);
+    visualPtr = Tk_Visual(tkwin);
+
+    colorTabPtr = Blt_CreateColorTable(tkwin);
+    /*
+     * Compute the number of distinct colors in each band
+     */
+    nr = ((unsigned int)visualPtr->red_mask >> redMaskShift) + 1;
+    ng = ((unsigned int)visualPtr->green_mask >> greenMaskShift) + 1;
+    nb = ((unsigned int)visualPtr->blue_mask >> blueMaskShift) + 1;
+
+#ifdef notdef
+    assert((nr <= visualPtr->map_entries) && (ng <= visualPtr->map_entries) &&
+       (nb <= visualPtr->map_entries));
+#endif
+    rBand = NCOLORS / nr;
+    gBand = NCOLORS / ng;
+    bBand = NCOLORS / nb;
+
+  retry:
+    color.flags = (DoRed | DoGreen | DoBlue);
+    rLast = gLast = bLast = 0;
+    r = g = b = 0;
+    for (i = 0; i < visualPtr->map_entries; i++) {
+       if (rLast < NCOLORS) {
+           r = rLast + rBand;
+           if (r > NCOLORS) {
+               r = NCOLORS;
+           }
+       }
+       if (gLast < NCOLORS) {
+           g = gLast + gBand;
+           if (g > NCOLORS) {
+               g = NCOLORS;
+           }
+       }
+       if (bLast < NCOLORS) {
+           b = bLast + bBand;
+           if (b > NCOLORS) {
+               b = NCOLORS;
+           }
+       }
+       color.red = (r - 1) * (NCOLORS + 1);
+       color.green = (g - 1) * (NCOLORS + 1);
+       color.blue = (b - 1) * (NCOLORS + 1);
+
+       if (!XAllocColor(display, colorTabPtr->colorMap, &color)) {
+           XFreeColors(display, colorTabPtr->colorMap,
+               colorTabPtr->pixelValues, i, 0);
+           if ((colorTabPtr->flags & PRIVATE_COLORMAP) == 0) {
+               /*
+                * If we can't allocate a color in the default
+                * colormap, try again, this time with a private
+                * colormap.
+                */
+               fprintf(stderr, "Need to allocate private colormap\n");
+               colorTabPtr->colorMap = Tk_GetColormap(interp, tkwin, ".");
+
+               XSetWindowColormap(display, Tk_WindowId(tkwin),
+                   colorTabPtr->colorMap);
+               colorTabPtr->flags |= PRIVATE_COLORMAP;
+               goto retry;
+           }
+#ifdef notdef
+           fprintf(stderr, "Failed to allocate after %d colors\n", i);
+#endif
+           Blt_Free(colorTabPtr);
+           return NULL;        /* Ran out of colors in private map? */
+       }
+       colorTabPtr->pixelValues[i] = color.pixel;
+       /*
+        * Fill in pixel values for each band at this intensity
+        */
+       value = color.pixel & visualPtr->red_mask;
+       while (rLast < r) {
+           colorTabPtr->red[rLast++] = value;
+       }
+       value = color.pixel & visualPtr->green_mask;
+       while (gLast < g) {
+           colorTabPtr->green[gLast++] = value;
+       }
+       value = color.pixel & visualPtr->blue_mask;
+       while (bLast < b) {
+           colorTabPtr->blue[bLast++] = value;
+       }
+    }
+    colorTabPtr->nPixels = i;
+    return colorTabPtr;
+}
+
+/*
+ * First attempt:
+ *     Allocate colors all the colors in the image (up to NCOLORS). Bail out
+ *     on the first failure or if we need more than NCOLORS.
+ */
+static int
+GetUniqueColors(image)
+    Blt_ColorImage image;
+{
+    register int i, nColors;
+    register Pix32 *pixelPtr;
+    Pix32 color;
+    Blt_HashEntry *hPtr;
+    int isNew, nPixels;
+    int refCount;
+    Blt_HashTable colorTable;
+
+    Blt_InitHashTable(&colorTable, BLT_ONE_WORD_KEYS);
+
+    nPixels = Blt_ColorImageWidth(image) * Blt_ColorImageHeight(image);
+    nColors = 0;
+    pixelPtr = Blt_ColorImageBits(image);
+    for (i = 0; i < nPixels; i++, pixelPtr++) {
+       color.value = pixelPtr->value;
+       color.Alpha = 0xFF;     /* Ignore alpha-channel values */
+       hPtr = Blt_CreateHashEntry(&colorTable, (char *)color.value, &isNew);
+       if (isNew) {
+           refCount = 1;
+           nColors++;
+       } else {
+           refCount = (int)Blt_GetHashValue(hPtr);
+           refCount++;
+       }
+       Blt_SetHashValue(hPtr, (ClientData)refCount);
+    }
+    Blt_DeleteHashTable(&colorTable);
+    return nColors;
+}
+
+#define Blt_DefaultColormap(tkwin)  \
+       DefaultColormap(Tk_Display(tkwin), Tk_ScreenNumber(tkwin))
+
+
+static void
+PrivateColormap(interp, colorTabPtr, image, tkwin)
+    Tcl_Interp *interp;
+    struct ColorTableStruct *colorTabPtr;
+    Blt_ColorImage image;
+    Tk_Window tkwin;
+{
+    int keepColors = 0;
+    register int i;
+    XColor usedColors[NCOLORS];
+    int nFreeColors, nUsedColors;
+    Colormap colorMap;
+    int inUse[NCOLORS];
+    XColor *colorPtr;
+    XColor *imageColors;
+
+    /*
+     * Create a private colormap if one doesn't already exist for the
+     * window.
+     */
+
+    colorTabPtr->colorMap = colorMap = Tk_Colormap(tkwin);
+
+    nUsedColors = 0;           /* Number of colors allocated */
+
+    if (colorTabPtr->nPixels > 0) {
+       XFreeColors(colorTabPtr->display, colorTabPtr->colorMap,
+           colorTabPtr->pixelValues, colorTabPtr->nPixels, 0);
+    }
+    nFreeColors = QueryColormap(colorTabPtr->display, colorMap, usedColors,
+       &nUsedColors);
+    memset((char *)inUse, 0, sizeof(int) * NCOLORS);
+    if ((nUsedColors == 0) && (keepColors > 0)) {
+
+       /*
+        * We're starting with a clean colormap so find out what colors
+        * have been used in the default colormap.
+        */
+
+       nFreeColors = QueryColormap(colorTabPtr->display,
+           Blt_DefaultColormap(tkwin), usedColors, &nUsedColors);
+
+       /*
+        * Copy a number of colors from the default colormap into the private
+        * colormap.  We can assume that this is the working set from most
+        * (non-image related) applications. While this doesn't stop our
+        * image from flashing and looking dumb when colormaps are swapped
+        * in and out, at least everything else should remain unaffected.
+        */
+
+       if (nUsedColors > keepColors) {
+           nUsedColors = keepColors;
+       }
+       /*
+        * We want to allocate colors in the same ordering as the old colormap,
+        * and we can't assume that the colors in the old map were contiguous.
+        * So mark the colormap locations (i.e. pixels) that we find in use.
+        */
+
+    }
+    for (colorPtr = usedColors, i = 0; i < nUsedColors; i++, colorPtr++) {
+       inUse[colorPtr->pixel] = TRUE;
+    }
+
+    /*
+     * In an "exact" colormap, we try to allocate as many of colors from the
+     * image as we can fit.  If necessary, we'll cheat and reduce the number
+     * of colors by quantizing.
+     */
+    imageColors = usedColors + nUsedColors;
+
+    Tk_SetWindowColormap(tkwin, colorMap);
+}
+
+ColorTable
+Blt_PseudoColorTable(interp, tkwin, image)
+    Tcl_Interp *interp;
+    Tk_Window tkwin;
+    Blt_ColorImage image;
+{
+    struct ColorTableStruct *colorTabPtr;
+    Colormap defColorMap;
+    int usePrivate;
+
+    colorTabPtr = Blt_CreateColorTable(tkwin);
+    defColorMap = DefaultColormap(colorTabPtr->display, Tk_ScreenNumber(tkwin));
+    if (colorTabPtr->colorMap == defColorMap) {
+       fprintf(stderr, "Using default colormap\n");
+    }
+    /* All other visuals use an 8-bit colormap */
+    colorTabPtr->lut = Blt_Malloc(sizeof(unsigned int) * 33 * 33 * 33);
+    assert(colorTabPtr->lut);
+
+    usePrivate = TRUE;
+    if (usePrivate) {
+       PrivateColormap(interp, colorTabPtr, image, tkwin);
+    } else {
+#ifdef notdef
+       ReadOnlyColormap(colorTabPtr, image, tkwin);
+#endif
+    }
+    return colorTabPtr;
+}
+
+#ifdef notdef
+
+static void
+ConvoleColorImage(srcImage, destImage, kernelPtr)
+    Blt_ColorImage srcImage, destImage;
+    ConvoleKernel *kernelPtr;
+{
+    Pix32 *srcPtr, *destPtr;
+    Pix32 *src[MAXROWS];
+    register int x, y, i, j;
+    int red, green, blue;
+
+    /* i = 0 case, ignore left column of pixels */
+
+    srcPtr = Blt_ColorImageBits(srcImage);
+    destPtr = Blt_ColorImageBits(destImage);
+
+    width = Blt_ColorImageWidth(srcImage);
+    height = Blt_ColorImageHeight(srcImage);
+
+    yOffset = kernelPtr->height / 2;
+    xOffset = kernelPtr->width / 2;
+    for (y = yOffset; y < (height - yOffset); y++) {
+       /* Set up pointers to individual rows */
+       for (i = 0; i < kernelPtr->height; i++) {
+           src[i] = srcPtr + (i * width);
+       }
+       for (x = xOffset; x < (width - xOffset); x++) {
+           red = green = blue = 0;
+           kernPtr = kernelPtr->values;
+           for (i = 0; i < kernelPtr->height; i++) {
+               for (j = 0; j < kernelPtr->width; j++) {
+                   red += *valuePtr * src[i][j].Red;
+                   green += *valuePtr * src[i][j].Green;
+                   blue += *valuePtr * src[i][j].Blue;
+                   valuePtr++;
+               }
+           }
+           destPtr->Red = red / kernelPtr->sum;
+           destPtr->Green = green / kernelPtr->sum;
+           destPtr->Blue = blue / kernelPtr->sum;
+           destPtr++;
+       }
+       srcPtr += width;
+    }
+    sum = bot[0].Red +
+       red = bot[0].Red + bot[1].Red + mid[1].Red + top[0].Red + top[1].Red;
+    green = bot[0].Green + bot[1].Green + mid[1].Green + top[0].Green +
+       top[1].Green;
+    blue = bot[0].Blue + bot[1].Blue + mid[1].Blue + top[0].Blue + top[1].Blue;
+    error = (red / 5) - mid[0].Red;
+    redVal = mid[0].Red - (error * blend / blend_divisor);
+    error = (green / 5) - mid[0].Green;
+    greenVal = mid[0].Green - (error * blend / blend_divisor);
+    error = (blue / 5) - mid[0].Blue;
+    blueVal = mid[0].Blue - (error * blend / blend_divisor);
+
+    out[0].Red = CLAMP(redVal);
+    out[0].Green = CLAMP(greenVal);
+    out[0].Blue = CLAMP(blueVal);
+
+    for (i = 1; i < (width - 1); i++) {
+       for (chan = 0; chan < 3; chan++) {
+           total = bot[chan][i - 1] + bot[chan][i] + bot[chan][i + 1] +
+               mid[chan][i - 1] + mid[chan][i + 1] +
+               top[chan][i - 1] + top[chan][i] + top[chan][i + 1];
+           avg = total >> 3;   /* divide by 8 */
+           diff = avg - mid[chan][i];
+           result = mid[chan][i] - (diff * blend / blend_divisor);
+           out[chan][i] = CLAMP(result);
+       }
+    }
+    /* i = in_hdr.xmax case, ignore right column of pixels */
+    for (chan = 0; chan < 3; chan++) {
+       total = bot[chan][i - 1] + bot[chan][i] +
+           mid[chan][i - 1] +
+           top[chan][i - 1] + top[chan][i];
+       avg = total / 5;
+       diff = avg - mid[chan][i];
+       result = mid[chan][i] - (diff * blend / blend_divisor);
+       out[chan][i] = CLAMP(result);
+    }
+}
+
+static void
+DitherRow(srcImage, destImage, lastRow, curRow)
+    Blt_ColorImage srcImage, destImage;
+    int width, height;
+    int bottom, top;
+{
+    int width, height;
+
+    width = Blt_ColorImageWidth(srcImage);
+    topPtr = Blt_ColorImageBits(destPtr) + (width * row);
+    rowPtr = topPtr + width;
+    botPtr = rowPtr + width;
+
+    for (x = 0; x < width; x++) {
+
+       /* Clamp current error entry */
+
+       midPtr->red = CLAMP(midPtr->red);
+       midPtr->blue = CLAMP(midPtr->blue);
+       midPtr->green = CLAMP(midPtr->green);
+
+       r = (midPtr->red >> 3) + 1;
+       g = (midPtr->green >> 3) + 1;
+       b = (midPtr->blue >> 3) + 1;
+       index = colorTabPtr->lut[r][g][b];
+
+       redVal = midPtr->red * (NCOLORS + 1);
+       greenVal = midPtr->green * (NCOLORS + 1);
+       blueVal = midPtr->blue * (NCOLORS + 1);
+
+       error = colorVal - colorMap[index].red;
+       if (x < 511) {
+           currRow[x + 1].Red = currRow[x + 1].Red + 7 * error / 16;
+           nextRow[x + 1].Red = nextRow[x + 1].Red + error / 16;
+       }
+       nextRow[x].Red = nextRow[x].Red + 5 * error / 16;
+       if (x > 0) {
+           nextRow[x - 1].Red = nextRow[x - 1].Red + 3 * error / 16;
+       }
+       error = row[x][c] - colormap[index][c];
+
+       value = srcPtr->channel[i] * error[i];
+       value = CLAMP(value);
+       destPtr->channel[i] = value;
+
+       /* Closest pixel */
+       pixel = PsuedoColorPixel();
+       error[RED] = colorPtr->Red - srcPtr->Red * (NCOLORS + 1);
+
+       /* translate pixel to colorInfoPtr to get error */
+       colorTabPtr->lut[r][g][b];
+       colorPtr = PixelToColorInfo(pixel);
+       error = colorPtr->error;
+
+       register rle_pixel *optr;
+       register int j;
+       register short *thisptr, *nextptr = NULL;
+       int chan;
+       static int nchan = 0;
+       int lastline = 0, lastpixel;
+       static int *cval = 0;
+       static rle_pixel *pixel = 0;
+
+       if (nchan != in_hdr->ncolors)
+           if (cval) {
+               Blt_Free(cval);
+               Blt_Free(pixel);
+           }
+       nchan = in_hdr->ncolors;
+       if (!cval) {
+           if ((cval = Blt_Malloc(nchan * sizeof(int))) == 0)
+                   malloc_ERR;
+           if ((pixel = Blt_Malloc(nchan * sizeof(rle_pixel))) == 0)
+               malloc_ERR;
+       }
+       optr = outrow[RLE_RED];
+
+       thisptr = row_top;
+       if (row_bottom)
+           nextptr = row_bottom;
+       else
+           lastline = 1;
+
+       for (x = 0; x < width; x++) {
+           int cmap_index = 0;
+
+           lastpixel = (x == (width - 1));
+           val = srcPtr->Red;
+
+           for (chan = 0; chan < 3; chan++) {
+               cval[chan] = *thisptr++;
+
+               /*
+                * Current channel value has been accumulating error,
+                * it could be out of range.
+                */
+               if (cval[chan] < 0)
+                   cval[chan] = 0;
+               else if (cval[chan] > 255)
+                   cval[chan] = 255;
+
+               pixel[chan] = cval[chan];
+           }
+
+           /* find closest color */
+           find_closest(map, nchan, maplen, pixel, &cmap_index);
+           *optr++ = cmap_index;
+
+           /* thisptr is now looking at pixel to the right of current pixel
+            * nextptr is looking at pixel below current pixel
+            * So, increment thisptr as stuff gets stored.  nextptr gets moved
+            * by one, and indexing is done +/- nchan.
+            */
+           for (chan = 0; chan < nchan; chan++) {
+               cval[chan] -= map[chan][cmap_index];
+
+               if (!lastpixel) {
+                   thisptr[chan] += cval[chan] * 7 / 16;
+               }
+               if (!lastline) {
+                   if (j != 0) {
+                       nextptr[-nchan] += cval[chan] * 3 / 16;
+                   }
+                   nextptr[0] += cval[chan] * 5 / 16;
+                   if (!lastpixel) {
+                       nextptr[nchan] += cval[chan] / 16;
+                   }
+                   nextptr++;
+               }
+           }
+       }
+    }
+}
+
+/********************************************/
+static Blt_ColorImage
+DoColorDither(pic24, pic8, w, h, rmap, gmap, bmap, rdisp, gdisp, bdisp, maplen)
+    byte *pic24, *pic8, *rmap, *gmap, *bmap, *rdisp, *gdisp, *bdisp;
+    int w, h, maplen;
+{
+    /* takes a 24 bit picture, of size w*h, dithers with the colors in
+       rdisp, gdisp, bdisp (which have already been allocated),
+       and generates an 8-bit w*h image, which it returns.
+       ignores input value 'pic8'
+       returns NULL on error
+
+       note: the rdisp,gdisp,bdisp arrays should be the 'displayed' colors,
+       not the 'desired' colors
+
+       if pic24 is NULL, uses the passed-in pic8 (an 8-bit image) as
+       the source, and the rmap,gmap,bmap arrays as the desired colors */
+
+    byte *np, *ep, *newpic;
+    short *cache;
+    int r2, g2, b2;
+    int *thisline, *nextline, *thisptr, *nextptr, *tmpptr;
+    int i, j, rerr, gerr, berr, pwide3;
+    int imax, jmax;
+    int key;
+    long cnt1, cnt2;
+    int error[512];            /* -255 .. 0 .. +255 */
+
+    /* compute somewhat non-linear floyd-steinberg error mapping table */
+    for (i = j = 0; i <= 0x40; i++, j++) {
+       error[256 + i] = j;
+       error[256 - i] = -j;
+    }
+    for ( /*empty*/ ; i < 0x80; i++, j += !(i & 1) ? 1 : 0) {
+       error[256 + i] = j;
+       error[256 - i] = -j;
+    }
+    for ( /*empty*/ ; i <= 0xff; i++) {
+       error[256 + i] = j;
+       error[256 - i] = -j;
+    }
+
+    cnt1 = cnt2 = 0;
+    pwide3 = w * 3;
+    imax = h - 1;
+    jmax = w - 1;
+    ep = (pic24) ? pic24 : pic8;
+
+    /* attempt to malloc things */
+    newpic = Blt_Malloc((size_t) (w * h));
+    cache = Blt_Calloc((size_t) (2 << 14), sizeof(short));
+    thisline = Blt_Malloc(pwide3 * sizeof(int));
+    nextline = Blt_Malloc(pwide3 * sizeof(int));
+    if (!cache || !newpic || !thisline || !nextline) {
+       if (newpic)
+           Blt_Free(newpic);
+       if (cache)
+           Blt_Free(cache);
+       if (thisline)
+           Blt_Free(thisline);
+       if (nextline)
+           Blt_Free(nextline);
+       return (byte *) NULL;
+    }
+    np = newpic;
+
+    /* Get first line of picture in reverse order. */
+
+    srcPtr = Blt_ColorImageBits(image), tempPtr = tempArr;
+    for (x = 0; x < width; x++, tempPtr++, srcPtr--) {
+       *tempPtr = *srcPtr;
+    }
+
+    for (y = 0; y < height; y++) {
+       tempPtr = curRowPtr, curRowPtr = nextRowPtr, nextRowPtr = tempPtr;
+
+       if (y != (height - 1)) {/* get next line */
+           for (x = 0; x < width; x++, tempPtr++, srcPtr--)
+               *tempPtr = *srcPtr;
+       }
+    }
+
+
+    Blt_Free(thisline);
+    Blt_Free(nextline);
+    Blt_Free(cache);
+
+    return newpic;
+}
+
+
+static void
+DitherImage(image)
+    Blt_ColorImage image;
+{
+    int width, height;
+
+
+
+}
+
+#endif
+
+#endif /* WIN32 */