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