fl_read_image.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. //
  2. // "$Id: fl_read_image.cxx 7903 2010-11-28 21:06:39Z matt $"
  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. int h, // I - Height of area to read
  84. int alpha) { // I - Alpha value for image (0 for none)
  85. XImage *image; // Captured image
  86. int i, maxindex; // Looping vars
  87. int x, y; // Current X & Y in image
  88. int d; // Depth of image
  89. unsigned char *line, // Array to hold image row
  90. *line_ptr; // Pointer to current line image
  91. unsigned char *pixel; // Current color value
  92. XColor colors[4096]; // Colors from the colormap...
  93. unsigned char cvals[4096][3]; // Color values from the colormap...
  94. unsigned index_mask,
  95. index_shift,
  96. red_mask,
  97. red_shift,
  98. green_mask,
  99. green_shift,
  100. blue_mask,
  101. blue_shift;
  102. //
  103. // Under X11 we have the option of the XGetImage() interface or SGI's
  104. // ReadDisplay extension which does all of the really hard work for
  105. // us...
  106. //
  107. # ifdef __sgi
  108. if (XReadDisplayQueryExtension(fl_display, &i, &i)) {
  109. image = XReadDisplay(fl_display, fl_window, X, Y, w, h, 0, NULL);
  110. } else
  111. # else
  112. image = 0;
  113. # endif // __sgi
  114. if (!image) {
  115. // fetch absolute coordinates
  116. int dx, dy, sx, sy, sw, sh;
  117. Window child_win;
  118. Fl_Window *win = fl_find(fl_window);
  119. if (win) {
  120. XTranslateCoordinates(fl_display, fl_window,
  121. RootWindow(fl_display, fl_screen), X, Y, &dx, &dy, &child_win);
  122. // screen dimensions
  123. Fl::screen_xywh(sx, sy, sw, sh, fl_screen);
  124. }
  125. if (!win || (dx >= sx && dy >= sy && dx + w <= sw && dy + h <= sh)) {
  126. // the image is fully contained, we can use the traditional method
  127. // however, if the window is obscured etc. the function will still fail. Make sure we
  128. // catch the error and continue, otherwise an exception will be thrown.
  129. XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
  130. image = XGetImage(fl_display, fl_window, X, Y, w, h, AllPlanes, ZPixmap);
  131. XSetErrorHandler(old_handler);
  132. } else {
  133. // image is crossing borders, determine visible region
  134. int nw, nh, noffx, noffy;
  135. noffx = fl_subimage_offsets(sx, sw, dx, w, nw);
  136. noffy = fl_subimage_offsets(sy, sh, dy, h, nh);
  137. if (nw <= 0 || nh <= 0) return 0;
  138. // allocate the image
  139. int bpp = fl_visual->depth + ((fl_visual->depth / 8) % 2) * 8;
  140. char* buf = (char*)malloc(bpp / 8 * w * h);
  141. image = XCreateImage(fl_display, fl_visual->visual,
  142. fl_visual->depth, ZPixmap, 0, buf, w, h, bpp, 0);
  143. if (!image) {
  144. if (buf) free(buf);
  145. return 0;
  146. }
  147. XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
  148. XImage *subimg = XGetSubImage(fl_display, fl_window, X + noffx, Y + noffy,
  149. nw, nh, AllPlanes, ZPixmap, image, noffx, noffy);
  150. XSetErrorHandler(old_handler);
  151. if (!subimg) {
  152. XDestroyImage(image);
  153. return 0;
  154. }
  155. }
  156. }
  157. if (!image) return 0;
  158. #ifdef DEBUG
  159. printf("width = %d\n", image->width);
  160. printf("height = %d\n", image->height);
  161. printf("xoffset = %d\n", image->xoffset);
  162. printf("format = %d\n", image->format);
  163. printf("data = %p\n", image->data);
  164. printf("byte_order = %d\n", image->byte_order);
  165. printf("bitmap_unit = %d\n", image->bitmap_unit);
  166. printf("bitmap_bit_order = %d\n", image->bitmap_bit_order);
  167. printf("bitmap_pad = %d\n", image->bitmap_pad);
  168. printf("depth = %d\n", image->depth);
  169. printf("bytes_per_line = %d\n", image->bytes_per_line);
  170. printf("bits_per_pixel = %d\n", image->bits_per_pixel);
  171. printf("red_mask = %08x\n", image->red_mask);
  172. printf("green_mask = %08x\n", image->green_mask);
  173. printf("blue_mask = %08x\n", image->blue_mask);
  174. printf("map_entries = %d\n", fl_visual->visual->map_entries);
  175. #endif // DEBUG
  176. d = alpha ? 4 : 3;
  177. // Allocate the image data array as needed...
  178. if (!p) p = new uchar[w * h * d];
  179. // Initialize the default colors/alpha in the whole image...
  180. memset(p, alpha, w * h * d);
  181. // Check that we have valid mask/shift values...
  182. if (!image->red_mask && image->bits_per_pixel > 12) {
  183. // Greater than 12 bits must be TrueColor...
  184. image->red_mask = fl_visual->visual->red_mask;
  185. image->green_mask = fl_visual->visual->green_mask;
  186. image->blue_mask = fl_visual->visual->blue_mask;
  187. #ifdef DEBUG
  188. puts("\n---- UPDATED ----");
  189. printf("fl_redmask = %08x\n", fl_redmask);
  190. printf("fl_redshift = %d\n", fl_redshift);
  191. printf("fl_greenmask = %08x\n", fl_greenmask);
  192. printf("fl_greenshift = %d\n", fl_greenshift);
  193. printf("fl_bluemask = %08x\n", fl_bluemask);
  194. printf("fl_blueshift = %d\n", fl_blueshift);
  195. printf("red_mask = %08x\n", image->red_mask);
  196. printf("green_mask = %08x\n", image->green_mask);
  197. printf("blue_mask = %08x\n", image->blue_mask);
  198. #endif // DEBUG
  199. }
  200. // Check if we have colormap image...
  201. if (!image->red_mask) {
  202. // Get the colormap entries for this window...
  203. maxindex = fl_visual->visual->map_entries;
  204. for (i = 0; i < maxindex; i ++) colors[i].pixel = i;
  205. XQueryColors(fl_display, fl_colormap, colors, maxindex);
  206. for (i = 0; i < maxindex; i ++) {
  207. cvals[i][0] = colors[i].red >> 8;
  208. cvals[i][1] = colors[i].green >> 8;
  209. cvals[i][2] = colors[i].blue >> 8;
  210. }
  211. // Read the pixels and output an RGB image...
  212. for (y = 0; y < image->height; y ++) {
  213. pixel = (unsigned char *)(image->data + y * image->bytes_per_line);
  214. line = p + y * w * d;
  215. switch (image->bits_per_pixel) {
  216. case 1 :
  217. for (x = image->width, line_ptr = line, index_mask = 128;
  218. x > 0;
  219. x --, line_ptr += d) {
  220. if (*pixel & index_mask) {
  221. line_ptr[0] = cvals[1][0];
  222. line_ptr[1] = cvals[1][1];
  223. line_ptr[2] = cvals[1][2];
  224. } else {
  225. line_ptr[0] = cvals[0][0];
  226. line_ptr[1] = cvals[0][1];
  227. line_ptr[2] = cvals[0][2];
  228. }
  229. if (index_mask > 1) {
  230. index_mask >>= 1;
  231. } else {
  232. index_mask = 128;
  233. pixel ++;
  234. }
  235. }
  236. break;
  237. case 2 :
  238. for (x = image->width, line_ptr = line, index_shift = 6;
  239. x > 0;
  240. x --, line_ptr += d) {
  241. i = (*pixel >> index_shift) & 3;
  242. line_ptr[0] = cvals[i][0];
  243. line_ptr[1] = cvals[i][1];
  244. line_ptr[2] = cvals[i][2];
  245. if (index_shift > 0) {
  246. index_mask >>= 2;
  247. index_shift -= 2;
  248. } else {
  249. index_mask = 192;
  250. index_shift = 6;
  251. pixel ++;
  252. }
  253. }
  254. break;
  255. case 4 :
  256. for (x = image->width, line_ptr = line, index_shift = 4;
  257. x > 0;
  258. x --, line_ptr += d) {
  259. if (index_shift == 4) i = (*pixel >> 4) & 15;
  260. else i = *pixel & 15;
  261. line_ptr[0] = cvals[i][0];
  262. line_ptr[1] = cvals[i][1];
  263. line_ptr[2] = cvals[i][2];
  264. if (index_shift > 0) {
  265. index_shift = 0;
  266. } else {
  267. index_shift = 4;
  268. pixel ++;
  269. }
  270. }
  271. break;
  272. case 8 :
  273. for (x = image->width, line_ptr = line;
  274. x > 0;
  275. x --, line_ptr += d, pixel ++) {
  276. line_ptr[0] = cvals[*pixel][0];
  277. line_ptr[1] = cvals[*pixel][1];
  278. line_ptr[2] = cvals[*pixel][2];
  279. }
  280. break;
  281. case 12 :
  282. for (x = image->width, line_ptr = line, index_shift = 0;
  283. x > 0;
  284. x --, line_ptr += d) {
  285. if (index_shift == 0) {
  286. i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095;
  287. } else {
  288. i = ((pixel[1] << 8) | pixel[2]) & 4095;
  289. }
  290. line_ptr[0] = cvals[i][0];
  291. line_ptr[1] = cvals[i][1];
  292. line_ptr[2] = cvals[i][2];
  293. if (index_shift == 0) {
  294. index_shift = 4;
  295. } else {
  296. index_shift = 0;
  297. pixel += 3;
  298. }
  299. }
  300. break;
  301. }
  302. }
  303. } else {
  304. // RGB(A) image, so figure out the shifts & masks...
  305. red_mask = image->red_mask;
  306. red_shift = 0;
  307. while ((red_mask & 1) == 0) {
  308. red_mask >>= 1;
  309. red_shift ++;
  310. }
  311. green_mask = image->green_mask;
  312. green_shift = 0;
  313. while ((green_mask & 1) == 0) {
  314. green_mask >>= 1;
  315. green_shift ++;
  316. }
  317. blue_mask = image->blue_mask;
  318. blue_shift = 0;
  319. while ((blue_mask & 1) == 0) {
  320. blue_mask >>= 1;
  321. blue_shift ++;
  322. }
  323. // Read the pixels and output an RGB image...
  324. for (y = 0; y < image->height; y ++) {
  325. pixel = (unsigned char *)(image->data + y * image->bytes_per_line);
  326. line = p + y * w * d;
  327. switch (image->bits_per_pixel) {
  328. case 8 :
  329. for (x = image->width, line_ptr = line;
  330. x > 0;
  331. x --, line_ptr += d, pixel ++) {
  332. i = *pixel;
  333. line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
  334. line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
  335. line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
  336. }
  337. break;
  338. case 12 :
  339. for (x = image->width, line_ptr = line, index_shift = 0;
  340. x > 0;
  341. x --, line_ptr += d) {
  342. if (index_shift == 0) {
  343. i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095;
  344. } else {
  345. i = ((pixel[1] << 8) | pixel[2]) & 4095;
  346. }
  347. line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
  348. line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
  349. line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
  350. if (index_shift == 0) {
  351. index_shift = 4;
  352. } else {
  353. index_shift = 0;
  354. pixel += 3;
  355. }
  356. }
  357. break;
  358. case 16 :
  359. if (image->byte_order == LSBFirst) {
  360. // Little-endian...
  361. for (x = image->width, line_ptr = line;
  362. x > 0;
  363. x --, line_ptr += d, pixel += 2) {
  364. i = (pixel[1] << 8) | pixel[0];
  365. line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
  366. line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
  367. line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
  368. }
  369. } else {
  370. // Big-endian...
  371. for (x = image->width, line_ptr = line;
  372. x > 0;
  373. x --, line_ptr += d, pixel += 2) {
  374. i = (pixel[0] << 8) | pixel[1];
  375. line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
  376. line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
  377. line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
  378. }
  379. }
  380. break;
  381. case 24 :
  382. if (image->byte_order == LSBFirst) {
  383. // Little-endian...
  384. for (x = image->width, line_ptr = line;
  385. x > 0;
  386. x --, line_ptr += d, pixel += 3) {
  387. i = (((pixel[2] << 8) | pixel[1]) << 8) | pixel[0];
  388. line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
  389. line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
  390. line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
  391. }
  392. } else {
  393. // Big-endian...
  394. for (x = image->width, line_ptr = line;
  395. x > 0;
  396. x --, line_ptr += d, pixel += 3) {
  397. i = (((pixel[0] << 8) | pixel[1]) << 8) | pixel[2];
  398. line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
  399. line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
  400. line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
  401. }
  402. }
  403. break;
  404. case 32 :
  405. if (image->byte_order == LSBFirst) {
  406. // Little-endian...
  407. for (x = image->width, line_ptr = line;
  408. x > 0;
  409. x --, line_ptr += d, pixel += 4) {
  410. i = (((((pixel[3] << 8) | pixel[2]) << 8) | pixel[1]) << 8) | pixel[0];
  411. line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
  412. line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
  413. line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
  414. }
  415. } else {
  416. // Big-endian...
  417. for (x = image->width, line_ptr = line;
  418. x > 0;
  419. x --, line_ptr += d, pixel += 4) {
  420. i = (((((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]) << 8) | pixel[3];
  421. line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
  422. line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
  423. line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
  424. }
  425. }
  426. break;
  427. }
  428. }
  429. }
  430. // Destroy the X image we've read and return the RGB(A) image...
  431. XDestroyImage(image);
  432. return p;
  433. }
  434. #endif
  435. //
  436. // End of "$Id: fl_read_image.cxx 7903 2010-11-28 21:06:39Z matt $".
  437. //