// Image.cc for Blackbox - an X11 Window manager // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // stupid macros needed to access some functions in version 2 of the GNU C // library #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif // _GNU_SOURCE #ifdef HAVE_CONFIG_H # include "../config.h" #endif // HAVE_CONFIG_H #include "i18n.hh" #include "BaseDisplay.hh" #include "Image.hh" #ifdef HAVE_SYS_TYPES_H # include #endif // HAVE_SYS_TYPES_H #ifndef u_int32_t # ifdef uint_32_t typedef uint32_t u_int32_t; # else # ifdef __uint32_t typedef __uint32_t u_int32_t; # else typedef unsigned int u_int32_t; # endif # endif #endif #ifdef STDC_HEADERS # include # include #endif // STDC_HEADERS #ifdef HAVE_STDIO_H # include #endif // HAVE_STDIO_H #ifdef HAVE_CTYPE_H # include #endif // HAVE_CTYPE_H static unsigned long bsqrt(unsigned long x) { if (x <= 0) return 0; if (x == 1) return 1; unsigned long r = x >> 1; unsigned long q; while (1) { q = x / r; if (q >= r) return r; r = (r + q) >> 1; } } BImage::BImage(BImageControl *c, unsigned int w, unsigned int h) { control = c; width = ((signed) w > 0) ? w : 1; height = ((signed) h > 0) ? h : 1; red = new unsigned char[width * height]; green = new unsigned char[width * height]; blue = new unsigned char[width * height]; xtable = ytable = (unsigned int *) 0; cpc = control->getColorsPerChannel(); cpccpc = cpc * cpc; control->getColorTables(&red_table, &green_table, &blue_table, &red_offset, &green_offset, &blue_offset, &red_bits, &green_bits, &blue_bits); if (control->getVisual()->c_class != TrueColor) control->getXColorTable(&colors, &ncolors); } BImage::~BImage(void) { if (red) delete [] red; if (green) delete [] green; if (blue) delete [] blue; } Pixmap BImage::render(BTexture *texture) { if (texture->getTexture() & BImage_ParentRelative) return ParentRelative; else if (texture->getTexture() & BImage_Solid) return render_solid(texture); else if (texture->getTexture() & BImage_Gradient) return render_gradient(texture); return None; } Pixmap BImage::render_solid(BTexture *texture) { Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(), control->getDrawable(), width, height, control->getDepth()); if (pixmap == None) { fprintf(stderr, I18n::instance()->getMessage( #ifdef NLS ImageSet, ImageErrorCreatingSolidPixmap, #else // !NLS 0, 0, #endif // NLS "BImage::render_solid: error creating pixmap\n")); return None; } XGCValues gcv; GC gc, hgc, lgc; gcv.foreground = texture->getColor()->getPixel(); gcv.fill_style = FillSolid; gc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap, GCForeground | GCFillStyle, &gcv); gcv.foreground = texture->getHiColor()->getPixel(); hgc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap, GCForeground, &gcv); gcv.foreground = texture->getLoColor()->getPixel(); lgc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap, GCForeground, &gcv); XFillRectangle(control->getBaseDisplay()->getXDisplay(), pixmap, gc, 0, 0, width, height); #ifdef INTERLACE if (texture->getTexture() & BImage_Interlaced) { gcv.foreground = texture->getColorTo()->getPixel(); GC igc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap, GCForeground, &gcv); register unsigned int i = 0; for (; i < height; i += 2) XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, igc, 0, i, width, i); XFreeGC(control->getBaseDisplay()->getXDisplay(), igc); } #endif // INTERLACE if (texture->getTexture() & BImage_Bevel1) { if (texture->getTexture() & BImage_Raised) { XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, 0, height - 1, width - 1, height - 1); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, width - 1, height - 1, width - 1, 0); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, 0, 0, width - 1, 0); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, 0, height - 1, 0, 0); } else if (texture->getTexture() & BImage_Sunken) { XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, 0, height - 1, width - 1, height - 1); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, width - 1, height - 1, width - 1, 0); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, 0, 0, width - 1, 0); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, 0, height - 1, 0, 0); } } else if (texture->getTexture() & BImage_Bevel2) { if (texture->getTexture() & BImage_Raised) { XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, 1, height - 3, width - 3, height - 3); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, width - 3, height - 3, width - 3, 1); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, 1, 1, width - 3, 1); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, 1, height - 3, 1, 1); } else if (texture->getTexture() & BImage_Sunken) { XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, 1, height - 3, width - 3, height - 3); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, width - 3, height - 3, width - 3, 1); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, 1, 1, width - 3, 1); XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, 1, height - 3, 1, 1); } } XFreeGC(control->getBaseDisplay()->getXDisplay(), gc); XFreeGC(control->getBaseDisplay()->getXDisplay(), hgc); XFreeGC(control->getBaseDisplay()->getXDisplay(), lgc); return pixmap; } Pixmap BImage::render_gradient(BTexture *texture) { int inverted = 0; #ifdef INTERLACE interlaced = texture->getTexture() & BImage_Interlaced; #endif // INTERLACE if (texture->getTexture() & BImage_Sunken) { from = texture->getColorTo(); to = texture->getColor(); if (! (texture->getTexture() & BImage_Invert)) inverted = 1; } else { from = texture->getColor(); to = texture->getColorTo(); if (texture->getTexture() & BImage_Invert) inverted = 1; } control->getGradientBuffers(width, height, &xtable, &ytable); if (texture->getTexture() & BImage_Diagonal) dgradient(); else if (texture->getTexture() & BImage_Elliptic) egradient(); else if (texture->getTexture() & BImage_Horizontal) hgradient(); else if (texture->getTexture() & BImage_Pyramid) pgradient(); else if (texture->getTexture() & BImage_Rectangle) rgradient(); else if (texture->getTexture() & BImage_Vertical) vgradient(); else if (texture->getTexture() & BImage_CrossDiagonal) cdgradient(); else if (texture->getTexture() & BImage_PipeCross) pcgradient(); if (texture->getTexture() & BImage_Bevel1) bevel1(); else if (texture->getTexture() & BImage_Bevel2) bevel2(); if (inverted) invert(); Pixmap pixmap = renderPixmap(); return pixmap; } XImage *BImage::renderXImage(void) { I18n *i18n = I18n::instance(); XImage *image = XCreateImage(control->getBaseDisplay()->getXDisplay(), control->getVisual(), control->getDepth(), ZPixmap, 0, 0, width, height, 32, 0); if (! image) { fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageErrorCreatingXImage, #else // !NLS 0, 0, #endif // NLS "BImage::renderXImage: error creating XImage\n")); return (XImage *) 0; } // insurance policy image->data = (char *) 0; unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)]; register unsigned int x, y, dithx, dithy, r, g, b, o, er, eg, eb, offset; unsigned char *pixel_data = d, *ppixel_data = d; unsigned long pixel; o = image->bits_per_pixel + ((image->byte_order == MSBFirst) ? 1 : 0); if (control->doDither() && width > 1 && height > 1) { unsigned char dither4[4][4] = { {0, 4, 1, 5}, {6, 2, 7, 3}, {1, 5, 0, 4}, {7, 3, 6, 2} }; #ifdef ORDEREDPSEUDO unsigned char dither8[8][8] = { { 0, 32, 8, 40, 2, 34, 10, 42 }, { 48, 16, 56, 24, 50, 18, 58, 26 }, { 12, 44, 4, 36, 14, 46, 6, 38 }, { 60, 28, 52, 20, 62, 30, 54, 22 }, { 3, 35, 11, 43, 1, 33, 9, 41 }, { 51, 19, 59, 27, 49, 17, 57, 25 }, { 15, 47, 7, 39, 13, 45, 5, 37 }, { 63, 31, 55, 23, 61, 29, 53, 21 } }; #endif // ORDEREDPSEUDO switch (control->getVisual()->c_class) { case TrueColor: // algorithm: ordered dithering... many many thanks to rasterman // (raster@rasterman.com) for telling me about this... portions of this // code is based off of his code in Imlib for (y = 0, offset = 0; y < height; y++) { dithy = y & 0x3; for (x = 0; x < width; x++, offset++) { dithx = x & 0x3; r = red[offset]; g = green[offset]; b = blue[offset]; er = r & (red_bits - 1); eg = g & (green_bits - 1); eb = b & (blue_bits - 1); r = red_table[r]; g = green_table[g]; b = blue_table[b]; if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++; if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++; if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++; pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset); switch (o) { case 8: // 8bpp *pixel_data++ = pixel; break; case 16: // 16bpp LSB *pixel_data++ = pixel; *pixel_data++ = pixel >> 8; break; case 17: // 16bpp MSB *pixel_data++ = pixel >> 8; *pixel_data++ = pixel; break; case 24: // 24bpp LSB *pixel_data++ = pixel; *pixel_data++ = pixel >> 8; *pixel_data++ = pixel >> 16; break; case 25: // 24bpp MSB *pixel_data++ = pixel >> 16; *pixel_data++ = pixel >> 8; *pixel_data++ = pixel; break; case 32: // 32bpp LSB *pixel_data++ = pixel; *pixel_data++ = pixel >> 8; *pixel_data++ = pixel >> 16; *pixel_data++ = pixel >> 24; break; case 33: // 32bpp MSB *pixel_data++ = pixel >> 24; *pixel_data++ = pixel >> 16; *pixel_data++ = pixel >> 8; *pixel_data++ = pixel; break; } } pixel_data = (ppixel_data += image->bytes_per_line); } break; case StaticColor: case PseudoColor: { #ifndef ORDEREDPSEUDO short *terr, *rerr = new short[width + 2], *gerr = new short[width + 2], *berr = new short[width + 2], *nrerr = new short[width + 2], *ngerr = new short[width + 2], *nberr = new short[width + 2]; int rr, gg, bb, rer, ger, ber; int dd = 255 / control->getColorsPerChannel(); for (x = 0; x < width; x++) { *(rerr + x) = *(red + x); *(gerr + x) = *(green + x); *(berr + x) = *(blue + x); } *(rerr + x) = *(gerr + x) = *(berr + x) = 0; #endif // ORDEREDPSEUDO for (y = 0, offset = 0; y < height; y++) { #ifdef ORDEREDPSEUDO dithy = y & 7; for (x = 0; x < width; x++, offset++) { dithx = x & 7; r = red[offset]; g = green[offset]; b = blue[offset]; er = r & (red_bits - 1); eg = g & (green_bits - 1); eb = b & (blue_bits - 1); r = red_table[r]; g = green_table[g]; b = blue_table[b]; if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++; if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++; if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++; pixel = (r * cpccpc) + (g * cpc) + b; *(pixel_data++) = colors[pixel].pixel; } pixel_data = (ppixel_data += image->bytes_per_line); } #else // !ORDEREDPSEUDO if (y < (height - 1)) { int i = offset + width; for (x = 0; x < width; x++, i++) { *(nrerr + x) = *(red + i); *(ngerr + x) = *(green + i); *(nberr + x) = *(blue + i); } *(nrerr + x) = *(red + (--i)); *(ngerr + x) = *(green + i); *(nberr + x) = *(blue + i); } for (x = 0; x < width; x++) { rr = rerr[x]; gg = gerr[x]; bb = berr[x]; if (rr > 255) rr = 255; else if (rr < 0) rr = 0; if (gg > 255) gg = 255; else if (gg < 0) gg = 0; if (bb > 255) bb = 255; else if (bb < 0) bb = 0; r = red_table[rr]; g = green_table[gg]; b = blue_table[bb]; rer = rerr[x] - r*dd; ger = gerr[x] - g*dd; ber = berr[x] - b*dd; pixel = (r * cpccpc) + (g * cpc) + b; *pixel_data++ = colors[pixel].pixel; r = rer >> 1; g = ger >> 1; b = ber >> 1; rerr[x+1] += r; gerr[x+1] += g; berr[x+1] += b; nrerr[x] += r; ngerr[x] += g; nberr[x] += b; } offset += width; pixel_data = (ppixel_data += image->bytes_per_line); terr = rerr; rerr = nrerr; nrerr = terr; terr = gerr; gerr = ngerr; ngerr = terr; terr = berr; berr = nberr; nberr = terr; } delete [] rerr; delete [] gerr; delete [] berr; delete [] nrerr; delete [] ngerr; delete [] nberr; #endif // ORDEREDPSUEDO break; } /* case StaticGray: case GrayScale: for (y = 0, offset = 0; y < height; y++) { dithy = y & 0x3; for (x = 0; x < width; x++, offset++) { dithx = x & 0x3; r = *(red + offset); g = *(green + offset); b = *(blue + offset); er = r & 0x7; eg = g & 0x7; eb = b & 0x7; if ((dither[dithy][dithx] < er) && (r < (256 - 8))) r += 8; if ((dither[dithy][dithx] < (eg << 1)) && (g < (256 - 4))) g += 4; if ((dither[dithy][dithx] < eb) && (b < (256 - 8))) b += 8; r = *(red_table + r); g = *(green_table + g); b = *(blue_table + b); g = ((r * 30) + (g * 59) + (b * 11)) / 100; *pixel_data++ = colors[g].pixel; } pixel_data = (ppixel_data += image->bytes_per_line); } break; */ default: fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageUnsupVisual, #else // !NLS 0, 0, #endif // NLS "BImage::renderXImage: unsupported visual\n")); delete [] d; XDestroyImage(image); return (XImage *) 0; } } else { switch (control->getVisual()->c_class) { case StaticColor: case PseudoColor: for (y = 0, offset = 0; y < height; y++) { for (x = 0; x < width; x++, offset++) { r = red_table[red[offset]]; g = green_table[green[offset]]; b = blue_table[blue[offset]]; pixel = (r * cpccpc) + (g * cpc) + b; *pixel_data++ = colors[pixel].pixel; } pixel_data = (ppixel_data += image->bytes_per_line); } break; case TrueColor: for (y = 0, offset = 0; y < height; y++) { for (x = 0; x < width; x++, offset++) { r = red_table[red[offset]]; g = green_table[green[offset]]; b = blue_table[blue[offset]]; pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset); switch (o) { case 8: // 8bpp *pixel_data++ = pixel; break; case 16: // 16bpp LSB *pixel_data++ = pixel; *pixel_data++ = pixel >> 8; break; case 17: // 16bpp MSB *pixel_data++ = pixel >> 8; *pixel_data++ = pixel; break; case 24: // 24bpp LSB *pixel_data++ = pixel; *pixel_data++ = pixel >> 8; *pixel_data++ = pixel >> 16; break; case 25: // 24bpp MSB *pixel_data++ = pixel >> 16; *pixel_data++ = pixel >> 8; *pixel_data++ = pixel; break; case 32: // 32bpp LSB *pixel_data++ = pixel; *pixel_data++ = pixel >> 8; *pixel_data++ = pixel >> 16; *pixel_data++ = pixel >> 24; break; case 33: // 32bpp MSB *pixel_data++ = pixel >> 24; *pixel_data++ = pixel >> 16; *pixel_data++ = pixel >> 8; *pixel_data++ = pixel; break; } } pixel_data = (ppixel_data += image->bytes_per_line); } break; case StaticGray: case GrayScale: for (y = 0, offset = 0; y < height; y++) { for (x = 0; x < width; x++, offset++) { r = *(red_table + *(red + offset)); g = *(green_table + *(green + offset)); b = *(blue_table + *(blue + offset)); g = ((r * 30) + (g * 59) + (b * 11)) / 100; *pixel_data++ = colors[g].pixel; } pixel_data = (ppixel_data += image->bytes_per_line); } break; default: fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageUnsupVisual, #else // !NLS 0, 0, #endif // NLS "BImage::renderXImage: unsupported visual\n")); delete [] d; XDestroyImage(image); return (XImage *) 0; } } image->data = (char *) d; return image; } Pixmap BImage::renderPixmap(void) { I18n *i18n = I18n::instance(); Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(), control->getDrawable(), width, height, control->getDepth()); if (pixmap == None) { fprintf(stderr, i18n->getMessage( #ifdef NLS ImageSet, ImageErrorCreatingPixmap, #else // !NLS 0, 0, #endif // NLS "BImage::renderPixmap: error creating pixmap\n")); return None; } XImage *image = renderXImage(); if (! image) { XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap); return None; } else if (! image->data) { XDestroyImage(image); XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap); return None; } XPutImage(control->getBaseDisplay()->getXDisplay(), pixmap, DefaultGC(control->getBaseDisplay()->getXDisplay(), control->getScreenInfo()->getScreenNumber()), image, 0, 0, 0, 0, width, height); if (image->data) { delete [] image->data; image->data = NULL; } XDestroyImage(image); return pixmap; } void BImage::bevel1(void) { if (width > 2 && height > 2) { unsigned char *pr = red, *pg = green, *pb = blue; register unsigned char r, g, b, rr ,gg ,bb; register unsigned int w = width, h = height - 1, wh = w * h; while (--w) { r = *pr; rr = r + (r >> 1); if (rr < r) rr = ~0; g = *pg; gg = g + (g >> 1); if (gg < g) gg = ~0; b = *pb; bb = b + (b >> 1); if (bb < b) bb = ~0; *pr = rr; *pg = gg; *pb = bb; r = *(pr + wh); rr = (r >> 2) + (r >> 1); if (rr > r) rr = 0; g = *(pg + wh); gg = (g >> 2) + (g >> 1); if (gg > g) gg = 0; b = *(pb + wh); bb = (b >> 2) + (b >> 1); if (bb > b) bb = 0; *((pr++) + wh) = rr; *((pg++) + wh) = gg; *((pb++) + wh) = bb; } r = *pr; rr = r + (r >> 1); if (rr < r) rr = ~0; g = *pg; gg = g + (g >> 1); if (gg < g) gg = ~0; b = *pb; bb = b + (b >> 1); if (bb < b) bb = ~0; *pr = rr; *pg = gg; *pb = bb; r = *(pr + wh); rr = (r >> 2) + (r >> 1); if (rr > r) rr = 0; g = *(pg + wh); gg = (g >> 2) + (g >> 1); if (gg > g) gg = 0; b = *(pb + wh); bb = (b >> 2) + (b >> 1); if (bb > b) bb = 0; *(pr + wh) = rr; *(pg + wh) = gg; *(pb + wh) = bb; pr = red + width; pg = green + width; pb = blue + width; while (--h) { r = *pr; rr = r + (r >> 1); if (rr < r) rr = ~0; g = *pg; gg = g + (g >> 1); if (gg < g) gg = ~0; b = *pb; bb = b + (b >> 1); if (bb < b) bb = ~0; *pr = rr; *pg = gg; *pb = bb; pr += width - 1; pg += width - 1; pb += width - 1; r = *pr; rr = (r >> 2) + (r >> 1); if (rr > r) rr = 0; g = *pg; gg = (g >> 2) + (g >> 1); if (gg > g) gg = 0; b = *pb; bb = (b >> 2) + (b >> 1); if (bb > b) bb = 0; *(pr++) = rr; *(pg++) = gg; *(pb++) = bb; } r = *pr; rr = r + (r >> 1); if (rr < r) rr = ~0; g = *pg; gg = g + (g >> 1); if (gg < g) gg = ~0; b = *pb; bb = b + (b >> 1); if (bb < b) bb = ~0; *pr = rr; *pg = gg; *pb = bb; pr += width - 1; pg += width - 1; pb += width - 1; r = *pr; rr = (r >> 2) + (r >> 1); if (rr > r) rr = 0; g = *pg; gg = (g >> 2) + (g >> 1); if (gg > g) gg = 0; b = *pb; bb = (b >> 2) + (b >> 1); if (bb > b) bb = 0; *pr = rr; *pg = gg; *pb = bb; } } void BImage::bevel2(void) { if (width > 4 && height > 4) { unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1, *pg = green + width + 1, *pb = blue + width + 1; unsigned int w = width - 2, h = height - 1, wh = width * (height - 3); while (--w) { r = *pr; rr = r + (r >> 1); if (rr < r) rr = ~0; g = *pg; gg = g + (g >> 1); if (gg < g) gg = ~0; b = *pb; bb = b + (b >> 1); if (bb < b) bb = ~0; *pr = rr; *pg = gg; *pb = bb; r = *(pr + wh); rr = (r >> 2) + (r >> 1); if (rr > r) rr = 0; g = *(pg + wh); gg = (g >> 2) + (g >> 1); if (gg > g) gg = 0; b = *(pb + wh); bb = (b >> 2) + (b >> 1); if (bb > b) bb = 0; *((pr++) + wh) = rr; *((pg++) + wh) = gg; *((pb++) + wh) = bb; } pr = red + width; pg = green + width; pb = blue + width; while (--h) { r = *pr; rr = r + (r >> 1); if (rr < r) rr = ~0; g = *pg; gg = g + (g >> 1); if (gg < g) gg = ~0; b = *pb; bb = b + (b >> 1); if (bb < b) bb = ~0; *(++pr) = rr; *(++pg) = gg; *(++pb) = bb; pr += width - 3; pg += width - 3; pb += width - 3; r = *pr; rr = (r >> 2) + (r >> 1); if (rr > r) rr = 0; g = *pg; gg = (g >> 2) + (g >> 1); if (gg > g) gg = 0; b = *pb; bb = (b >> 2) + (b >> 1); if (bb > b) bb = 0; *(pr++) = rr; *(pg++) = gg; *(pb++) = bb; pr++; pg++; pb++; } } } void BImage::invert(void) { register unsigned int i, j, wh = (width * height) - 1; unsigned char tmp; for (i = 0, j = wh; j > i; j--, i++) { tmp = *(red + j); *(red + j) = *(red + i); *(red + i) = tmp; tmp = *(green + j); *(green + j) = *(green + i); *(green + i) = tmp; tmp = *(blue + j); *(blue + j) = *(blue + i); *(blue + i) = tmp; } } void BImage::dgradient(void) { // diagonal gradient code was written by Mike Cole // modified for interlacing by Brad Hughes float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, xr = (float) from->getRed(), xg = (float) from->getGreen(), xb = (float) from->getBlue(); unsigned char *pr = red, *pg = green, *pb = blue; unsigned int w = width * 2, h = height * 2, *xt = xtable, *yt = ytable; register unsigned int x, y; dry = drx = (float) (to->getRed() - from->getRed()); dgy = dgx = (float) (to->getGreen() - from->getGreen()); dby = dbx = (float) (to->getBlue() - from->getBlue()); // Create X table drx /= w; dgx /= w; dbx /= w; for (x = 0; x < width; x++) { *(xt++) = (unsigned char) (xr); *(xt++) = (unsigned char) (xg); *(xt++) = (unsigned char) (xb); xr += drx; xg += dgx; xb += dbx; } // Create Y table dry /= h; dgy /= h; dby /= h; for (y = 0; y < height; y++) { *(yt++) = ((unsigned char) yr); *(yt++) = ((unsigned char) yg); *(yt++) = ((unsigned char) yb); yr += dry; yg += dgy; yb += dby; } // Combine tables to create gradient #ifdef INTERLACE if (! interlaced) { #endif // INTERLACE // normal dgradient for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { *(pr++) = *(xt++) + *(yt); *(pg++) = *(xt++) + *(yt + 1); *(pb++) = *(xt++) + *(yt + 2); } } #ifdef INTERLACE } else { // faked interlacing effect unsigned char channel, channel2; for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { if (y & 1) { channel = *(xt++) + *(yt); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pr++) = channel2; channel = *(xt++) + *(yt + 1); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pg++) = channel2; channel = *(xt++) + *(yt + 2); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pb++) = channel2; } else { channel = *(xt++) + *(yt); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pr++) = channel2; channel = *(xt++) + *(yt + 1); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pg++) = channel2; channel = *(xt++) + *(yt + 2); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pb++) = channel2; } } } } #endif // INTERLACE } void BImage::hgradient(void) { float drx, dgx, dbx, xr = (float) from->getRed(), xg = (float) from->getGreen(), xb = (float) from->getBlue(); unsigned char *pr = red, *pg = green, *pb = blue; register unsigned int x, y; drx = (float) (to->getRed() - from->getRed()); dgx = (float) (to->getGreen() - from->getGreen()); dbx = (float) (to->getBlue() - from->getBlue()); drx /= width; dgx /= width; dbx /= width; #ifdef INTERLACE if (interlaced && height > 2) { // faked interlacing effect unsigned char channel, channel2; for (x = 0; x < width; x++, pr++, pg++, pb++) { channel = (unsigned char) xr; channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *pr = channel2; channel = (unsigned char) xg; channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *pg = channel2; channel = (unsigned char) xb; channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *pb = channel2; channel = (unsigned char) xr; channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pr + width) = channel2; channel = (unsigned char) xg; channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pg + width) = channel2; channel = (unsigned char) xb; channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pb + width) = channel2; xr += drx; xg += dgx; xb += dbx; } pr += width; pg += width; pb += width; int offset; for (y = 2; y < height; y++, pr += width, pg += width, pb += width) { if (y & 1) offset = width; else offset = 0; memcpy(pr, (red + offset), width); memcpy(pg, (green + offset), width); memcpy(pb, (blue + offset), width); } } else { #endif // INTERLACE // normal hgradient for (x = 0; x < width; x++) { *(pr++) = (unsigned char) (xr); *(pg++) = (unsigned char) (xg); *(pb++) = (unsigned char) (xb); xr += drx; xg += dgx; xb += dbx; } for (y = 1; y < height; y++, pr += width, pg += width, pb += width) { memcpy(pr, red, width); memcpy(pg, green, width); memcpy(pb, blue, width); } #ifdef INTERLACE } #endif // INTERLACE } void BImage::vgradient(void) { float dry, dgy, dby, yr = (float) from->getRed(), yg = (float) from->getGreen(), yb = (float) from->getBlue(); unsigned char *pr = red, *pg = green, *pb = blue; register unsigned int y; dry = (float) (to->getRed() - from->getRed()); dgy = (float) (to->getGreen() - from->getGreen()); dby = (float) (to->getBlue() - from->getBlue()); dry /= height; dgy /= height; dby /= height; #ifdef INTERLACE if (interlaced) { // faked interlacing effect unsigned char channel, channel2; for (y = 0; y < height; y++, pr += width, pg += width, pb += width) { if (y & 1) { channel = (unsigned char) yr; channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; memset(pr, channel2, width); channel = (unsigned char) yg; channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; memset(pg, channel2, width); channel = (unsigned char) yb; channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; memset(pb, channel2, width); } else { channel = (unsigned char) yr; channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; memset(pr, channel2, width); channel = (unsigned char) yg; channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; memset(pg, channel2, width); channel = (unsigned char) yb; channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; memset(pb, channel2, width); } yr += dry; yg += dgy; yb += dby; } } else { #endif // INTERLACE // normal vgradient for (y = 0; y < height; y++, pr += width, pg += width, pb += width) { memset(pr, (unsigned char) yr, width); memset(pg, (unsigned char) yg, width); memset(pb, (unsigned char) yb, width); yr += dry; yg += dgy; yb += dby; } #ifdef INTERLACE } #endif // INTERLACE } void BImage::pgradient(void) { // pyramid gradient - based on original dgradient, written by // Mosfet (mosfet@kde.org) // adapted from kde sources for Blackbox by Brad Hughes float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby, xr, xg, xb; int rsign, gsign, bsign; unsigned char *pr = red, *pg = green, *pb = blue; unsigned int tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(), *xt = xtable, *yt = ytable; register unsigned int x, y; dry = drx = (float) (to->getRed() - from->getRed()); dgy = dgx = (float) (to->getGreen() - from->getGreen()); dby = dbx = (float) (to->getBlue() - from->getBlue()); rsign = (drx < 0) ? -1 : 1; gsign = (dgx < 0) ? -1 : 1; bsign = (dbx < 0) ? -1 : 1; xr = yr = (drx / 2); xg = yg = (dgx / 2); xb = yb = (dbx / 2); // Create X table drx /= width; dgx /= width; dbx /= width; for (x = 0; x < width; x++) { *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); xr -= drx; xg -= dgx; xb -= dbx; } // Create Y table dry /= height; dgy /= height; dby /= height; for (y = 0; y < height; y++) { *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); yr -= dry; yg -= dgy; yb -= dby; } // Combine tables to create gradient #ifdef INTERLACE if (! interlaced) { #endif // INTERLACE // normal pgradient for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); } } #ifdef INTERLACE } else { // faked interlacing effect unsigned char channel, channel2; for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { if (y & 1) { channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pr++) = channel2; channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pg++) = channel2; channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pb++) = channel2; } else { channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pr++) = channel2; channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pg++) = channel2; channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pb++) = channel2; } } } } #endif // INTERLACE } void BImage::rgradient(void) { // rectangle gradient - based on original dgradient, written by // Mosfet (mosfet@kde.org) // adapted from kde sources for Blackbox by Brad Hughes float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb; int rsign, gsign, bsign; unsigned char *pr = red, *pg = green, *pb = blue; unsigned int tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(), *xt = xtable, *yt = ytable; register unsigned int x, y; dry = drx = (float) (to->getRed() - from->getRed()); dgy = dgx = (float) (to->getGreen() - from->getGreen()); dby = dbx = (float) (to->getBlue() - from->getBlue()); rsign = (drx < 0) ? -2 : 2; gsign = (dgx < 0) ? -2 : 2; bsign = (dbx < 0) ? -2 : 2; xr = yr = (drx / 2); xg = yg = (dgx / 2); xb = yb = (dbx / 2); // Create X table drx /= width; dgx /= width; dbx /= width; for (x = 0; x < width; x++) { *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); xr -= drx; xg -= dgx; xb -= dbx; } // Create Y table dry /= height; dgy /= height; dby /= height; for (y = 0; y < height; y++) { *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); yr -= dry; yg -= dgy; yb -= dby; } // Combine tables to create gradient #ifdef INTERLACE if (! interlaced) { #endif // INTERLACE // normal rgradient for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { *(pr++) = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); *(pg++) = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); *(pb++) = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); } } #ifdef INTERLACE } else { // faked interlacing effect unsigned char channel, channel2; for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { if (y & 1) { channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pr++) = channel2; channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pg++) = channel2; channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pb++) = channel2; } else { channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pr++) = channel2; channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pg++) = channel2; channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pb++) = channel2; } } } } #endif // INTERLACE } void BImage::egradient(void) { // elliptic gradient - based on original dgradient, written by // Mosfet (mosfet@kde.org) // adapted from kde sources for Blackbox by Brad Hughes float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb; int rsign, gsign, bsign; unsigned char *pr = red, *pg = green, *pb = blue; unsigned int *xt = xtable, *yt = ytable, tr = (unsigned long) to->getRed(), tg = (unsigned long) to->getGreen(), tb = (unsigned long) to->getBlue(); register unsigned int x, y; dry = drx = (float) (to->getRed() - from->getRed()); dgy = dgx = (float) (to->getGreen() - from->getGreen()); dby = dbx = (float) (to->getBlue() - from->getBlue()); rsign = (drx < 0) ? -1 : 1; gsign = (dgx < 0) ? -1 : 1; bsign = (dbx < 0) ? -1 : 1; xr = yr = (drx / 2); xg = yg = (dgx / 2); xb = yb = (dbx / 2); // Create X table drx /= width; dgx /= width; dbx /= width; for (x = 0; x < width; x++) { *(xt++) = (unsigned long) (xr * xr); *(xt++) = (unsigned long) (xg * xg); *(xt++) = (unsigned long) (xb * xb); xr -= drx; xg -= dgx; xb -= dbx; } // Create Y table dry /= height; dgy /= height; dby /= height; for (y = 0; y < height; y++) { *(yt++) = (unsigned long) (yr * yr); *(yt++) = (unsigned long) (yg * yg); *(yt++) = (unsigned long) (yb * yb); yr -= dry; yg -= dgy; yb -= dby; } // Combine tables to create gradient #ifdef INTERLACE if (! interlaced) { #endif // INTERLACE // normal egradient for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { *(pr++) = (unsigned char) (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); *(pg++) = (unsigned char) (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); *(pb++) = (unsigned char) (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); } } #ifdef INTERLACE } else { // faked interlacing effect unsigned char channel, channel2; for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { if (y & 1) { channel = (unsigned char) (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pr++) = channel2; channel = (unsigned char) (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pg++) = channel2; channel = (unsigned char) (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pb++) = channel2; } else { channel = (unsigned char) (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pr++) = channel2; channel = (unsigned char) (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pg++) = channel2; channel = (unsigned char) (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pb++) = channel2; } } } } #endif // INTERLACE } void BImage::pcgradient(void) { // pipe cross gradient - based on original dgradient, written by // Mosfet (mosfet@kde.org) // adapted from kde sources for Blackbox by Brad Hughes float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb; int rsign, gsign, bsign; unsigned char *pr = red, *pg = green, *pb = blue; unsigned int *xt = xtable, *yt = ytable, tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(); register unsigned int x, y; dry = drx = (float) (to->getRed() - from->getRed()); dgy = dgx = (float) (to->getGreen() - from->getGreen()); dby = dbx = (float) (to->getBlue() - from->getBlue()); rsign = (drx < 0) ? -2 : 2; gsign = (dgx < 0) ? -2 : 2; bsign = (dbx < 0) ? -2 : 2; xr = yr = (drx / 2); xg = yg = (dgx / 2); xb = yb = (dbx / 2); // Create X table drx /= width; dgx /= width; dbx /= width; for (x = 0; x < width; x++) { *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); xr -= drx; xg -= dgx; xb -= dbx; } // Create Y table dry /= height; dgy /= height; dby /= height; for (y = 0; y < height; y++) { *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); yr -= dry; yg -= dgy; yb -= dby; } // Combine tables to create gradient #ifdef INTERLACE if (! interlaced) { #endif // INTERLACE // normal pcgradient for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { *(pr++) = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); *(pg++) = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1)))); *(pb++) = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2)))); } } #ifdef INTERLACE } else { // faked interlacing effect unsigned char channel, channel2; for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { if (y & 1) { channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pr++) = channel2; channel = (unsigned char) (tg - (bsign * min(*(xt++), *(yt + 1)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pg++) = channel2; channel = (unsigned char) (tb - (gsign * min(*(xt++), *(yt + 2)))); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pb++) = channel2; } else { channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pr++) = channel2; channel = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pg++) = channel2; channel = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2)))); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pb++) = channel2; } } } } #endif // INTERLACE } void BImage::cdgradient(void) { // cross diagonal gradient - based on original dgradient, written by // Mosfet (mosfet@kde.org) // adapted from kde sources for Blackbox by Brad Hughes float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, xr = (float) from->getRed(), xg = (float) from->getGreen(), xb = (float) from->getBlue(); unsigned char *pr = red, *pg = green, *pb = blue; unsigned int w = width * 2, h = height * 2, *xt, *yt; register unsigned int x, y; dry = drx = (float) (to->getRed() - from->getRed()); dgy = dgx = (float) (to->getGreen() - from->getGreen()); dby = dbx = (float) (to->getBlue() - from->getBlue()); // Create X table drx /= w; dgx /= w; dbx /= w; for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) { *(xt--) = (unsigned char) xb; *(xt--) = (unsigned char) xg; *(xt--) = (unsigned char) xr; xr += drx; xg += dgx; xb += dbx; } // Create Y table dry /= h; dgy /= h; dby /= h; for (yt = ytable, y = 0; y < height; y++) { *(yt++) = (unsigned char) yr; *(yt++) = (unsigned char) yg; *(yt++) = (unsigned char) yb; yr += dry; yg += dgy; yb += dby; } // Combine tables to create gradient #ifdef INTERLACE if (! interlaced) { #endif // INTERLACE // normal cdgradient for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { *(pr++) = *(xt++) + *(yt); *(pg++) = *(xt++) + *(yt + 1); *(pb++) = *(xt++) + *(yt + 2); } } #ifdef INTERLACE } else { // faked interlacing effect unsigned char channel, channel2; for (yt = ytable, y = 0; y < height; y++, yt += 3) { for (xt = xtable, x = 0; x < width; x++) { if (y & 1) { channel = *(xt++) + *(yt); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pr++) = channel2; channel = *(xt++) + *(yt + 1); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pg++) = channel2; channel = *(xt++) + *(yt + 2); channel2 = (channel >> 1) + (channel >> 2); if (channel2 > channel) channel2 = 0; *(pb++) = channel2; } else { channel = *(xt++) + *(yt); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pr++) = channel2; channel = *(xt++) + *(yt + 1); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pg++) = channel2; channel = *(xt++) + *(yt + 2); channel2 = channel + (channel >> 3); if (channel2 < channel) channel2 = ~0; *(pb++) = channel2; } } } } #endif // INTERLACE } BImageControl::BImageControl(BaseDisplay *dpy, ScreenInfo *scrn, Bool _dither, int _cpc, unsigned long cache_timeout, unsigned long cmax) { I18n *i18n = I18n::instance(); basedisplay = dpy; screeninfo = scrn; setDither(_dither); setColorsPerChannel(_cpc); cache_max = cmax; #ifdef TIMEDCACHE if (cache_timeout) { timer = new BTimer(basedisplay, this); timer->setTimeout(cache_timeout); timer->start(); } else timer = (BTimer *) 0; #endif // TIMEDCACHE colors = (XColor *) 0; ncolors = 0; grad_xbuffer = grad_ybuffer = (unsigned int *) 0; grad_buffer_width = grad_buffer_height = 0; sqrt_table = (unsigned long *) 0; screen_depth = screeninfo->getDepth(); window = screeninfo->getRootWindow(); screen_number = screeninfo->getScreenNumber(); int count; XPixmapFormatValues *pmv = XListPixmapFormats(basedisplay->getXDisplay(), &count); colormap = screeninfo->getColormap(); if (pmv) { bits_per_pixel = 0; for (int i = 0; i < count; i++) { if (pmv[i].depth == screen_depth) { bits_per_pixel = pmv[i].bits_per_pixel; break; } } XFree(pmv); } if (bits_per_pixel == 0) bits_per_pixel = screen_depth; if (bits_per_pixel >= 24) setDither(False); red_offset = green_offset = blue_offset = 0; switch (getVisual()->c_class) { case TrueColor: { int i; // compute color tables unsigned long red_mask = getVisual()->red_mask, green_mask = getVisual()->green_mask, blue_mask = getVisual()->blue_mask; while (! (red_mask & 1)) { red_offset++; red_mask >>= 1; } while (! (green_mask & 1)) { green_offset++; green_mask >>= 1; } while (! (blue_mask & 1)) { blue_offset++; blue_mask >>= 1; } red_bits = 255 / red_mask; green_bits = 255 / green_mask; blue_bits = 255 / blue_mask; for (i = 0; i < 256; i++) { red_color_table[i] = i / red_bits; green_color_table[i] = i / green_bits; blue_color_table[i] = i / blue_bits; } } break; case PseudoColor: case StaticColor: { ncolors = colors_per_channel * colors_per_channel * colors_per_channel; if (ncolors > (1 << screen_depth)) { colors_per_channel = (1 << screen_depth) / 3; ncolors = colors_per_channel * colors_per_channel * colors_per_channel; } if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) { fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageInvalidColormapSize, #else // !NLS 0, 0, #endif // NLS "BImageControl::BImageControl: invalid colormap size %d " "(%d/%d/%d) - reducing"), ncolors, colors_per_channel, colors_per_channel, colors_per_channel); colors_per_channel = (1 << screen_depth) / 3; } colors = new XColor[ncolors]; if (! colors) { fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageErrorAllocatingColormap, #else // !NLS 0, 0, #endif // NLS "BImageControl::BImageControl: error allocating " "colormap\n")); throw static_cast(1); //throw exit code 1 } int i = 0, ii, p, r, g, b, #ifdef ORDEREDPSEUDO bits = 256 / colors_per_channel; #else // !ORDEREDPSEUDO bits = 255 / (colors_per_channel - 1); #endif // ORDEREDPSEUDO red_bits = green_bits = blue_bits = bits; for (i = 0; i < 256; i++) red_color_table[i] = green_color_table[i] = blue_color_table[i] = i / bits; for (r = 0, i = 0; r < colors_per_channel; r++) for (g = 0; g < colors_per_channel; g++) for (b = 0; b < colors_per_channel; b++, i++) { colors[i].red = (r * 0xffff) / (colors_per_channel - 1); colors[i].green = (g * 0xffff) / (colors_per_channel - 1); colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);; colors[i].flags = DoRed|DoGreen|DoBlue; } basedisplay->grab(); for (i = 0; i < ncolors; i++) { if (! XAllocColor(basedisplay->getXDisplay(), colormap, &colors[i])) { fprintf(stderr, i18n->getMessage( #ifdef NLS ImageSet, ImageColorAllocFail, #else // !NLS 0, 0, #endif // NLS "couldn't alloc color %i %i %i\n"), colors[i].red, colors[i].green, colors[i].blue); colors[i].flags = 0; } else colors[i].flags = DoRed|DoGreen|DoBlue; } basedisplay->ungrab(); XColor icolors[256]; int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth)); for (i = 0; i < incolors; i++) icolors[i].pixel = i; XQueryColors(basedisplay->getXDisplay(), colormap, icolors, incolors); for (i = 0; i < ncolors; i++) { if (! colors[i].flags) { unsigned long chk = 0xffffffff, pixel, close = 0; p = 2; while (p--) { for (ii = 0; ii < incolors; ii++) { r = (colors[i].red - icolors[i].red) >> 8; g = (colors[i].green - icolors[i].green) >> 8; b = (colors[i].blue - icolors[i].blue) >> 8; pixel = (r * r) + (g * g) + (b * b); if (pixel < chk) { chk = pixel; close = ii; } colors[i].red = icolors[close].red; colors[i].green = icolors[close].green; colors[i].blue = icolors[close].blue; if (XAllocColor(basedisplay->getXDisplay(), colormap, &colors[i])) { colors[i].flags = DoRed|DoGreen|DoBlue; break; } } } } } break; } case GrayScale: case StaticGray: { if (getVisual()->c_class == StaticGray) { ncolors = 1 << screen_depth; } else { ncolors = colors_per_channel * colors_per_channel * colors_per_channel; if (ncolors > (1 << screen_depth)) { colors_per_channel = (1 << screen_depth) / 3; ncolors = colors_per_channel * colors_per_channel * colors_per_channel; } } if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) { fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageInvalidColormapSize, #else // !NLS 0, 0, #endif // NLS "BImageControl::BImageControl: invalid colormap size %d " "(%d/%d/%d) - reducing"), ncolors, colors_per_channel, colors_per_channel, colors_per_channel); colors_per_channel = (1 << screen_depth) / 3; } colors = new XColor[ncolors]; if (! colors) { fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageErrorAllocatingColormap, #else // !NLS 0, 0, #endif // NLS "BImageControl::BImageControl: error allocating " "colormap\n")); throw static_cast(1); // throw exit code 1 } int i = 0, ii, p, bits = 255 / (colors_per_channel - 1); red_bits = green_bits = blue_bits = bits; for (i = 0; i < 256; i++) red_color_table[i] = green_color_table[i] = blue_color_table[i] = i / bits; basedisplay->grab(); for (i = 0; i < ncolors; i++) { colors[i].red = (i * 0xffff) / (colors_per_channel - 1); colors[i].green = (i * 0xffff) / (colors_per_channel - 1); colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);; colors[i].flags = DoRed|DoGreen|DoBlue; if (! XAllocColor(basedisplay->getXDisplay(), colormap, &colors[i])) { fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageColorAllocFail, #else // !NLS 0, 0, #endif // NLS "couldn't alloc color %i %i %i\n"), colors[i].red, colors[i].green, colors[i].blue); colors[i].flags = 0; } else colors[i].flags = DoRed|DoGreen|DoBlue; } basedisplay->ungrab(); XColor icolors[256]; int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth)); for (i = 0; i < incolors; i++) icolors[i].pixel = i; XQueryColors(basedisplay->getXDisplay(), colormap, icolors, incolors); for (i = 0; i < ncolors; i++) { if (! colors[i].flags) { unsigned long chk = 0xffffffff, pixel, close = 0; p = 2; while (p--) { for (ii = 0; ii < incolors; ii++) { int r = (colors[i].red - icolors[i].red) >> 8; int g = (colors[i].green - icolors[i].green) >> 8; int b = (colors[i].blue - icolors[i].blue) >> 8; pixel = (r * r) + (g * g) + (b * b); if (pixel < chk) { chk = pixel; close = ii; } colors[i].red = icolors[close].red; colors[i].green = icolors[close].green; colors[i].blue = icolors[close].blue; if (XAllocColor(basedisplay->getXDisplay(), colormap, &colors[i])) { colors[i].flags = DoRed|DoGreen|DoBlue; break; } } } } } break; } default: fprintf(stderr, i18n-> getMessage( #ifdef NLS ImageSet, ImageUnsupVisual, #else // !NLS 0, 0, #endif // NLS "BImageControl::BImageControl: unsupported visual %d\n"), getVisual()->c_class); throw static_cast(1); //throw error code 1 } cache = new LinkedList; } BImageControl::~BImageControl(void) { if (sqrt_table) { delete [] sqrt_table; } if (grad_xbuffer) { delete [] grad_xbuffer; } if (grad_ybuffer) { delete [] grad_ybuffer; } if (colors) { unsigned long *pixels = new unsigned long [ncolors]; int i; for (i = 0; i < ncolors; i++) *(pixels + i) = (*(colors + i)).pixel; XFreeColors(basedisplay->getXDisplay(), colormap, pixels, ncolors, 0); delete [] colors; } if (cache->count()) { int i, n = cache->count(); fprintf(stderr, I18n::instance()-> getMessage( #ifdef NLS ImageSet, ImagePixmapRelease, #else // !NLS 0, 0, #endif // NLS "BImageContol::~BImageControl: pixmap cache - " "releasing %d pixmaps\n"), n); for (i = 0; i < n; i++) { Cache *tmp = cache->first(); XFreePixmap(basedisplay->getXDisplay(), tmp->pixmap); cache->remove(tmp); delete tmp; } #ifdef TIMEDCACHE if (timer) { timer->stop(); delete timer; } #endif // TIMEDCACHE } delete cache; } Pixmap BImageControl::searchCache(unsigned int width, unsigned int height, unsigned long texture, BColor *c1, BColor *c2) { if (cache->count()) { LinkedListIterator it(cache); for (; it.current(); it++) { if ((it.current()->width == width) && (it.current()->height == height) && (it.current()->texture == texture) && (it.current()->pixel1 == c1->getPixel())) if (texture & BImage_Gradient) { if (it.current()->pixel2 == c2->getPixel()) { it.current()->count++; return it.current()->pixmap; } } else { it.current()->count++; return it.current()->pixmap; } } } return None; } Pixmap BImageControl::renderImage(unsigned int width, unsigned int height, BTexture *texture) { if (texture->getTexture() & BImage_ParentRelative) return ParentRelative; Pixmap pixmap = searchCache(width, height, texture->getTexture(), texture->getColor(), texture->getColorTo()); if (pixmap) return pixmap; BImage image(this, width, height); pixmap = image.render(texture); if (pixmap) { Cache *tmp = new Cache; tmp->pixmap = pixmap; tmp->width = width; tmp->height = height; tmp->count = 1; tmp->texture = texture->getTexture(); tmp->pixel1 = texture->getColor()->getPixel(); if (texture->getTexture() & BImage_Gradient) tmp->pixel2 = texture->getColorTo()->getPixel(); else tmp->pixel2 = 0l; cache->insert(tmp); if ((unsigned) cache->count() > cache_max) { #ifdef DEBUG fprintf(stderr, I18n::instance()-> getMessage( #ifdef NLS ImageSet, ImagePixmapCacheLarge, #else // !NLS 0, 0, #endif // NLS "BImageControl::renderImage: cache is large, " "forcing cleanout\n")); #endif // DEBUG timeout(); } return pixmap; } return None; } void BImageControl::removeImage(Pixmap pixmap) { if (pixmap) { LinkedListIterator it(cache); for (; it.current(); it++) { if (it.current()->pixmap == pixmap) { Cache *tmp = it.current(); if (tmp->count) { tmp->count--; #ifdef TIMEDCACHE if (! timer) timeout(); #else // !TIMEDCACHE if (! tmp->count) timeout(); #endif // TIMEDCACHE } return; } } } } unsigned long BImageControl::getColor(const char *colorname, unsigned char *r, unsigned char *g, unsigned char *b) { XColor color; color.pixel = 0; if (! XParseColor(basedisplay->getXDisplay(), colormap, colorname, &color)) fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n", colorname); else if (! XAllocColor(basedisplay->getXDisplay(), colormap, &color)) fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n", colorname); if (color.red == 65535) *r = 0xff; else *r = (unsigned char) (color.red / 0xff); if (color.green == 65535) *g = 0xff; else *g = (unsigned char) (color.green / 0xff); if (color.blue == 65535) *b = 0xff; else *b = (unsigned char) (color.blue / 0xff); return color.pixel; } unsigned long BImageControl::getColor(const char *colorname) { XColor color; color.pixel = 0; if (! XParseColor(basedisplay->getXDisplay(), colormap, colorname, &color)) fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n", colorname); else { if (! XAllocColor(basedisplay->getXDisplay(), colormap, &color)) fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n", colorname); else fprintf(stderr, "%s(%d) Allocated color:%s", __FILE__, __LINE__, colorname); } return color.pixel; } void BImageControl::getColorTables(unsigned char **rmt, unsigned char **gmt, unsigned char **bmt, int *roff, int *goff, int *boff, int *rbit, int *gbit, int *bbit) { if (rmt) *rmt = red_color_table; if (gmt) *gmt = green_color_table; if (bmt) *bmt = blue_color_table; if (roff) *roff = red_offset; if (goff) *goff = green_offset; if (boff) *boff = blue_offset; if (rbit) *rbit = red_bits; if (gbit) *gbit = green_bits; if (bbit) *bbit = blue_bits; } void BImageControl::getXColorTable(XColor **c, int *n) { if (c) *c = colors; if (n) *n = ncolors; } void BImageControl::getGradientBuffers(unsigned int w, unsigned int h, unsigned int **xbuf, unsigned int **ybuf) { if (w > grad_buffer_width) { if (grad_xbuffer) { delete [] grad_xbuffer; } grad_buffer_width = w; grad_xbuffer = new unsigned int[grad_buffer_width * 3]; } if (h > grad_buffer_height) { if (grad_ybuffer) { delete [] grad_ybuffer; } grad_buffer_height = h; grad_ybuffer = new unsigned int[grad_buffer_height * 3]; } *xbuf = grad_xbuffer; *ybuf = grad_ybuffer; } void BImageControl::installRootColormap(void) { basedisplay->grab(); Bool install = True; int i = 0, ncmap = 0; Colormap *cmaps = XListInstalledColormaps(basedisplay->getXDisplay(), window, &ncmap); if (cmaps) { for (i = 0; i < ncmap; i++) if (*(cmaps + i) == colormap) install = False; if (install) XInstallColormap(basedisplay->getXDisplay(), colormap); XFree(cmaps); } basedisplay->ungrab(); } void BImageControl::setColorsPerChannel(int cpc) { if (cpc < 2) cpc = 2; if (cpc > 6) cpc = 6; colors_per_channel = cpc; } unsigned long BImageControl::getSqrt(unsigned int x) { if (! sqrt_table) { // build sqrt table for use with elliptic gradient sqrt_table = new unsigned long[(256 * 256 * 2) + 1]; int i = 0; for (; i < (256 * 256 * 2); i++) *(sqrt_table + i) = bsqrt(i); } return (*(sqrt_table + x)); } void BImageControl::parseTexture(BTexture *texture, char *t) { if ((! texture) || (! t)) return; int t_len = strlen(t) + 1, i; char *ts = new char[t_len]; if (! ts) return; // convert to lower case for (i = 0; i < t_len; i++) *(ts + i) = tolower(*(t + i)); if (strstr(ts, "parentrelative")) { texture->setTexture(BImage_ParentRelative); } else { texture->setTexture(0); if (strstr(ts, "solid")) texture->addTexture(BImage_Solid); else if (strstr(ts, "gradient")) { texture->addTexture(BImage_Gradient); if (strstr(ts, "crossdiagonal")) texture->addTexture(BImage_CrossDiagonal); else if (strstr(ts, "rectangle")) texture->addTexture(BImage_Rectangle); else if (strstr(ts, "pyramid")) texture->addTexture(BImage_Pyramid); else if (strstr(ts, "pipecross")) texture->addTexture(BImage_PipeCross); else if (strstr(ts, "elliptic")) texture->addTexture(BImage_Elliptic); else if (strstr(ts, "diagonal")) texture->addTexture(BImage_Diagonal); else if (strstr(ts, "horizontal")) texture->addTexture(BImage_Horizontal); else if (strstr(ts, "vertical")) texture->addTexture(BImage_Vertical); else texture->addTexture(BImage_Diagonal); } else texture->addTexture(BImage_Solid); if (strstr(ts, "raised")) texture->addTexture(BImage_Raised); else if (strstr(ts, "sunken")) texture->addTexture(BImage_Sunken); else if (strstr(ts, "flat")) texture->addTexture(BImage_Flat); else texture->addTexture(BImage_Raised); if (! (texture->getTexture() & BImage_Flat)) if (strstr(ts, "bevel2")) texture->addTexture(BImage_Bevel2); else texture->addTexture(BImage_Bevel1); #ifdef INTERLACE if (strstr(ts, "interlaced")) texture->addTexture(BImage_Interlaced); #endif // INTERLACE } delete [] ts; } void BImageControl::parseColor(BColor *color, char *c) { if (! color) return; if (color->isAllocated()) { unsigned long pixel = color->getPixel(); XFreeColors(basedisplay->getXDisplay(), colormap, &pixel, 1, 0); color->setPixel(0l); color->setRGB(0, 0, 0); color->setAllocated(False); } if (c) { unsigned char r, g, b; color->setPixel(getColor(c, &r, &g, &b)); color->setRGB(r, g, b); color->setAllocated(True); } } void BImageControl::timeout(void) { LinkedListIterator it(cache); for (; it.current(); it++) { Cache *tmp = it.current(); if (tmp->count <= 0) { XFreePixmap(basedisplay->getXDisplay(), tmp->pixmap); cache->remove(tmp); delete tmp; } } }