2 // "$Id: fl_read_image.cxx 8593 2011-04-15 21:38:05Z manolo $"
4 // X11 image reading routines for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
30 #include <FL/fl_draw.H>
38 # include "fl_read_image_win32.cxx"
39 #elif defined(__APPLE__)
40 # include "fl_read_image_mac.cxx"
42 # include <X11/Xutil.h>
44 # include <X11/extensions/readdisplay.h>
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
;
54 // 'fl_subimage_offsets()' - Calculate subimage offsets for an axis
56 fl_subimage_offsets(int a
, int aw
, int b
, int bw
, int &obw
)
71 if (ob
+ bw
<= a
+ aw
) {
80 // this handler will catch and ignore exceptions during XGetImage
81 // to avoid an application crash
82 static int xgetimageerrhandler(Display
*display
, XErrorEvent
*error
) {
87 // 'fl_read_image()' - Read an image from the current window.
90 uchar
* // O - Pixel buffer or NULL if failed
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 // negative allows capture of window title bar and frame
96 int h
, // I - Height of area to read
97 int alpha
) { // I - Alpha value for image (0 for none)
98 XImage
*image
; // Captured image
99 int i
, maxindex
; // Looping vars
100 int x
, y
; // Current X & Y in image
101 int d
; // Depth of image
102 unsigned char *line
, // Array to hold image row
103 *line_ptr
; // Pointer to current line image
104 unsigned char *pixel
; // Current color value
105 XColor colors
[4096]; // Colors from the colormap...
106 unsigned char cvals
[4096][3]; // Color values from the colormap...
118 // Under X11 we have the option of the XGetImage() interface or SGI's
119 // ReadDisplay extension which does all of the really hard work for
122 int allow_outside
= w
< 0; // negative w allows negative X or Y, that is, window frame
126 if (XReadDisplayQueryExtension(fl_display
, &i
, &i
)) {
127 image
= XReadDisplay(fl_display
, fl_window
, X
, Y
, w
, h
, 0, NULL
);
134 // fetch absolute coordinates
135 int dx
, dy
, sx
, sy
, sw
, sh
;
139 if (allow_outside
) win
= (Fl_Window
*)1;
140 else win
= fl_find(fl_window
);
142 XTranslateCoordinates(fl_display
, fl_window
,
143 RootWindow(fl_display
, fl_screen
), X
, Y
, &dx
, &dy
, &child_win
);
145 Fl::screen_xywh(sx
, sy
, sw
, sh
, fl_screen
);
147 if (!win
|| (dx
>= sx
&& dy
>= sy
&& dx
+ w
<= sw
&& dy
+ h
<= sh
)) {
148 // the image is fully contained, we can use the traditional method
149 // however, if the window is obscured etc. the function will still fail. Make sure we
150 // catch the error and continue, otherwise an exception will be thrown.
151 XErrorHandler old_handler
= XSetErrorHandler(xgetimageerrhandler
);
152 image
= XGetImage(fl_display
, fl_window
, X
, Y
, w
, h
, AllPlanes
, ZPixmap
);
153 XSetErrorHandler(old_handler
);
155 // image is crossing borders, determine visible region
156 int nw
, nh
, noffx
, noffy
;
157 noffx
= fl_subimage_offsets(sx
, sw
, dx
, w
, nw
);
158 noffy
= fl_subimage_offsets(sy
, sh
, dy
, h
, nh
);
159 if (nw
<= 0 || nh
<= 0) return 0;
161 // allocate the image
162 int bpp
= fl_visual
->depth
+ ((fl_visual
->depth
/ 8) % 2) * 8;
163 char* buf
= (char*)malloc(bpp
/ 8 * w
* h
);
164 image
= XCreateImage(fl_display
, fl_visual
->visual
,
165 fl_visual
->depth
, ZPixmap
, 0, buf
, w
, h
, bpp
, 0);
171 XErrorHandler old_handler
= XSetErrorHandler(xgetimageerrhandler
);
172 XImage
*subimg
= XGetSubImage(fl_display
, fl_window
, X
+ noffx
, Y
+ noffy
,
173 nw
, nh
, AllPlanes
, ZPixmap
, image
, noffx
, noffy
);
174 XSetErrorHandler(old_handler
);
176 XDestroyImage(image
);
182 if (!image
) return 0;
185 printf("width = %d\n", image
->width
);
186 printf("height = %d\n", image
->height
);
187 printf("xoffset = %d\n", image
->xoffset
);
188 printf("format = %d\n", image
->format
);
189 printf("data = %p\n", image
->data
);
190 printf("byte_order = %d\n", image
->byte_order
);
191 printf("bitmap_unit = %d\n", image
->bitmap_unit
);
192 printf("bitmap_bit_order = %d\n", image
->bitmap_bit_order
);
193 printf("bitmap_pad = %d\n", image
->bitmap_pad
);
194 printf("depth = %d\n", image
->depth
);
195 printf("bytes_per_line = %d\n", image
->bytes_per_line
);
196 printf("bits_per_pixel = %d\n", image
->bits_per_pixel
);
197 printf("red_mask = %08x\n", image
->red_mask
);
198 printf("green_mask = %08x\n", image
->green_mask
);
199 printf("blue_mask = %08x\n", image
->blue_mask
);
200 printf("map_entries = %d\n", fl_visual
->visual
->map_entries
);
205 // Allocate the image data array as needed...
206 if (!p
) p
= new uchar
[w
* h
* d
];
208 // Initialize the default colors/alpha in the whole image...
209 memset(p
, alpha
, w
* h
* d
);
211 // Check that we have valid mask/shift values...
212 if (!image
->red_mask
&& image
->bits_per_pixel
> 12) {
213 // Greater than 12 bits must be TrueColor...
214 image
->red_mask
= fl_visual
->visual
->red_mask
;
215 image
->green_mask
= fl_visual
->visual
->green_mask
;
216 image
->blue_mask
= fl_visual
->visual
->blue_mask
;
219 puts("\n---- UPDATED ----");
220 printf("fl_redmask = %08x\n", fl_redmask
);
221 printf("fl_redshift = %d\n", fl_redshift
);
222 printf("fl_greenmask = %08x\n", fl_greenmask
);
223 printf("fl_greenshift = %d\n", fl_greenshift
);
224 printf("fl_bluemask = %08x\n", fl_bluemask
);
225 printf("fl_blueshift = %d\n", fl_blueshift
);
226 printf("red_mask = %08x\n", image
->red_mask
);
227 printf("green_mask = %08x\n", image
->green_mask
);
228 printf("blue_mask = %08x\n", image
->blue_mask
);
232 // Check if we have colormap image...
233 if (!image
->red_mask
) {
234 // Get the colormap entries for this window...
235 maxindex
= fl_visual
->visual
->map_entries
;
237 for (i
= 0; i
< maxindex
; i
++) colors
[i
].pixel
= i
;
239 XQueryColors(fl_display
, fl_colormap
, colors
, maxindex
);
241 for (i
= 0; i
< maxindex
; i
++) {
242 cvals
[i
][0] = colors
[i
].red
>> 8;
243 cvals
[i
][1] = colors
[i
].green
>> 8;
244 cvals
[i
][2] = colors
[i
].blue
>> 8;
247 // Read the pixels and output an RGB image...
248 for (y
= 0; y
< image
->height
; y
++) {
249 pixel
= (unsigned char *)(image
->data
+ y
* image
->bytes_per_line
);
250 line
= p
+ y
* w
* d
;
252 switch (image
->bits_per_pixel
) {
254 for (x
= image
->width
, line_ptr
= line
, index_mask
= 128;
256 x
--, line_ptr
+= d
) {
257 if (*pixel
& index_mask
) {
258 line_ptr
[0] = cvals
[1][0];
259 line_ptr
[1] = cvals
[1][1];
260 line_ptr
[2] = cvals
[1][2];
262 line_ptr
[0] = cvals
[0][0];
263 line_ptr
[1] = cvals
[0][1];
264 line_ptr
[2] = cvals
[0][2];
267 if (index_mask
> 1) {
277 for (x
= image
->width
, line_ptr
= line
, index_shift
= 6;
279 x
--, line_ptr
+= d
) {
280 i
= (*pixel
>> index_shift
) & 3;
282 line_ptr
[0] = cvals
[i
][0];
283 line_ptr
[1] = cvals
[i
][1];
284 line_ptr
[2] = cvals
[i
][2];
286 if (index_shift
> 0) {
298 for (x
= image
->width
, line_ptr
= line
, index_shift
= 4;
300 x
--, line_ptr
+= d
) {
301 if (index_shift
== 4) i
= (*pixel
>> 4) & 15;
302 else i
= *pixel
& 15;
304 line_ptr
[0] = cvals
[i
][0];
305 line_ptr
[1] = cvals
[i
][1];
306 line_ptr
[2] = cvals
[i
][2];
308 if (index_shift
> 0) {
318 for (x
= image
->width
, line_ptr
= line
;
320 x
--, line_ptr
+= d
, pixel
++) {
321 line_ptr
[0] = cvals
[*pixel
][0];
322 line_ptr
[1] = cvals
[*pixel
][1];
323 line_ptr
[2] = cvals
[*pixel
][2];
328 for (x
= image
->width
, line_ptr
= line
, index_shift
= 0;
330 x
--, line_ptr
+= d
) {
331 if (index_shift
== 0) {
332 i
= ((pixel
[0] << 4) | (pixel
[1] >> 4)) & 4095;
334 i
= ((pixel
[1] << 8) | pixel
[2]) & 4095;
337 line_ptr
[0] = cvals
[i
][0];
338 line_ptr
[1] = cvals
[i
][1];
339 line_ptr
[2] = cvals
[i
][2];
341 if (index_shift
== 0) {
352 // RGB(A) image, so figure out the shifts & masks...
353 red_mask
= image
->red_mask
;
356 while ((red_mask
& 1) == 0) {
361 green_mask
= image
->green_mask
;
364 while ((green_mask
& 1) == 0) {
369 blue_mask
= image
->blue_mask
;
372 while ((blue_mask
& 1) == 0) {
377 // Read the pixels and output an RGB image...
378 for (y
= 0; y
< image
->height
; y
++) {
379 pixel
= (unsigned char *)(image
->data
+ y
* image
->bytes_per_line
);
380 line
= p
+ y
* w
* d
;
382 switch (image
->bits_per_pixel
) {
384 for (x
= image
->width
, line_ptr
= line
;
386 x
--, line_ptr
+= d
, pixel
++) {
389 line_ptr
[0] = 255 * ((i
>> red_shift
) & red_mask
) / red_mask
;
390 line_ptr
[1] = 255 * ((i
>> green_shift
) & green_mask
) / green_mask
;
391 line_ptr
[2] = 255 * ((i
>> blue_shift
) & blue_mask
) / blue_mask
;
396 for (x
= image
->width
, line_ptr
= line
, index_shift
= 0;
398 x
--, line_ptr
+= d
) {
399 if (index_shift
== 0) {
400 i
= ((pixel
[0] << 4) | (pixel
[1] >> 4)) & 4095;
402 i
= ((pixel
[1] << 8) | pixel
[2]) & 4095;
405 line_ptr
[0] = 255 * ((i
>> red_shift
) & red_mask
) / red_mask
;
406 line_ptr
[1] = 255 * ((i
>> green_shift
) & green_mask
) / green_mask
;
407 line_ptr
[2] = 255 * ((i
>> blue_shift
) & blue_mask
) / blue_mask
;
409 if (index_shift
== 0) {
419 if (image
->byte_order
== LSBFirst
) {
421 for (x
= image
->width
, line_ptr
= line
;
423 x
--, line_ptr
+= d
, pixel
+= 2) {
424 i
= (pixel
[1] << 8) | pixel
[0];
426 line_ptr
[0] = 255 * ((i
>> red_shift
) & red_mask
) / red_mask
;
427 line_ptr
[1] = 255 * ((i
>> green_shift
) & green_mask
) / green_mask
;
428 line_ptr
[2] = 255 * ((i
>> blue_shift
) & blue_mask
) / blue_mask
;
432 for (x
= image
->width
, line_ptr
= line
;
434 x
--, line_ptr
+= d
, pixel
+= 2) {
435 i
= (pixel
[0] << 8) | pixel
[1];
437 line_ptr
[0] = 255 * ((i
>> red_shift
) & red_mask
) / red_mask
;
438 line_ptr
[1] = 255 * ((i
>> green_shift
) & green_mask
) / green_mask
;
439 line_ptr
[2] = 255 * ((i
>> blue_shift
) & blue_mask
) / blue_mask
;
445 if (image
->byte_order
== LSBFirst
) {
447 for (x
= image
->width
, line_ptr
= line
;
449 x
--, line_ptr
+= d
, pixel
+= 3) {
450 i
= (((pixel
[2] << 8) | pixel
[1]) << 8) | pixel
[0];
452 line_ptr
[0] = 255 * ((i
>> red_shift
) & red_mask
) / red_mask
;
453 line_ptr
[1] = 255 * ((i
>> green_shift
) & green_mask
) / green_mask
;
454 line_ptr
[2] = 255 * ((i
>> blue_shift
) & blue_mask
) / blue_mask
;
458 for (x
= image
->width
, line_ptr
= line
;
460 x
--, line_ptr
+= d
, pixel
+= 3) {
461 i
= (((pixel
[0] << 8) | pixel
[1]) << 8) | pixel
[2];
463 line_ptr
[0] = 255 * ((i
>> red_shift
) & red_mask
) / red_mask
;
464 line_ptr
[1] = 255 * ((i
>> green_shift
) & green_mask
) / green_mask
;
465 line_ptr
[2] = 255 * ((i
>> blue_shift
) & blue_mask
) / blue_mask
;
471 if (image
->byte_order
== LSBFirst
) {
473 for (x
= image
->width
, line_ptr
= line
;
475 x
--, line_ptr
+= d
, pixel
+= 4) {
476 i
= (((((pixel
[3] << 8) | pixel
[2]) << 8) | pixel
[1]) << 8) | pixel
[0];
478 line_ptr
[0] = 255 * ((i
>> red_shift
) & red_mask
) / red_mask
;
479 line_ptr
[1] = 255 * ((i
>> green_shift
) & green_mask
) / green_mask
;
480 line_ptr
[2] = 255 * ((i
>> blue_shift
) & blue_mask
) / blue_mask
;
484 for (x
= image
->width
, line_ptr
= line
;
486 x
--, line_ptr
+= d
, pixel
+= 4) {
487 i
= (((((pixel
[0] << 8) | pixel
[1]) << 8) | pixel
[2]) << 8) | pixel
[3];
489 line_ptr
[0] = 255 * ((i
>> red_shift
) & red_mask
) / red_mask
;
490 line_ptr
[1] = 255 * ((i
>> green_shift
) & green_mask
) / green_mask
;
491 line_ptr
[2] = 255 * ((i
>> blue_shift
) & blue_mask
) / blue_mask
;
499 // Destroy the X image we've read and return the RGB(A) image...
500 XDestroyImage(image
);
508 // End of "$Id: fl_read_image.cxx 8593 2011-04-15 21:38:05Z manolo $".