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