Change to the linux kernel coding style
[wmaker-crm.git] / wrlib / convert.c
dissimilarity index 91%
index cd54304..46519e2 100644 (file)
-/* convert.c - convert RImage to Pixmap
- *
- * Raster graphics library
- *
- * Copyright (c) 1997-2003 Alfredo K. Kojima
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Library General Public License for more details.
- *
- *  You should have received a copy of the GNU Library General Public
- *  License along with this library; if not, write to the Free
- *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Problems:
- *   1. Using Grayscale visual with Dithering crashes wmaker
- *   2. Ghost dock/appicon is wrong in Pseudocolor, Staticgray, Grayscale
- */
-
-#include <config.h>
-
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <assert.h>
-
-
-#ifdef BENCH
-#include "bench.h"
-#endif
-
-#include "wraster.h"
-
-#ifdef XSHM
-extern Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
-
-#endif
-
-
-#ifdef ASM_X86
-extern void x86_PseudoColor_32_to_8(unsigned char *image,
-                                    unsigned char *ximage,
-                                    char *err, char *nerr,
-                                    short *ctable,
-                                    int dr, int dg, int db,
-                                    unsigned long *pixels,
-                                    int cpc,
-                                    int width, int height,
-                                    int bytesPerPixel,
-                                    int line_offset);
-#endif /* ASM_X86 */
-
-#ifdef ASM_X86_MMX
-
-extern int x86_check_mmx();
-
-extern void x86_mmx_TrueColor_32_to_16(unsigned char *image,
-                                       unsigned short *ximage,
-                                       short *err, short *nerr,
-                                       const unsigned short *rtable,
-                                       const unsigned short *gtable,
-                                       const unsigned short *btable,
-                                       int dr, int dg, int db,
-                                       unsigned int roffs,
-                                       unsigned int goffs,
-                                       unsigned int boffs,
-                                       int width, int height,
-                                       int line_offset);
-
-
-
-#endif /* ASM_X86_MMX */
-
-#define NFREE(n)  if (n) free(n)
-
-#define HAS_ALPHA(I)   ((I)->format == RRGBAFormat)
-
-
-typedef struct RConversionTable {
-    unsigned short table[256];
-    unsigned short index;
-
-    struct RConversionTable *next;
-} RConversionTable;
-
-
-typedef struct RStdConversionTable {
-    unsigned int table[256];
-
-    unsigned short mult;
-    unsigned short max;
-
-    struct RStdConversionTable *next;
-} RStdConversionTable;
-
-
-
-static RConversionTable *conversionTable = NULL;
-static RStdConversionTable *stdConversionTable = NULL;
-
-
-static unsigned short*
-computeTable(unsigned short mask)
-{
-    RConversionTable *tmp = conversionTable;
-    int i;
-
-    while (tmp) {
-        if (tmp->index == mask)
-            break;
-        tmp = tmp->next;
-    }
-
-    if (tmp)
-        return tmp->table;
-
-    tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
-    if (tmp == NULL)
-        return NULL;
-
-    for (i=0;i<256;i++)
-        tmp->table[i] = (i*mask + 0x7f)/0xff;
-
-    tmp->index = mask;
-    tmp->next = conversionTable;
-    conversionTable = tmp;
-    return tmp->table;
-}
-
-
-static unsigned int*
-computeStdTable(unsigned int mult, unsigned int max)
-{
-    RStdConversionTable *tmp = stdConversionTable;
-    unsigned int i;
-
-    while (tmp) {
-        if (tmp->mult == mult && tmp->max == max)
-            break;
-        tmp = tmp->next;
-    }
-
-    if (tmp)
-        return tmp->table;
-
-    tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable));
-    if (tmp == NULL)
-        return NULL;
-
-    for (i=0; i<256; i++) {
-        tmp->table[i] = (i*max)/0xff * mult;
-    }
-    tmp->mult = mult;
-    tmp->max = max;
-
-    tmp->next = stdConversionTable;
-    stdConversionTable = tmp;
-
-    return tmp->table;
-}
-
-/***************************************************************************/
-
-
-static void
-convertTrueColor_generic(RXImage *ximg, RImage *image,
-                         signed char *err, signed char *nerr,
-                         const unsigned short *rtable,
-                         const unsigned short *gtable,
-                         const unsigned short *btable,
-                         const int dr, const int dg, const int db,
-                         const unsigned short roffs,
-                         const unsigned short goffs,
-                         const unsigned short boffs)
-{
-    signed char *terr;
-    int x, y, r, g, b;
-    int pixel;
-    int rer, ger, ber;
-    unsigned char *ptr = image->data;
-    int channels = (HAS_ALPHA(image) ? 4 : 3);
-
-    /* convert and dither the image to XImage */
-    for (y=0; y<image->height; y++) {
-        nerr[0] = 0;
-        nerr[1] = 0;
-        nerr[2] = 0;
-        for (x=0; x<image->width; x++, ptr+=channels) {
-
-            /* reduce pixel */
-            pixel = *ptr + err[x];
-            if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-            r = rtable[pixel];
-            /* calc error */
-            rer = pixel - r*dr;
-
-            /* reduce pixel */
-            pixel = *(ptr+1) + err[x+1];
-            if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-            g = gtable[pixel];
-            /* calc error */
-            ger = pixel - g*dg;
-
-            /* reduce pixel */
-            pixel = *(ptr+2) + err[x+2];
-            if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-            b = btable[pixel];
-            /* calc error */
-            ber = pixel - b*db;
-
-
-            pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
-            XPutPixel(ximg->image, x, y, pixel);
-
-            /* distribute error */
-            r = (rer*3)/8;
-            g = (ger*3)/8;
-            b = (ber*3)/8;
-            /* x+1, y */
-            err[x+3*1]+=r;
-            err[x+1+3*1]+=g;
-            err[x+2+3*1]+=b;
-            /* x, y+1 */
-            nerr[x]+=r;
-            nerr[x+1]+=g;
-            nerr[x+2]+=b;
-            /* x+1, y+1 */
-            nerr[x+3*1]=rer-2*r;
-            nerr[x+1+3*1]=ger-2*g;
-            nerr[x+2+3*1]=ber-2*b;
-        }
-        /* skip to next line */
-        terr = err;
-        err = nerr;
-        nerr = terr;
-    }
-
-    /* redither the 1st line to distribute error better */
-    ptr=image->data;
-    y=0;
-    nerr[0] = 0;
-    nerr[1] = 0;
-    nerr[2] = 0;
-    for (x=0; x<image->width; x++, ptr+=channels) {
-
-        /* reduce pixel */
-        pixel = *ptr + err[x];
-        if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-        r = rtable[pixel];
-        /* calc error */
-        rer = pixel - r*dr;
-
-        /* reduce pixel */
-        pixel = *(ptr+1) + err[x+1];
-        if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-        g = gtable[pixel];
-        /* calc error */
-        ger = pixel - g*dg;
-
-        /* reduce pixel */
-        pixel = *(ptr+2) + err[x+2];
-        if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-        b = btable[pixel];
-        /* calc error */
-        ber = pixel - b*db;
-
-
-        pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
-        XPutPixel(ximg->image, x, y, pixel);
-
-        /* distribute error */
-        r = (rer*3)/8;
-        g = (ger*3)/8;
-        b = (ber*3)/8;
-        /* x+1, y */
-        err[x+3*1]+=r;
-        err[x+1+3*1]+=g;
-        err[x+2+3*1]+=b;
-        /* x, y+1 */
-        nerr[x]+=r;
-        nerr[x+1]+=g;
-        nerr[x+2]+=b;
-        /* x+1, y+1 */
-        nerr[x+3*1]=rer-2*r;
-        nerr[x+1+3*1]=ger-2*g;
-        nerr[x+2+3*1]=ber-2*b;
-    }
-}
-
-
-
-
-static RXImage*
-image2TrueColor(RContext *ctx, RImage *image)
-{
-    RXImage *ximg;
-    unsigned short rmask, gmask, bmask;
-    unsigned short roffs, goffs, boffs;
-    unsigned short *rtable, *gtable, *btable;
-    int channels = (HAS_ALPHA(image) ? 4 : 3);
-
-    ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
-    if (!ximg) {
-        return NULL;
-    }
-
-    roffs = ctx->red_offset;
-    goffs = ctx->green_offset;
-    boffs = ctx->blue_offset;
-
-    rmask = ctx->visual->red_mask >> roffs;
-    gmask = ctx->visual->green_mask >> goffs;
-    bmask = ctx->visual->blue_mask >> boffs;
-
-    rtable = computeTable(rmask);
-    gtable = computeTable(gmask);
-    btable = computeTable(bmask);
-
-    if (rtable==NULL || gtable==NULL || btable==NULL) {
-        RErrorCode = RERR_NOMEMORY;
-        RDestroyXImage(ctx, ximg);
-        return NULL;
-    }
-
-
-#ifdef BENCH
-    cycle_bench(1);
-#endif
-
-    if (ctx->attribs->render_mode==RBestMatchRendering) {
-        int ofs, r, g, b;
-        int x, y;
-        unsigned long pixel;
-        unsigned char *ptr = image->data;
-
-        /* fake match */
-#ifdef DEBUG
-        puts("true color match");
-#endif
-        if (rmask==0xff && gmask==0xff && bmask==0xff) {
-            for (y=0; y < image->height; y++) {
-                for (x=0; x < image->width; x++, ptr+=channels) {
-                    /* reduce pixel */
-                    pixel = (*(ptr)<<roffs) | (*(ptr+1)<<goffs) | (*(ptr+2)<<boffs);
-                    XPutPixel(ximg->image, x, y, pixel);
-                }
-            }
-        } else {
-            for (y=0, ofs=0; y < image->height; y++) {
-                for (x=0; x < image->width; x++, ofs+=channels-3) {
-                    /* reduce pixel */
-                    r = rtable[ptr[ofs++]];
-                    g = gtable[ptr[ofs++]];
-                    b = btable[ptr[ofs++]];
-                    pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
-                    XPutPixel(ximg->image, x, y, pixel);
-                }
-            }
-        }
-    } else {
-        /* dither */
-        const int dr=0xff/rmask;
-        const int dg=0xff/gmask;
-        const int db=0xff/bmask;
-
-#ifdef DEBUG
-        puts("true color dither");
-#endif
-
-#ifdef ASM_X86_MMX
-        if (ctx->depth==16 && HAS_ALPHA(image) && x86_check_mmx()) {
-            short *err;
-            short *nerr;
-
-            err = malloc(8*(image->width+3));
-            nerr = malloc(8*(image->width+3));
-            if (!err || !nerr) {
-                NFREE(err);
-                NFREE(nerr);
-                RErrorCode = RERR_NOMEMORY;
-                RDestroyXImage(ctx, ximg);
-                return NULL;
-            }
-            memset(err, 0, 8*(image->width+3));
-            memset(nerr, 0, 8*(image->width+3));
-
-            x86_mmx_TrueColor_32_to_16(image->data,
-                                       (unsigned short*)ximg->image->data,
-                                       err+8, nerr+8,
-                                       rtable, gtable, btable,
-                                       dr, dg, db,
-                                       roffs, goffs, boffs,
-                                       image->width, image->height,
-                                       ximg->image->bytes_per_line - 2*image->width);
-
-            free(err);
-            free(nerr);
-        } else
-#endif /* ASM_X86_MMX */
-        {
-            signed char *err;
-            signed char *nerr;
-            int ch = (HAS_ALPHA(image) ? 4 : 3);
-
-            err = malloc(ch*(image->width+2));
-            nerr = malloc(ch*(image->width+2));
-            if (!err || !nerr) {
-                NFREE(err);
-                NFREE(nerr);
-                RErrorCode = RERR_NOMEMORY;
-                RDestroyXImage(ctx, ximg);
-                return NULL;
-            }
-
-            memset(err, 0, ch*(image->width+2));
-            memset(nerr, 0, ch*(image->width+2));
-
-            convertTrueColor_generic(ximg, image, err, nerr,
-                                     rtable, gtable, btable,
-                                     dr, dg, db, roffs, goffs, boffs);
-            free(err);
-            free(nerr);
-        }
-
-    }
-
-#ifdef BENCH
-    cycle_bench(0);
-#endif
-
-    return ximg;
-}
-
-
-/***************************************************************************/
-
-static void
-convertPseudoColor_to_8(RXImage *ximg, RImage *image,
-                        signed char *err, signed char *nerr,
-                        const unsigned short *rtable,
-                        const unsigned short *gtable,
-                        const unsigned short *btable,
-                        const int dr, const int dg, const int db,
-                        unsigned long *pixels,
-                        int cpc)
-{
-    signed char *terr;
-    int x, y, r, g, b;
-    int pixel;
-    int rer, ger, ber;
-    unsigned char *ptr = image->data;
-    unsigned char *optr = (unsigned char*)ximg->image->data;
-    int channels = (HAS_ALPHA(image) ? 4 : 3);
-    int cpcpc = cpc*cpc;
-
-    /* convert and dither the image to XImage */
-    for (y=0; y<image->height; y++) {
-        nerr[0] = 0;
-        nerr[1] = 0;
-        nerr[2] = 0;
-        for (x=0; x<image->width*3; x+=3, ptr+=channels) {
-
-            /* reduce pixel */
-            pixel = *ptr + err[x];
-            if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-            r = rtable[pixel];
-            /* calc error */
-            rer = pixel - r*dr;
-
-            /* reduce pixel */
-            pixel = *(ptr+1) + err[x+1];
-            if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-            g = gtable[pixel];
-            /* calc error */
-            ger = pixel - g*dg;
-
-            /* reduce pixel */
-            pixel = *(ptr+2) + err[x+2];
-            if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
-            b = btable[pixel];
-            /* calc error */
-            ber = pixel - b*db;
-
-            *optr++ = pixels[r*cpcpc + g*cpc + b];
-
-            /* distribute error */
-            r = (rer*3)/8;
-            g = (ger*3)/8;
-            b = (ber*3)/8;
-
-            /* x+1, y */
-            err[x+3*1]+=r;
-            err[x+1+3*1]+=g;
-            err[x+2+3*1]+=b;
-            /* x, y+1 */
-            nerr[x]+=r;
-            nerr[x+1]+=g;
-            nerr[x+2]+=b;
-            /* x+1, y+1 */
-            nerr[x+3*1]=rer-2*r;
-            nerr[x+1+3*1]=ger-2*g;
-            nerr[x+2+3*1]=ber-2*b;
-        }
-        /* skip to next line */
-        terr = err;
-        err = nerr;
-        nerr = terr;
-
-        optr += ximg->image->bytes_per_line - image->width;
-    }
-}
-
-
-
-static RXImage*
-image2PseudoColor(RContext *ctx, RImage *image)
-{
-    RXImage *ximg;
-    register int x, y, r, g, b;
-    unsigned char *ptr;
-    unsigned long pixel;
-    const int cpc=ctx->attribs->colors_per_channel;
-    const unsigned short rmask = cpc-1; /* different sizes could be used */
-    const unsigned short gmask = rmask; /* for r,g,b */
-    const unsigned short bmask = rmask;
-    unsigned short *rtable, *gtable, *btable;
-    const int cpccpc = cpc*cpc;
-    int channels = (HAS_ALPHA(image) ? 4 : 3);
-
-    ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
-    if (!ximg) {
-        return NULL;
-    }
-
-    ptr = image->data;
-
-    /* Tables are same at the moment because rmask==gmask==bmask. */
-    rtable = computeTable(rmask);
-    gtable = computeTable(gmask);
-    btable = computeTable(bmask);
-
-    if (rtable==NULL || gtable==NULL || btable==NULL) {
-        RErrorCode = RERR_NOMEMORY;
-        RDestroyXImage(ctx, ximg);
-        return NULL;
-    }
-
-    if (ctx->attribs->render_mode == RBestMatchRendering) {
-        /* fake match */
-#ifdef DEBUG
-        printf("pseudo color match with %d colors per channel\n", cpc);
-#endif
-        for (y=0; y<image->height; y++) {
-            for (x=0; x<image->width; x++, ptr+=channels-3) {
-                /* reduce pixel */
-                r = rtable[*ptr++];
-                g = gtable[*ptr++];
-                b = btable[*ptr++];
-                pixel = r*cpccpc + g*cpc + b;
-                /*data[ofs] = ctx->colors[pixel].pixel;*/
-                XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
-            }
-        }
-    } else {
-        /* dither */
-        signed char *err;
-        signed char *nerr;
-        const int dr=0xff/rmask;
-        const int dg=0xff/gmask;
-        const int db=0xff/bmask;
-
-
-#ifdef DEBUG
-        printf("pseudo color dithering with %d colors per channel\n", cpc);
-#endif
-        err = malloc(4*(image->width+3));
-        nerr = malloc(4*(image->width+3));
-        if (!err || !nerr) {
-            NFREE(err);
-            NFREE(nerr);
-            RErrorCode = RERR_NOMEMORY;
-            RDestroyXImage(ctx, ximg);
-            return NULL;
-        }
-        memset(err, 0, 4*(image->width+3));
-        memset(nerr, 0, 4*(image->width+3));
-
-        /*#ifdef ASM_X86*/
-#if 0
-        x86_PseudoColor_32_to_8(image->data, ximg->image->data,
-                                err+4, nerr+4,
-                                rtable,
-                                dr, dg, db, ctx->pixels, cpc,
-                                image->width, image->height,
-                                channels,
-                                ximg->image->bytes_per_line - image->width);
-#else
-        convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
-                                rtable,        gtable, btable,
-                                dr, dg, db, ctx->pixels, cpc);
-#endif
-
-        free(err);
-        free(nerr);
-    }
-
-    return ximg;
-}
-
-
-/*
- * For standard colormap
- */
-static RXImage*
-image2StandardPseudoColor(RContext *ctx, RImage *image)
-{
-    RXImage *ximg;
-    register int x, y, r, g, b;
-    unsigned char *ptr;
-    unsigned long pixel;
-    unsigned char *data;
-    unsigned int *rtable, *gtable, *btable;
-    unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
-    int channels = (HAS_ALPHA(image) ? 4 : 3);
-
-
-    ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
-    if (!ximg) {
-        return NULL;
-    }
-
-    ptr = image->data;
-
-    data = (unsigned char *)ximg->image->data;
-
-
-    rtable = computeStdTable(ctx->std_rgb_map->red_mult,
-                             ctx->std_rgb_map->red_max);
-
-    gtable = computeStdTable(ctx->std_rgb_map->green_mult,
-                             ctx->std_rgb_map->green_max);
-
-    btable = computeStdTable(ctx->std_rgb_map->blue_mult,
-                             ctx->std_rgb_map->blue_max);
-
-    if (rtable==NULL || gtable==NULL || btable==NULL) {
-        RErrorCode = RERR_NOMEMORY;
-        RDestroyXImage(ctx, ximg);
-        return NULL;
-    }
-
-
-    if (ctx->attribs->render_mode == RBestMatchRendering) {
-        for (y=0; y<image->height; y++) {
-            for (x=0; x<image->width; x++, ptr+=channels) {
-                /* reduce pixel */
-                pixel = (rtable[*ptr] + gtable[*(ptr+1)]
-                         + btable[*(ptr+2)] + base_pixel) & 0xffffffff;
-
-                XPutPixel(ximg->image, x, y, pixel);
-            }
-        }
-    } else {
-        /* dither */
-        signed short *err, *nerr;
-        signed short *terr;
-        int rer, ger, ber;
-        int x1, ofs;
-
-#ifdef DEBUG
-        printf("pseudo color dithering with %d colors per channel\n",
-               ctx->attribs->colors_per_channel);
-#endif
-        err = (short*)malloc(3*(image->width+2)*sizeof(short));
-        nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
-        if (!err || !nerr) {
-            NFREE(err);
-            NFREE(nerr);
-            RErrorCode = RERR_NOMEMORY;
-            RDestroyXImage(ctx, ximg);
-            return NULL;
-        }
-        for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
-            err[x++] = ptr[x1++];
-            err[x++] = ptr[x1++];
-            err[x++] = ptr[x1++];
-        }
-        err[x] = err[x+1] = err[x+2] = 0;
-        /* convert and dither the image to XImage */
-        for (y=0, ofs=0; y<image->height; y++) {
-            if (y<image->height-1) {
-                int x1;
-                for (x=0, x1=(y+1)*image->width*channels;
-                     x<image->width*3;
-                     x1+=channels-3) {
-                    nerr[x++] = ptr[x1++];
-                    nerr[x++] = ptr[x1++];
-                    nerr[x++] = ptr[x1++];
-                }
-                /* last column */
-                x1-=channels;
-                nerr[x++] = ptr[x1++];
-                nerr[x++] = ptr[x1++];
-                nerr[x++] = ptr[x1++];
-            }
-            for (x=0; x<image->width*3; x+=3, ofs++) {
-                /* reduce pixel */
-                if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
-                if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
-                if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
-
-                r = rtable[err[x]];
-                g = gtable[err[x+1]];
-                b = btable[err[x+2]];
-
-                pixel = r + g + b;
-
-                data[ofs] = base_pixel + pixel;
-
-                /* calc error */
-                rer = err[x] - (ctx->colors[pixel].red>>8);
-                ger = err[x+1] - (ctx->colors[pixel].green>>8);
-                ber = err[x+2] - (ctx->colors[pixel].blue>>8);
-
-                /* distribute error */
-                err[x+3*1]+=(rer*7)/16;
-                err[x+1+3*1]+=(ger*7)/16;
-                err[x+2+3*1]+=(ber*7)/16;
-
-                nerr[x]+=(rer*5)/16;
-                nerr[x+1]+=(ger*5)/16;
-                nerr[x+2]+=(ber*5)/16;
-
-                if (x>0) {
-                    nerr[x-3*1]+=(rer*3)/16;
-                    nerr[x-3*1+1]+=(ger*3)/16;
-                    nerr[x-3*1+2]+=(ber*3)/16;
-                }
-
-                nerr[x+3*1]+=rer/16;
-                nerr[x+1+3*1]+=ger/16;
-                nerr[x+2+3*1]+=ber/16;
-            }
-            /* skip to next line */
-            terr = err;
-            err = nerr;
-            nerr = terr;
-
-            ofs += ximg->image->bytes_per_line - image->width;
-        }
-        free(err);
-        free(nerr);
-    }
-    ximg->image->data = (char*)data;
-
-    return ximg;
-}
-
-
-
-static RXImage*
-image2GrayScale(RContext *ctx, RImage *image)
-{
-    RXImage *ximg;
-    register int x, y, g;
-    unsigned char *ptr;
-    const int cpc=ctx->attribs->colors_per_channel;
-    unsigned short gmask;
-    unsigned short *table;
-    unsigned char *data;
-    int channels = (HAS_ALPHA(image) ? 4 : 3);
-
-
-    ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
-    if (!ximg) {
-        return NULL;
-    }
-
-    ptr = image->data;
-
-    data = (unsigned char *)ximg->image->data;
-
-    if (ctx->vclass == StaticGray)
-        gmask = (1<<ctx->depth) - 1; /* use all grays */
-    else
-        gmask  = cpc*cpc*cpc-1;
-
-    table = computeTable(gmask);
-
-    if (table==NULL) {
-        RErrorCode = RERR_NOMEMORY;
-        RDestroyXImage(ctx, ximg);
-        return NULL;
-    }
-
-    if (ctx->attribs->render_mode == RBestMatchRendering) {
-        /* fake match */
-#ifdef DEBUG
-        printf("grayscale match with %d colors per channel\n", cpc);
-#endif
-        for (y=0; y<image->height; y++) {
-            for (x=0; x<image->width; x++) {
-                /* reduce pixel */
-                g = table[(*ptr * 30 + *(ptr+1) * 59 + *(ptr+2) * 11)/100];
-                ptr += channels;
-                /*data[ofs] = ctx->colors[g].pixel;*/
-                XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
-            }
-        }
-    } else {
-        /* dither */
-        short *gerr;
-        short *ngerr;
-        short *terr;
-        int ger;
-        const int dg=0xff/gmask;
-
-#ifdef DEBUG
-        printf("grayscale dither with %d colors per channel\n", cpc);
-#endif
-        gerr = (short*)malloc((image->width+2)*sizeof(short));
-        ngerr = (short*)malloc((image->width+2)*sizeof(short));
-        if (!gerr || !ngerr) {
-            NFREE(gerr);
-            NFREE(ngerr);
-            RErrorCode = RERR_NOMEMORY;
-            RDestroyXImage(ctx, ximg);
-            return NULL;
-        }
-        for (x=0, y=0; x<image->width; x++, y+=channels) {
-            gerr[x] = (ptr[y]*30 + ptr[y+1]*59 + ptr[y+2]*11)/100;
-        }
-        gerr[x] = 0;
-        /* convert and dither the image to XImage */
-        for (y=0; y<image->height; y++) {
-            if (y<image->height-1) {
-                int x1;
-                for (x=0, x1=(y+1)*image->width*channels; x<image->width; x++, x1+=channels) {
-                    ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
-                }
-                /* last column */
-                x1-=channels;
-                ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
-            }
-            for (x=0; x<image->width; x++) {
-                /* reduce pixel */
-                if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
-
-                g = table[gerr[x]];
-
-                /*data[ofs] = ctx->colors[g].pixel;*/
-                XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
-                /* calc error */
-                ger = gerr[x] - g*dg;
-
-                /* distribute error */
-                g = (ger*3)/8;
-                /* x+1, y */
-                gerr[x+1]+=g;
-                /* x, y+1 */
-                ngerr[x]+=g;
-                /* x+1, y+1 */
-                ngerr[x+1]+=ger-2*g;
-            }
-            /* skip to next line */
-            terr = gerr;
-            gerr = ngerr;
-            ngerr = terr;
-        }
-        free(gerr);
-        free(ngerr);
-    }
-    ximg->image->data = (char*)data;
-
-    return ximg;
-}
-
-
-static RXImage*
-image2Bitmap(RContext *ctx, RImage *image, int threshold)
-{
-    RXImage *ximg;
-    unsigned char *alpha;
-    int x, y;
-
-    ximg = RCreateXImage(ctx, 1, image->width, image->height);
-    if (!ximg) {
-        return NULL;
-    }
-    alpha = image->data+3;
-
-    for (y = 0; y < image->height; y++) {
-        for (x = 0; x < image->width; x++) {
-            XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
-            alpha+=4;
-        }
-    }
-
-    return ximg;
-}
-
-
-int
-RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
-{
-    RXImage *ximg=NULL;
-#ifdef XSHM
-    Pixmap tmp;
-#endif
-
-    assert(context!=NULL);
-    assert(image!=NULL);
-    assert(pixmap!=NULL);
-
-    switch (context->vclass) {
-    case TrueColor:
-#ifdef BENCH
-        cycle_bench(1);
-#endif
-        ximg = image2TrueColor(context, image);
-#ifdef BENCH
-        cycle_bench(0);
-#endif
-        break;
-
-    case PseudoColor:
-    case StaticColor:
-#ifdef BENCH
-        cycle_bench(1);
-#endif
-        if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
-            ximg = image2StandardPseudoColor(context, image);
-        else
-            ximg = image2PseudoColor(context, image);
-#ifdef BENCH
-        cycle_bench(0);
-#endif
-        break;
-
-    case GrayScale:
-    case StaticGray:
-        ximg = image2GrayScale(context, image);
-        break;
-    }
-
-
-    if (!ximg) {
-        return False;
-    }
-
-    *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
-                            image->height, context->depth);
-
-#ifdef XSHM
-    if (context->flags.use_shared_pixmap && ximg->is_shared)
-        tmp = R_CreateXImageMappedPixmap(context, ximg);
-    else
-        tmp = None;
-    if (tmp) {
-        /*
-         * We have to copy the shm Pixmap into a normal Pixmap because
-         * otherwise, we would have to control when Pixmaps are freed so
-         * that we can detach their shm segments. This is a problem if the
-         * program crash, leaving stale shared memory segments in the
-         * system (lots of them). But with some work, we can optimize
-         * things and remove this XCopyArea. This will require
-         * explicitly freeing all pixmaps when exiting or restarting
-         * wmaker.
-         */
-        XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
-                  image->width, image->height, 0, 0);
-        XFreePixmap(context->dpy, tmp);
-    } else {
-        RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
-                   image->width, image->height);
-    }
-#else /* !XSHM */
-    RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
-               image->width, image->height);
-#endif /* !XSHM */
-
-    RDestroyXImage(context, ximg);
-
-    return True;
-}
-
-
-/* make the gc permanent (create with context creation).
- * GC creation is very expensive. altering its properties is not. -Dan
- */
-int
-RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
-                  Pixmap *mask, int threshold)
-{
-    GC gc;
-    XGCValues gcv;
-    RXImage *ximg=NULL;
-
-    assert(context!=NULL);
-    assert(image!=NULL);
-    assert(pixmap!=NULL);
-    assert(mask!=NULL);
-
-    if (!RConvertImage(context, image, pixmap))
-        return False;
-
-    if (image->format==RRGBFormat) {
-        *mask = None;
-        return True;
-    }
-
-    ximg = image2Bitmap(context, image, threshold);
-
-    if (!ximg) {
-        return False;
-    }
-    *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
-                          image->height, 1);
-    gcv.foreground = context->black;
-    gcv.background = context->white;
-    gcv.graphics_exposures = False;
-    gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
-                   |GCGraphicsExposures, &gcv);
-    RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
-               image->width, image->height);
-    RDestroyXImage(context, ximg);
-    XFreeGC(context->dpy, gc);
-
-    return True;
-}
-
-
-Bool
-RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
-{
-    if (context->vclass == TrueColor) {
-        unsigned short rmask, gmask, bmask;
-        unsigned short roffs, goffs, boffs;
-        unsigned short *rtable, *gtable, *btable;
-
-        roffs = context->red_offset;
-        goffs = context->green_offset;
-        boffs = context->blue_offset;
-
-        rmask = context->visual->red_mask >> roffs;
-        gmask = context->visual->green_mask >> goffs;
-        bmask = context->visual->blue_mask >> boffs;
-
-        rtable = computeTable(rmask);
-        gtable = computeTable(gmask);
-        btable = computeTable(bmask);
-
-        retColor->pixel = (rtable[color->red]<<roffs) |
-            (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
-
-        retColor->red = color->red << 8;
-        retColor->green = color->green << 8;
-        retColor->blue = color->blue << 8;
-        retColor->flags = DoRed|DoGreen|DoBlue;
-
-    } else if (context->vclass == PseudoColor
-               || context->vclass == StaticColor) {
-
-        if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
-            unsigned int *rtable, *gtable, *btable;
-
-            rtable = computeStdTable(context->std_rgb_map->red_mult,
-                                     context->std_rgb_map->red_max);
-
-            gtable = computeStdTable(context->std_rgb_map->green_mult,
-                                     context->std_rgb_map->green_max);
-
-            btable = computeStdTable(context->std_rgb_map->blue_mult,
-                                     context->std_rgb_map->blue_max);
-
-            if (rtable==NULL || gtable==NULL || btable==NULL) {
-                RErrorCode = RERR_NOMEMORY;
-                return False;
-            }
-
-            retColor->pixel = (rtable[color->red]
-                               + gtable[color->green]
-                               + btable[color->blue]
-                               + context->std_rgb_map->base_pixel) & 0xffffffff;
-            retColor->red = color->red<<8;
-            retColor->green = color->green<<8;
-            retColor->blue = color->blue<<8;
-            retColor->flags = DoRed|DoGreen|DoBlue;
-
-        } else {
-            const int cpc=context->attribs->colors_per_channel;
-            const unsigned short rmask = cpc-1; /* different sizes could be used */
-            const unsigned short gmask = rmask; /* for r,g,b */
-            const unsigned short bmask = rmask;
-            unsigned short *rtable, *gtable, *btable;
-            const int cpccpc = cpc*cpc;
-            int index;
-
-            rtable = computeTable(rmask);
-            gtable = computeTable(gmask);
-            btable = computeTable(bmask);
-
-            if (rtable==NULL || gtable==NULL || btable==NULL) {
-                RErrorCode = RERR_NOMEMORY;
-                return False;
-            }
-            index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
-                + btable[color->blue];
-            *retColor = context->colors[index];
-        }
-
-    } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
-
-        const int cpc = context->attribs->colors_per_channel;
-        unsigned short gmask;
-        unsigned short *table;
-        int index;
-
-        if (context->vclass == StaticGray)
-            gmask = (1<<context->depth) - 1; /* use all grays */
-        else
-            gmask  = cpc*cpc*cpc-1;
-
-        table = computeTable(gmask);
-        if (!table)
-            return False;
-
-        index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
-
-        *retColor = context->colors[index];
-    } else {
-        RErrorCode = RERR_INTERNAL;
-        return False;
-    }
-
-    return True;
-}
-
-
+/* convert.c - convert RImage to Pixmap
+ *
+ * Raster graphics library
+ *
+ * Copyright (c) 1997-2003 Alfredo K. Kojima
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Problems:
+ *   1. Using Grayscale visual with Dithering crashes wmaker
+ *   2. Ghost dock/appicon is wrong in Pseudocolor, Staticgray, Grayscale
+ */
+
+#include <config.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <assert.h>
+
+#ifdef BENCH
+#include "bench.h"
+#endif
+
+#include "wraster.h"
+
+#ifdef XSHM
+extern Pixmap R_CreateXImageMappedPixmap(RContext * context, RXImage * ximage);
+
+#endif
+
+#ifdef ASM_X86
+extern void x86_PseudoColor_32_to_8(unsigned char *image,
+                                   unsigned char *ximage,
+                                   char *err, char *nerr,
+                                   short *ctable,
+                                   int dr, int dg, int db,
+                                   unsigned long *pixels,
+                                   int cpc, int width, int height, int bytesPerPixel, int line_offset);
+#endif                         /* ASM_X86 */
+
+#ifdef ASM_X86_MMX
+
+extern int x86_check_mmx();
+
+extern void x86_mmx_TrueColor_32_to_16(unsigned char *image,
+                                      unsigned short *ximage,
+                                      short *err, short *nerr,
+                                      const unsigned short *rtable,
+                                      const unsigned short *gtable,
+                                      const unsigned short *btable,
+                                      int dr, int dg, int db,
+                                      unsigned int roffs,
+                                      unsigned int goffs,
+                                      unsigned int boffs, int width, int height, int line_offset);
+
+#endif                         /* ASM_X86_MMX */
+
+#define NFREE(n)  if (n) free(n)
+
+#define HAS_ALPHA(I)   ((I)->format == RRGBAFormat)
+
+typedef struct RConversionTable {
+       unsigned short table[256];
+       unsigned short index;
+
+       struct RConversionTable *next;
+} RConversionTable;
+
+typedef struct RStdConversionTable {
+       unsigned int table[256];
+
+       unsigned short mult;
+       unsigned short max;
+
+       struct RStdConversionTable *next;
+} RStdConversionTable;
+
+static RConversionTable *conversionTable = NULL;
+static RStdConversionTable *stdConversionTable = NULL;
+
+static unsigned short *computeTable(unsigned short mask)
+{
+       RConversionTable *tmp = conversionTable;
+       int i;
+
+       while (tmp) {
+               if (tmp->index == mask)
+                       break;
+               tmp = tmp->next;
+       }
+
+       if (tmp)
+               return tmp->table;
+
+       tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
+       if (tmp == NULL)
+               return NULL;
+
+       for (i = 0; i < 256; i++)
+               tmp->table[i] = (i * mask + 0x7f) / 0xff;
+
+       tmp->index = mask;
+       tmp->next = conversionTable;
+       conversionTable = tmp;
+       return tmp->table;
+}
+
+static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
+{
+       RStdConversionTable *tmp = stdConversionTable;
+       unsigned int i;
+
+       while (tmp) {
+               if (tmp->mult == mult && tmp->max == max)
+                       break;
+               tmp = tmp->next;
+       }
+
+       if (tmp)
+               return tmp->table;
+
+       tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
+       if (tmp == NULL)
+               return NULL;
+
+       for (i = 0; i < 256; i++) {
+               tmp->table[i] = (i * max) / 0xff * mult;
+       }
+       tmp->mult = mult;
+       tmp->max = max;
+
+       tmp->next = stdConversionTable;
+       stdConversionTable = tmp;
+
+       return tmp->table;
+}
+
+/***************************************************************************/
+
+static void
+convertTrueColor_generic(RXImage * ximg, RImage * image,
+                        signed char *err, signed char *nerr,
+                        const unsigned short *rtable,
+                        const unsigned short *gtable,
+                        const unsigned short *btable,
+                        const int dr, const int dg, const int db,
+                        const unsigned short roffs, const unsigned short goffs, const unsigned short boffs)
+{
+       signed char *terr;
+       int x, y, r, g, b;
+       int pixel;
+       int rer, ger, ber;
+       unsigned char *ptr = image->data;
+       int channels = (HAS_ALPHA(image) ? 4 : 3);
+
+       /* convert and dither the image to XImage */
+       for (y = 0; y < image->height; y++) {
+               nerr[0] = 0;
+               nerr[1] = 0;
+               nerr[2] = 0;
+               for (x = 0; x < image->width; x++, ptr += channels) {
+
+                       /* reduce pixel */
+                       pixel = *ptr + err[x];
+                       if (pixel < 0)
+                               pixel = 0;
+                       else if (pixel > 0xff)
+                               pixel = 0xff;
+                       r = rtable[pixel];
+                       /* calc error */
+                       rer = pixel - r * dr;
+
+                       /* reduce pixel */
+                       pixel = *(ptr + 1) + err[x + 1];
+                       if (pixel < 0)
+                               pixel = 0;
+                       else if (pixel > 0xff)
+                               pixel = 0xff;
+                       g = gtable[pixel];
+                       /* calc error */
+                       ger = pixel - g * dg;
+
+                       /* reduce pixel */
+                       pixel = *(ptr + 2) + err[x + 2];
+                       if (pixel < 0)
+                               pixel = 0;
+                       else if (pixel > 0xff)
+                               pixel = 0xff;
+                       b = btable[pixel];
+                       /* calc error */
+                       ber = pixel - b * db;
+
+                       pixel = (r << roffs) | (g << goffs) | (b << boffs);
+                       XPutPixel(ximg->image, x, y, pixel);
+
+                       /* distribute error */
+                       r = (rer * 3) / 8;
+                       g = (ger * 3) / 8;
+                       b = (ber * 3) / 8;
+                       /* x+1, y */
+                       err[x + 3 * 1] += r;
+                       err[x + 1 + 3 * 1] += g;
+                       err[x + 2 + 3 * 1] += b;
+                       /* x, y+1 */
+                       nerr[x] += r;
+                       nerr[x + 1] += g;
+                       nerr[x + 2] += b;
+                       /* x+1, y+1 */
+                       nerr[x + 3 * 1] = rer - 2 * r;
+                       nerr[x + 1 + 3 * 1] = ger - 2 * g;
+                       nerr[x + 2 + 3 * 1] = ber - 2 * b;
+               }
+               /* skip to next line */
+               terr = err;
+               err = nerr;
+               nerr = terr;
+       }
+
+       /* redither the 1st line to distribute error better */
+       ptr = image->data;
+       y = 0;
+       nerr[0] = 0;
+       nerr[1] = 0;
+       nerr[2] = 0;
+       for (x = 0; x < image->width; x++, ptr += channels) {
+
+               /* reduce pixel */
+               pixel = *ptr + err[x];
+               if (pixel < 0)
+                       pixel = 0;
+               else if (pixel > 0xff)
+                       pixel = 0xff;
+               r = rtable[pixel];
+               /* calc error */
+               rer = pixel - r * dr;
+
+               /* reduce pixel */
+               pixel = *(ptr + 1) + err[x + 1];
+               if (pixel < 0)
+                       pixel = 0;
+               else if (pixel > 0xff)
+                       pixel = 0xff;
+               g = gtable[pixel];
+               /* calc error */
+               ger = pixel - g * dg;
+
+               /* reduce pixel */
+               pixel = *(ptr + 2) + err[x + 2];
+               if (pixel < 0)
+                       pixel = 0;
+               else if (pixel > 0xff)
+                       pixel = 0xff;
+               b = btable[pixel];
+               /* calc error */
+               ber = pixel - b * db;
+
+               pixel = (r << roffs) | (g << goffs) | (b << boffs);
+               XPutPixel(ximg->image, x, y, pixel);
+
+               /* distribute error */
+               r = (rer * 3) / 8;
+               g = (ger * 3) / 8;
+               b = (ber * 3) / 8;
+               /* x+1, y */
+               err[x + 3 * 1] += r;
+               err[x + 1 + 3 * 1] += g;
+               err[x + 2 + 3 * 1] += b;
+               /* x, y+1 */
+               nerr[x] += r;
+               nerr[x + 1] += g;
+               nerr[x + 2] += b;
+               /* x+1, y+1 */
+               nerr[x + 3 * 1] = rer - 2 * r;
+               nerr[x + 1 + 3 * 1] = ger - 2 * g;
+               nerr[x + 2 + 3 * 1] = ber - 2 * b;
+       }
+}
+
+static RXImage *image2TrueColor(RContext * ctx, RImage * image)
+{
+       RXImage *ximg;
+       unsigned short rmask, gmask, bmask;
+       unsigned short roffs, goffs, boffs;
+       unsigned short *rtable, *gtable, *btable;
+       int channels = (HAS_ALPHA(image) ? 4 : 3);
+
+       ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
+       if (!ximg) {
+               return NULL;
+       }
+
+       roffs = ctx->red_offset;
+       goffs = ctx->green_offset;
+       boffs = ctx->blue_offset;
+
+       rmask = ctx->visual->red_mask >> roffs;
+       gmask = ctx->visual->green_mask >> goffs;
+       bmask = ctx->visual->blue_mask >> boffs;
+
+       rtable = computeTable(rmask);
+       gtable = computeTable(gmask);
+       btable = computeTable(bmask);
+
+       if (rtable == NULL || gtable == NULL || btable == NULL) {
+               RErrorCode = RERR_NOMEMORY;
+               RDestroyXImage(ctx, ximg);
+               return NULL;
+       }
+
+#ifdef BENCH
+       cycle_bench(1);
+#endif
+
+       if (ctx->attribs->render_mode == RBestMatchRendering) {
+               int ofs, r, g, b;
+               int x, y;
+               unsigned long pixel;
+               unsigned char *ptr = image->data;
+
+               /* fake match */
+#ifdef DEBUG
+               puts("true color match");
+#endif
+               if (rmask == 0xff && gmask == 0xff && bmask == 0xff) {
+                       for (y = 0; y < image->height; y++) {
+                               for (x = 0; x < image->width; x++, ptr += channels) {
+                                       /* reduce pixel */
+                                       pixel = (*(ptr) << roffs) | (*(ptr + 1) << goffs) | (*(ptr + 2) << boffs);
+                                       XPutPixel(ximg->image, x, y, pixel);
+                               }
+                       }
+               } else {
+                       for (y = 0, ofs = 0; y < image->height; y++) {
+                               for (x = 0; x < image->width; x++, ofs += channels - 3) {
+                                       /* reduce pixel */
+                                       r = rtable[ptr[ofs++]];
+                                       g = gtable[ptr[ofs++]];
+                                       b = btable[ptr[ofs++]];
+                                       pixel = (r << roffs) | (g << goffs) | (b << boffs);
+                                       XPutPixel(ximg->image, x, y, pixel);
+                               }
+                       }
+               }
+       } else {
+               /* dither */
+               const int dr = 0xff / rmask;
+               const int dg = 0xff / gmask;
+               const int db = 0xff / bmask;
+
+#ifdef DEBUG
+               puts("true color dither");
+#endif
+
+#ifdef ASM_X86_MMX
+               if (ctx->depth == 16 && HAS_ALPHA(image) && x86_check_mmx()) {
+                       short *err;
+                       short *nerr;
+
+                       err = malloc(8 * (image->width + 3));
+                       nerr = malloc(8 * (image->width + 3));
+                       if (!err || !nerr) {
+                               NFREE(err);
+                               NFREE(nerr);
+                               RErrorCode = RERR_NOMEMORY;
+                               RDestroyXImage(ctx, ximg);
+                               return NULL;
+                       }
+                       memset(err, 0, 8 * (image->width + 3));
+                       memset(nerr, 0, 8 * (image->width + 3));
+
+                       x86_mmx_TrueColor_32_to_16(image->data,
+                                                  (unsigned short *)ximg->image->data,
+                                                  err + 8, nerr + 8,
+                                                  rtable, gtable, btable,
+                                                  dr, dg, db,
+                                                  roffs, goffs, boffs,
+                                                  image->width, image->height,
+                                                  ximg->image->bytes_per_line - 2 * image->width);
+
+                       free(err);
+                       free(nerr);
+               } else
+#endif                         /* ASM_X86_MMX */
+               {
+                       signed char *err;
+                       signed char *nerr;
+                       int ch = (HAS_ALPHA(image) ? 4 : 3);
+
+                       err = malloc(ch * (image->width + 2));
+                       nerr = malloc(ch * (image->width + 2));
+                       if (!err || !nerr) {
+                               NFREE(err);
+                               NFREE(nerr);
+                               RErrorCode = RERR_NOMEMORY;
+                               RDestroyXImage(ctx, ximg);
+                               return NULL;
+                       }
+
+                       memset(err, 0, ch * (image->width + 2));
+                       memset(nerr, 0, ch * (image->width + 2));
+
+                       convertTrueColor_generic(ximg, image, err, nerr,
+                                                rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
+                       free(err);
+                       free(nerr);
+               }
+
+       }
+
+#ifdef BENCH
+       cycle_bench(0);
+#endif
+
+       return ximg;
+}
+
+/***************************************************************************/
+
+static void
+convertPseudoColor_to_8(RXImage * ximg, RImage * image,
+                       signed char *err, signed char *nerr,
+                       const unsigned short *rtable,
+                       const unsigned short *gtable,
+                       const unsigned short *btable,
+                       const int dr, const int dg, const int db, unsigned long *pixels, int cpc)
+{
+       signed char *terr;
+       int x, y, r, g, b;
+       int pixel;
+       int rer, ger, ber;
+       unsigned char *ptr = image->data;
+       unsigned char *optr = (unsigned char *)ximg->image->data;
+       int channels = (HAS_ALPHA(image) ? 4 : 3);
+       int cpcpc = cpc * cpc;
+
+       /* convert and dither the image to XImage */
+       for (y = 0; y < image->height; y++) {
+               nerr[0] = 0;
+               nerr[1] = 0;
+               nerr[2] = 0;
+               for (x = 0; x < image->width * 3; x += 3, ptr += channels) {
+
+                       /* reduce pixel */
+                       pixel = *ptr + err[x];
+                       if (pixel < 0)
+                               pixel = 0;
+                       else if (pixel > 0xff)
+                               pixel = 0xff;
+                       r = rtable[pixel];
+                       /* calc error */
+                       rer = pixel - r * dr;
+
+                       /* reduce pixel */
+                       pixel = *(ptr + 1) + err[x + 1];
+                       if (pixel < 0)
+                               pixel = 0;
+                       else if (pixel > 0xff)
+                               pixel = 0xff;
+                       g = gtable[pixel];
+                       /* calc error */
+                       ger = pixel - g * dg;
+
+                       /* reduce pixel */
+                       pixel = *(ptr + 2) + err[x + 2];
+                       if (pixel < 0)
+                               pixel = 0;
+                       else if (pixel > 0xff)
+                               pixel = 0xff;
+                       b = btable[pixel];
+                       /* calc error */
+                       ber = pixel - b * db;
+
+                       *optr++ = pixels[r * cpcpc + g * cpc + b];
+
+                       /* distribute error */
+                       r = (rer * 3) / 8;
+                       g = (ger * 3) / 8;
+                       b = (ber * 3) / 8;
+
+                       /* x+1, y */
+                       err[x + 3 * 1] += r;
+                       err[x + 1 + 3 * 1] += g;
+                       err[x + 2 + 3 * 1] += b;
+                       /* x, y+1 */
+                       nerr[x] += r;
+                       nerr[x + 1] += g;
+                       nerr[x + 2] += b;
+                       /* x+1, y+1 */
+                       nerr[x + 3 * 1] = rer - 2 * r;
+                       nerr[x + 1 + 3 * 1] = ger - 2 * g;
+                       nerr[x + 2 + 3 * 1] = ber - 2 * b;
+               }
+               /* skip to next line */
+               terr = err;
+               err = nerr;
+               nerr = terr;
+
+               optr += ximg->image->bytes_per_line - image->width;
+       }
+}
+
+static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
+{
+       RXImage *ximg;
+       register int x, y, r, g, b;
+       unsigned char *ptr;
+       unsigned long pixel;
+       const int cpc = ctx->attribs->colors_per_channel;
+       const unsigned short rmask = cpc - 1;   /* different sizes could be used */
+       const unsigned short gmask = rmask;     /* for r,g,b */
+       const unsigned short bmask = rmask;
+       unsigned short *rtable, *gtable, *btable;
+       const int cpccpc = cpc * cpc;
+       int channels = (HAS_ALPHA(image) ? 4 : 3);
+
+       ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
+       if (!ximg) {
+               return NULL;
+       }
+
+       ptr = image->data;
+
+       /* Tables are same at the moment because rmask==gmask==bmask. */
+       rtable = computeTable(rmask);
+       gtable = computeTable(gmask);
+       btable = computeTable(bmask);
+
+       if (rtable == NULL || gtable == NULL || btable == NULL) {
+               RErrorCode = RERR_NOMEMORY;
+               RDestroyXImage(ctx, ximg);
+               return NULL;
+       }
+
+       if (ctx->attribs->render_mode == RBestMatchRendering) {
+               /* fake match */
+#ifdef DEBUG
+               printf("pseudo color match with %d colors per channel\n", cpc);
+#endif
+               for (y = 0; y < image->height; y++) {
+                       for (x = 0; x < image->width; x++, ptr += channels - 3) {
+                               /* reduce pixel */
+                               r = rtable[*ptr++];
+                               g = gtable[*ptr++];
+                               b = btable[*ptr++];
+                               pixel = r * cpccpc + g * cpc + b;
+                               /*data[ofs] = ctx->colors[pixel].pixel; */
+                               XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
+                       }
+               }
+       } else {
+               /* dither */
+               signed char *err;
+               signed char *nerr;
+               const int dr = 0xff / rmask;
+               const int dg = 0xff / gmask;
+               const int db = 0xff / bmask;
+
+#ifdef DEBUG
+               printf("pseudo color dithering with %d colors per channel\n", cpc);
+#endif
+               err = malloc(4 * (image->width + 3));
+               nerr = malloc(4 * (image->width + 3));
+               if (!err || !nerr) {
+                       NFREE(err);
+                       NFREE(nerr);
+                       RErrorCode = RERR_NOMEMORY;
+                       RDestroyXImage(ctx, ximg);
+                       return NULL;
+               }
+               memset(err, 0, 4 * (image->width + 3));
+               memset(nerr, 0, 4 * (image->width + 3));
+
+               /*#ifdef ASM_X86 */
+#if 0
+               x86_PseudoColor_32_to_8(image->data, ximg->image->data,
+                                       err + 4, nerr + 4,
+                                       rtable,
+                                       dr, dg, db, ctx->pixels, cpc,
+                                       image->width, image->height,
+                                       channels, ximg->image->bytes_per_line - image->width);
+#else
+               convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
+                                       rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
+#endif
+
+               free(err);
+               free(nerr);
+       }
+
+       return ximg;
+}
+
+/*
+ * For standard colormap
+ */
+static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
+{
+       RXImage *ximg;
+       register int x, y, r, g, b;
+       unsigned char *ptr;
+       unsigned long pixel;
+       unsigned char *data;
+       unsigned int *rtable, *gtable, *btable;
+       unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
+       int channels = (HAS_ALPHA(image) ? 4 : 3);
+
+       ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
+       if (!ximg) {
+               return NULL;
+       }
+
+       ptr = image->data;
+
+       data = (unsigned char *)ximg->image->data;
+
+       rtable = computeStdTable(ctx->std_rgb_map->red_mult, ctx->std_rgb_map->red_max);
+
+       gtable = computeStdTable(ctx->std_rgb_map->green_mult, ctx->std_rgb_map->green_max);
+
+       btable = computeStdTable(ctx->std_rgb_map->blue_mult, ctx->std_rgb_map->blue_max);
+
+       if (rtable == NULL || gtable == NULL || btable == NULL) {
+               RErrorCode = RERR_NOMEMORY;
+               RDestroyXImage(ctx, ximg);
+               return NULL;
+       }
+
+       if (ctx->attribs->render_mode == RBestMatchRendering) {
+               for (y = 0; y < image->height; y++) {
+                       for (x = 0; x < image->width; x++, ptr += channels) {
+                               /* reduce pixel */
+                               pixel = (rtable[*ptr] + gtable[*(ptr + 1)]
+                                        + btable[*(ptr + 2)] + base_pixel) & 0xffffffff;
+
+                               XPutPixel(ximg->image, x, y, pixel);
+                       }
+               }
+       } else {
+               /* dither */
+               signed short *err, *nerr;
+               signed short *terr;
+               int rer, ger, ber;
+               int x1, ofs;
+
+#ifdef DEBUG
+               printf("pseudo color dithering with %d colors per channel\n", ctx->attribs->colors_per_channel);
+#endif
+               err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
+               nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
+               if (!err || !nerr) {
+                       NFREE(err);
+                       NFREE(nerr);
+                       RErrorCode = RERR_NOMEMORY;
+                       RDestroyXImage(ctx, ximg);
+                       return NULL;
+               }
+               for (x = 0, x1 = 0; x < image->width * 3; x1 += channels - 3) {
+                       err[x++] = ptr[x1++];
+                       err[x++] = ptr[x1++];
+                       err[x++] = ptr[x1++];
+               }
+               err[x] = err[x + 1] = err[x + 2] = 0;
+               /* convert and dither the image to XImage */
+               for (y = 0, ofs = 0; y < image->height; y++) {
+                       if (y < image->height - 1) {
+                               int x1;
+                               for (x = 0, x1 = (y + 1) * image->width * channels;
+                                    x < image->width * 3; x1 += channels - 3) {
+                                       nerr[x++] = ptr[x1++];
+                                       nerr[x++] = ptr[x1++];
+                                       nerr[x++] = ptr[x1++];
+                               }
+                               /* last column */
+                               x1 -= channels;
+                               nerr[x++] = ptr[x1++];
+                               nerr[x++] = ptr[x1++];
+                               nerr[x++] = ptr[x1++];
+                       }
+                       for (x = 0; x < image->width * 3; x += 3, ofs++) {
+                               /* reduce pixel */
+                               if (err[x] > 0xff)
+                                       err[x] = 0xff;
+                               else if (err[x] < 0)
+                                       err[x] = 0;
+                               if (err[x + 1] > 0xff)
+                                       err[x + 1] = 0xff;
+                               else if (err[x + 1] < 0)
+                                       err[x + 1] = 0;
+                               if (err[x + 2] > 0xff)
+                                       err[x + 2] = 0xff;
+                               else if (err[x + 2] < 0)
+                                       err[x + 2] = 0;
+
+                               r = rtable[err[x]];
+                               g = gtable[err[x + 1]];
+                               b = btable[err[x + 2]];
+
+                               pixel = r + g + b;
+
+                               data[ofs] = base_pixel + pixel;
+
+                               /* calc error */
+                               rer = err[x] - (ctx->colors[pixel].red >> 8);
+                               ger = err[x + 1] - (ctx->colors[pixel].green >> 8);
+                               ber = err[x + 2] - (ctx->colors[pixel].blue >> 8);
+
+                               /* distribute error */
+                               err[x + 3 * 1] += (rer * 7) / 16;
+                               err[x + 1 + 3 * 1] += (ger * 7) / 16;
+                               err[x + 2 + 3 * 1] += (ber * 7) / 16;
+
+                               nerr[x] += (rer * 5) / 16;
+                               nerr[x + 1] += (ger * 5) / 16;
+                               nerr[x + 2] += (ber * 5) / 16;
+
+                               if (x > 0) {
+                                       nerr[x - 3 * 1] += (rer * 3) / 16;
+                                       nerr[x - 3 * 1 + 1] += (ger * 3) / 16;
+                                       nerr[x - 3 * 1 + 2] += (ber * 3) / 16;
+                               }
+
+                               nerr[x + 3 * 1] += rer / 16;
+                               nerr[x + 1 + 3 * 1] += ger / 16;
+                               nerr[x + 2 + 3 * 1] += ber / 16;
+                       }
+                       /* skip to next line */
+                       terr = err;
+                       err = nerr;
+                       nerr = terr;
+
+                       ofs += ximg->image->bytes_per_line - image->width;
+               }
+               free(err);
+               free(nerr);
+       }
+       ximg->image->data = (char *)data;
+
+       return ximg;
+}
+
+static RXImage *image2GrayScale(RContext * ctx, RImage * image)
+{
+       RXImage *ximg;
+       register int x, y, g;
+       unsigned char *ptr;
+       const int cpc = ctx->attribs->colors_per_channel;
+       unsigned short gmask;
+       unsigned short *table;
+       unsigned char *data;
+       int channels = (HAS_ALPHA(image) ? 4 : 3);
+
+       ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
+       if (!ximg) {
+               return NULL;
+       }
+
+       ptr = image->data;
+
+       data = (unsigned char *)ximg->image->data;
+
+       if (ctx->vclass == StaticGray)
+               gmask = (1 << ctx->depth) - 1;  /* use all grays */
+       else
+               gmask = cpc * cpc * cpc - 1;
+
+       table = computeTable(gmask);
+
+       if (table == NULL) {
+               RErrorCode = RERR_NOMEMORY;
+               RDestroyXImage(ctx, ximg);
+               return NULL;
+       }
+
+       if (ctx->attribs->render_mode == RBestMatchRendering) {
+               /* fake match */
+#ifdef DEBUG
+               printf("grayscale match with %d colors per channel\n", cpc);
+#endif
+               for (y = 0; y < image->height; y++) {
+                       for (x = 0; x < image->width; x++) {
+                               /* reduce pixel */
+                               g = table[(*ptr * 30 + *(ptr + 1) * 59 + *(ptr + 2) * 11) / 100];
+                               ptr += channels;
+                               /*data[ofs] = ctx->colors[g].pixel; */
+                               XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
+                       }
+               }
+       } else {
+               /* dither */
+               short *gerr;
+               short *ngerr;
+               short *terr;
+               int ger;
+               const int dg = 0xff / gmask;
+
+#ifdef DEBUG
+               printf("grayscale dither with %d colors per channel\n", cpc);
+#endif
+               gerr = (short *)malloc((image->width + 2) * sizeof(short));
+               ngerr = (short *)malloc((image->width + 2) * sizeof(short));
+               if (!gerr || !ngerr) {
+                       NFREE(gerr);
+                       NFREE(ngerr);
+                       RErrorCode = RERR_NOMEMORY;
+                       RDestroyXImage(ctx, ximg);
+                       return NULL;
+               }
+               for (x = 0, y = 0; x < image->width; x++, y += channels) {
+                       gerr[x] = (ptr[y] * 30 + ptr[y + 1] * 59 + ptr[y + 2] * 11) / 100;
+               }
+               gerr[x] = 0;
+               /* convert and dither the image to XImage */
+               for (y = 0; y < image->height; y++) {
+                       if (y < image->height - 1) {
+                               int x1;
+                               for (x = 0, x1 = (y + 1) * image->width * channels; x < image->width;
+                                    x++, x1 += channels) {
+                                       ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
+                               }
+                               /* last column */
+                               x1 -= channels;
+                               ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
+                       }
+                       for (x = 0; x < image->width; x++) {
+                               /* reduce pixel */
+                               if (gerr[x] > 0xff)
+                                       gerr[x] = 0xff;
+                               else if (gerr[x] < 0)
+                                       gerr[x] = 0;
+
+                               g = table[gerr[x]];
+
+                               /*data[ofs] = ctx->colors[g].pixel; */
+                               XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
+                               /* calc error */
+                               ger = gerr[x] - g * dg;
+
+                               /* distribute error */
+                               g = (ger * 3) / 8;
+                               /* x+1, y */
+                               gerr[x + 1] += g;
+                               /* x, y+1 */
+                               ngerr[x] += g;
+                               /* x+1, y+1 */
+                               ngerr[x + 1] += ger - 2 * g;
+                       }
+                       /* skip to next line */
+                       terr = gerr;
+                       gerr = ngerr;
+                       ngerr = terr;
+               }
+               free(gerr);
+               free(ngerr);
+       }
+       ximg->image->data = (char *)data;
+
+       return ximg;
+}
+
+static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
+{
+       RXImage *ximg;
+       unsigned char *alpha;
+       int x, y;
+
+       ximg = RCreateXImage(ctx, 1, image->width, image->height);
+       if (!ximg) {
+               return NULL;
+       }
+       alpha = image->data + 3;
+
+       for (y = 0; y < image->height; y++) {
+               for (x = 0; x < image->width; x++) {
+                       XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
+                       alpha += 4;
+               }
+       }
+
+       return ximg;
+}
+
+int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
+{
+       RXImage *ximg = NULL;
+#ifdef XSHM
+       Pixmap tmp;
+#endif
+
+       assert(context != NULL);
+       assert(image != NULL);
+       assert(pixmap != NULL);
+
+       switch (context->vclass) {
+       case TrueColor:
+#ifdef BENCH
+               cycle_bench(1);
+#endif
+               ximg = image2TrueColor(context, image);
+#ifdef BENCH
+               cycle_bench(0);
+#endif
+               break;
+
+       case PseudoColor:
+       case StaticColor:
+#ifdef BENCH
+               cycle_bench(1);
+#endif
+               if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
+                       ximg = image2StandardPseudoColor(context, image);
+               else
+                       ximg = image2PseudoColor(context, image);
+#ifdef BENCH
+               cycle_bench(0);
+#endif
+               break;
+
+       case GrayScale:
+       case StaticGray:
+               ximg = image2GrayScale(context, image);
+               break;
+       }
+
+       if (!ximg) {
+               return False;
+       }
+
+       *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth);
+
+#ifdef XSHM
+       if (context->flags.use_shared_pixmap && ximg->is_shared)
+               tmp = R_CreateXImageMappedPixmap(context, ximg);
+       else
+               tmp = None;
+       if (tmp) {
+               /*
+                * We have to copy the shm Pixmap into a normal Pixmap because
+                * otherwise, we would have to control when Pixmaps are freed so
+                * that we can detach their shm segments. This is a problem if the
+                * program crash, leaving stale shared memory segments in the
+                * system (lots of them). But with some work, we can optimize
+                * things and remove this XCopyArea. This will require
+                * explicitly freeing all pixmaps when exiting or restarting
+                * wmaker.
+                */
+               XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0);
+               XFreePixmap(context->dpy, tmp);
+       } else {
+               RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
+       }
+#else                          /* !XSHM */
+       RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
+#endif                         /* !XSHM */
+
+       RDestroyXImage(context, ximg);
+
+       return True;
+}
+
+/* make the gc permanent (create with context creation).
+ * GC creation is very expensive. altering its properties is not. -Dan
+ */
+int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
+{
+       GC gc;
+       XGCValues gcv;
+       RXImage *ximg = NULL;
+
+       assert(context != NULL);
+       assert(image != NULL);
+       assert(pixmap != NULL);
+       assert(mask != NULL);
+
+       if (!RConvertImage(context, image, pixmap))
+               return False;
+
+       if (image->format == RRGBFormat) {
+               *mask = None;
+               return True;
+       }
+
+       ximg = image2Bitmap(context, image, threshold);
+
+       if (!ximg) {
+               return False;
+       }
+       *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1);
+       gcv.foreground = context->black;
+       gcv.background = context->white;
+       gcv.graphics_exposures = False;
+       gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+       RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height);
+       RDestroyXImage(context, ximg);
+       XFreeGC(context->dpy, gc);
+
+       return True;
+}
+
+Bool RGetClosestXColor(RContext * context, RColor * color, XColor * retColor)
+{
+       if (context->vclass == TrueColor) {
+               unsigned short rmask, gmask, bmask;
+               unsigned short roffs, goffs, boffs;
+               unsigned short *rtable, *gtable, *btable;
+
+               roffs = context->red_offset;
+               goffs = context->green_offset;
+               boffs = context->blue_offset;
+
+               rmask = context->visual->red_mask >> roffs;
+               gmask = context->visual->green_mask >> goffs;
+               bmask = context->visual->blue_mask >> boffs;
+
+               rtable = computeTable(rmask);
+               gtable = computeTable(gmask);
+               btable = computeTable(bmask);
+
+               retColor->pixel = (rtable[color->red] << roffs) |
+                   (gtable[color->green] << goffs) | (btable[color->blue] << boffs);
+
+               retColor->red = color->red << 8;
+               retColor->green = color->green << 8;
+               retColor->blue = color->blue << 8;
+               retColor->flags = DoRed | DoGreen | DoBlue;
+
+       } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
+
+               if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
+                       unsigned int *rtable, *gtable, *btable;
+
+                       rtable = computeStdTable(context->std_rgb_map->red_mult, context->std_rgb_map->red_max);
+
+                       gtable = computeStdTable(context->std_rgb_map->green_mult,
+                                                context->std_rgb_map->green_max);
+
+                       btable = computeStdTable(context->std_rgb_map->blue_mult, context->std_rgb_map->blue_max);
+
+                       if (rtable == NULL || gtable == NULL || btable == NULL) {
+                               RErrorCode = RERR_NOMEMORY;
+                               return False;
+                       }
+
+                       retColor->pixel = (rtable[color->red]
+                                          + gtable[color->green]
+                                          + btable[color->blue]
+                                          + context->std_rgb_map->base_pixel) & 0xffffffff;
+                       retColor->red = color->red << 8;
+                       retColor->green = color->green << 8;
+                       retColor->blue = color->blue << 8;
+                       retColor->flags = DoRed | DoGreen | DoBlue;
+
+               } else {
+                       const int cpc = context->attribs->colors_per_channel;
+                       const unsigned short rmask = cpc - 1;   /* different sizes could be used */
+                       const unsigned short gmask = rmask;     /* for r,g,b */
+                       const unsigned short bmask = rmask;
+                       unsigned short *rtable, *gtable, *btable;
+                       const int cpccpc = cpc * cpc;
+                       int index;
+
+                       rtable = computeTable(rmask);
+                       gtable = computeTable(gmask);
+                       btable = computeTable(bmask);
+
+                       if (rtable == NULL || gtable == NULL || btable == NULL) {
+                               RErrorCode = RERR_NOMEMORY;
+                               return False;
+                       }
+                       index = rtable[color->red] * cpccpc + gtable[color->green] * cpc + btable[color->blue];
+                       *retColor = context->colors[index];
+               }
+
+       } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
+
+               const int cpc = context->attribs->colors_per_channel;
+               unsigned short gmask;
+               unsigned short *table;
+               int index;
+
+               if (context->vclass == StaticGray)
+                       gmask = (1 << context->depth) - 1;      /* use all grays */
+               else
+                       gmask = cpc * cpc * cpc - 1;
+
+               table = computeTable(gmask);
+               if (!table)
+                       return False;
+
+               index = table[(color->red * 30 + color->green * 59 + color->blue * 11) / 100];
+
+               *retColor = context->colors[index];
+       } else {
+               RErrorCode = RERR_INTERNAL;
+               return False;
+       }
+
+       return True;
+}