1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Image.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000, 2002 - 2005
5 // Bradley T Hughes <bhughes at trolltech.com>
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
34 #include <X11/Xutil.h>
36 # include <sys/types.h>
40 # include <X11/extensions/XShm.h>
48 // #define COLORTABLE_DEBUG
49 // #define MITSHM_DEBUG
52 static unsigned int right_align(unsigned int v
)
59 static int lowest_bit(unsigned int v
)
63 for (i
= 0; ((v
& b
) == 0u) && i
< 32; ++i
)
65 return i
== 32 ? -1 : i
;
69 unsigned int bt::Image::global_maximumColors
= 0u; // automatic
70 bt::DitherMode
bt::Image::global_ditherMode
= bt::OrderedDither
;
77 XColorTable(const Display
&dpy
, unsigned int screen
,
78 unsigned int maxColors
);
81 inline bt::DitherMode
ditherMode(void) const
83 return ((n_red
< 256u || n_green
< 256u || n_blue
< 256u)
84 ? bt::Image::ditherMode()
88 void map(unsigned int &red
,
91 unsigned long pixel(unsigned int red
,
99 unsigned int n_red
, n_green
, n_blue
;
100 int red_shift
, green_shift
, blue_shift
;
102 std::vector
<unsigned long> colors
;
106 typedef std::vector
<unsigned char> Buffer
;
107 static Buffer buffer
;
110 typedef std::vector
<XColorTable
*> XColorTableList
;
111 static XColorTableList colorTableList
;
114 void destroyColorTables(void) {
115 XColorTableList::iterator it
= colorTableList
.begin(),
116 end
= colorTableList
.end();
117 for (; it
!= end
; ++it
) {
122 colorTableList
.clear();
128 static XShmSegmentInfo shm_info
;
129 static bool use_shm
= false;
130 static bool shm_attached
= false;
131 static int shm_id
= -1;
132 static char *shm_addr
= reinterpret_cast<char *>(-1);
135 static int handleShmError(::Display
*, XErrorEvent
*) {
141 void startupShm(const Display
&display
) {
142 // query MIT-SHM extension
143 if (!XShmQueryExtension(display
.XDisplay()))
149 void destroyShmImage(const Display
&display
, XImage
*image
) {
150 // tell the X server to detach
152 XShmDetach(display
.XDisplay(), &shm_info
);
154 // wait for the server to render the image and detach the memory
156 XSync(display
.XDisplay(), False
);
158 shm_attached
= false;
161 // detach shared memory segment
162 if (shm_addr
!= reinterpret_cast<char *>(-1))
164 shm_addr
= reinterpret_cast<char *>(-1);
166 // destroy shared memory id
168 shmctl(shm_id
, IPC_RMID
, 0);
173 XDestroyImage(image
);
177 XImage
*createShmImage(const Display
&display
, const ScreenInfo
&screeninfo
,
178 unsigned int width
, unsigned int height
) {
182 // use MIT-SHM extension
183 XImage
*image
= XShmCreateImage(display
.XDisplay(), screeninfo
.visual(),
184 screeninfo
.depth(), ZPixmap
, 0,
185 &shm_info
, width
, height
);
189 // get shared memory id
190 unsigned int usage
= image
->bytes_per_line
* image
->height
;
191 shm_id
= shmget(IPC_PRIVATE
, usage
, IPC_CREAT
| 0644);
194 perror("bt::createShmImage: shmget");
195 #endif // MITSHM_DEBUG
198 XDestroyImage(image
);
202 // attached shared memory segment
203 shm_addr
= static_cast<char *>(shmat(shm_id
, 0, 0));
204 if (shm_addr
== reinterpret_cast<char *>(-1)) {
206 perror("bt::createShmImage: shmat");
207 #endif // MITSHM_DEBUG
210 destroyShmImage(display
, image
);
214 // tell the X server to attach
215 shm_info
.shmid
= shm_id
;
216 shm_info
.shmaddr
= shm_addr
;
217 shm_info
.readOnly
= True
;
219 static bool test_server_attach
= true;
220 if (test_server_attach
) {
221 // never checked if the X server can do shared memory...
222 XErrorHandler old_handler
= XSetErrorHandler(handleShmError
);
223 XShmAttach(display
.XDisplay(), &shm_info
);
224 XSync(display
.XDisplay(), False
);
225 XSetErrorHandler(old_handler
);
228 // the X server failed to attach the shm segment
231 fprintf(stderr
, "bt::createShmImage: X server failed to attach\n");
232 #endif // MITSHM_DEBUG
234 destroyShmImage(display
, image
);
238 test_server_attach
= false;
240 // we know the X server can attach to the memory segment
241 XShmAttach(display
.XDisplay(), &shm_info
);
245 image
->data
= shm_addr
;
253 bt::XColorTable::XColorTable(const Display
&dpy
, unsigned int screen
,
254 unsigned int maxColors
)
255 : _dpy(dpy
), _screen(screen
),
256 n_red(0u), n_green(0u), n_blue(0u),
257 red_shift(0u), green_shift(0u), blue_shift(0u)
259 const ScreenInfo
&screeninfo
= _dpy
.screenInfo(_screen
);
260 const Visual
* const visual
= screeninfo
.visual();
261 const Colormap colormap
= screeninfo
.colormap();
263 visual_class
= visual
->c_class
;
265 bool query_colormap
= false;
267 switch (visual_class
) {
271 if (visual_class
== GrayScale
) {
272 if (maxColors
== 0u) {
273 // inspired by libXmu...
274 if (visual
->map_entries
> 65000)
276 else if (visual
->map_entries
> 4000)
278 else if (visual
->map_entries
> 250)
285 std::min(static_cast<unsigned int>(visual
->map_entries
), maxColors
);
286 n_red
= n_green
= n_blue
= maxColors
;
288 n_red
= n_green
= n_blue
= visual
->map_entries
;
289 query_colormap
= true;
292 colors
.resize(n_green
);
294 const unsigned int g_max
= n_green
- 1;
295 const unsigned int g_round
= g_max
/ 2;
297 for (unsigned int g
= 0; g
< n_green
; ++g
) {
300 if (visual_class
& 1) {
301 const int gray
= (g
* 0xffff + g_round
) / g_max
;
309 if (XAllocColor(_dpy
.XDisplay(), colormap
, &xcolor
))
310 colors
[g
] = xcolor
.pixel
;
312 query_colormap
= true;
321 if (visual_class
== PseudoColor
) {
322 if (maxColors
== 0u) {
323 // inspired by libXmu...
324 if (visual
->map_entries
> 65000)
325 maxColors
= 32 * 32 * 16;
326 else if (visual
->map_entries
> 4000)
327 maxColors
= 16 * 16 * 8;
328 else if (visual
->map_entries
> 250)
329 maxColors
= visual
->map_entries
- 125;
331 maxColors
= visual
->map_entries
;
335 std::min(static_cast<unsigned int>(visual
->map_entries
), maxColors
);
337 // calculate 2:2:1 proportions
342 if ((n_blue
* 2u) < n_red
343 && (n_blue
+ 1u) * n_red
* n_green
<= maxColors
)
345 else if (n_red
< n_green
346 && n_blue
* (n_red
+ 1u) * n_green
<= maxColors
)
348 else if (n_blue
* n_red
* (n_green
+ 1u) <= maxColors
)
354 n_red
= right_align(visual
->red_mask
) + 1;
355 n_green
= right_align(visual
->green_mask
) + 1;
356 n_blue
= right_align(visual
->blue_mask
) + 1;
357 query_colormap
= true;
360 colors
.resize(n_red
* n_green
* n_blue
);
362 const int r_max
= n_red
- 1;
363 const int r_round
= r_max
/ 2;
364 const int g_max
= n_green
- 1;
365 const int g_round
= g_max
/ 2;
366 const int b_max
= n_blue
- 1;
367 const int b_round
= b_max
/ 2;
370 for (unsigned int x
= 0, r
= 0; r
< n_red
; ++r
) {
371 for (unsigned int g
= 0; g
< n_green
; ++g
) {
372 for (unsigned int b
= 0; b
< n_blue
; ++b
, ++x
) {
375 if (visual_class
& 1) {
377 xcolor
.red
= (r
* 0xffff + r_round
) / r_max
;
378 xcolor
.green
= (g
* 0xffff + g_round
) / g_max
;
379 xcolor
.blue
= (b
* 0xffff + b_round
) / b_max
;
382 if (XAllocColor(_dpy
.XDisplay(), colormap
, &xcolor
))
383 colors
[x
] = xcolor
.pixel
;
385 query_colormap
= true;
394 n_red
= right_align(visual
->red_mask
) + 1;
395 n_green
= right_align(visual
->green_mask
) + 1;
396 n_blue
= right_align(visual
->blue_mask
) + 1;
398 red_shift
= lowest_bit(visual
->red_mask
);
399 green_shift
= lowest_bit(visual
->green_mask
);
400 blue_shift
= lowest_bit(visual
->blue_mask
);
405 n_red
= n_green
= n_blue
= (visual
->map_entries
/ 2) - 1;
409 #ifdef COLORTABLE_DEBUG
410 switch (visual_class
) {
413 for (int x
= 0; x
< colors
.size(); ++x
) {
414 const int gray
= (x
* 0xffff + (n_green
- 1) / 2) / (n_green
- 1);
415 fprintf(stderr
, "%s %3u: gray %04x\n",
416 colors
[x
] == ~0ul ? "req " : "alloc", x
, gray
);
421 for (int x
= 0; x
< colors
.size(); ++x
) {
422 int r
= (x
/ (n_green
* n_blue
)) % n_red
;
423 int g
= (x
/ n_blue
) % n_green
;
426 r
= (r
* 0xffff + (n_red
- 1) / 2) / (n_red
- 1);
427 g
= (g
* 0xffff + (n_green
- 1) / 2) / (n_green
- 1);
428 b
= (b
* 0xffff + (n_blue
- 1) / 2) / (n_blue
- 1);
430 fprintf(stderr
, "%s %3u: %04x/%04x/%04x\n",
431 colors
[x
] == ~0ul ? "req " : "alloc", x
, r
, g
, b
);
437 #endif // COLORTABLE_DEBUG
439 if (colors
.empty() || !query_colormap
)
442 // query existing colormap
443 const int depth
= screeninfo
.depth();
444 int q_colors
= (((1u << depth
) > 256u) ? 256u : (1u << depth
));
446 for (int x
= 0; x
< q_colors
; ++x
)
447 queried
[x
].pixel
= x
;
448 XQueryColors(_dpy
.XDisplay(), colormap
, queried
, q_colors
);
450 #ifdef COLORTABLE_DEBUG
451 for (int x
= 0; x
< q_colors
; ++x
) {
452 if (queried
[x
].red
== 0
453 && queried
[x
].green
== 0
454 && queried
[x
].blue
== 0
455 && queried
[x
].pixel
!= BlackPixel(_dpy
.XDisplay(), _screen
)) {
460 fprintf(stderr
, "query %3u: %04x/%04x/%04x\n",
461 x
, queried
[x
].red
, queried
[x
].green
, queried
[x
].blue
);
463 #endif // COLORTABLE_DEBUG
465 // for missing colors, find the closest color in the existing colormap
466 for (unsigned int x
= 0; x
< colors
.size(); ++x
) {
467 if (colors
[x
] != ~0ul)
470 int red
, green
, blue
, gray
;
472 switch (visual_class
) {
475 red
= green
= blue
= gray
=
476 (x
* 0xffff - (n_green
- 1) / 2) / (n_green
- 1);
480 red
= (x
/ (n_green
* n_blue
)) % n_red
;
481 green
= (x
/ n_blue
) % n_green
;
484 red
= (red
* 0xffff + (n_red
- 1) / 2) / (n_red
- 1);
485 green
= (green
* 0xffff + (n_green
- 1) / 2) / (n_green
- 1);
486 blue
= (blue
* 0xffff + (n_blue
- 1) / 2) / (n_blue
- 1);
488 gray
= ((red
* 30 + green
* 59 + blue
* 11) / 100);
494 int mindist
= INT_MAX
, best
= -1;
495 for (int y
= 0; y
< q_colors
; ++y
) {
496 const int r
= (red
- queried
[y
].red
) >> 8;
497 const int g
= (green
- queried
[y
].green
) >> 8;
498 const int b
= (blue
- queried
[y
].blue
) >> 8;
499 const int dist
= (r
* r
) + (g
* g
) + (b
* b
);
501 if (dist
< mindist
) {
506 assert(best
>= 0 && best
< q_colors
);
508 #ifdef COLORTABLE_DEBUG
509 fprintf(stderr
, "close %3u: %04x/%04x/%04x\n",
510 x
, queried
[best
].red
, queried
[best
].green
, queried
[best
].blue
);
511 #endif // COLORTABLE_DEBUG
513 if (visual_class
& 1) {
514 XColor xcolor
= queried
[best
];
516 if (XAllocColor(_dpy
.XDisplay(), colormap
, &xcolor
)) {
517 colors
[x
] = xcolor
.pixel
;
519 colors
[x
] = gray
< SHRT_MAX
520 ? BlackPixel(_dpy
.XDisplay(), _screen
)
521 : WhitePixel(_dpy
.XDisplay(), _screen
);
530 bt::XColorTable::~XColorTable(void) {
531 if (!colors
.empty()) {
532 XFreeColors(_dpy
.XDisplay(), _dpy
.screenInfo(_screen
).colormap(),
533 &colors
[0], colors
.size(), 0);
539 void bt::XColorTable::map(unsigned int &red
,
541 unsigned int &blue
) {
542 red
= (red
* n_red
) >> 8;
543 green
= (green
* n_green
) >> 8;
544 blue
= (blue
* n_blue
) >> 8;
548 unsigned long bt::XColorTable::pixel(unsigned int red
,
551 switch (visual_class
) {
554 return colors
[(red
* 30 + green
* 59 + blue
* 11) / 100];
558 return colors
[(red
* n_green
* n_blue
) + (green
* n_blue
) + blue
];
562 return ((red
<< red_shift
)
563 | (green
<< green_shift
)
564 | (blue
<< blue_shift
));
568 return 0; // shut up compiler warning
572 bt::Image::Image(unsigned int w
, unsigned int h
)
573 : data(0), width(w
), height(h
)
580 bt::Image::~Image(void) {
586 Pixmap
bt::Image::render(const Display
&display
, unsigned int screen
,
587 const bt::Texture
&texture
) {
588 if (texture
.texture() & bt::Texture::Parent_Relative
)
589 return ParentRelative
;
590 if (texture
.texture() & bt::Texture::Solid
)
592 if (!(texture
.texture() & bt::Texture::Gradient
))
596 bool interlaced
= texture
.texture() & bt::Texture::Interlaced
;
598 if (texture
.texture() & bt::Texture::Sunken
) {
599 from
= texture
.color2();
600 to
= texture
.color1();
602 from
= texture
.color1();
603 to
= texture
.color2();
606 data
= static_cast<RGB
*>(malloc(width
* height
* sizeof(RGB
)));
608 if (texture
.texture() & bt::Texture::Diagonal
)
609 dgradient(from
, to
, interlaced
);
610 else if (texture
.texture() & bt::Texture::Elliptic
)
611 egradient(from
, to
, interlaced
);
612 else if (texture
.texture() & bt::Texture::Horizontal
)
613 hgradient(from
, to
, interlaced
);
614 else if (texture
.texture() & bt::Texture::Pyramid
)
615 pgradient(from
, to
, interlaced
);
616 else if (texture
.texture() & bt::Texture::Rectangle
)
617 rgradient(from
, to
, interlaced
);
618 else if (texture
.texture() & bt::Texture::Vertical
)
619 vgradient(from
, to
, interlaced
);
620 else if (texture
.texture() & bt::Texture::CrossDiagonal
)
621 cdgradient(from
, to
, interlaced
);
622 else if (texture
.texture() & bt::Texture::PipeCross
)
623 pcgradient(from
, to
, interlaced
);
625 if (texture
.texture() & (bt::Texture::Sunken
| bt::Texture::Raised
))
626 bevel(texture
.borderWidth());
628 Pixmap pixmap
= renderPixmap(display
, screen
);
631 if (texture
.texture() & bt::Texture::Border
) {
632 Pen
penborder(screen
, texture
.borderColor());
633 bw
= texture
.borderWidth();
635 for (unsigned int i
= 0; i
< bw
; ++i
) {
636 XDrawRectangle(penborder
.XDisplay(), pixmap
, penborder
.gc(),
637 i
, i
, width
- (i
* 2) - 1, height
- (i
* 2) - 1);
646 * Ordered dither table
648 static const unsigned int dither16
[16][16] = {
649 { 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512,
650 768, 49920, 13056, 62208, 3840, 52992, 16128, 65280 },
651 { 32768, 16384, 45056, 28672, 35840, 19456, 48128, 31744,
652 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512 },
653 { 8192, 57344, 4096, 53248, 11264, 60416, 7168, 56320,
654 8960, 58112, 4864, 54016, 12032, 61184, 7936, 57088 },
655 { 40960, 24576, 36864, 20480, 44032, 27648, 39936, 23552,
656 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320 },
657 { 2048, 51200, 14336, 63488, 1024, 50176, 13312, 62464,
658 2816, 51968, 15104, 64256, 1792, 50944, 14080, 63232 },
659 { 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
660 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464 },
661 { 10240, 59392, 6144, 55296, 9216, 58368, 5120, 54272,
662 11008, 60160, 6912, 56064, 9984, 59136, 5888, 55040 },
663 { 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504,
664 43776, 27392, 39680, 23296, 42752, 26368, 38656, 22272 },
665 { 512, 49664, 12800, 61952, 3584, 52736, 15872, 65024,
666 256, 49408, 12544, 61696, 3328, 52480, 15616, 64768 },
667 { 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256,
668 33024, 16640, 45312, 28928, 36096, 19712, 48384, 32000 },
669 { 8704, 57856, 4608, 53760, 11776, 60928, 7680, 56832,
670 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576 },
671 { 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064,
672 41216, 24832, 37120, 20736, 44288, 27904, 40192, 23808 },
673 { 2560, 51712, 14848, 64000, 1536, 50688, 13824, 62976,
674 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720 },
675 { 35328, 18944, 47616, 31232, 34304, 17920, 46592, 30208,
676 35072, 18688, 47360, 30976, 34048, 17664, 46336, 29952 },
677 { 10752, 59904, 6656, 55808, 9728, 58880, 5632, 54784,
678 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528 },
679 { 43520, 27136, 39424, 23040, 42496, 26112, 38400, 22016,
680 43264, 26880, 39168, 22784, 42240, 25856, 38144, 21760 }
685 * Helper function for TrueColorDither and renderXImage
687 * This handles the proper setting of the image data based on the image depth
688 * and the machine's byte ordering
690 static void assignPixelData(unsigned int bit_depth
, unsigned char **data
,
691 unsigned long pixel
) {
692 unsigned char *pixel_data
= *data
;
695 pixel_data
[0] = pixel
;
699 case 16: // 16bpp LSB
700 pixel_data
[0] = pixel
;
701 pixel_data
[1] = pixel
>> 8;
705 case 17: // 16bpp MSB
706 pixel_data
[0] = pixel
>> 8;
707 pixel_data
[1] = pixel
;
711 case 24: // 24bpp LSB
712 pixel_data
[0] = pixel
;
713 pixel_data
[1] = pixel
>> 8;
714 pixel_data
[2] = pixel
>> 16;
718 case 25: // 24bpp MSB
719 pixel_data
[0] = pixel
>> 16;
720 pixel_data
[1] = pixel
>> 8;
721 pixel_data
[2] = pixel
;
725 case 32: // 32bpp LSB
726 pixel_data
[0] = pixel
;
727 pixel_data
[1] = pixel
>> 8;
728 pixel_data
[2] = pixel
>> 16;
729 pixel_data
[3] = pixel
>> 24;
733 case 33: // 32bpp MSB
734 pixel_data
[0] = pixel
>> 24;
735 pixel_data
[1] = pixel
>> 16;
736 pixel_data
[2] = pixel
>> 8;
737 pixel_data
[3] = pixel
;
741 *data
= pixel_data
; // assign back so we don't lose our place
745 // algorithm: ordered dithering... many many thanks to rasterman
746 // (raster@rasterman.com) for telling me about this... portions of this
747 // code is based off of his code in Imlib
748 void bt::Image::OrderedDither(XColorTable
*colortable
,
749 unsigned int bit_depth
,
750 unsigned int bytes_per_line
,
751 unsigned char *pixel_data
) {
752 unsigned int x
, y
, dithx
, dithy
, r
, g
, b
, error
, offset
;
753 unsigned char *ppixel_data
= pixel_data
;
755 unsigned int maxr
= 255, maxg
= 255, maxb
= 255;
756 colortable
->map(maxr
, maxg
, maxb
);
758 for (y
= 0, offset
= 0; y
< height
; ++y
) {
761 for (x
= 0; x
< width
; ++x
, ++offset
) {
764 error
= dither16
[dithy
][dithx
];
766 r
= (((256 * maxr
+ maxr
+ 1) * data
[offset
].red
+ error
) / 65536);
767 g
= (((256 * maxg
+ maxg
+ 1) * data
[offset
].green
+ error
) / 65536);
768 b
= (((256 * maxb
+ maxb
+ 1) * data
[offset
].blue
+ error
) / 65536);
770 assignPixelData(bit_depth
, &pixel_data
, colortable
->pixel(r
, g
, b
));
773 pixel_data
= (ppixel_data
+= bytes_per_line
);
778 void bt::Image::FloydSteinbergDither(XColorTable
*colortable
,
779 unsigned int bit_depth
,
780 unsigned int bytes_per_line
,
781 unsigned char *pixel_data
) {
782 int * const error
= new int[width
* 6];
783 int * const r_line1
= error
+ (width
* 0);
784 int * const g_line1
= error
+ (width
* 1);
785 int * const b_line1
= error
+ (width
* 2);
786 int * const r_line2
= error
+ (width
* 3);
787 int * const g_line2
= error
+ (width
* 4);
788 int * const b_line2
= error
+ (width
* 5);
791 unsigned int x
, y
, r
, g
, b
, offset
;
792 unsigned char *ppixel_data
= pixel_data
;
793 RGB
*pixels
= new RGB
[width
];
795 unsigned int maxr
= 255, maxg
= 255, maxb
= 255;
796 colortable
->map(maxr
, maxg
, maxb
);
801 for (y
= 0, offset
= 0; y
< height
; ++y
) {
802 const bool reverse
= bool(y
& 1);
804 int * const rl1
= (reverse
) ? r_line2
: r_line1
;
805 int * const gl1
= (reverse
) ? g_line2
: g_line1
;
806 int * const bl1
= (reverse
) ? b_line2
: b_line1
;
807 int * const rl2
= (reverse
) ? r_line1
: r_line2
;
808 int * const gl2
= (reverse
) ? g_line1
: g_line2
;
809 int * const bl2
= (reverse
) ? b_line1
: b_line2
;
812 for (x
= 0; x
< width
; ++x
) {
813 rl1
[x
] = static_cast<int>(data
[x
].red
);
814 gl1
[x
] = static_cast<int>(data
[x
].green
);
815 bl1
[x
] = static_cast<int>(data
[x
].blue
);
819 for (x
= 0; x
< width
; ++x
) {
820 rl2
[x
] = static_cast<int>(data
[offset
+ width
+ x
].red
);
821 gl2
[x
] = static_cast<int>(data
[offset
+ width
+ x
].green
);
822 bl2
[x
] = static_cast<int>(data
[offset
+ width
+ x
].blue
);
826 // bi-directional dither
828 for (x
= 0; x
< width
; ++x
) {
829 r
= static_cast<unsigned int>(std::max(std::min(rl1
[x
], 255), 0));
830 g
= static_cast<unsigned int>(std::max(std::min(gl1
[x
], 255), 0));
831 b
= static_cast<unsigned int>(std::max(std::min(bl1
[x
], 255), 0));
833 colortable
->map(r
, g
, b
);
839 rer
= rl1
[x
] - static_cast<int>(r
* maxr
);
840 ger
= gl1
[x
] - static_cast<int>(g
* maxg
);
841 ber
= bl1
[x
] - static_cast<int>(b
* maxb
);
844 rl1
[x
+1] += rer
* 7 / 16;
845 gl1
[x
+1] += ger
* 7 / 16;
846 bl1
[x
+1] += ber
* 7 / 16;
847 rl2
[x
+1] += rer
* 1 / 16;
848 gl2
[x
+1] += ger
* 1 / 16;
849 bl2
[x
+1] += ber
* 1 / 16;
851 rl2
[x
] += rer
* 5 / 16;
852 gl2
[x
] += ger
* 5 / 16;
853 bl2
[x
] += ber
* 5 / 16;
855 rl2
[x
-1] += rer
* 3 / 16;
856 gl2
[x
-1] += ger
* 3 / 16;
857 bl2
[x
-1] += ber
* 3 / 16;
861 for (x
= width
; x
-- > 0; ) {
862 r
= static_cast<unsigned int>(std::max(std::min(rl1
[x
], 255), 0));
863 g
= static_cast<unsigned int>(std::max(std::min(gl1
[x
], 255), 0));
864 b
= static_cast<unsigned int>(std::max(std::min(bl1
[x
], 255), 0));
866 colortable
->map(r
, g
, b
);
872 rer
= rl1
[x
] - static_cast<int>(r
* maxr
);
873 ger
= gl1
[x
] - static_cast<int>(g
* maxg
);
874 ber
= bl1
[x
] - static_cast<int>(b
* maxb
);
877 rl1
[x
-1] += rer
* 7 / 16;
878 gl1
[x
-1] += ger
* 7 / 16;
879 bl1
[x
-1] += ber
* 7 / 16;
880 rl2
[x
-1] += rer
* 1 / 16;
881 gl2
[x
-1] += ger
* 1 / 16;
882 bl2
[x
-1] += ber
* 1 / 16;
884 rl2
[x
] += rer
* 5 / 16;
885 gl2
[x
] += ger
* 5 / 16;
886 bl2
[x
] += ber
* 5 / 16;
888 rl2
[x
+1] += rer
* 3 / 16;
889 gl2
[x
+1] += ger
* 3 / 16;
890 bl2
[x
+1] += ber
* 3 / 16;
894 for (x
= 0; x
< width
; ++x
) {
898 assignPixelData(bit_depth
, &pixel_data
, colortable
->pixel(r
, g
, b
));
902 pixel_data
= (ppixel_data
+= bytes_per_line
);
910 Pixmap
bt::Image::renderPixmap(const Display
&display
, unsigned int screen
) {
911 // get the colortable for the screen. if necessary, we will create one.
912 if (colorTableList
.empty())
913 colorTableList
.resize(display
.screenCount(), 0);
915 if (!colorTableList
[screen
])
916 colorTableList
[screen
] = new XColorTable(display
, screen
, maximumColors());
918 XColorTable
*colortable
= colorTableList
[screen
];
919 const ScreenInfo
&screeninfo
= display
.screenInfo(screen
);
924 // try to use MIT-SHM extension
926 image
= createShmImage(display
, screeninfo
, width
, height
);
927 shm_ok
= (image
!= 0);
933 image
= XCreateImage(display
.XDisplay(), screeninfo
.visual(),
934 screeninfo
.depth(), ZPixmap
,
935 0, 0, width
, height
, 32, 0);
939 buffer
.reserve(image
->bytes_per_line
* (height
+ 1));
940 image
->data
= reinterpret_cast<char *>(&buffer
[0]);
943 unsigned char *d
= reinterpret_cast<unsigned char *>(image
->data
);
944 unsigned int o
= image
->bits_per_pixel
945 + ((image
->byte_order
== MSBFirst
) ? 1 : 0);
948 (width
> 1 && height
> 1) ? colortable
->ditherMode() : NoDither
;
952 case bt::FloydSteinbergDither
:
953 FloydSteinbergDither(colortable
, o
, image
->bytes_per_line
, d
);
956 case bt::OrderedDither
:
957 OrderedDither(colortable
, o
, image
->bytes_per_line
, d
);
961 unsigned int x
, y
, offset
, r
, g
, b
;
962 unsigned char *pixel_data
= d
, *ppixel_data
= d
;
964 for (y
= 0, offset
= 0; y
< height
; ++y
) {
965 for (x
= 0; x
< width
; ++x
, ++offset
) {
966 r
= data
[offset
].red
;
967 g
= data
[offset
].green
;
968 b
= data
[offset
].blue
;
970 colortable
->map(r
, g
, b
);
971 assignPixelData(o
, &pixel_data
, colortable
->pixel(r
, g
, b
));
974 pixel_data
= (ppixel_data
+= image
->bytes_per_line
);
980 Pixmap pixmap
= XCreatePixmap(display
.XDisplay(), screeninfo
.rootWindow(),
981 width
, height
, screeninfo
.depth());
982 if (pixmap
== None
) {
984 XDestroyImage(image
);
989 Pen
pen(screen
, Color(0, 0, 0));
993 // use MIT-SHM extension
994 XShmPutImage(pen
.XDisplay(), pixmap
, pen
.gc(), image
,
995 0, 0, 0, 0, width
, height
, False
);
997 destroyShmImage(display
, image
);
1002 XPutImage(pen
.XDisplay(), pixmap
, pen
.gc(), image
,
1003 0, 0, 0, 0, width
, height
);
1006 XDestroyImage(image
);
1013 void bt::Image::bevel(unsigned int border_width
) {
1014 if (width
<= 2 || height
<= 2 ||
1015 width
<= (border_width
* 4) || height
<= (border_width
* 4))
1018 RGB
*p
= data
+ (border_width
* width
) + border_width
;
1019 unsigned int w
= width
- (border_width
* 2);
1020 unsigned int h
= height
- (border_width
* 2) - 2;
1021 unsigned char rr
, gg
, bb
;
1025 rr
= p
->red
+ (p
->red
>> 1);
1026 gg
= p
->green
+ (p
->green
>> 1);
1027 bb
= p
->blue
+ (p
->blue
>> 1);
1043 p
+= border_width
+ border_width
;
1044 w
= width
- (border_width
* 2);
1046 // left and right of the bevel
1048 rr
= p
->red
+ (p
->red
>> 1);
1049 gg
= p
->green
+ (p
->green
>> 1);
1050 bb
= p
->blue
+ (p
->blue
>> 1);
1065 rr
= (p
->red
>> 2) + (p
->red
>> 1);
1066 gg
= (p
->green
>> 2) + (p
->green
>> 1);
1067 bb
= (p
->blue
>> 2) + (p
->blue
>> 1);
1080 p
+= border_width
+ border_width
+ 1;
1083 w
= width
- (border_width
* 2);
1085 // bottom of the bevel
1087 rr
= (p
->red
>> 2) + (p
->red
>> 1);
1088 gg
= (p
->green
>> 2) + (p
->green
>> 1);
1089 bb
= (p
->blue
>> 2) + (p
->blue
>> 1);
1107 void bt::Image::dgradient(const Color
&from
, const Color
&to
,
1109 // diagonal gradient code was written by Mike Cole <mike@mydot.com>
1110 // modified for interlacing by Brad Hughes
1112 double drx
, dgx
, dbx
, dry
, dgy
, dby
;
1113 double yr
= 0.0, yg
= 0.0, yb
= 0.0,
1114 xr
= static_cast<double>(from
.red()),
1115 xg
= static_cast<double>(from
.green()),
1116 xb
= static_cast<double>(from
.blue());
1119 unsigned int w
= width
* 2, h
= height
* 2;
1122 const unsigned int dimension
= std::max(width
, height
);
1123 unsigned int *alloc
= new unsigned int[dimension
* 6];
1124 unsigned int *xt
[3], *yt
[3];
1125 xt
[0] = alloc
+ (dimension
* 0);
1126 xt
[1] = alloc
+ (dimension
* 1);
1127 xt
[2] = alloc
+ (dimension
* 2);
1128 yt
[0] = alloc
+ (dimension
* 3);
1129 yt
[1] = alloc
+ (dimension
* 4);
1130 yt
[2] = alloc
+ (dimension
* 5);
1132 dry
= drx
= static_cast<double>(to
.red() - from
.red());
1133 dgy
= dgx
= static_cast<double>(to
.green() - from
.green());
1134 dby
= dbx
= static_cast<double>(to
.blue() - from
.blue());
1141 for (x
= 0; x
< width
; ++x
) {
1142 xt
[0][x
] = static_cast<unsigned char>(xr
);
1143 xt
[1][x
] = static_cast<unsigned char>(xg
);
1144 xt
[2][x
] = static_cast<unsigned char>(xb
);
1156 for (y
= 0; y
< height
; ++y
) {
1157 yt
[0][y
] = static_cast<unsigned char>(yr
);
1158 yt
[1][y
] = static_cast<unsigned char>(yg
);
1159 yt
[2][y
] = static_cast<unsigned char>(yb
);
1166 // Combine tables to create gradient
1170 for (y
= 0; y
< height
; ++y
) {
1171 for (x
= 0; x
< width
; ++x
, ++p
) {
1172 p
->red
= xt
[0][x
] + yt
[0][y
];
1173 p
->green
= xt
[1][x
] + yt
[1][y
];
1174 p
->blue
= xt
[2][x
] + yt
[2][y
];
1178 // interlacing effect
1179 for (y
= 0; y
< height
; ++y
) {
1180 for (x
= 0; x
< width
; ++x
, ++p
) {
1181 p
->red
= xt
[0][x
] + yt
[0][y
];
1182 p
->green
= xt
[1][x
] + yt
[1][y
];
1183 p
->blue
= xt
[2][x
] + yt
[2][y
];
1186 p
->red
= (p
->red
>> 1) + (p
->red
>> 2);
1187 p
->green
= (p
->green
>> 1) + (p
->green
>> 2);
1188 p
->blue
= (p
->blue
>> 1) + (p
->blue
>> 2);
1198 void bt::Image::hgradient(const Color
&from
, const Color
&to
,
1200 double drx
, dgx
, dbx
,
1201 xr
= static_cast<double>(from
.red()),
1202 xg
= static_cast<double>(from
.green()),
1203 xb
= static_cast<double>(from
.blue());
1205 unsigned int total
= width
* (height
- 2);
1208 drx
= static_cast<double>(to
.red() - from
.red());
1209 dgx
= static_cast<double>(to
.green() - from
.green());
1210 dbx
= static_cast<double>(to
.blue() - from
.blue());
1216 if (interlaced
&& height
> 1) {
1217 // interlacing effect
1220 for (x
= 0; x
< width
; ++x
, ++p
) {
1221 p
->red
= static_cast<unsigned char>(xr
);
1222 p
->green
= static_cast<unsigned char>(xg
);
1223 p
->blue
= static_cast<unsigned char>(xb
);
1231 xr
= static_cast<double>(from
.red()),
1232 xg
= static_cast<double>(from
.green()),
1233 xb
= static_cast<double>(from
.blue());
1235 for (x
= 0; x
< width
; ++x
, ++p
) {
1236 p
->red
= static_cast<unsigned char>(xr
);
1237 p
->green
= static_cast<unsigned char>(xg
);
1238 p
->blue
= static_cast<unsigned char>(xb
);
1240 p
->red
= (p
->red
>> 1) + (p
->red
>> 2);
1241 p
->green
= (p
->green
>> 1) + (p
->green
>> 2);
1242 p
->blue
= (p
->blue
>> 1) + (p
->blue
>> 2);
1250 for (x
= 0; x
< width
; ++x
, ++p
) {
1251 p
->red
= static_cast<unsigned char>(xr
);
1252 p
->green
= static_cast<unsigned char>(xg
);
1253 p
->blue
= static_cast<unsigned char>(xb
);
1262 memcpy(p
, data
, width
* sizeof(RGB
));
1267 // rest of the gradient
1268 for (x
= 0; x
< total
; ++x
)
1273 void bt::Image::vgradient(const Color
&from
, const Color
&to
,
1275 double dry
, dgy
, dby
,
1276 yr
= static_cast<double>(from
.red() ),
1277 yg
= static_cast<double>(from
.green()),
1278 yb
= static_cast<double>(from
.blue() );
1282 dry
= static_cast<double>(to
.red() - from
.red() );
1283 dgy
= static_cast<double>(to
.green() - from
.green());
1284 dby
= static_cast<double>(to
.blue() - from
.blue() );
1291 // faked interlacing effect
1292 for (y
= 0; y
< height
; ++y
) {
1294 static_cast<unsigned char>((y
& 1) ? (yr
* 3. / 4.) : yr
),
1295 static_cast<unsigned char>((y
& 1) ? (yg
* 3. / 4.) : yg
),
1296 static_cast<unsigned char>((y
& 1) ? (yb
* 3. / 4.) : yb
),
1299 for (x
= 0; x
< width
; ++x
, ++p
)
1308 for (y
= 0; y
< height
; ++y
) {
1310 static_cast<unsigned char>(yr
),
1311 static_cast<unsigned char>(yg
),
1312 static_cast<unsigned char>(yb
),
1315 for (x
= 0; x
< width
; ++x
, ++p
)
1326 void bt::Image::pgradient(const Color
&from
, const Color
&to
,
1328 // pyramid gradient - based on original dgradient, written by
1329 // Mosfet (mosfet@kde.org)
1330 // adapted from kde sources for Blackbox by Brad Hughes
1332 double yr
, yg
, yb
, drx
, dgx
, dbx
, dry
, dgy
, dby
, xr
, xg
, xb
;
1333 int rsign
, gsign
, bsign
;
1335 unsigned int tr
= to
.red(), tg
= to
.green(), tb
= to
.blue();
1338 const unsigned int dimension
= std::max(width
, height
);
1339 unsigned int *alloc
= new unsigned int[dimension
* 6];
1340 unsigned int *xt
[3], *yt
[3];
1341 xt
[0] = alloc
+ (dimension
* 0);
1342 xt
[1] = alloc
+ (dimension
* 1);
1343 xt
[2] = alloc
+ (dimension
* 2);
1344 yt
[0] = alloc
+ (dimension
* 3);
1345 yt
[1] = alloc
+ (dimension
* 4);
1346 yt
[2] = alloc
+ (dimension
* 5);
1348 dry
= drx
= static_cast<double>(to
.red() - from
.red());
1349 dgy
= dgx
= static_cast<double>(to
.green() - from
.green());
1350 dby
= dbx
= static_cast<double>(to
.blue() - from
.blue());
1352 rsign
= (drx
< 0) ? -1 : 1;
1353 gsign
= (dgx
< 0) ? -1 : 1;
1354 bsign
= (dbx
< 0) ? -1 : 1;
1356 xr
= yr
= (drx
/ 2);
1357 xg
= yg
= (dgx
/ 2);
1358 xb
= yb
= (dbx
/ 2);
1365 for (x
= 0; x
< width
; ++x
) {
1366 xt
[0][x
] = static_cast<unsigned char>(fabs(xr
));
1367 xt
[1][x
] = static_cast<unsigned char>(fabs(xg
));
1368 xt
[2][x
] = static_cast<unsigned char>(fabs(xb
));
1380 for (y
= 0; y
< height
; ++y
) {
1381 yt
[0][y
] = static_cast<unsigned char>(fabs(yr
));
1382 yt
[1][y
] = static_cast<unsigned char>(fabs(yg
));
1383 yt
[2][y
] = static_cast<unsigned char>(fabs(yb
));
1390 // Combine tables to create gradient
1394 for (y
= 0; y
< height
; ++y
) {
1395 for (x
= 0; x
< width
; ++x
, ++p
) {
1397 static_cast<unsigned char>(tr
- (rsign
* (xt
[0][x
] + yt
[0][y
])));
1399 static_cast<unsigned char>(tg
- (gsign
* (xt
[1][x
] + yt
[1][y
])));
1401 static_cast<unsigned char>(tb
- (bsign
* (xt
[2][x
] + yt
[2][y
])));
1405 // interlacing effect
1406 for (y
= 0; y
< height
; ++y
) {
1407 for (x
= 0; x
< width
; ++x
, ++p
) {
1409 static_cast<unsigned char>(tr
- (rsign
* (xt
[0][x
] + yt
[0][y
])));
1411 static_cast<unsigned char>(tg
- (gsign
* (xt
[1][x
] + yt
[1][y
])));
1413 static_cast<unsigned char>(tb
- (bsign
* (xt
[2][x
] + yt
[2][y
])));
1416 p
->red
= (p
->red
>> 1) + (p
->red
>> 2);
1417 p
->green
= (p
->green
>> 1) + (p
->green
>> 2);
1418 p
->blue
= (p
->blue
>> 1) + (p
->blue
>> 2);
1428 void bt::Image::rgradient(const Color
&from
, const Color
&to
,
1430 // rectangle gradient - based on original dgradient, written by
1431 // Mosfet (mosfet@kde.org)
1432 // adapted from kde sources for Blackbox by Brad Hughes
1434 double drx
, dgx
, dbx
, dry
, dgy
, dby
, xr
, xg
, xb
, yr
, yg
, yb
;
1435 int rsign
, gsign
, bsign
;
1437 unsigned int tr
= to
.red(), tg
= to
.green(), tb
= to
.blue();
1440 const unsigned int dimension
= std::max(width
, height
);
1441 unsigned int *alloc
= new unsigned int[dimension
* 6];
1442 unsigned int *xt
[3], *yt
[3];
1443 xt
[0] = alloc
+ (dimension
* 0);
1444 xt
[1] = alloc
+ (dimension
* 1);
1445 xt
[2] = alloc
+ (dimension
* 2);
1446 yt
[0] = alloc
+ (dimension
* 3);
1447 yt
[1] = alloc
+ (dimension
* 4);
1448 yt
[2] = alloc
+ (dimension
* 5);
1450 dry
= drx
= static_cast<double>(to
.red() - from
.red());
1451 dgy
= dgx
= static_cast<double>(to
.green() - from
.green());
1452 dby
= dbx
= static_cast<double>(to
.blue() - from
.blue());
1454 rsign
= (drx
< 0) ? -2 : 2;
1455 gsign
= (dgx
< 0) ? -2 : 2;
1456 bsign
= (dbx
< 0) ? -2 : 2;
1458 xr
= yr
= (drx
/ 2);
1459 xg
= yg
= (dgx
/ 2);
1460 xb
= yb
= (dbx
/ 2);
1467 for (x
= 0; x
< width
; ++x
) {
1468 xt
[0][x
] = static_cast<unsigned char>(fabs(xr
));
1469 xt
[1][x
] = static_cast<unsigned char>(fabs(xg
));
1470 xt
[2][x
] = static_cast<unsigned char>(fabs(xb
));
1482 for (y
= 0; y
< height
; ++y
) {
1483 yt
[0][y
] = static_cast<unsigned char>(fabs(yr
));
1484 yt
[1][y
] = static_cast<unsigned char>(fabs(yg
));
1485 yt
[2][y
] = static_cast<unsigned char>(fabs(yb
));
1492 // Combine tables to create gradient
1496 for (y
= 0; y
< height
; ++y
) {
1497 for (x
= 0; x
< width
; ++x
, ++p
) {
1499 static_cast<unsigned char>(tr
- (rsign
*
1500 std::max(xt
[0][x
], yt
[0][y
])));
1502 static_cast<unsigned char>(tg
- (gsign
*
1503 std::max(xt
[1][x
], yt
[1][y
])));
1505 static_cast<unsigned char>(tb
- (bsign
*
1506 std::max(xt
[2][x
], yt
[2][y
])));
1510 // interlacing effect
1511 for (y
= 0; y
< height
; ++y
) {
1512 for (x
= 0; x
< width
; ++x
, ++p
) {
1514 static_cast<unsigned char>(tr
- (rsign
*
1515 std::max(xt
[0][x
], yt
[0][y
])));
1517 static_cast<unsigned char>(tg
- (gsign
*
1518 std::max(xt
[1][x
], yt
[1][y
])));
1520 static_cast<unsigned char>(tb
- (bsign
*
1521 std::max(xt
[2][x
], yt
[2][y
])));
1524 p
->red
= (p
->red
>> 1) + (p
->red
>> 2);
1525 p
->green
= (p
->green
>> 1) + (p
->green
>> 2);
1526 p
->blue
= (p
->blue
>> 1) + (p
->blue
>> 2);
1536 void bt::Image::egradient(const Color
&from
, const Color
&to
,
1538 // elliptic gradient - based on original dgradient, written by
1539 // Mosfet (mosfet@kde.org)
1540 // adapted from kde sources for Blackbox by Brad Hughes
1542 double drx
, dgx
, dbx
, dry
, dgy
, dby
, yr
, yg
, yb
, xr
, xg
, xb
;
1543 int rsign
, gsign
, bsign
;
1545 unsigned int tr
= to
.red(), tg
= to
.green(), tb
= to
.blue();
1548 const unsigned int dimension
= std::max(width
, height
);
1549 unsigned int *alloc
= new unsigned int[dimension
* 6];
1550 unsigned int *xt
[3], *yt
[3];
1551 xt
[0] = alloc
+ (dimension
* 0);
1552 xt
[1] = alloc
+ (dimension
* 1);
1553 xt
[2] = alloc
+ (dimension
* 2);
1554 yt
[0] = alloc
+ (dimension
* 3);
1555 yt
[1] = alloc
+ (dimension
* 4);
1556 yt
[2] = alloc
+ (dimension
* 5);
1558 dry
= drx
= static_cast<double>(to
.red() - from
.red());
1559 dgy
= dgx
= static_cast<double>(to
.green() - from
.green());
1560 dby
= dbx
= static_cast<double>(to
.blue() - from
.blue());
1562 rsign
= (drx
< 0) ? -1 : 1;
1563 gsign
= (dgx
< 0) ? -1 : 1;
1564 bsign
= (dbx
< 0) ? -1 : 1;
1566 xr
= yr
= (drx
/ 2);
1567 xg
= yg
= (dgx
/ 2);
1568 xb
= yb
= (dbx
/ 2);
1575 for (x
= 0; x
< width
; x
++) {
1576 xt
[0][x
] = static_cast<unsigned int>(xr
* xr
);
1577 xt
[1][x
] = static_cast<unsigned int>(xg
* xg
);
1578 xt
[2][x
] = static_cast<unsigned int>(xb
* xb
);
1590 for (y
= 0; y
< height
; y
++) {
1591 yt
[0][y
] = static_cast<unsigned int>(yr
* yr
);
1592 yt
[1][y
] = static_cast<unsigned int>(yg
* yg
);
1593 yt
[2][y
] = static_cast<unsigned int>(yb
* yb
);
1600 // Combine tables to create gradient
1604 for (y
= 0; y
< height
; ++y
) {
1605 for (x
= 0; x
< width
; ++x
, ++p
) {
1606 p
->red
= static_cast<unsigned char>
1607 (tr
- (rsign
* static_cast<int>(sqrt(xt
[0][x
] +
1609 p
->green
= static_cast<unsigned char>
1610 (tg
- (gsign
* static_cast<int>(sqrt(xt
[1][x
] +
1612 p
->blue
= static_cast<unsigned char>
1613 (tb
- (bsign
* static_cast<int>(sqrt(xt
[2][x
] +
1618 // interlacing effect
1619 for (y
= 0; y
< height
; ++y
) {
1620 for (x
= 0; x
< width
; ++x
, ++p
) {
1621 p
->red
= static_cast<unsigned char>
1622 (tr
- (rsign
* static_cast<int>(sqrt(xt
[0][x
]
1624 p
->green
= static_cast<unsigned char>
1625 (tg
- (gsign
* static_cast<int>(sqrt(xt
[1][x
]
1627 p
->blue
= static_cast<unsigned char>
1628 (tb
- (bsign
* static_cast<int>(sqrt(xt
[2][x
]
1632 p
->red
= (p
->red
>> 1) + (p
->red
>> 2);
1633 p
->green
= (p
->green
>> 1) + (p
->green
>> 2);
1634 p
->blue
= (p
->blue
>> 1) + (p
->blue
>> 2);
1644 void bt::Image::pcgradient(const Color
&from
, const Color
&to
,
1646 // pipe cross gradient - based on original dgradient, written by
1647 // Mosfet (mosfet@kde.org)
1648 // adapted from kde sources for Blackbox by Brad Hughes
1650 double drx
, dgx
, dbx
, dry
, dgy
, dby
, xr
, xg
, xb
, yr
, yg
, yb
;
1651 int rsign
, gsign
, bsign
;
1653 unsigned int tr
= to
.red(), tg
= to
.green(), tb
= to
.blue();
1656 const unsigned int dimension
= std::max(width
, height
);
1657 unsigned int *alloc
= new unsigned int[dimension
* 6];
1658 unsigned int *xt
[3], *yt
[3];
1659 xt
[0] = alloc
+ (dimension
* 0);
1660 xt
[1] = alloc
+ (dimension
* 1);
1661 xt
[2] = alloc
+ (dimension
* 2);
1662 yt
[0] = alloc
+ (dimension
* 3);
1663 yt
[1] = alloc
+ (dimension
* 4);
1664 yt
[2] = alloc
+ (dimension
* 5);
1666 dry
= drx
= static_cast<double>(to
.red() - from
.red());
1667 dgy
= dgx
= static_cast<double>(to
.green() - from
.green());
1668 dby
= dbx
= static_cast<double>(to
.blue() - from
.blue());
1670 rsign
= (drx
< 0) ? -2 : 2;
1671 gsign
= (dgx
< 0) ? -2 : 2;
1672 bsign
= (dbx
< 0) ? -2 : 2;
1674 xr
= yr
= (drx
/ 2);
1675 xg
= yg
= (dgx
/ 2);
1676 xb
= yb
= (dbx
/ 2);
1683 for (x
= 0; x
< width
; ++x
) {
1684 xt
[0][x
] = static_cast<unsigned char>(fabs(xr
));
1685 xt
[1][x
] = static_cast<unsigned char>(fabs(xg
));
1686 xt
[2][x
] = static_cast<unsigned char>(fabs(xb
));
1698 for (y
= 0; y
< height
; ++y
) {
1699 yt
[0][y
] = static_cast<unsigned char>(fabs(yr
));
1700 yt
[1][y
] = static_cast<unsigned char>(fabs(yg
));
1701 yt
[2][y
] = static_cast<unsigned char>(fabs(yb
));
1708 // Combine tables to create gradient
1712 for (y
= 0; y
< height
; ++y
) {
1713 for (x
= 0; x
< width
; ++x
, ++p
) {
1715 static_cast<unsigned char>(tr
- (rsign
*
1716 std::min(xt
[0][x
], yt
[0][y
])));
1718 static_cast<unsigned char>(tg
- (gsign
*
1719 std::min(xt
[1][x
], yt
[1][y
])));
1721 static_cast<unsigned char>(tb
- (bsign
*
1722 std::min(xt
[2][x
], yt
[2][y
])));
1726 // interlacing effect
1727 for (y
= 0; y
< height
; ++y
) {
1728 for (x
= 0; x
< width
; ++x
, ++p
) {
1730 static_cast<unsigned char>(tr
- (rsign
*
1731 std::min(xt
[0][x
], yt
[0][y
])));
1733 static_cast<unsigned char>(tg
- (gsign
*
1734 std::min(xt
[1][x
], yt
[1][y
])));
1736 static_cast<unsigned char>(tb
- (bsign
*
1737 std::min(xt
[2][x
], yt
[2][y
])));
1740 p
->red
= (p
->red
>> 1) + (p
->red
>> 2);
1741 p
->green
= (p
->green
>> 1) + (p
->green
>> 2);
1742 p
->blue
= (p
->blue
>> 1) + (p
->blue
>> 2);
1752 void bt::Image::cdgradient(const Color
&from
, const Color
&to
,
1754 // cross diagonal gradient - based on original dgradient, written by
1755 // Mosfet (mosfet@kde.org)
1756 // adapted from kde sources for Blackbox by Brad Hughes
1758 double drx
, dgx
, dbx
, dry
, dgy
, dby
;
1759 double yr
= 0.0, yg
= 0.0, yb
= 0.0,
1760 xr
= static_cast<double>(from
.red() ),
1761 xg
= static_cast<double>(from
.green()),
1762 xb
= static_cast<double>(from
.blue() );
1764 unsigned int w
= width
* 2, h
= height
* 2;
1767 const unsigned int dimension
= std::max(width
, height
);
1768 unsigned int *alloc
= new unsigned int[dimension
* 6];
1769 unsigned int *xt
[3], *yt
[3];
1770 xt
[0] = alloc
+ (dimension
* 0);
1771 xt
[1] = alloc
+ (dimension
* 1);
1772 xt
[2] = alloc
+ (dimension
* 2);
1773 yt
[0] = alloc
+ (dimension
* 3);
1774 yt
[1] = alloc
+ (dimension
* 4);
1775 yt
[2] = alloc
+ (dimension
* 5);
1777 dry
= drx
= static_cast<double>(to
.red() - from
.red() );
1778 dgy
= dgx
= static_cast<double>(to
.green() - from
.green());
1779 dby
= dbx
= static_cast<double>(to
.blue() - from
.blue() );
1786 for (x
= width
- 1; x
!= 0; --x
) {
1787 xt
[0][x
] = static_cast<unsigned char>(xr
);
1788 xt
[1][x
] = static_cast<unsigned char>(xg
);
1789 xt
[2][x
] = static_cast<unsigned char>(xb
);
1796 xt
[0][x
] = static_cast<unsigned char>(xr
);
1797 xt
[1][x
] = static_cast<unsigned char>(xg
);
1798 xt
[2][x
] = static_cast<unsigned char>(xb
);
1805 for (y
= 0; y
< height
; ++y
) {
1806 yt
[0][y
] = static_cast<unsigned char>(yr
);
1807 yt
[1][y
] = static_cast<unsigned char>(yg
);
1808 yt
[2][y
] = static_cast<unsigned char>(yb
);
1815 // Combine tables to create gradient
1819 for (y
= 0; y
< height
; ++y
) {
1820 for (x
= 0; x
< width
; ++x
, ++p
) {
1821 p
->red
= xt
[0][x
] + yt
[0][y
];
1822 p
->green
= xt
[1][x
] + yt
[1][y
];
1823 p
->blue
= xt
[2][x
] + yt
[2][y
];
1827 // interlacing effect
1828 for (y
= 0; y
< height
; ++y
) {
1829 for (x
= 0; x
< width
; ++x
, ++p
) {
1830 p
->red
= xt
[0][x
] + yt
[0][y
];
1831 p
->green
= xt
[1][x
] + yt
[1][y
];
1832 p
->blue
= xt
[2][x
] + yt
[2][y
];
1835 p
->red
= (p
->red
>> 1) + (p
->red
>> 2);
1836 p
->green
= (p
->green
>> 1) + (p
->green
>> 2);
1837 p
->blue
= (p
->blue
>> 1) + (p
->blue
>> 2);