]> icculus.org git repositories - dana/openbox.git/blob - src/Image.cc
sync with bb-cvs
[dana/openbox.git] / src / Image.cc
1 // -*- mode: C++; indent-tabs-mode: nil; -*-
2 // Image.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef    HAVE_CONFIG_H
25 #  include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 #ifdef    HAVE_STDIO_H
29 #  include <stdio.h>
30 #endif // HAVE_STDIO_H
31
32 #include <algorithm>
33 using std::max;
34 using std::min;
35
36 #include "blackbox.hh"
37 #include "i18n.hh"
38 #include "BaseDisplay.hh"
39 #include "GCCache.hh"
40 #include "Image.hh"
41 #include "Texture.hh"
42
43
44 BImage::BImage(BImageControl *c, int w, int h) {
45   control = c;
46
47   width = (w > 0) ? w : 1;
48   height = (h > 0) ? h : 1;
49
50   red = new unsigned char[width * height];
51   green = new unsigned char[width * height];
52   blue = new unsigned char[width * height];
53
54   xtable = ytable = (unsigned int *) 0;
55
56   cpc = control->getColorsPerChannel();
57   cpccpc = cpc * cpc;
58
59   control->getColorTables(&red_table, &green_table, &blue_table,
60                           &red_offset, &green_offset, &blue_offset,
61                           &red_bits, &green_bits, &blue_bits);
62
63   if (control->getVisual()->c_class != TrueColor)
64     control->getXColorTable(&colors, &ncolors);
65 }
66
67
68 BImage::~BImage(void) {
69   delete [] red;
70   delete [] green;
71   delete [] blue;
72 }
73
74
75 Pixmap BImage::render(const BTexture &texture) {
76   if (texture.texture() & BTexture::Parent_Relative)
77     return ParentRelative;
78   else if (texture.texture() & BTexture::Solid)
79     return render_solid(texture);
80   else if (texture.texture() & BTexture::Gradient)
81     return render_gradient(texture);
82   return None;
83 }
84
85
86 Pixmap BImage::render_solid(const BTexture &texture) {
87   Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(),
88                                 control->getDrawable(), width,
89                                 height, control->getDepth());
90   if (pixmap == None) {
91     fprintf(stderr, i18n(ImageSet, ImageErrorCreatingSolidPixmap,
92                          "BImage::render_solid: error creating pixmap\n"));
93     return None;
94   }
95
96   Display *display = control->getBaseDisplay()->getXDisplay();
97
98   BPen pen(texture.color());
99   BPen penlight(texture.lightColor());
100   BPen penshadow(texture.shadowColor());
101
102   XFillRectangle(display, pixmap, pen.gc(), 0, 0, width, height);
103
104   if (texture.texture() & BTexture::Interlaced) {
105     BPen peninterlace(texture.colorTo());
106     for (unsigned int i = 0; i < height; i += 2)
107       XDrawLine(display, pixmap, peninterlace.gc(), 0, i, width, i);
108   }
109
110   if (texture.texture() & BTexture::Bevel1) {
111     if (texture.texture() & BTexture::Raised) {
112       XDrawLine(display, pixmap, penshadow.gc(),
113                 0, height - 1, width - 1, height - 1);
114       XDrawLine(display, pixmap, penshadow.gc(),
115                 width - 1, height - 1, width - 1, 0);
116
117       XDrawLine(display, pixmap, penlight.gc(),
118                 0, 0, width - 1, 0);
119       XDrawLine(display, pixmap, penlight.gc(),
120                 0, height - 1, 0, 0);
121     } else if (texture.texture() & BTexture::Sunken) {
122       XDrawLine(display, pixmap, penlight.gc(),
123                 0, height - 1, width - 1, height - 1);
124       XDrawLine(display, pixmap, penlight.gc(),
125                 width - 1, height - 1, width - 1, 0);
126
127       XDrawLine(display, pixmap, penshadow.gc(),
128                 0, 0, width - 1, 0);
129       XDrawLine(display, pixmap, penshadow.gc(),
130                 0, height - 1, 0, 0);
131     }
132   } else if (texture.texture() & BTexture::Bevel2) {
133     if (texture.texture() & BTexture::Raised) {
134       XDrawLine(display, pixmap, penshadow.gc(),
135                 1, height - 3, width - 3, height - 3);
136       XDrawLine(display, pixmap, penshadow.gc(),
137                 width - 3, height - 3, width - 3, 1);
138
139       XDrawLine(display, pixmap, penlight.gc(),
140                 1, 1, width - 3, 1);
141       XDrawLine(display, pixmap, penlight.gc(),
142                 1, height - 3, 1, 1);
143     } else if (texture.texture() & BTexture::Sunken) {
144       XDrawLine(display, pixmap, penlight.gc(),
145                 1, height - 3, width - 3, height - 3);
146       XDrawLine(display, pixmap, penlight.gc(),
147                 width - 3, height - 3, width - 3, 1);
148
149       XDrawLine(display, pixmap, penshadow.gc(),
150                 1, 1, width - 3, 1);
151       XDrawLine(display, pixmap, penshadow.gc(),
152                 1, height - 3, 1, 1);
153     }
154   }
155
156   return pixmap;
157 }
158
159
160 Pixmap BImage::render_gradient(const BTexture &texture) {
161   bool inverted = False;
162
163   interlaced = texture.texture() & BTexture::Interlaced;
164
165   if (texture.texture() & BTexture::Sunken) {
166     from = texture.colorTo();
167     to = texture.color();
168
169     if (! (texture.texture() & BTexture::Invert)) inverted = True;
170   } else {
171     from = texture.color();
172     to = texture.colorTo();
173
174     if (texture.texture() & BTexture::Invert) inverted = True;
175   }
176
177   control->getGradientBuffers(width, height, &xtable, &ytable);
178
179   if (texture.texture() & BTexture::Diagonal) dgradient();
180   else if (texture.texture() & BTexture::Elliptic) egradient();
181   else if (texture.texture() & BTexture::Horizontal) hgradient();
182   else if (texture.texture() & BTexture::Pyramid) pgradient();
183   else if (texture.texture() & BTexture::Rectangle) rgradient();
184   else if (texture.texture() & BTexture::Vertical) vgradient();
185   else if (texture.texture() & BTexture::CrossDiagonal) cdgradient();
186   else if (texture.texture() & BTexture::PipeCross) pcgradient();
187
188   if (texture.texture() & BTexture::Bevel1) bevel1();
189   else if (texture.texture() & BTexture::Bevel2) bevel2();
190
191   if (inverted) invert();
192
193   return renderPixmap();
194
195 }
196
197
198 static const unsigned char dither4[4][4] = {
199   {0, 4, 1, 5},
200   {6, 2, 7, 3},
201   {1, 5, 0, 4},
202   {7, 3, 6, 2}
203 };
204
205
206 /*
207  * Helper function for TrueColorDither and renderXImage
208  *
209  * This handles the proper setting of the image data based on the image depth
210  * and the machine's byte ordering
211  */
212 static inline
213 void assignPixelData(unsigned int bit_depth, unsigned char **data,
214                      unsigned long pixel) {
215   unsigned char *pixel_data = *data;
216   switch (bit_depth) {
217   case  8: //  8bpp
218     *pixel_data++ = pixel;
219     break;
220
221   case 16: // 16bpp LSB
222     *pixel_data++ = pixel;
223     *pixel_data++ = pixel >> 8;
224     break;
225
226   case 17: // 16bpp MSB
227     *pixel_data++ = pixel >> 8;
228     *pixel_data++ = pixel;
229     break;
230
231   case 24: // 24bpp LSB
232     *pixel_data++ = pixel;
233     *pixel_data++ = pixel >> 8;
234     *pixel_data++ = pixel >> 16;
235     break;
236
237   case 25: // 24bpp MSB
238     *pixel_data++ = pixel >> 16;
239     *pixel_data++ = pixel >> 8;
240     *pixel_data++ = pixel;
241     break;
242
243   case 32: // 32bpp LSB
244     *pixel_data++ = pixel;
245     *pixel_data++ = pixel >> 8;
246     *pixel_data++ = pixel >> 16;
247     *pixel_data++ = pixel >> 24;
248     break;
249
250   case 33: // 32bpp MSB
251     *pixel_data++ = pixel >> 24;
252     *pixel_data++ = pixel >> 16;
253     *pixel_data++ = pixel >> 8;
254     *pixel_data++ = pixel;
255     break;
256   }
257   *data = pixel_data; // assign back so we don't lose our place
258 }
259
260
261 // algorithm: ordered dithering... many many thanks to rasterman
262 // (raster@rasterman.com) for telling me about this... portions of this
263 // code is based off of his code in Imlib
264 void BImage::TrueColorDither(unsigned int bit_depth, int bytes_per_line,
265                              unsigned char *pixel_data) {
266   unsigned int x, y, dithx, dithy, r, g, b, er, eg, eb, offset;
267   unsigned char *ppixel_data = pixel_data;
268   unsigned long pixel;
269
270   for (y = 0, offset = 0; y < height; y++) {
271     dithy = y & 0x3;
272
273     for (x = 0; x < width; x++, offset++) {
274       dithx = x & 0x3;
275       r = red[offset];
276       g = green[offset];
277       b = blue[offset];
278
279       er = r & (red_bits - 1);
280       eg = g & (green_bits - 1);
281       eb = b & (blue_bits - 1);
282
283       r = red_table[r];
284       g = green_table[g];
285       b = blue_table[b];
286
287       if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++;
288       if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++;
289       if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++;
290
291       pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
292       assignPixelData(bit_depth, &pixel_data, pixel);
293     }
294
295     pixel_data = (ppixel_data += bytes_per_line);
296   }
297 }
298
299 #ifdef ORDEREDPSEUDO
300 const static unsigned char dither8[8][8] = {
301   { 0,  32, 8,  40, 2,  34, 10, 42},
302   { 48, 16, 56, 24, 50, 18, 58, 26},
303   { 12, 44, 4,  36, 14, 46, 6,  38},
304   { 60, 28, 52, 20, 62, 30, 54, 22},
305   { 3,  35, 11, 43, 1,  33, 9,  41},
306   { 51, 19, 59, 27, 49, 17, 57, 25},
307   { 15, 47, 7,  39, 13, 45, 5,  37},
308   { 63, 31, 55, 23, 61, 29, 53, 21}
309 };
310
311 void BImage::OrderedPseudoColorDither(int bytes_per_line,
312                                       unsigned char *pixel_data) {
313   unsigned int x, y, dithx, dithy, r, g, b, er, eg, eb, offset;
314   unsigned long pixel;
315   unsigned char *ppixel_data = pixel_data;
316
317   for (y = 0, offset = 0; y < height; y++) {
318     dithy = y & 7;
319
320     for (x = 0; x < width; x++, offset++) {
321       dithx = x & 7;
322
323       r = red[offset];
324       g = green[offset];
325       b = blue[offset];
326
327       er = r & (red_bits - 1);
328       eg = g & (green_bits - 1);
329       eb = b & (blue_bits - 1);
330
331       r = red_table[r];
332       g = green_table[g];
333       b = blue_table[b];
334
335       if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++;
336       if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++;
337       if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++;
338
339       pixel = (r * cpccpc) + (g * cpc) + b;
340       *(pixel_data++) = colors[pixel].pixel;
341     }
342
343     pixel_data = (ppixel_data += bytes_per_line);
344   }
345 }
346 #endif
347
348 void BImage::PseudoColorDither(int bytes_per_line, unsigned char *pixel_data) {
349   short *terr,
350     *rerr = new short[width + 2],
351     *gerr = new short[width + 2],
352     *berr = new short[width + 2],
353     *nrerr = new short[width + 2],
354     *ngerr = new short[width + 2],
355     *nberr = new short[width + 2];
356
357   int rr, gg, bb, rer, ger, ber;
358   int dd = 255 / control->getColorsPerChannel();
359   unsigned int x, y, r, g, b, offset;
360   unsigned long pixel;
361   unsigned char *ppixel_data = pixel_data;
362
363   for (x = 0; x < width; x++) {
364     *(rerr + x) = *(red + x);
365     *(gerr + x) = *(green + x);
366     *(berr + x) = *(blue + x);
367   }
368
369   *(rerr + x) = *(gerr + x) = *(berr + x) = 0;
370
371   for (y = 0, offset = 0; y < height; y++) {
372     if (y < (height - 1)) {
373       int i = offset + width;
374       for (x = 0; x < width; x++, i++) {
375         *(nrerr + x) = *(red + i);
376         *(ngerr + x) = *(green + i);
377         *(nberr + x) = *(blue + i);
378       }
379
380       *(nrerr + x) = *(red + (--i));
381       *(ngerr + x) = *(green + i);
382       *(nberr + x) = *(blue + i);
383     }
384
385     for (x = 0; x < width; x++) {
386       rr = rerr[x];
387       gg = gerr[x];
388       bb = berr[x];
389
390       if (rr > 255) rr = 255; else if (rr < 0) rr = 0;
391       if (gg > 255) gg = 255; else if (gg < 0) gg = 0;
392       if (bb > 255) bb = 255; else if (bb < 0) bb = 0;
393
394       r = red_table[rr];
395       g = green_table[gg];
396       b = blue_table[bb];
397
398       rer = rerr[x] - r*dd;
399       ger = gerr[x] - g*dd;
400       ber = berr[x] - b*dd;
401
402       pixel = (r * cpccpc) + (g * cpc) + b;
403       *pixel_data++ = colors[pixel].pixel;
404
405       r = rer >> 1;
406       g = ger >> 1;
407       b = ber >> 1;
408       rerr[x+1] += r;
409       gerr[x+1] += g;
410       berr[x+1] += b;
411       nrerr[x] += r;
412       ngerr[x] += g;
413       nberr[x] += b;
414     }
415
416     offset += width;
417
418     pixel_data = (ppixel_data += bytes_per_line);
419
420     terr = rerr;
421     rerr = nrerr;
422     nrerr = terr;
423
424     terr = gerr;
425     gerr = ngerr;
426     ngerr = terr;
427
428     terr = berr;
429     berr = nberr;
430     nberr = terr;
431   }
432
433   delete [] rerr;
434   delete [] gerr;
435   delete [] berr;
436   delete [] nrerr;
437   delete [] ngerr;
438   delete [] nberr;
439 }
440
441 XImage *BImage::renderXImage(void) {
442   XImage *image =
443     XCreateImage(control->getBaseDisplay()->getXDisplay(),
444                  control->getVisual(), control->getDepth(), ZPixmap, 0, 0,
445                  width, height, 32, 0);
446
447   if (! image) {
448     fprintf(stderr, i18n(ImageSet, ImageErrorCreatingXImage,
449                          "BImage::renderXImage: error creating XImage\n"));
450     return (XImage *) 0;
451   }
452
453   // insurance policy
454   image->data = (char *) 0;
455
456   unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)];
457
458   unsigned int o = image->bits_per_pixel +
459     ((image->byte_order == MSBFirst) ? 1 : 0);
460
461   bool unsupported = False;
462
463   if (control->doDither() && width > 1 && height > 1) {
464     switch (control->getVisual()->c_class) {
465     case TrueColor:
466       TrueColorDither(o, image->bytes_per_line, d);
467       break;
468
469     case StaticColor:
470     case PseudoColor: {
471 #ifdef ORDEREDPSEUDO
472       OrderedPseudoColorDither(image->bytes_per_line, d);
473 #else
474       PseudoColorDither(image->bytes_per_line, d);
475 #endif
476       break;
477     }
478
479     default:
480       unsupported = True;
481     }
482   } else {
483     unsigned int x, y, r, g, b, offset;
484     unsigned char *pixel_data = d, *ppixel_data = d;
485     unsigned long pixel;
486
487     switch (control->getVisual()->c_class) {
488     case StaticColor:
489     case PseudoColor:
490       for (y = 0, offset = 0; y < height; ++y) {
491         for (x = 0; x < width; ++x, ++offset) {
492           r = red_table[red[offset]];
493           g = green_table[green[offset]];
494           b = blue_table[blue[offset]];
495
496           pixel = (r * cpccpc) + (g * cpc) + b;
497           *pixel_data++ = colors[pixel].pixel;
498         }
499
500         pixel_data = (ppixel_data += image->bytes_per_line);
501       }
502
503       break;
504
505     case TrueColor:
506       for (y = 0, offset = 0; y < height; y++) {
507         for (x = 0; x < width; x++, offset++) {
508           r = red_table[red[offset]];
509           g = green_table[green[offset]];
510           b = blue_table[blue[offset]];
511
512           pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
513           assignPixelData(o, &pixel_data, pixel);
514         }
515
516         pixel_data = (ppixel_data += image->bytes_per_line);
517       }
518
519       break;
520
521     case StaticGray:
522     case GrayScale:
523       for (y = 0, offset = 0; y < height; y++) {
524         for (x = 0; x < width; x++, offset++) {
525           r = *(red_table + *(red + offset));
526           g = *(green_table + *(green + offset));
527           b = *(blue_table + *(blue + offset));
528
529           g = ((r * 30) + (g * 59) + (b * 11)) / 100;
530           *pixel_data++ = colors[g].pixel;
531         }
532
533         pixel_data = (ppixel_data += image->bytes_per_line);
534       }
535
536       break;
537
538     default:
539       unsupported = True;
540     }
541   }
542
543   if (unsupported) {
544     fprintf(stderr, i18n(ImageSet, ImageUnsupVisual,
545                          "BImage::renderXImage: unsupported visual\n"));
546     delete [] d;
547     XDestroyImage(image);
548     return (XImage *) 0;
549   }
550
551   image->data = (char *) d;
552
553   return image;
554 }
555
556
557 Pixmap BImage::renderPixmap(void) {
558   Pixmap pixmap =
559     XCreatePixmap(control->getBaseDisplay()->getXDisplay(),
560                   control->getDrawable(), width, height, control->getDepth());
561
562   if (pixmap == None) {
563     fprintf(stderr, i18n(ImageSet, ImageErrorCreatingPixmap,
564                          "BImage::renderPixmap: error creating pixmap\n"));
565     return None;
566   }
567
568   XImage *image = renderXImage();
569
570   if (! image) {
571     XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap);
572     return None;
573   }
574
575   if (! image->data) {
576     XDestroyImage(image);
577     XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap);
578     return None;
579   }
580
581   XPutImage(control->getBaseDisplay()->getXDisplay(), pixmap,
582             DefaultGC(control->getBaseDisplay()->getXDisplay(),
583                       control->getScreenInfo()->getScreenNumber()),
584             image, 0, 0, 0, 0, width, height);
585
586   if (image->data) {
587     delete [] image->data;
588     image->data = NULL;
589   }
590
591   XDestroyImage(image);
592
593   return pixmap;
594 }
595
596
597 void BImage::bevel1(void) {
598   if (width > 2 && height > 2) {
599     unsigned char *pr = red, *pg = green, *pb = blue;
600
601     register unsigned char r, g, b, rr ,gg ,bb;
602     register unsigned int w = width, h = height - 1, wh = w * h;
603
604     while (--w) {
605       r = *pr;
606       rr = r + (r >> 1);
607       if (rr < r) rr = ~0;
608       g = *pg;
609       gg = g + (g >> 1);
610       if (gg < g) gg = ~0;
611       b = *pb;
612       bb = b + (b >> 1);
613       if (bb < b) bb = ~0;
614
615       *pr = rr;
616       *pg = gg;
617       *pb = bb;
618
619       r = *(pr + wh);
620       rr = (r >> 2) + (r >> 1);
621       if (rr > r) rr = 0;
622       g = *(pg + wh);
623       gg = (g >> 2) + (g >> 1);
624       if (gg > g) gg = 0;
625       b = *(pb + wh);
626       bb = (b >> 2) + (b >> 1);
627       if (bb > b) bb = 0;
628
629       *((pr++) + wh) = rr;
630       *((pg++) + wh) = gg;
631       *((pb++) + wh) = bb;
632     }
633
634     r = *pr;
635     rr = r + (r >> 1);
636     if (rr < r) rr = ~0;
637     g = *pg;
638     gg = g + (g >> 1);
639     if (gg < g) gg = ~0;
640     b = *pb;
641     bb = b + (b >> 1);
642     if (bb < b) bb = ~0;
643
644     *pr = rr;
645     *pg = gg;
646     *pb = bb;
647
648     r = *(pr + wh);
649     rr = (r >> 2) + (r >> 1);
650     if (rr > r) rr = 0;
651     g = *(pg + wh);
652     gg = (g >> 2) + (g >> 1);
653     if (gg > g) gg = 0;
654     b = *(pb + wh);
655     bb = (b >> 2) + (b >> 1);
656     if (bb > b) bb = 0;
657
658     *(pr + wh) = rr;
659     *(pg + wh) = gg;
660     *(pb + wh) = bb;
661
662     pr = red + width;
663     pg = green + width;
664     pb = blue + width;
665
666     while (--h) {
667       r = *pr;
668       rr = r + (r >> 1);
669       if (rr < r) rr = ~0;
670       g = *pg;
671       gg = g + (g >> 1);
672       if (gg < g) gg = ~0;
673       b = *pb;
674       bb = b + (b >> 1);
675       if (bb < b) bb = ~0;
676
677       *pr = rr;
678       *pg = gg;
679       *pb = bb;
680
681       pr += width - 1;
682       pg += width - 1;
683       pb += width - 1;
684
685       r = *pr;
686       rr = (r >> 2) + (r >> 1);
687       if (rr > r) rr = 0;
688       g = *pg;
689       gg = (g >> 2) + (g >> 1);
690       if (gg > g) gg = 0;
691       b = *pb;
692       bb = (b >> 2) + (b >> 1);
693       if (bb > b) bb = 0;
694
695       *(pr++) = rr;
696       *(pg++) = gg;
697       *(pb++) = bb;
698     }
699
700     r = *pr;
701     rr = r + (r >> 1);
702     if (rr < r) rr = ~0;
703     g = *pg;
704     gg = g + (g >> 1);
705     if (gg < g) gg = ~0;
706     b = *pb;
707     bb = b + (b >> 1);
708     if (bb < b) bb = ~0;
709
710     *pr = rr;
711     *pg = gg;
712     *pb = bb;
713
714     pr += width - 1;
715     pg += width - 1;
716     pb += width - 1;
717
718     r = *pr;
719     rr = (r >> 2) + (r >> 1);
720     if (rr > r) rr = 0;
721     g = *pg;
722     gg = (g >> 2) + (g >> 1);
723     if (gg > g) gg = 0;
724     b = *pb;
725     bb = (b >> 2) + (b >> 1);
726     if (bb > b) bb = 0;
727
728     *pr = rr;
729     *pg = gg;
730     *pb = bb;
731   }
732 }
733
734
735 void BImage::bevel2(void) {
736   if (width > 4 && height > 4) {
737     unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1,
738       *pg = green + width + 1, *pb = blue + width + 1;
739     unsigned int w = width - 2, h = height - 1, wh = width * (height - 3);
740
741     while (--w) {
742       r = *pr;
743       rr = r + (r >> 1);
744       if (rr < r) rr = ~0;
745       g = *pg;
746       gg = g + (g >> 1);
747       if (gg < g) gg = ~0;
748       b = *pb;
749       bb = b + (b >> 1);
750       if (bb < b) bb = ~0;
751
752       *pr = rr;
753       *pg = gg;
754       *pb = bb;
755
756       r = *(pr + wh);
757       rr = (r >> 2) + (r >> 1);
758       if (rr > r) rr = 0;
759       g = *(pg + wh);
760       gg = (g >> 2) + (g >> 1);
761       if (gg > g) gg = 0;
762       b = *(pb + wh);
763       bb = (b >> 2) + (b >> 1);
764       if (bb > b) bb = 0;
765
766       *((pr++) + wh) = rr;
767       *((pg++) + wh) = gg;
768       *((pb++) + wh) = bb;
769     }
770
771     pr = red + width;
772     pg = green + width;
773     pb = blue + width;
774
775     while (--h) {
776       r = *pr;
777       rr = r + (r >> 1);
778       if (rr < r) rr = ~0;
779       g = *pg;
780       gg = g + (g >> 1);
781       if (gg < g) gg = ~0;
782       b = *pb;
783       bb = b + (b >> 1);
784       if (bb < b) bb = ~0;
785
786       *(++pr) = rr;
787       *(++pg) = gg;
788       *(++pb) = bb;
789
790       pr += width - 3;
791       pg += width - 3;
792       pb += width - 3;
793
794       r = *pr;
795       rr = (r >> 2) + (r >> 1);
796       if (rr > r) rr = 0;
797       g = *pg;
798       gg = (g >> 2) + (g >> 1);
799       if (gg > g) gg = 0;
800       b = *pb;
801       bb = (b >> 2) + (b >> 1);
802       if (bb > b) bb = 0;
803
804       *(pr++) = rr;
805       *(pg++) = gg;
806       *(pb++) = bb;
807
808       pr++; pg++; pb++;
809     }
810   }
811 }
812
813
814 void BImage::invert(void) {
815   register unsigned int i, j, wh = (width * height) - 1;
816   unsigned char tmp;
817
818   for (i = 0, j = wh; j > i; j--, i++) {
819     tmp = *(red + j);
820     *(red + j) = *(red + i);
821     *(red + i) = tmp;
822
823     tmp = *(green + j);
824     *(green + j) = *(green + i);
825     *(green + i) = tmp;
826
827     tmp = *(blue + j);
828     *(blue + j) = *(blue + i);
829     *(blue + i) = tmp;
830   }
831 }
832
833
834 void BImage::dgradient(void) {
835   // diagonal gradient code was written by Mike Cole <mike@mydot.com>
836   // modified for interlacing by Brad Hughes
837
838   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
839     xr = (float) from.red(),
840     xg = (float) from.green(),
841     xb = (float) from.blue();
842   unsigned char *pr = red, *pg = green, *pb = blue;
843   unsigned int w = width * 2, h = height * 2, *xt = xtable, *yt = ytable;
844
845   register unsigned int x, y;
846
847   dry = drx = (float) (to.red() - from.red());
848   dgy = dgx = (float) (to.green() - from.green());
849   dby = dbx = (float) (to.blue() - from.blue());
850
851   // Create X table
852   drx /= w;
853   dgx /= w;
854   dbx /= w;
855
856   for (x = 0; x < width; x++) {
857     *(xt++) = (unsigned char) (xr);
858     *(xt++) = (unsigned char) (xg);
859     *(xt++) = (unsigned char) (xb);
860
861     xr += drx;
862     xg += dgx;
863     xb += dbx;
864   }
865
866   // Create Y table
867   dry /= h;
868   dgy /= h;
869   dby /= h;
870
871   for (y = 0; y < height; y++) {
872     *(yt++) = ((unsigned char) yr);
873     *(yt++) = ((unsigned char) yg);
874     *(yt++) = ((unsigned char) yb);
875
876     yr += dry;
877     yg += dgy;
878     yb += dby;
879   }
880
881   // Combine tables to create gradient
882
883   if (! interlaced) {
884     // normal dgradient
885     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
886       for (xt = xtable, x = 0; x < width; x++) {
887         *(pr++) = *(xt++) + *(yt);
888         *(pg++) = *(xt++) + *(yt + 1);
889         *(pb++) = *(xt++) + *(yt + 2);
890       }
891     }
892   } else {
893     // faked interlacing effect
894     unsigned char channel, channel2;
895
896     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
897       for (xt = xtable, x = 0; x < width; x++) {
898         if (y & 1) {
899           channel = *(xt++) + *(yt);
900           channel2 = (channel >> 1) + (channel >> 2);
901           if (channel2 > channel) channel2 = 0;
902           *(pr++) = channel2;
903
904           channel = *(xt++) + *(yt + 1);
905           channel2 = (channel >> 1) + (channel >> 2);
906           if (channel2 > channel) channel2 = 0;
907           *(pg++) = channel2;
908
909           channel = *(xt++) + *(yt + 2);
910           channel2 = (channel >> 1) + (channel >> 2);
911           if (channel2 > channel) channel2 = 0;
912           *(pb++) = channel2;
913         } else {
914           channel = *(xt++) + *(yt);
915           channel2 = channel + (channel >> 3);
916           if (channel2 < channel) channel2 = ~0;
917           *(pr++) = channel2;
918
919           channel = *(xt++) + *(yt + 1);
920           channel2 = channel + (channel >> 3);
921           if (channel2 < channel) channel2 = ~0;
922           *(pg++) = channel2;
923
924           channel = *(xt++) + *(yt + 2);
925           channel2 = channel + (channel >> 3);
926           if (channel2 < channel) channel2 = ~0;
927           *(pb++) = channel2;
928         }
929       }
930     }
931   }
932 }
933
934
935 void BImage::hgradient(void) {
936   float drx, dgx, dbx,
937     xr = (float) from.red(),
938     xg = (float) from.green(),
939     xb = (float) from.blue();
940   unsigned char *pr = red, *pg = green, *pb = blue;
941
942   register unsigned int x, y;
943
944   drx = (float) (to.red() - from.red());
945   dgx = (float) (to.green() - from.green());
946   dbx = (float) (to.blue() - from.blue());
947
948   drx /= width;
949   dgx /= width;
950   dbx /= width;
951
952   if (interlaced && height > 2) {
953     // faked interlacing effect
954     unsigned char channel, channel2;
955
956     for (x = 0; x < width; x++, pr++, pg++, pb++) {
957       channel = (unsigned char) xr;
958       channel2 = (channel >> 1) + (channel >> 2);
959       if (channel2 > channel) channel2 = 0;
960       *pr = channel2;
961
962       channel = (unsigned char) xg;
963       channel2 = (channel >> 1) + (channel >> 2);
964       if (channel2 > channel) channel2 = 0;
965       *pg = channel2;
966
967       channel = (unsigned char) xb;
968       channel2 = (channel >> 1) + (channel >> 2);
969       if (channel2 > channel) channel2 = 0;
970       *pb = channel2;
971
972
973       channel = (unsigned char) xr;
974       channel2 = channel + (channel >> 3);
975       if (channel2 < channel) channel2 = ~0;
976       *(pr + width) = channel2;
977
978       channel = (unsigned char) xg;
979       channel2 = channel + (channel >> 3);
980       if (channel2 < channel) channel2 = ~0;
981       *(pg + width) = channel2;
982
983       channel = (unsigned char) xb;
984       channel2 = channel + (channel >> 3);
985       if (channel2 < channel) channel2 = ~0;
986       *(pb + width) = channel2;
987
988       xr += drx;
989       xg += dgx;
990       xb += dbx;
991     }
992
993     pr += width;
994     pg += width;
995     pb += width;
996
997     int offset;
998
999     for (y = 2; y < height; y++, pr += width, pg += width, pb += width) {
1000       if (y & 1) offset = width; else offset = 0;
1001
1002       memcpy(pr, (red + offset), width);
1003       memcpy(pg, (green + offset), width);
1004       memcpy(pb, (blue + offset), width);
1005     }
1006   } else {
1007     // normal hgradient
1008     for (x = 0; x < width; x++) {
1009       *(pr++) = (unsigned char) (xr);
1010       *(pg++) = (unsigned char) (xg);
1011       *(pb++) = (unsigned char) (xb);
1012
1013       xr += drx;
1014       xg += dgx;
1015       xb += dbx;
1016     }
1017
1018     for (y = 1; y < height; y++, pr += width, pg += width, pb += width) {
1019       memcpy(pr, red, width);
1020       memcpy(pg, green, width);
1021       memcpy(pb, blue, width);
1022     }
1023   }
1024 }
1025
1026
1027 void BImage::vgradient(void) {
1028   float dry, dgy, dby,
1029     yr = (float) from.red(),
1030     yg = (float) from.green(),
1031     yb = (float) from.blue();
1032   unsigned char *pr = red, *pg = green, *pb = blue;
1033
1034   register unsigned int y;
1035
1036   dry = (float) (to.red() - from.red());
1037   dgy = (float) (to.green() - from.green());
1038   dby = (float) (to.blue() - from.blue());
1039
1040   dry /= height;
1041   dgy /= height;
1042   dby /= height;
1043
1044   if (interlaced) {
1045     // faked interlacing effect
1046     unsigned char channel, channel2;
1047
1048     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1049       if (y & 1) {
1050         channel = (unsigned char) yr;
1051         channel2 = (channel >> 1) + (channel >> 2);
1052         if (channel2 > channel) channel2 = 0;
1053         memset(pr, channel2, width);
1054
1055         channel = (unsigned char) yg;
1056         channel2 = (channel >> 1) + (channel >> 2);
1057         if (channel2 > channel) channel2 = 0;
1058         memset(pg, channel2, width);
1059
1060         channel = (unsigned char) yb;
1061         channel2 = (channel >> 1) + (channel >> 2);
1062         if (channel2 > channel) channel2 = 0;
1063         memset(pb, channel2, width);
1064       } else {
1065         channel = (unsigned char) yr;
1066         channel2 = channel + (channel >> 3);
1067         if (channel2 < channel) channel2 = ~0;
1068         memset(pr, channel2, width);
1069
1070         channel = (unsigned char) yg;
1071         channel2 = channel + (channel >> 3);
1072         if (channel2 < channel) channel2 = ~0;
1073         memset(pg, channel2, width);
1074
1075         channel = (unsigned char) yb;
1076         channel2 = channel + (channel >> 3);
1077         if (channel2 < channel) channel2 = ~0;
1078         memset(pb, channel2, width);
1079       }
1080
1081       yr += dry;
1082       yg += dgy;
1083       yb += dby;
1084     }
1085   } else {
1086     // normal vgradient
1087     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1088       memset(pr, (unsigned char) yr, width);
1089       memset(pg, (unsigned char) yg, width);
1090       memset(pb, (unsigned char) yb, width);
1091
1092       yr += dry;
1093       yg += dgy;
1094       yb += dby;
1095     }
1096   }
1097 }
1098
1099
1100 void BImage::pgradient(void) {
1101   // pyramid gradient -  based on original dgradient, written by
1102   // Mosfet (mosfet@kde.org)
1103   // adapted from kde sources for Blackbox by Brad Hughes
1104
1105   float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby,
1106     xr, xg, xb;
1107   int rsign, gsign, bsign;
1108   unsigned char *pr = red, *pg = green, *pb = blue;
1109   unsigned int tr = to.red(), tg = to.green(), tb = to.blue(),
1110     *xt = xtable, *yt = ytable;
1111
1112   register unsigned int x, y;
1113
1114   dry = drx = (float) (to.red() - from.red());
1115   dgy = dgx = (float) (to.green() - from.green());
1116   dby = dbx = (float) (to.blue() - from.blue());
1117
1118   rsign = (drx < 0) ? -1 : 1;
1119   gsign = (dgx < 0) ? -1 : 1;
1120   bsign = (dbx < 0) ? -1 : 1;
1121
1122   xr = yr = (drx / 2);
1123   xg = yg = (dgx / 2);
1124   xb = yb = (dbx / 2);
1125
1126   // Create X table
1127   drx /= width;
1128   dgx /= width;
1129   dbx /= width;
1130
1131   for (x = 0; x < width; x++) {
1132     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1133     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1134     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1135
1136     xr -= drx;
1137     xg -= dgx;
1138     xb -= dbx;
1139   }
1140
1141   // Create Y table
1142   dry /= height;
1143   dgy /= height;
1144   dby /= height;
1145
1146   for (y = 0; y < height; y++) {
1147     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1148     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1149     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1150
1151     yr -= dry;
1152     yg -= dgy;
1153     yb -= dby;
1154   }
1155
1156   // Combine tables to create gradient
1157
1158   if (! interlaced) {
1159     // normal pgradient
1160     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1161       for (xt = xtable, x = 0; x < width; x++) {
1162         *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1163         *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1164         *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1165       }
1166     }
1167   } else {
1168     // faked interlacing effect
1169     unsigned char channel, channel2;
1170
1171     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1172       for (xt = xtable, x = 0; x < width; x++) {
1173         if (y & 1) {
1174           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1175           channel2 = (channel >> 1) + (channel >> 2);
1176           if (channel2 > channel) channel2 = 0;
1177           *(pr++) = channel2;
1178
1179           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1180           channel2 = (channel >> 1) + (channel >> 2);
1181           if (channel2 > channel) channel2 = 0;
1182           *(pg++) = channel2;
1183
1184           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1185           channel2 = (channel >> 1) + (channel >> 2);
1186           if (channel2 > channel) channel2 = 0;
1187           *(pb++) = channel2;
1188         } else {
1189           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1190           channel2 = channel + (channel >> 3);
1191           if (channel2 < channel) channel2 = ~0;
1192           *(pr++) = channel2;
1193
1194           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1195           channel2 = channel + (channel >> 3);
1196           if (channel2 < channel) channel2 = ~0;
1197           *(pg++) = channel2;
1198
1199           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1200           channel2 = channel + (channel >> 3);
1201           if (channel2 < channel) channel2 = ~0;
1202           *(pb++) = channel2;
1203         }
1204       }
1205     }
1206   }
1207 }
1208
1209
1210 void BImage::rgradient(void) {
1211   // rectangle gradient -  based on original dgradient, written by
1212   // Mosfet (mosfet@kde.org)
1213   // adapted from kde sources for Blackbox by Brad Hughes
1214
1215   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1216   int rsign, gsign, bsign;
1217   unsigned char *pr = red, *pg = green, *pb = blue;
1218   unsigned int tr = to.red(), tg = to.green(), tb = to.blue(),
1219     *xt = xtable, *yt = ytable;
1220
1221   register unsigned int x, y;
1222
1223   dry = drx = (float) (to.red() - from.red());
1224   dgy = dgx = (float) (to.green() - from.green());
1225   dby = dbx = (float) (to.blue() - from.blue());
1226
1227   rsign = (drx < 0) ? -2 : 2;
1228   gsign = (dgx < 0) ? -2 : 2;
1229   bsign = (dbx < 0) ? -2 : 2;
1230
1231   xr = yr = (drx / 2);
1232   xg = yg = (dgx / 2);
1233   xb = yb = (dbx / 2);
1234
1235   // Create X table
1236   drx /= width;
1237   dgx /= width;
1238   dbx /= width;
1239
1240   for (x = 0; x < width; x++) {
1241     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1242     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1243     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1244
1245     xr -= drx;
1246     xg -= dgx;
1247     xb -= dbx;
1248   }
1249
1250   // Create Y table
1251   dry /= height;
1252   dgy /= height;
1253   dby /= height;
1254
1255   for (y = 0; y < height; y++) {
1256     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1257     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1258     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1259
1260     yr -= dry;
1261     yg -= dgy;
1262     yb -= dby;
1263   }
1264
1265   // Combine tables to create gradient
1266
1267   if (! interlaced) {
1268     // normal rgradient
1269     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1270       for (xt = xtable, x = 0; x < width; x++) {
1271         *(pr++) = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1272         *(pg++) = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1273         *(pb++) = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1274       }
1275     }
1276   } else {
1277     // faked interlacing effect
1278     unsigned char channel, channel2;
1279
1280     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1281       for (xt = xtable, x = 0; x < width; x++) {
1282         if (y & 1) {
1283           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1284           channel2 = (channel >> 1) + (channel >> 2);
1285           if (channel2 > channel) channel2 = 0;
1286           *(pr++) = channel2;
1287
1288           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1289           channel2 = (channel >> 1) + (channel >> 2);
1290           if (channel2 > channel) channel2 = 0;
1291           *(pg++) = channel2;
1292
1293           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1294           channel2 = (channel >> 1) + (channel >> 2);
1295           if (channel2 > channel) channel2 = 0;
1296           *(pb++) = channel2;
1297         } else {
1298           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1299           channel2 = channel + (channel >> 3);
1300           if (channel2 < channel) channel2 = ~0;
1301           *(pr++) = channel2;
1302
1303           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1304           channel2 = channel + (channel >> 3);
1305           if (channel2 < channel) channel2 = ~0;
1306           *(pg++) = channel2;
1307
1308           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1309           channel2 = channel + (channel >> 3);
1310           if (channel2 < channel) channel2 = ~0;
1311           *(pb++) = channel2;
1312         }
1313       }
1314     }
1315   }
1316 }
1317
1318
1319 void BImage::egradient(void) {
1320   // elliptic gradient -  based on original dgradient, written by
1321   // Mosfet (mosfet@kde.org)
1322   // adapted from kde sources for Blackbox by Brad Hughes
1323
1324   float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb;
1325   int rsign, gsign, bsign;
1326   unsigned char *pr = red, *pg = green, *pb = blue;
1327   unsigned int *xt = xtable, *yt = ytable,
1328     tr = (unsigned long) to.red(),
1329     tg = (unsigned long) to.green(),
1330     tb = (unsigned long) to.blue();
1331
1332   register unsigned int x, y;
1333
1334   dry = drx = (float) (to.red() - from.red());
1335   dgy = dgx = (float) (to.green() - from.green());
1336   dby = dbx = (float) (to.blue() - from.blue());
1337
1338   rsign = (drx < 0) ? -1 : 1;
1339   gsign = (dgx < 0) ? -1 : 1;
1340   bsign = (dbx < 0) ? -1 : 1;
1341
1342   xr = yr = (drx / 2);
1343   xg = yg = (dgx / 2);
1344   xb = yb = (dbx / 2);
1345
1346   // Create X table
1347   drx /= width;
1348   dgx /= width;
1349   dbx /= width;
1350
1351   for (x = 0; x < width; x++) {
1352     *(xt++) = (unsigned long) (xr * xr);
1353     *(xt++) = (unsigned long) (xg * xg);
1354     *(xt++) = (unsigned long) (xb * xb);
1355
1356     xr -= drx;
1357     xg -= dgx;
1358     xb -= dbx;
1359   }
1360
1361   // Create Y table
1362   dry /= height;
1363   dgy /= height;
1364   dby /= height;
1365
1366   for (y = 0; y < height; y++) {
1367     *(yt++) = (unsigned long) (yr * yr);
1368     *(yt++) = (unsigned long) (yg * yg);
1369     *(yt++) = (unsigned long) (yb * yb);
1370
1371     yr -= dry;
1372     yg -= dgy;
1373     yb -= dby;
1374   }
1375
1376   // Combine tables to create gradient
1377
1378   if (! interlaced) {
1379     // normal egradient
1380     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1381       for (xt = xtable, x = 0; x < width; x++) {
1382         *(pr++) = (unsigned char)
1383           (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1384         *(pg++) = (unsigned char)
1385           (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1386         *(pb++) = (unsigned char)
1387           (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1388       }
1389     }
1390   } else {
1391     // faked interlacing effect
1392     unsigned char channel, channel2;
1393
1394     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1395       for (xt = xtable, x = 0; x < width; x++) {
1396         if (y & 1) {
1397           channel = (unsigned char)
1398             (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1399           channel2 = (channel >> 1) + (channel >> 2);
1400           if (channel2 > channel) channel2 = 0;
1401           *(pr++) = channel2;
1402
1403           channel = (unsigned char)
1404             (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1405           channel2 = (channel >> 1) + (channel >> 2);
1406           if (channel2 > channel) channel2 = 0;
1407           *(pg++) = channel2;
1408
1409           channel = (unsigned char)
1410             (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1411           channel2 = (channel >> 1) + (channel >> 2);
1412           if (channel2 > channel) channel2 = 0;
1413           *(pb++) = channel2;
1414         } else {
1415           channel = (unsigned char)
1416             (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1417           channel2 = channel + (channel >> 3);
1418           if (channel2 < channel) channel2 = ~0;
1419           *(pr++) = channel2;
1420
1421           channel = (unsigned char)
1422           (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1423           channel2 = channel + (channel >> 3);
1424           if (channel2 < channel) channel2 = ~0;
1425           *(pg++) = channel2;
1426
1427           channel = (unsigned char)
1428             (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1429           channel2 = channel + (channel >> 3);
1430           if (channel2 < channel) channel2 = ~0;
1431           *(pb++) = channel2;
1432         }
1433       }
1434     }
1435   }
1436 }
1437
1438
1439 void BImage::pcgradient(void) {
1440   // pipe cross gradient -  based on original dgradient, written by
1441   // Mosfet (mosfet@kde.org)
1442   // adapted from kde sources for Blackbox by Brad Hughes
1443
1444   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1445   int rsign, gsign, bsign;
1446   unsigned char *pr = red, *pg = green, *pb = blue;
1447   unsigned int *xt = xtable, *yt = ytable,
1448     tr = to.red(),
1449     tg = to.green(),
1450     tb = to.blue();
1451
1452   register unsigned int x, y;
1453
1454   dry = drx = (float) (to.red() - from.red());
1455   dgy = dgx = (float) (to.green() - from.green());
1456   dby = dbx = (float) (to.blue() - from.blue());
1457
1458   rsign = (drx < 0) ? -2 : 2;
1459   gsign = (dgx < 0) ? -2 : 2;
1460   bsign = (dbx < 0) ? -2 : 2;
1461
1462   xr = yr = (drx / 2);
1463   xg = yg = (dgx / 2);
1464   xb = yb = (dbx / 2);
1465
1466   // Create X table
1467   drx /= width;
1468   dgx /= width;
1469   dbx /= width;
1470
1471   for (x = 0; x < width; x++) {
1472     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1473     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1474     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1475
1476     xr -= drx;
1477     xg -= dgx;
1478     xb -= dbx;
1479   }
1480
1481   // Create Y table
1482   dry /= height;
1483   dgy /= height;
1484   dby /= height;
1485
1486   for (y = 0; y < height; y++) {
1487     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1488     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1489     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1490
1491     yr -= dry;
1492     yg -= dgy;
1493     yb -= dby;
1494   }
1495
1496   // Combine tables to create gradient
1497
1498   if (! interlaced) {
1499     // normal pcgradient
1500     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1501       for (xt = xtable, x = 0; x < width; x++) {
1502         *(pr++) = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1503         *(pg++) = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1504         *(pb++) = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1505       }
1506     }
1507   } else {
1508     // faked interlacing effect
1509     unsigned char channel, channel2;
1510
1511     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1512       for (xt = xtable, x = 0; x < width; x++) {
1513         if (y & 1) {
1514           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1515           channel2 = (channel >> 1) + (channel >> 2);
1516           if (channel2 > channel) channel2 = 0;
1517           *(pr++) = channel2;
1518
1519           channel = (unsigned char) (tg - (bsign * min(*(xt++), *(yt + 1))));
1520           channel2 = (channel >> 1) + (channel >> 2);
1521           if (channel2 > channel) channel2 = 0;
1522           *(pg++) = channel2;
1523
1524           channel = (unsigned char) (tb - (gsign * min(*(xt++), *(yt + 2))));
1525           channel2 = (channel >> 1) + (channel >> 2);
1526           if (channel2 > channel) channel2 = 0;
1527           *(pb++) = channel2;
1528         } else {
1529           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1530           channel2 = channel + (channel >> 3);
1531           if (channel2 < channel) channel2 = ~0;
1532           *(pr++) = channel2;
1533
1534           channel = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1535           channel2 = channel + (channel >> 3);
1536           if (channel2 < channel) channel2 = ~0;
1537           *(pg++) = channel2;
1538
1539           channel = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1540           channel2 = channel + (channel >> 3);
1541           if (channel2 < channel) channel2 = ~0;
1542           *(pb++) = channel2;
1543         }
1544       }
1545     }
1546   }
1547 }
1548
1549
1550 void BImage::cdgradient(void) {
1551   // cross diagonal gradient -  based on original dgradient, written by
1552   // Mosfet (mosfet@kde.org)
1553   // adapted from kde sources for Blackbox by Brad Hughes
1554
1555   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
1556     xr = (float) from.red(),
1557     xg = (float) from.green(),
1558     xb = (float) from.blue();
1559   unsigned char *pr = red, *pg = green, *pb = blue;
1560   unsigned int w = width * 2, h = height * 2, *xt, *yt;
1561
1562   register unsigned int x, y;
1563
1564   dry = drx = (float) (to.red() - from.red());
1565   dgy = dgx = (float) (to.green() - from.green());
1566   dby = dbx = (float) (to.blue() - from.blue());
1567
1568   // Create X table
1569   drx /= w;
1570   dgx /= w;
1571   dbx /= w;
1572
1573   for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) {
1574     *(xt--) = (unsigned char) xb;
1575     *(xt--) = (unsigned char) xg;
1576     *(xt--) = (unsigned char) xr;
1577
1578     xr += drx;
1579     xg += dgx;
1580     xb += dbx;
1581   }
1582
1583   // Create Y table
1584   dry /= h;
1585   dgy /= h;
1586   dby /= h;
1587
1588   for (yt = ytable, y = 0; y < height; y++) {
1589     *(yt++) = (unsigned char) yr;
1590     *(yt++) = (unsigned char) yg;
1591     *(yt++) = (unsigned char) yb;
1592
1593     yr += dry;
1594     yg += dgy;
1595     yb += dby;
1596   }
1597
1598   // Combine tables to create gradient
1599
1600   if (! interlaced) {
1601     // normal cdgradient
1602     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1603       for (xt = xtable, x = 0; x < width; x++) {
1604         *(pr++) = *(xt++) + *(yt);
1605         *(pg++) = *(xt++) + *(yt + 1);
1606         *(pb++) = *(xt++) + *(yt + 2);
1607       }
1608     }
1609   } else {
1610     // faked interlacing effect
1611     unsigned char channel, channel2;
1612
1613     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1614       for (xt = xtable, x = 0; x < width; x++) {
1615         if (y & 1) {
1616           channel = *(xt++) + *(yt);
1617           channel2 = (channel >> 1) + (channel >> 2);
1618           if (channel2 > channel) channel2 = 0;
1619           *(pr++) = channel2;
1620
1621           channel = *(xt++) + *(yt + 1);
1622           channel2 = (channel >> 1) + (channel >> 2);
1623           if (channel2 > channel) channel2 = 0;
1624           *(pg++) = channel2;
1625
1626           channel = *(xt++) + *(yt + 2);
1627           channel2 = (channel >> 1) + (channel >> 2);
1628           if (channel2 > channel) channel2 = 0;
1629           *(pb++) = channel2;
1630         } else {
1631           channel = *(xt++) + *(yt);
1632           channel2 = channel + (channel >> 3);
1633           if (channel2 < channel) channel2 = ~0;
1634           *(pr++) = channel2;
1635
1636           channel = *(xt++) + *(yt + 1);
1637           channel2 = channel + (channel >> 3);
1638           if (channel2 < channel) channel2 = ~0;
1639           *(pg++) = channel2;
1640
1641           channel = *(xt++) + *(yt + 2);
1642           channel2 = channel + (channel >> 3);
1643           if (channel2 < channel) channel2 = ~0;
1644           *(pb++) = channel2;
1645         }
1646       }
1647     }
1648   }
1649 }