1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 04:20:27 +01:00
Files
wmaker/wrlib/convert.c
dan ddde229665 - fixed speckles (white dots) on dithered images (bug still present on the
PowerPC architecture, because on LinuxPPC char is unsigned by default, not
  signed like on the other platforms).
  Bug fixed by Philip Derrin <philipd@student.unsw.edu.au>
- miscelaneous bug fixes

We would like people with cvs access experimenting the white 'speckles' on
images to test if they still have the problem.
2001-05-10 00:16:28 +00:00

1101 lines
27 KiB
C

/* convert.c - convert RImage to Pixmap
*
* Raster graphics library
*
* Copyright (c) 1997-2000 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 "wrasterP.h"
#ifdef XSHM
extern Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
#endif
#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 short *rtable,
const short *gtable,
const 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 = image->format == RRGBAFormat ? 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;
}
}
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 = (image->format == RRGBAFormat ? 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
{
char *err;
char *nerr;
int ch = image->format == RRGBAFormat ? 4 : 3;
err = malloc(ch*(image->width+2));
nerr = malloc(ch*(image->width+2));
if (!err || !nerr) {
if (nerr)
free(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 short *rtable,
const short *gtable,
const 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 = ximg->image->data;
int channels = image->format == RRGBAFormat ? 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 = image->format == RRGBAFormat ? 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 */
char *err;
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) {
if (nerr)
free(nerr);
RErrorCode = RERR_NOMEMORY;
RDestroyXImage(ctx, ximg);
return NULL;
}
memset(err, 0, 4*(image->width+3));
memset(nerr, 0, 4*(image->width+3));
convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
rtable, gtable, btable,
dr, dg, db, ctx->pixels, cpc);
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 = image->format == RRGBAFormat ? 4 : 3;
/*register unsigned char maxrgb = 0xff;*/
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", cpc);
#endif
err = (short*)malloc(3*(image->width+2)*sizeof(short));
nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
if (!err || !nerr) {
if (err)
free(err);
if (nerr)
free(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 = image->format == RRGBAFormat ? 4 : 3;
/*register unsigned char maxrgb = 0xff;*/
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 += 3;
/*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) {
if (ngerr)
free(ngerr);
RErrorCode = RERR_NOMEMORY;
RDestroyXImage(ctx, ximg);
return NULL;
}
for (x=0; x<image->width; x++) {
gerr[x] = (ptr[x*3]*30 + ptr[x*3+1]*59 + ptr[x*3+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*3; x<image->width; 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;
}
#ifdef HAVE_HERMES
static RXImage*
hermesConvert(RContext *context, RImage *image)
{
HermesFormat source;
HermesFormat dest;
RXImage *ximage;
ximage = RCreateXImage(context, context->depth,
image->width, image->height);
if (!ximage) {
return NULL;
}
if (HAS_ALPHA(image)) {
if (ximage->image->byte_order==LSBFirst) {
source.r = 0x000000ff;
source.g = 0x0000ff00;
source.b = 0x00ff0000;
source.a = 0xff000000;
} else {
source.r = 0xff000000;
source.g = 0x00ff0000;
source.b = 0x0000ff00;
source.a = 0x000000ff;
}
source.bits = 32;
} else {
if (ximage->image->byte_order==LSBFirst) {
source.r = 0x0000ff;
source.g = 0x00ff00;
source.b = 0xff0000;
} else {
source.r = 0xff0000;
source.g = 0x00ff00;
source.b = 0x0000ff;
}
source.a = 0x000000;
source.bits = 24;
}
source.indexed = 0;
source.has_colorkey = 0;
dest.r = context->visual->red_mask;
dest.g = context->visual->green_mask;
dest.b = context->visual->blue_mask;
dest.a = 0;
dest.bits = ximage->image->bits_per_pixel;
if (context->vclass == TrueColor)
dest.indexed = 0;
else
dest.indexed = 1;
dest.has_colorkey = 0;
/*printf("source r=0x%x, g=0x%x, b=0x%x, a=0x%x, b=%d, i=%d, c=%d\n",
source.r, source.g, source.b, source.a,
source.bits, source.indexed, source.has_colorkey);
printf("dest r=0x%x, g=0x%x, b=0x%x, a=0x%x, b=%d, i=%d, c=%d\n",
dest.r, dest.g, dest.b, dest.a,
dest.bits, dest.indexed, dest.has_colorkey);
*/
Hermes_ConverterRequest(context->hermes_data->converter, &source, &dest);
Hermes_ConverterPalette(context->hermes_data->converter,
context->hermes_data->palette, 0);
Hermes_ConverterCopy(context->hermes_data->converter,
image->data, 0, 0, image->width, image->height,
image->width * (image->format == RRGBFormat ? 3 : 4),
ximage->image->data, 0, 0,
image->width, image->height,
ximage->image->bytes_per_line);
return ximage;
}
#endif /* HAVE_HERMES */
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);
#ifdef HAVE_HERMES
ximg = hermesConvert(context, image);
#else /* !HAVE_HERMES */
/* clear error message */
switch (context->vclass) {
case TrueColor:
ximg = image2TrueColor(context, image);
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;
}
#endif /* !HAVE_HERMES */
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;
}
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);
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;
}