// Image.cc adapted for use in bbtools 03-1999 by John Kennis // // // Original notice: // // Image.cc for Blackbox - an X11 Window manager // Copyright (c) 1997 - 1999 by Brad Hughes, bhughes@tcac.net // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // (See the included file COPYING / GPL-2.0) // #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef HAVE_CONFIG_H # include "../config.h" #endif #include "Basewindow.hh" #include "Image.hh" #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_MALLOC_H # include #else # ifdef STDC_HEADERS # include # endif #endif BImage::BImage(BImageControl *c, unsigned int w, unsigned int h) { control = c; colors = NULL; red = NULL; green = NULL; blue = NULL; tr = NULL; tg = NULL; tb = NULL; from.allocated = 0; to.allocated = 0; 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]; cpc = control->getColorsPerChannel(); cpccpc = cpc * cpc; control->getMaskTables(&tr, &tg, &tb, &roff, &goff, &boff); if (control->getVisual()->c_class != TrueColor) control->getColorTable(&colors, &ncolors); } BImage::~BImage(void) { if (red) delete [] red; if (green) delete [] green; if (blue) delete [] blue; } Pixmap BImage::render(const BTexture *texture) { if (texture->texture & BImage_Solid) { return render_solid(texture); } else if (texture->texture & BImage_Gradient) return render_gradient(texture); return None; } Pixmap BImage::render_solid(const BTexture *texture) { Pixmap pixmap = XCreatePixmap(control->getDisplay(), control->getDrawable(), width, height, control->getDepth()); if (pixmap == None) { fprintf(stderr, "BImage::render_solid: error creating pixmap\n"); return None; } XGCValues gcv; GC gc, hgc, lgc; gcv.foreground = texture->color.pixel; gcv.fill_style = FillSolid; gc = XCreateGC(control->getDisplay(), pixmap, GCForeground | GCFillStyle, &gcv); gcv.foreground = texture->hiColor.pixel; hgc = XCreateGC(control->getDisplay(), pixmap, GCForeground, &gcv); gcv.foreground = texture->loColor.pixel; lgc = XCreateGC(control->getDisplay(), pixmap, GCForeground, &gcv); XFillRectangle(control->getDisplay(), pixmap, gc, 0, 0, width, height); if (texture->texture & BImage_Bevel1) { if (texture->texture & BImage_Raised) { XDrawLine(control->getDisplay(), pixmap, lgc, 0, height - 1, width - 1, height - 1); XDrawLine(control->getDisplay(), pixmap, lgc, width - 1, height - 1, width - 1, 0); XDrawLine(control->getDisplay(), pixmap, hgc, 0, 0, width - 1, 0); XDrawLine(control->getDisplay(), pixmap, hgc, 0, height - 1, 0, 0); } else if (texture->texture & BImage_Sunken) { XDrawLine(control->getDisplay(), pixmap, hgc, 0, height - 1, width - 1, height - 1); XDrawLine(control->getDisplay(), pixmap, hgc, width - 1, height - 1, width - 1, 0); XDrawLine(control->getDisplay(), pixmap, lgc, 0, 0, width - 1, 0); XDrawLine(control->getDisplay(), pixmap, lgc, 0, height - 1, 0, 0); } } else if (texture->texture & BImage_Bevel2) { if (texture->texture & BImage_Raised) { XDrawLine(control->getDisplay(), pixmap, lgc, 1, height - 3, width - 3, height - 3); XDrawLine(control->getDisplay(), pixmap, lgc, width - 3, height - 3, width - 3, 1); XDrawLine(control->getDisplay(), pixmap, hgc, 1, 1, width - 3, 1); XDrawLine(control->getDisplay(), pixmap, hgc, 1, height - 3, 1, 1); } else if (texture->texture & BImage_Sunken) { XDrawLine(control->getDisplay(), pixmap, hgc, 1, height - 3, width - 3, height - 3); XDrawLine(control->getDisplay(), pixmap, hgc, width - 3, height - 3, width - 3, 1); XDrawLine(control->getDisplay(), pixmap, lgc, 1, 1, width - 3, 1); XDrawLine(control->getDisplay(), pixmap, lgc, 1, height - 3, 1, 1); } } XFreeGC(control->getDisplay(), gc); XFreeGC(control->getDisplay(), hgc); XFreeGC(control->getDisplay(), lgc); return pixmap; } Pixmap BImage::render_gradient(const BTexture *texture) { int inverted = 0; if (texture->texture & BImage_Sunken) { from = texture->colorTo; to = texture->color; if (! (texture->texture & BImage_Invert)) inverted = 1; } else { from = texture->color; to = texture->colorTo; if (texture>texture & BImage_Invert) inverted = 1; } if (texture->texture & BImage_Diagonal) dgradient(); else if (texture->texture & BImage_Horizontal) hgradient(); else if (texture->texture & BImage_Vertical) vgradient(); if (texture->texture & BImage_Bevel1) bevel1(); else if (texture->texture & BImage_Bevel2) bevel2(); if (inverted) invert(); return renderPixmap(); } XImage *BImage::renderXImage(void) { XImage *image = XCreateImage(control->getDisplay(), control->getVisual(), control->getDepth(), ZPixmap, 0, 0, width, height, 32, 0); if (! image) { fprintf(stderr, "BImage::renderXImage: error creating XImage\n"); return 0; } unsigned char *d = (unsigned char *) malloc(image->bytes_per_line * height); if (! d) { fprintf(stderr, "BImage::renderXImage: error allocating memory for image\n"); XDestroyImage(image); return 0; } register unsigned int x, y, r = 0, g = 0, b = 0, i, off; unsigned char *idata = d, *pd = d, *pr, *pg, *pb; unsigned long pixel; if ((! tr) || (! tg) || (! tb)) { fprintf(stderr, "BImage::renderXImage: error getting color mask tables\n"); XDestroyImage(image); return 0; } if (control->getVisual()->c_class != TrueColor) if ((! colors) || (! ncolors)) { fprintf(stderr, "BImage::renderXImage: error getting pseudo color tables\n"); XDestroyImage(image); return 0; } if (control->doDither()) { short er, eg, eb, *bbor, *og, *ob, *nor, *nog, *nob, *por, *pog, *pob; unsigned short *ort, *ogt, *obt; control->getDitherBuffers(width + 2, &bbor, &og, &ob, &nor, &nog, &nob, &ort, &ogt, &obt); if ((! bbor) || (! og) || (! ob) || (! nor) || (! nog) || (! nob) || (! ort) || (! ogt) || (! obt)) { fprintf(stderr, "BImage::renderXImage: error getting dither information\n"); XDestroyImage(image); return 0; } x = width; por = bbor; pog = og; pob = ob; pr = red; pg = green; pb = blue; while (x--) { *(por++) = *(pr++); *(pog++) = *(pg++); *(pob++) = *(pb++); } *por = *pog = *pob = 0; for (y = 0, off = 0; y < height; y++) { if (y < (height - 1)) { for (x = 0, i = off + width; x < width; x++, i++) { *(nor + x) = *(red + i); *(nog + x) = *(green + i); *(nob + x) = *(blue + i); } i--; *(nor + x) = *(red + i); *(nog + x) = *(green + i); *(nob + x) = *(blue + i); } for (x = 0; x < width; x++) { if (*(bbor + x) > 255) *(bbor + x) = 255; else if (*(bbor + x) < 0) *(bbor + x) = 0; if (*(og + x) > 255) *(og + x) = 255; else if (*(og + x) < 0) *(og + x) = 0; if (*(ob + x) > 255) *(ob + x) = 255; else if (*(ob + x) < 0) *(ob + x) = 0; r = *(tr + *(bbor + x)); g = *(tg + *(og + x)); b = *(tb + *(ob + x)); switch (control->getVisual()->c_class) { case StaticColor: case PseudoColor: pixel = (r * cpccpc) + (g * cpc) + b; *idata++ = colors[pixel].pixel; break; case TrueColor: pixel = (r << roff) | (g << goff) | (b << boff); switch (image->byte_order) { case MSBFirst: { switch (image->bits_per_pixel) { case 32: *(idata++) = (pixel >> 24); case 24: *(idata++) = (pixel >> 16); case 16: *(idata++) = (pixel >> 8); default: *(idata++) = (pixel); } break; } case LSBFirst: { *(idata++) = pixel; switch (image->bits_per_pixel) { case 32: *(idata++) = (pixel >> 8); *(idata++) = (pixel >> 16); *(idata++) = (pixel >> 24); break; case 24: *(idata++) = (pixel >> 8); *(idata++) = (pixel >> 16); break; case 16: *(idata++) = (pixel >> 8); break; } break; } } break; default: fprintf(stderr, "BImage::renderXImage: unsupported visual\n"); image->data = (char *) d; XDestroyImage(image); return 0; } er = *(bbor + x) - *(ort + *(bbor + x)); eg = *(og + x) - *(ogt + *(og + x)); eb = *(ob + x) - *(obt + *(ob + x)); *(bbor + x + 1) += er; *(og + x + 1) += eg; *(ob + x + 1) += eb; *(nor + x) += er; *(nog + x) += eg; *(nob + x) += eb; *(nor + x + 1) -= (er >> 1) + (er >> 2); *(nog + x + 1) -= (eg >> 1) + (eg >> 2); *(nob + x + 1) -= (eb >> 1) + (eb >> 2); } off += image->width; idata = (pd += image->bytes_per_line); por = bbor; bbor = nor; nor = por; pog = og; og = nog; nog = pog; pob = ob; ob = nob; nob = pob; } } else { for (y = 0, off = 0; y < height; y++) { for (x = 0; x < width; x++, off++) { r = *(tr + *(red + off)); g = *(tg + *(green + off)); b = *(tb + *(blue + off)); switch (control->getVisual()->c_class) { case StaticColor: case PseudoColor: pixel = (r * cpccpc) + (g * cpc) + b; *idata++ = colors[pixel].pixel; break; case TrueColor: pixel = (r << roff) | (g << goff) | (b << boff); switch (image->byte_order) { case MSBFirst: { switch (image->bits_per_pixel) { case 32: *(idata++) = (pixel >> 24); case 24: *(idata++) = (pixel >> 16); case 16: *(idata++) = (pixel >> 8); default: *(idata++) = (pixel); } break; } case LSBFirst: { *(idata++) = pixel; switch (image->bits_per_pixel) { case 32: *(idata++) = (pixel >> 8); *(idata++) = (pixel >> 16); *(idata++) = (pixel >> 24); break; case 24: *(idata++) = (pixel >> 8); *(idata++) = (pixel >> 16); break; case 16: *(idata++) = (pixel >> 8); break; } break; } } break; default: fprintf(stderr, "BImage::renderXImage: unsupported visual\n"); image->data = (char *) d; XDestroyImage(image); return 0; } } idata = (pd += image->bytes_per_line); } } image->data = (char *) d; return image; } Pixmap BImage::renderPixmap(void) { Pixmap pixmap = XCreatePixmap(control->getDisplay(), control->getDrawable(), width, height, control->getDepth()); if (pixmap == None) { fprintf(stderr, "BImage::renderPixmap: error creating pixmap\n"); return None; } XImage *image = renderXImage(); if (! image) { XFreePixmap(control->getDisplay(), pixmap); return None; } XPutImage(control->getDisplay(), pixmap, DefaultGC(control->getDisplay(), control->getScreenNumber()), image, 0, 0, 0, 0, width, height); 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) { float fr = (float) from.red, fg = (float) from.green, fb = (float) from.blue, tr = (float) to.red, tg = (float) to.green, tb = (float) to.blue, w = (float) (width * 2), h = (float) (height * 2), yr = 0.0, yg = 0.0, yb = 0.0, xr, xg, xb, drx, dgx, dbx, dry, dgy, dby; unsigned char *pr = red, *pg = green, *pb = blue; register unsigned int x, y; drx = dry = (tr - fr); dgx = dgy = (tg - fg); dbx = dby = (tb - fb); drx /= w; dgx /= w; dbx /= w; dry /= h; dgy /= h; dby /= h; for (y = 0; y < height; y++) { xr = fr + yr; xg = fg + yg; xb = fb + yb; for (x = 0; x < width; x++) { *(pr++) = (unsigned char) (xr); *(pg++) = (unsigned char) (xg); *(pb++) = (unsigned char) (xb); xr += drx; xg += dgx; xb += dbx; } yr += dry; yg += dgy; yb += dby; } } void BImage::hgradient(void) { float fr, fg, fb, tr, tg, tb, drx, dgx, dbx, xr, xg, xb, w = (float) width; unsigned char *pr, *pg, *pb, *rr, *gg, *bb; register unsigned int x, y; xr = fr = (float) from.red; xg = fg = (float) from.green; xb = fb = (float) from.blue; tr = (float) to.red; tg = (float) to.green; tb = (float) to.blue; drx = (tr - fr) / w; dgx = (tg - fg) / w; dbx = (tb - fb) / w; pr = red; pg = green; pb = blue; // this renders one line of the 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; } // and this copies to the rest of the image for (y = 1; y < height; y++) { rr = red; gg = green; bb = blue; for (x = 0; x < width; x++) { *(pr++) = *(rr++); *(pg++) = *(gg++); *(pb++) = *(bb++); } } } void BImage::vgradient(void) { float fr, fg, fb, tr, tg, tb, dry, dgy, dby, yr, yg, yb, h = (float) height; unsigned char *pr = red, *pg = green, *pb = blue; register unsigned char r, g, b; register unsigned int x, y; yr = fr = (float) from.red; yg = fg = (float) from.green; yb = fb = (float) from.blue; tr = (float) to.red; tg = (float) to.green; tb = (float) to.blue; dry = (tr - fr) / h; dgy = (tg - fg) / h; dby = (tb - fb) / h; for (y = 0; y < height; y++) { yr += dry; yg += dgy; yb += dby; r = (unsigned char) (yr); g = (unsigned char) (yg); b = (unsigned char) (yb); for (x = 0; x < width; x++) { *(pr++) = r; *(pg++) = g; *(pb++) = b; } } } BImageControl::BImageControl(Basewindow *bb) { blackbox = bb; display = blackbox->getDisplay(); screen_depth = blackbox->getDepth(); window = blackbox->getRootWindow(); screen_number = blackbox->getScreenNumber(); colors = NULL; red_err = NULL; green_err = NULL; blue_err = NULL; next_red_err = NULL; next_green_err = NULL; next_blue_err = NULL; cache = NULL; colors_per_channel = ncolors = 0; int count; XPixmapFormatValues *pmv = XListPixmapFormats(display, &count); root_colormap = DefaultColormap(display, screen_number); 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; } } if (bits_per_pixel == 0) bits_per_pixel = screen_depth; if (pmv) XFree(pmv); red_offset = green_offset = blue_offset = 0; switch (blackbox->getVisual()->c_class) { case TrueColor: { int i; // compute tables for red channel unsigned long mask = blackbox->getVisual()->red_mask, emask = mask; while (! (mask & 1)) { red_offset++; mask >>= 1; } for (i = 0; i < 256; i++) { rmask_table[i] = (i * mask + 0x7f) / 0xff; rerr_table[i] = ((rmask_table[i] << 8) / (emask >> red_offset)); } // compute tables for green channel emask = mask = blackbox->getVisual()->green_mask; while (! (mask & 1)) { green_offset++; mask >>= 1; } for (i = 0; i < 256; i++) { gmask_table[i] = (i * mask + 0x7f) / 0xff; gerr_table[i] = ((gmask_table[i] << 8) / (emask >> green_offset)); } // compute tables for blue channel emask = mask = blackbox->getVisual()->blue_mask; while (! (mask & 1)) { blue_offset++; mask >>= 1; } for (i = 0; i < 256; i++) { bmask_table[i] = (i * mask + 0x7f) / 0xff; berr_table[i] = ((bmask_table[i] << 8) / (emask >> blue_offset)); } } break; case PseudoColor: case StaticColor: { colors_per_channel = blackbox->getColorsPerChannel(); 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, "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, "BImageControl::BImageControl: error allocating " "colormap\n"); exit(1); } int i = 0, ii, p, r, g, b; unsigned long mask = colors_per_channel - 1; for (i = 0; i < 256; i++) { rmask_table[i] = gmask_table[i] = bmask_table[i] = (i * mask + 0x7f) / 0xff; rerr_table[i] = gerr_table[i] = berr_table[i] = ((rmask_table[i] << 8) / (mask)); } 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; } blackbox->grab(); for (i = 0; i < ncolors; i++) if (! XAllocColor(display, root_colormap, &colors[i])) { fprintf(stderr, "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; blackbox->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(display, root_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(display, root_colormap, &colors[i])) { colors[i].flags = DoRed|DoGreen|DoBlue; break; } } } } } break; } case GrayScale: case StaticGray: fprintf(stderr, "BImageControl::BImageControl: GrayScale/StaticGray " "visual unsupported\n"); break; default: fprintf(stderr, "BImageControl::BImageControl: unsupported visual %d\n", blackbox->getVisual()->c_class); exit(1); } cache = new LinkedList; dither_buf_width = 0; red_err = green_err = blue_err = next_red_err = next_green_err = next_blue_err = 0; } BImageControl::~BImageControl(void) { if (red_err) delete [] red_err; if (green_err) delete [] green_err; if (blue_err) delete [] blue_err; if (next_red_err) delete [] next_red_err; if (next_green_err) delete [] next_green_err; if (next_blue_err) delete [] next_blue_err; if (colors) { unsigned long *pixels = new unsigned long [ncolors]; int i; for (i = 0; i < ncolors; i++) *(pixels + i) = (*(colors + i)).pixel; XFreeColors(display, DefaultColormap(display, screen_number), pixels, ncolors, 0); delete [] colors; } if (cache->count()) { int i, n = cache->count(); fprintf(stderr, "BImageContol::~BImageControl: pixmap cache - " "releasing %d pixmaps\n", n); for (i = 0; i < n; i++) { Cache *tmp = cache->first(); XFreePixmap(display, tmp->pixmap); cache->remove(tmp); delete tmp; } } delete cache; } Bool BImageControl::doDither(void) { return blackbox->hasImageDither(); } Visual *BImageControl::getVisual(void) { return blackbox->getVisual(); } Pixmap BImageControl::searchCache(unsigned int width, unsigned int height, unsigned long texture, const BColor &c1, const 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.pixel)) if (texture & BImage_Gradient) { if (it.current()->pixel2 == c2.pixel) { 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, const BTexture *texture) { Pixmap pixmap = searchCache(width, height, texture->texture, texture->color, texture->colorTo); 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->texture; tmp->pixel1 = texture->color.pixel; if (texture->texture & BImage_Gradient) tmp->pixel2 = texture->colorTo.pixel; else tmp->pixel2 = 0l; cache->insert(tmp); 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(); tmp->count--; if (! tmp->count) { XFreePixmap(display, tmp->pixmap); cache->remove(tmp); delete tmp; } return; } } } } unsigned long BImageControl::getColor(const char *colorname, unsigned char *r, unsigned char *g, unsigned char *b) { XColor color; color.pixel = 0; if (! XParseColor(display, DefaultColormap(display, screen_number), colorname, &color)) { fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n", colorname); } else if (! XAllocColor(display, DefaultColormap(display, screen_number), &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(display, DefaultColormap(display, screen_number), colorname, &color)) { fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n", colorname); } else if (! XAllocColor(display, DefaultColormap(display, screen_number), &color)) { fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n", colorname); } return color.pixel; } void BImageControl::getMaskTables(unsigned short **rmt, unsigned short **gmt, unsigned short **bmt, int *roff, int *goff, int *boff) { if (rmt) *rmt = rmask_table; if (gmt) *gmt = gmask_table; if (bmt) *bmt = bmask_table; if (roff) *roff = red_offset; if (goff) *goff = green_offset; if (boff) *boff = blue_offset; } void BImageControl::getColorTable(XColor **c, int *n) { if (c) *c = colors; if (n) *n = ncolors; } void BImageControl::getDitherBuffers(unsigned int w, short **r, short **g, short **b, short **nr, short **ng, short **nb, unsigned short **ret, unsigned short **get, unsigned short **bet) { if (w > dither_buf_width) { if (red_err) delete [] red_err; if (green_err) delete [] green_err; if (blue_err) delete [] blue_err; if (next_red_err) delete [] next_red_err; if (next_green_err) delete [] next_green_err; if (next_blue_err) delete [] next_blue_err; dither_buf_width = w; red_err = new short[dither_buf_width]; green_err = new short[dither_buf_width]; blue_err = new short[dither_buf_width]; next_red_err = new short[dither_buf_width]; next_green_err = new short[dither_buf_width]; next_blue_err = new short[dither_buf_width]; } *r = red_err; *g = green_err; *b = blue_err; *nr = next_red_err; *ng = next_green_err; *nb = next_blue_err; *ret = rerr_table; *get = gerr_table; *bet = berr_table; } void BImageControl::installRootColormap(void) { blackbox->grab(); Bool install = True; int i = 0, ncmap = 0; Colormap *cmaps = XListInstalledColormaps(display, window, &ncmap); if (cmaps) { for (i = 0; i < ncmap; i++) if (*(cmaps + i) == root_colormap) install = False; if (install) XInstallColormap(display, root_colormap); XFree(cmaps); } blackbox->ungrab(); }