587 lines
14 KiB
C
587 lines
14 KiB
C
/* WMGlobe 1.3 - All the Earth on a WMaker Icon
|
|
* myconvert.c - an adaptation of wrlib for use in wmglobe
|
|
* initial source taken in WindowMaker-0.20.3/wrlib :
|
|
*/
|
|
|
|
/* convert.c - convert RImage to Pixmap
|
|
* Raster graphics library
|
|
*
|
|
* Copyright (c) 1997 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.
|
|
*/
|
|
|
|
#include "wmglobe.h"
|
|
|
|
typedef struct RConversionTable {
|
|
unsigned short table[256];
|
|
unsigned short index;
|
|
struct RConversionTable *next;
|
|
} RConversionTable;
|
|
|
|
|
|
static RConversionTable *conversionTable = NULL;
|
|
static RConversionTable *pif[3];
|
|
static short *re, *ge, *be;
|
|
static short *nre, *nge, *nbe;
|
|
static RXImage *ximgok;
|
|
|
|
void initmyconvert()
|
|
{
|
|
pif[0] = (RConversionTable *) malloc(sizeof(RConversionTable));
|
|
pif[1] = (RConversionTable *) malloc(sizeof(RConversionTable));
|
|
pif[2] = (RConversionTable *) malloc(sizeof(RConversionTable));
|
|
re = (short *) malloc((DIAMETRE + 2) * sizeof(short));
|
|
ge = (short *) malloc((DIAMETRE + 2) * sizeof(short));
|
|
be = (short *) malloc((DIAMETRE + 2) * sizeof(short));
|
|
nre = (short *) malloc((DIAMETRE + 2) * sizeof(short));
|
|
nge = (short *) malloc((DIAMETRE + 2) * sizeof(short));
|
|
nbe = (short *) malloc((DIAMETRE + 2) * sizeof(short));
|
|
ximgok = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
static unsigned short *computeTable(unsigned short mask, int hop)
|
|
{
|
|
RConversionTable *tmp = conversionTable;
|
|
int i;
|
|
|
|
tmp = pif[hop];
|
|
|
|
for (i = 0; i < 256; i++)
|
|
tmp->table[i] = (i * mask + 0x7f) / 0xff;
|
|
|
|
tmp->index = mask;
|
|
return tmp->table;
|
|
}
|
|
|
|
|
|
static RXImage *image2TrueColor(RContext * ctx, RImage * image)
|
|
{
|
|
RXImage *ximg;
|
|
register int x, y, r, g, b;
|
|
unsigned char *red, *grn, *blu;
|
|
unsigned long pixel;
|
|
unsigned short rmask, gmask, bmask;
|
|
unsigned short roffs, goffs, boffs;
|
|
unsigned short *rtable, *gtable, *btable;
|
|
int ofs;
|
|
|
|
if (ximgok == NULL)
|
|
ximgok =
|
|
RCreateXImage(ctx, ctx->depth, image->width, image->height);
|
|
|
|
ximg = ximgok;
|
|
if (!ximg) {
|
|
puts("err ");
|
|
return NULL;
|
|
}
|
|
|
|
red = image->data;
|
|
grn = image->data + 1;
|
|
blu = image->data + 2;
|
|
|
|
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, 0);
|
|
gtable = computeTable(gmask, 1);
|
|
btable = computeTable(bmask, 2);
|
|
|
|
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
|
|
puts("true color match");
|
|
#endif
|
|
for (y = 0, ofs = 0; y < image->height; y++) {
|
|
for (x = 0; x < image->width; x++, ofs += 3) {
|
|
/* reduce pixel */
|
|
r = rtable[red[ofs]];
|
|
g = gtable[grn[ofs]];
|
|
b = btable[blu[ofs]];
|
|
pixel = (r << roffs) | (g << goffs) | (b << boffs);
|
|
XPutPixel(ximg->image, x, y, pixel);
|
|
}
|
|
}
|
|
} else {
|
|
/* dither */
|
|
short *rerr, *gerr, *berr;
|
|
short *nrerr, *ngerr, *nberr;
|
|
short *terr;
|
|
int rer, ger, ber;
|
|
const int dr = 0xff / rmask;
|
|
const int dg = 0xff / gmask;
|
|
const int db = 0xff / bmask;
|
|
register int x1;
|
|
|
|
#ifdef DEBUG
|
|
puts("true color dither");
|
|
#endif
|
|
rerr = re;
|
|
gerr = ge;
|
|
berr = be;
|
|
nrerr = nre;
|
|
ngerr = nge;
|
|
nberr = nbe;
|
|
|
|
if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
|
|
RErrorCode = RERR_NOMEMORY;
|
|
RDestroyXImage(ctx, ximg);
|
|
return NULL;
|
|
}
|
|
for (x = x1 = 0; x < image->width; x++, x1 += 3) {
|
|
|
|
rerr[x] = red[x1];
|
|
gerr[x] = grn[x1];
|
|
berr[x] = blu[x1];
|
|
}
|
|
rerr[x] = gerr[x] = berr[x] = 0;
|
|
/* convert and dither the image to XImage */
|
|
for (y = 0, ofs = 0; y < image->height; y++) {
|
|
if (y < image->height - 1) {
|
|
|
|
for (x = 0, x1 = 3 * (ofs + image->width); x <
|
|
image->width; x++, x1 += 3) {
|
|
|
|
nrerr[x] = red[x1];
|
|
ngerr[x] = grn[x1];
|
|
nberr[x] = blu[x1];
|
|
}
|
|
/* last column */
|
|
x1-=3;
|
|
nrerr[x] = red[x1];
|
|
ngerr[x] = grn[x1];
|
|
nberr[x] = blu[x1];
|
|
}
|
|
for (x = 0; x < image->width; x++) {
|
|
/* reduce pixel */
|
|
if (rerr[x] > 0xff)
|
|
rerr[x] = 0xff;
|
|
else if (rerr[x] < 0)
|
|
rerr[x] = 0;
|
|
if (gerr[x] > 0xff)
|
|
gerr[x] = 0xff;
|
|
else if (gerr[x] < 0)
|
|
gerr[x] = 0;
|
|
if (berr[x] > 0xff)
|
|
berr[x] = 0xff;
|
|
else if (berr[x] < 0)
|
|
berr[x] = 0;
|
|
|
|
r = rtable[rerr[x]];
|
|
g = gtable[gerr[x]];
|
|
b = btable[berr[x]];
|
|
|
|
pixel = (r << roffs) | (g << goffs) | (b << boffs);
|
|
XPutPixel(ximg->image, x, y, pixel);
|
|
/* calc error */
|
|
rer = rerr[x] - r * dr;
|
|
ger = gerr[x] - g * dg;
|
|
ber = berr[x] - b * db;
|
|
|
|
/* distribute error */
|
|
r = (rer * 3) / 8;
|
|
g = (ger * 3) / 8;
|
|
b = (ber * 3) / 8;
|
|
/* x+1, y */
|
|
rerr[x + 1] += r;
|
|
gerr[x + 1] += g;
|
|
berr[x + 1] += b;
|
|
/* x, y+1 */
|
|
nrerr[x] += r;
|
|
ngerr[x] += g;
|
|
nberr[x] += b;
|
|
/* x+1, y+1 */
|
|
nrerr[x + 1] += rer - 2 * r;
|
|
ngerr[x + 1] += ger - 2 * g;
|
|
nberr[x + 1] += ber - 2 * b;
|
|
}
|
|
ofs += image->width;
|
|
/* skip to next line */
|
|
terr = rerr;
|
|
rerr = nrerr;
|
|
nrerr = terr;
|
|
|
|
terr = gerr;
|
|
gerr = ngerr;
|
|
ngerr = terr;
|
|
|
|
terr = berr;
|
|
berr = nberr;
|
|
nberr = terr;
|
|
}
|
|
}
|
|
return ximg;
|
|
}
|
|
|
|
|
|
static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
|
|
{
|
|
RXImage *ximg;
|
|
register int x, y, r, g, b;
|
|
unsigned char *red, *grn, *blu;
|
|
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;
|
|
unsigned char *data;
|
|
int ofs;
|
|
/*register unsigned char maxrgb = 0xff; */
|
|
|
|
if (ximgok == NULL)
|
|
ximgok =
|
|
RCreateXImage(ctx, ctx->depth, image->width, image->height);
|
|
|
|
ximg = ximgok;
|
|
|
|
if (!ximg) {
|
|
puts("err psc");
|
|
return NULL;
|
|
}
|
|
red = image->data;
|
|
grn = image->data + 1;
|
|
blu = image->data + 2;
|
|
|
|
data = ximg->image->data;
|
|
|
|
/* Tables are same at the moment because rmask==gmask==bmask. */
|
|
rtable = computeTable(rmask, 0);
|
|
gtable = computeTable(gmask, 1);
|
|
btable = computeTable(bmask, 2);
|
|
|
|
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, ofs = 0; y < image->height; y++) {
|
|
for (x = 0; x < image->width; x++, ofs += 3) {
|
|
/* reduce pixel */
|
|
r = rtable[red[ofs]];
|
|
g = gtable[grn[ofs]];
|
|
b = btable[blu[ofs]];
|
|
pixel = r * cpccpc + g * cpc + b;
|
|
/*data[ofs] = ctx->colors[pixel].pixel; */
|
|
XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
|
|
}
|
|
}
|
|
} else {
|
|
/* dither */
|
|
short *rerr, *gerr, *berr;
|
|
short *nrerr, *ngerr, *nberr;
|
|
short *terr;
|
|
int rer, ger, ber;
|
|
const int dr = 0xff / rmask;
|
|
const int dg = 0xff / gmask;
|
|
const int db = 0xff / bmask;
|
|
register int x1;
|
|
|
|
#ifdef DEBUG
|
|
printf("pseudo color dithering with %d colors per channel\n", cpc);
|
|
#endif
|
|
rerr = re;
|
|
gerr = ge;
|
|
berr = be;
|
|
nrerr = nre;
|
|
ngerr = nge;
|
|
nberr = nbe;
|
|
if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
|
|
RErrorCode = RERR_NOMEMORY;
|
|
RDestroyXImage(ctx, ximg);
|
|
return NULL;
|
|
}
|
|
for (x = x1 = 0; x < image->width; x++, x1+=3) {
|
|
rerr[x] = red[x1];
|
|
gerr[x] = grn[x1];
|
|
berr[x] = blu[x1];
|
|
}
|
|
rerr[x] = gerr[x] = berr[x] = 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 = 3*(ofs + image->width); x <
|
|
image->width; x++, x1 += 3) {
|
|
nrerr[x] = red[x1];
|
|
ngerr[x] = grn[x1];
|
|
nberr[x] = blu[x1];
|
|
}
|
|
/* last column */
|
|
x1-=3;
|
|
nrerr[x] = red[x1];
|
|
ngerr[x] = grn[x1];
|
|
nberr[x] = blu[x1];
|
|
}
|
|
for (x = 0; x < image->width; x++, ofs++) {
|
|
/* reduce pixel */
|
|
if (rerr[x] > 0xff)
|
|
rerr[x] = 0xff;
|
|
else if (rerr[x] < 0)
|
|
rerr[x] = 0;
|
|
if (gerr[x] > 0xff)
|
|
gerr[x] = 0xff;
|
|
else if (gerr[x] < 0)
|
|
gerr[x] = 0;
|
|
if (berr[x] > 0xff)
|
|
berr[x] = 0xff;
|
|
else if (berr[x] < 0)
|
|
berr[x] = 0;
|
|
|
|
r = rtable[rerr[x]];
|
|
g = gtable[gerr[x]];
|
|
b = btable[berr[x]];
|
|
|
|
pixel = r * cpccpc + g * cpc + b;
|
|
/*data[ofs] = ctx->colors[pixel].pixel; */
|
|
XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
|
|
|
|
/* calc error */
|
|
rer = rerr[x] - r * dr;
|
|
ger = gerr[x] - g * dg;
|
|
ber = berr[x] - b * db;
|
|
|
|
/* distribute error */
|
|
rerr[x + 1] += (rer * 7) / 16;
|
|
gerr[x + 1] += (ger * 7) / 16;
|
|
berr[x + 1] += (ber * 7) / 16;
|
|
|
|
nrerr[x] += (rer * 5) / 16;
|
|
ngerr[x] += (ger * 5) / 16;
|
|
nberr[x] += (ber * 5) / 16;
|
|
|
|
if (x > 0) {
|
|
nrerr[x - 1] += (rer * 3) / 16;
|
|
ngerr[x - 1] += (ger * 3) / 16;
|
|
nberr[x - 1] += (ber * 3) / 16;
|
|
}
|
|
nrerr[x + 1] += rer / 16;
|
|
ngerr[x + 1] += ger / 16;
|
|
nberr[x + 1] += ber / 16;
|
|
}
|
|
/* skip to next line */
|
|
terr = rerr;
|
|
rerr = nrerr;
|
|
nrerr = terr;
|
|
|
|
terr = gerr;
|
|
gerr = ngerr;
|
|
ngerr = terr;
|
|
|
|
terr = berr;
|
|
berr = nberr;
|
|
nberr = terr;
|
|
}
|
|
}
|
|
ximg->image->data = (char *) data;
|
|
|
|
return ximg;
|
|
}
|
|
|
|
|
|
static RXImage *image2GrayScale(RContext * ctx, RImage * image)
|
|
{
|
|
RXImage *ximg;
|
|
register int x, y, g;
|
|
unsigned char *red, *grn, *blu;
|
|
const int cpc = ctx->attribs->colors_per_channel;
|
|
unsigned short gmask;
|
|
unsigned short *table;
|
|
unsigned char *data;
|
|
int ofs;
|
|
/*register unsigned char maxrgb = 0xff; */
|
|
|
|
if (ximgok == NULL)
|
|
ximgok =
|
|
RCreateXImage(ctx, ctx->depth, image->width, image->height);
|
|
|
|
ximg = ximgok;
|
|
|
|
if (!ximg) {
|
|
puts("error!");
|
|
return NULL;
|
|
}
|
|
red = image->data;
|
|
grn = image->data + 1;
|
|
blu = image->data + 2;
|
|
|
|
data = ximg->image->data;
|
|
|
|
if (ctx->vclass == StaticGray)
|
|
gmask = (1 << ctx->depth) - 1; /* use all grays */
|
|
else
|
|
gmask = cpc * cpc * cpc - 1;
|
|
|
|
table = computeTable(gmask, 0);
|
|
|
|
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, ofs = 0; y < image->height; y++) {
|
|
for (x = 0; x < image->width; x++, ofs++) {
|
|
/* reduce pixel */
|
|
g =
|
|
table[(red[ofs] * 30 + grn[ofs] * 59 + blu[ofs] * 11) /
|
|
100];
|
|
|
|
/*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 = ge;
|
|
ngerr = nge;
|
|
if (!gerr || !ngerr) {
|
|
RErrorCode = RERR_NOMEMORY;
|
|
RDestroyXImage(ctx, ximg);
|
|
return NULL;
|
|
}
|
|
for (x = 0; x < image->width; x++) {
|
|
gerr[x] = (red[x] * 30 + grn[x] * 59 + blu[x] * 11) / 100;
|
|
}
|
|
gerr[x] = 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 = ofs + image->width; x < image->width;
|
|
x++, x1++) {
|
|
ngerr[x] =
|
|
(red[x1] * 30 + grn[x1] * 59 + blu[x1] * 11) / 100;
|
|
}
|
|
/* last column */
|
|
x1--;
|
|
ngerr[x] =
|
|
(red[x1] * 30 + grn[x1] * 59 + blu[x1] * 11) / 100;
|
|
}
|
|
for (x = 0; x < image->width; x++, ofs++) {
|
|
/* 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;
|
|
}
|
|
}
|
|
ximg->image->data = (char *) data;
|
|
|
|
return ximg;
|
|
}
|
|
|
|
|
|
|
|
int myRConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
|
|
{
|
|
RXImage *ximg = NULL;
|
|
|
|
|
|
assert(context != NULL);
|
|
assert(image != NULL);
|
|
assert(pixmap != NULL);
|
|
|
|
/* clear error message */
|
|
if (context->vclass == TrueColor)
|
|
ximg = image2TrueColor(context, image);
|
|
else if (context->vclass == PseudoColor
|
|
|| context->vclass == StaticColor) ximg =
|
|
image2PseudoColor(context, image);
|
|
else if (context->vclass == GrayScale || context->vclass == StaticGray)
|
|
ximg = image2GrayScale(context, image);
|
|
|
|
if (!ximg) {
|
|
#ifdef C_ALLOCA
|
|
alloca(0);
|
|
#endif
|
|
return False;
|
|
}
|
|
/*
|
|
* *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
|
|
* image->height, context->depth);
|
|
*/
|
|
|
|
|
|
RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
|
|
image->width, image->height);
|
|
|
|
|
|
/*
|
|
* RDestroyXImage(context, ximg);
|
|
*/
|
|
|
|
#ifdef C_ALLOCA
|
|
|
|
alloca(0);
|
|
#endif
|
|
return True;
|
|
}
|