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