You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

510 lines
15KB

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