1 //
2 // "$Id: fl_read_image.cxx 6475 2008-10-19 20:35:32Z matt $"
3 //
4 // X11 image reading routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2005 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 // http://www.fltk.org/str.php
26 //
27
28 #include <FL/x.H>
29 #include <FL/Fl.H>
30 #include <FL/fl_draw.H>
31 #include "flstring.h"
32
33 #ifdef DEBUG
34 # include <stdio.h>
35 #endif // DEBUG
36
37 #ifdef WIN32
38 # include "fl_read_image_win32.cxx"
39 #elif defined(__APPLE__)
40 # include "fl_read_image_mac.cxx"
41 #else
42 # include <X11/Xutil.h>
43 # ifdef __sgi
44 # include <X11/extensions/readdisplay.h>
45 # else
46 # include <stdlib.h>
47 # endif // __sgi
48
49 // Defined in fl_color.cxx
50 extern uchar fl_redmask, fl_greenmask, fl_bluemask;
51 extern int fl_redshift, fl_greenshift, fl_blueshift, fl_extrashift;
52
53 //
54 // 'fl_subimage_offsets()' - Calculate subimage offsets for an axis
55 static inline int
fl_subimage_offsets(int a,int aw,int b,int bw,int & obw)56 fl_subimage_offsets(int a, int aw, int b, int bw, int &obw)
57 {
58 int off;
59 int ob;
60
61 if (b >= a) {
62 ob = b;
63 off = 0;
64 } else {
65 ob = a;
66 off = a - b;
67 }
68
69 bw -= off;
70
71 if (ob + bw <= a + aw) {
72 obw = bw;
73 } else {
74 obw = (a + aw) - ob;
75 }
76
77 return off;
78 }
79
80 // this handler will catch and ignore exceptions during XGetImage
81 // to avoid an application crash
xgetimageerrhandler(Display * display,XErrorEvent * error)82 static int xgetimageerrhandler(Display *display, XErrorEvent *error) {
83 return 0;
84 }
85
86 //
87 // 'fl_read_image()' - Read an image from the current window.
88 //
89
90 uchar * // O - Pixel buffer or NULL if failed
fl_read_image(uchar * p,int X,int Y,int w,int h,int alpha)91 fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate
92 int X, // I - Left position
93 int Y, // I - Top position
94 int w, // I - Width of area to read
95 int h, // I - Height of area to read
96 int alpha) { // I - Alpha value for image (0 for none)
97 XImage *image; // Captured image
98 int i, maxindex; // Looping vars
99 int x, y; // Current X & Y in image
100 int d; // Depth of image
101 unsigned char *line, // Array to hold image row
102 *line_ptr; // Pointer to current line image
103 unsigned char *pixel; // Current color value
104 XColor colors[4096]; // Colors from the colormap...
105 unsigned char cvals[4096][3]; // Color values from the colormap...
106 unsigned index_mask,
107 index_shift,
108 red_mask,
109 red_shift,
110 green_mask,
111 green_shift,
112 blue_mask,
113 blue_shift;
114
115
116 //
117 // Under X11 we have the option of the XGetImage() interface or SGI's
118 // ReadDisplay extension which does all of the really hard work for
119 // us...
120 //
121
122 # ifdef __sgi
123 if (XReadDisplayQueryExtension(fl_display, &i, &i)) {
124 image = XReadDisplay(fl_display, fl_window, X, Y, w, h, 0, NULL);
125 } else
126 # else
127 image = 0;
128 # endif // __sgi
129
130 if (!image) {
131 // fetch absolute coordinates
132 int dx, dy, sx, sy, sw, sh;
133 Window child_win;
134 Fl_Window *win = fl_find(fl_window);
135 if (win) {
136 XTranslateCoordinates(fl_display, fl_window,
137 RootWindow(fl_display, fl_screen), X, Y, &dx, &dy, &child_win);
138 // screen dimensions
139 Fl::screen_xywh(sx, sy, sw, sh, fl_screen);
140 }
141 if (!win || (dx >= sx && dy >= sy && dx + w <= sw && dy + h <= sh)) {
142 // the image is fully contained, we can use the traditional method
143 // however, if the window is obscured etc. the function will still fail. Make sure we
144 // catch the error and continue, otherwise an exception will be thrown.
145 XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
146 image = XGetImage(fl_display, fl_window, X, Y, w, h, AllPlanes, ZPixmap);
147 XSetErrorHandler(old_handler);
148 } else {
149 // image is crossing borders, determine visible region
150 int nw, nh, noffx, noffy;
151 noffx = fl_subimage_offsets(sx, sw, dx, w, nw);
152 noffy = fl_subimage_offsets(sy, sh, dy, h, nh);
153 if (nw <= 0 || nh <= 0) return 0;
154
155 // allocate the image
156 int bpp = fl_visual->depth + ((fl_visual->depth / 8) % 2) * 8;
157 char* buf = (char*)malloc(bpp / 8 * w * h);
158 image = XCreateImage(fl_display, fl_visual->visual,
159 fl_visual->depth, ZPixmap, 0, buf, w, h, bpp, 0);
160 if (!image) {
161 if (buf) free(buf);
162 return 0;
163 }
164
165 XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
166 XImage *subimg = XGetSubImage(fl_display, fl_window, X + noffx, Y + noffy,
167 nw, nh, AllPlanes, ZPixmap, image, noffx, noffy);
168 XSetErrorHandler(old_handler);
169 if (!subimg) {
170 XDestroyImage(image);
171 return 0;
172 }
173 }
174 }
175
176 if (!image) return 0;
177
178 #ifdef DEBUG
179 printf("width = %d\n", image->width);
180 printf("height = %d\n", image->height);
181 printf("xoffset = %d\n", image->xoffset);
182 printf("format = %d\n", image->format);
183 printf("data = %p\n", image->data);
184 printf("byte_order = %d\n", image->byte_order);
185 printf("bitmap_unit = %d\n", image->bitmap_unit);
186 printf("bitmap_bit_order = %d\n", image->bitmap_bit_order);
187 printf("bitmap_pad = %d\n", image->bitmap_pad);
188 printf("depth = %d\n", image->depth);
189 printf("bytes_per_line = %d\n", image->bytes_per_line);
190 printf("bits_per_pixel = %d\n", image->bits_per_pixel);
191 printf("red_mask = %08x\n", image->red_mask);
192 printf("green_mask = %08x\n", image->green_mask);
193 printf("blue_mask = %08x\n", image->blue_mask);
194 printf("map_entries = %d\n", fl_visual->visual->map_entries);
195 #endif // DEBUG
196
197 d = alpha ? 4 : 3;
198
199 // Allocate the image data array as needed...
200 if (!p) p = new uchar[w * h * d];
201
202 // Initialize the default colors/alpha in the whole image...
203 memset(p, alpha, w * h * d);
204
205 // Check that we have valid mask/shift values...
206 if (!image->red_mask && image->bits_per_pixel > 12) {
207 // Greater than 12 bits must be TrueColor...
208 image->red_mask = fl_visual->visual->red_mask;
209 image->green_mask = fl_visual->visual->green_mask;
210 image->blue_mask = fl_visual->visual->blue_mask;
211
212 #ifdef DEBUG
213 puts("\n---- UPDATED ----");
214 printf("fl_redmask = %08x\n", fl_redmask);
215 printf("fl_redshift = %d\n", fl_redshift);
216 printf("fl_greenmask = %08x\n", fl_greenmask);
217 printf("fl_greenshift = %d\n", fl_greenshift);
218 printf("fl_bluemask = %08x\n", fl_bluemask);
219 printf("fl_blueshift = %d\n", fl_blueshift);
220 printf("red_mask = %08x\n", image->red_mask);
221 printf("green_mask = %08x\n", image->green_mask);
222 printf("blue_mask = %08x\n", image->blue_mask);
223 #endif // DEBUG
224 }
225
226 // Check if we have colormap image...
227 if (!image->red_mask) {
228 // Get the colormap entries for this window...
229 maxindex = fl_visual->visual->map_entries;
230
231 for (i = 0; i < maxindex; i ++) colors[i].pixel = i;
232
233 XQueryColors(fl_display, fl_colormap, colors, maxindex);
234
235 for (i = 0; i < maxindex; i ++) {
236 cvals[i][0] = colors[i].red >> 8;
237 cvals[i][1] = colors[i].green >> 8;
238 cvals[i][2] = colors[i].blue >> 8;
239 }
240
241 // Read the pixels and output an RGB image...
242 for (y = 0; y < image->height; y ++) {
243 pixel = (unsigned char *)(image->data + y * image->bytes_per_line);
244 line = p + y * w * d;
245
246 switch (image->bits_per_pixel) {
247 case 1 :
248 for (x = image->width, line_ptr = line, index_mask = 128;
249 x > 0;
250 x --, line_ptr += d) {
251 if (*pixel & index_mask) {
252 line_ptr[0] = cvals[1][0];
253 line_ptr[1] = cvals[1][1];
254 line_ptr[2] = cvals[1][2];
255 } else {
256 line_ptr[0] = cvals[0][0];
257 line_ptr[1] = cvals[0][1];
258 line_ptr[2] = cvals[0][2];
259 }
260
261 if (index_mask > 1) {
262 index_mask >>= 1;
263 } else {
264 index_mask = 128;
265 pixel ++;
266 }
267 }
268 break;
269
270 case 2 :
271 for (x = image->width, line_ptr = line, index_shift = 6;
272 x > 0;
273 x --, line_ptr += d) {
274 i = (*pixel >> index_shift) & 3;
275
276 line_ptr[0] = cvals[i][0];
277 line_ptr[1] = cvals[i][1];
278 line_ptr[2] = cvals[i][2];
279
280 if (index_shift > 0) {
281 index_mask >>= 2;
282 index_shift -= 2;
283 } else {
284 index_mask = 192;
285 index_shift = 6;
286 pixel ++;
287 }
288 }
289 break;
290
291 case 4 :
292 for (x = image->width, line_ptr = line, index_shift = 4;
293 x > 0;
294 x --, line_ptr += d) {
295 if (index_shift == 4) i = (*pixel >> 4) & 15;
296 else i = *pixel & 15;
297
298 line_ptr[0] = cvals[i][0];
299 line_ptr[1] = cvals[i][1];
300 line_ptr[2] = cvals[i][2];
301
302 if (index_shift > 0) {
303 index_shift = 0;
304 } else {
305 index_shift = 4;
306 pixel ++;
307 }
308 }
309 break;
310
311 case 8 :
312 for (x = image->width, line_ptr = line;
313 x > 0;
314 x --, line_ptr += d, pixel ++) {
315 line_ptr[0] = cvals[*pixel][0];
316 line_ptr[1] = cvals[*pixel][1];
317 line_ptr[2] = cvals[*pixel][2];
318 }
319 break;
320
321 case 12 :
322 for (x = image->width, line_ptr = line, index_shift = 0;
323 x > 0;
324 x --, line_ptr += d) {
325 if (index_shift == 0) {
326 i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095;
327 } else {
328 i = ((pixel[1] << 8) | pixel[2]) & 4095;
329 }
330
331 line_ptr[0] = cvals[i][0];
332 line_ptr[1] = cvals[i][1];
333 line_ptr[2] = cvals[i][2];
334
335 if (index_shift == 0) {
336 index_shift = 4;
337 } else {
338 index_shift = 0;
339 pixel += 3;
340 }
341 }
342 break;
343 }
344 }
345 } else {
346 // RGB(A) image, so figure out the shifts & masks...
347 red_mask = image->red_mask;
348 red_shift = 0;
349
350 while ((red_mask & 1) == 0) {
351 red_mask >>= 1;
352 red_shift ++;
353 }
354
355 green_mask = image->green_mask;
356 green_shift = 0;
357
358 while ((green_mask & 1) == 0) {
359 green_mask >>= 1;
360 green_shift ++;
361 }
362
363 blue_mask = image->blue_mask;
364 blue_shift = 0;
365
366 while ((blue_mask & 1) == 0) {
367 blue_mask >>= 1;
368 blue_shift ++;
369 }
370
371 // Read the pixels and output an RGB image...
372 for (y = 0; y < image->height; y ++) {
373 pixel = (unsigned char *)(image->data + y * image->bytes_per_line);
374 line = p + y * w * d;
375
376 switch (image->bits_per_pixel) {
377 case 8 :
378 for (x = image->width, line_ptr = line;
379 x > 0;
380 x --, line_ptr += d, pixel ++) {
381 i = *pixel;
382
383 line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
384 line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
385 line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
386 }
387 break;
388
389 case 12 :
390 for (x = image->width, line_ptr = line, index_shift = 0;
391 x > 0;
392 x --, line_ptr += d) {
393 if (index_shift == 0) {
394 i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095;
395 } else {
396 i = ((pixel[1] << 8) | pixel[2]) & 4095;
397 }
398
399 line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
400 line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
401 line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
402
403 if (index_shift == 0) {
404 index_shift = 4;
405 } else {
406 index_shift = 0;
407 pixel += 3;
408 }
409 }
410 break;
411
412 case 16 :
413 if (image->byte_order == LSBFirst) {
414 // Little-endian...
415 for (x = image->width, line_ptr = line;
416 x > 0;
417 x --, line_ptr += d, pixel += 2) {
418 i = (pixel[1] << 8) | pixel[0];
419
420 line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
421 line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
422 line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
423 }
424 } else {
425 // Big-endian...
426 for (x = image->width, line_ptr = line;
427 x > 0;
428 x --, line_ptr += d, pixel += 2) {
429 i = (pixel[0] << 8) | pixel[1];
430
431 line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
432 line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
433 line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
434 }
435 }
436 break;
437
438 case 24 :
439 if (image->byte_order == LSBFirst) {
440 // Little-endian...
441 for (x = image->width, line_ptr = line;
442 x > 0;
443 x --, line_ptr += d, pixel += 3) {
444 i = (((pixel[2] << 8) | pixel[1]) << 8) | pixel[0];
445
446 line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
447 line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
448 line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
449 }
450 } else {
451 // Big-endian...
452 for (x = image->width, line_ptr = line;
453 x > 0;
454 x --, line_ptr += d, pixel += 3) {
455 i = (((pixel[0] << 8) | pixel[1]) << 8) | pixel[2];
456
457 line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
458 line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
459 line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
460 }
461 }
462 break;
463
464 case 32 :
465 if (image->byte_order == LSBFirst) {
466 // Little-endian...
467 for (x = image->width, line_ptr = line;
468 x > 0;
469 x --, line_ptr += d, pixel += 4) {
470 i = (((((pixel[3] << 8) | pixel[2]) << 8) | pixel[1]) << 8) | pixel[0];
471
472 line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
473 line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
474 line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
475 }
476 } else {
477 // Big-endian...
478 for (x = image->width, line_ptr = line;
479 x > 0;
480 x --, line_ptr += d, pixel += 4) {
481 i = (((((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]) << 8) | pixel[3];
482
483 line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
484 line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
485 line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
486 }
487 }
488 break;
489 }
490 }
491 }
492
493 // Destroy the X image we've read and return the RGB(A) image...
494 XDestroyImage(image);
495
496 return p;
497 }
498
499 #endif
500
501 //
502 // End of "$Id: fl_read_image.cxx 6475 2008-10-19 20:35:32Z matt $".
503 //
504