]> icculus.org git repositories - dana/openbox.git/blob - render2/color.c
add pixmap to rgba converter
[dana/openbox.git] / render2 / color.c
1 #include <glib.h>
2 #include "render.h"
3 #include "instance.h"
4 #include "debug.h"
5 #include "color.h"
6 #include <X11/Xlib.h>
7
8 void RrColorInspect(struct RrInstance *i)
9 {
10     unsigned long red_mask, green_mask, blue_mask;
11     XImage *timage = NULL;
12     timage = XCreateImage(i->display, i->visual, i->depth,
13                           ZPixmap, 0, NULL, 1, 1, 32, 0);
14     g_assert(timage != NULL);
15     /* find the offsets for each color in the visual's masks */
16     i->red_mask = red_mask = timage->red_mask;
17     i->green_mask = green_mask = timage->green_mask;
18     i->blue_mask = blue_mask = timage->blue_mask;
19     i->red_offset = 0;
20     i->green_offset = 0;
21     i->blue_offset = 0;
22     while (! (red_mask & 1))   { i->red_offset++;   red_mask   >>= 1; }
23     while (! (green_mask & 1)) { i->green_offset++; green_mask >>= 1; }
24     while (! (blue_mask & 1))  { i->blue_offset++;  blue_mask  >>= 1; }
25     i->red_shift = i->green_shift = i->blue_shift = 8;
26     while (red_mask)   { red_mask   >>= 1; i->red_shift--;   }
27     while (green_mask) { green_mask >>= 1; i->green_shift--; }
28     while (blue_mask)  { blue_mask  >>= 1; i->blue_shift--;  }
29     XFree(timage);
30 }
31
32 int RrColorParse(struct RrInstance *inst, const char *colorname,
33                  struct RrColor *ret)
34 {
35     XColor xcol;
36
37     if (!XParseColor(RrDisplay(inst), RrColormap(inst), colorname, &xcol)) {
38         RrDebug("unable to parse color '%s'", colorname);
39         ret->r = 0.0;
40         ret->g = 0.0;
41         ret->b = 0.0;
42         ret->a = 0.0;
43         return 0;
44     }
45     ret->r = (xcol.red >> 8) / 255.0;
46     ret->g = (xcol.green >> 8) / 255.0;
47     ret->b = (xcol.blue >> 8) / 255.0;
48     ret->a = 0.0;
49     return 1;
50 }
51
52 static void swap_byte_order(XImage *im)
53 {
54     int x, y, di;
55
56     g_message("SWAPPING BYTE ORDER");
57
58     di = 0;
59     for (y = 0; y < im->height; ++y) {
60         for (x = 0; x < im->height; ++x) {
61             char *c = &im->data[di + x * im->bits_per_pixel / 8];
62             char t;
63
64             switch (im->bits_per_pixel) {
65             case 32:
66                 t = c[2];
67                 c[2] = c[3];
68                 c[3] = t;
69             case 16:
70                 t = c[0];
71                 c[0] = c[1];
72                 c[1] = t;
73             case 8:
74                 break;
75             default:
76                 g_message("your bit depth is currently unhandled\n");
77             }
78         }
79         di += im->bytes_per_line;
80     }
81
82     if (im->byte_order == LSBFirst)
83         im->byte_order = MSBFirst;
84     else
85         im->byte_order = LSBFirst;
86 }
87
88 void RrIncreaseDepth(struct RrInstance *i, RrData32 *data, XImage *im)
89 {
90     int r, g, b;
91     int x,y;
92     RrData32 *p32 = (RrData32 *) im->data;
93     guint16 *p16 = (guint16 *) im->data;
94     unsigned char *p8 = (unsigned char *)im->data;
95
96     if (im->byte_order != render_endian)
97         swap_byte_order(im);
98
99     switch (im->bits_per_pixel) {
100     case 32:
101         for (y = 0; y < im->height; y++) {
102             for (x = 0; x < im->width; x++) {
103                 r = (p32[x] >> i->red_offset) & 0xff;
104                 g = (p32[x] >> i->green_offset) & 0xff;
105                 b = (p32[x] >> i->blue_offset) & 0xff;
106                 data[x] = (r << default_red_offset)
107                     + (g << default_green_offset)
108                     + (b << default_blue_offset)
109                     + (0xff << default_alpha_offset);
110             }
111             data += im->width;
112             p32 += im->bytes_per_line/4;
113         }
114         break;
115     case 16:
116         for (y = 0; y < im->height; y++) {
117             for (x = 0; x < im->width; x++) {
118                 r = (p16[x] & i->red_mask) >> i->red_offset <<
119                     i->red_shift;
120                 g = (p16[x] & i->green_mask) >> i->green_offset <<
121                     i->green_shift;
122                 b = (p16[x] & i->blue_mask) >> i->blue_offset <<
123                     i->blue_shift;
124                 data[x] = (r << default_red_offset)
125                     + (g << default_green_offset)
126                     + (b << default_blue_offset)
127                     + (0xff << default_alpha_offset);
128             }
129             data += im->width;
130             p16 += im->bytes_per_line/2;
131         }
132         break;
133     case 8:
134         g_message("this image bit depth is currently unhandled\n");
135         break;
136     case 1:
137         for (y = 0; y < im->height; y++) {
138             for (x = 0; x < im->width; x++) {
139                 if (!(((p8[x / 8]) >> (x % 8)) & 0x1))
140                     data[x] = 0xff << default_alpha_offset; /* black */
141                 else
142                     data[x] = 0xffffffff; /* white */
143             }
144             data += im->width;
145             p8 += im->bytes_per_line;
146         }
147         break;
148     default:
149         g_message("this image bit depth is currently unhandled\n");
150     }
151 }
152
153
154 gboolean RrPixmapToRGBA(struct RrInstance *inst, Pixmap pmap, 
155                                Pixmap mask, int *w, int *h, RrData32 **data)
156 {
157     Window xr;
158     int xx, xy;
159     guint pw, ph, mw, mh, xb, xd, i, x, y, di;
160     XImage *xi, *xm = NULL;
161     if (!XGetGeometry(inst->display, pmap, &xr, &xx, &xy, &pw, &ph, &xb, &xd))
162         return FALSE;
163     if (mask) {
164         if (!XGetGeometry(inst->display, mask,
165                           &xr, &xx, &xy, &mw, &mh, &xb, &xd))
166             return FALSE;
167         if (pw != mw || ph != mh || xd != 1)
168             return FALSE;
169     }
170     xi = XGetImage(inst->display, pmap, 0, 0, pw, ph, 0xffffffff, ZPixmap);
171     if (!xi)
172         return FALSE;
173     if (mask) {
174         xm = XGetImage(inst->display, mask, 0, 0, mw, mh, 0xffffffff, ZPixmap);
175         if (!xm)
176             return FALSE;
177     }
178     *data = g_new(RrData32, pw * ph);
179     RrIncreaseDepth(inst, *data, xi);
180     if (mask) {
181         /* apply transparency from the mask */
182         di = 0;
183         for (i = 0, y = 0; y < ph; ++y) {
184             for (x = 0; x < pw; ++x, ++i) {
185                 if (!((((unsigned)xm->data[di + x / 8]) >> (x % 8)) & 0x1))
186                     (*data)[i] &= ~(0xff << default_alpha_offset);
187             }
188             di += xm->bytes_per_line;
189         }
190     }
191     *w = pw;
192     *h = ph;
193     return TRUE;
194 }