fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

fl_read_image.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: fl_read_image.cxx 7903 2010-11-28 21:06:39Z matt $"
00003 //
00004 // X11 image reading routines for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 #include <FL/x.H>
00029 #include <FL/Fl.H>
00030 #include <FL/fl_draw.H>
00031 #include "flstring.h"
00032 
00033 #ifdef DEBUG
00034 #  include <stdio.h>
00035 #endif // DEBUG
00036 
00037 #ifdef WIN32
00038 #  include "fl_read_image_win32.cxx"
00039 #elif defined(__APPLE__)
00040 #  include "fl_read_image_mac.cxx"
00041 #else
00042 #  include <X11/Xutil.h>
00043 #  ifdef __sgi
00044 #    include <X11/extensions/readdisplay.h>
00045 #  else
00046 #    include <stdlib.h>
00047 #  endif // __sgi
00048 
00049 // Defined in fl_color.cxx
00050 extern uchar fl_redmask, fl_greenmask, fl_bluemask;
00051 extern int fl_redshift, fl_greenshift, fl_blueshift, fl_extrashift;
00052 
00053 //
00054 // 'fl_subimage_offsets()' - Calculate subimage offsets for an axis
00055 static inline int
00056 fl_subimage_offsets(int a, int aw, int b, int bw, int &obw)
00057 {
00058   int off;
00059   int ob;
00060 
00061   if (b >= a) {
00062     ob = b;
00063     off = 0;
00064   } else {
00065     ob = a;
00066     off = a - b;
00067   }
00068 
00069   bw -= off;
00070 
00071   if (ob + bw <= a + aw) {
00072     obw = bw;
00073   } else {
00074     obw = (a + aw) - ob;
00075   }
00076 
00077   return off;
00078 }
00079 
00080 // this handler will catch and ignore exceptions during XGetImage
00081 // to avoid an application crash
00082 static int xgetimageerrhandler(Display *display, XErrorEvent *error) {
00083   return 0;
00084 }
00085 
00086 //
00087 // 'fl_read_image()' - Read an image from the current window.
00088 //
00089 
00090 uchar *                         // O - Pixel buffer or NULL if failed
00091 fl_read_image(uchar *p,         // I - Pixel buffer or NULL to allocate
00092               int   X,          // I - Left position
00093               int   Y,          // I - Top position
00094               int   w,          // I - Width of area to read
00095               int   h,          // I - Height of area to read
00096               int   alpha) {    // I - Alpha value for image (0 for none)
00097   XImage        *image;         // Captured image
00098   int           i, maxindex;    // Looping vars
00099   int           x, y;           // Current X & Y in image
00100   int           d;              // Depth of image
00101   unsigned char *line,          // Array to hold image row
00102                 *line_ptr;      // Pointer to current line image
00103   unsigned char *pixel;         // Current color value
00104   XColor        colors[4096];   // Colors from the colormap...
00105   unsigned char cvals[4096][3]; // Color values from the colormap...
00106   unsigned      index_mask,
00107                 index_shift,
00108                 red_mask,
00109                 red_shift,
00110                 green_mask,
00111                 green_shift,
00112                 blue_mask,
00113                 blue_shift;
00114 
00115 
00116   //
00117   // Under X11 we have the option of the XGetImage() interface or SGI's
00118   // ReadDisplay extension which does all of the really hard work for
00119   // us...
00120   //
00121 
00122 #  ifdef __sgi
00123   if (XReadDisplayQueryExtension(fl_display, &i, &i)) {
00124     image = XReadDisplay(fl_display, fl_window, X, Y, w, h, 0, NULL);
00125   } else
00126 #  else
00127   image = 0;
00128 #  endif // __sgi
00129 
00130   if (!image) {
00131     // fetch absolute coordinates
00132     int dx, dy, sx, sy, sw, sh;
00133     Window child_win;
00134     Fl_Window *win = fl_find(fl_window);
00135     if (win) {
00136       XTranslateCoordinates(fl_display, fl_window,
00137           RootWindow(fl_display, fl_screen), X, Y, &dx, &dy, &child_win);
00138       // screen dimensions
00139       Fl::screen_xywh(sx, sy, sw, sh, fl_screen);
00140     }
00141     if (!win || (dx >= sx && dy >= sy && dx + w <= sw && dy + h <= sh)) {
00142       // the image is fully contained, we can use the traditional method
00143       // however, if the window is obscured etc. the function will still fail. Make sure we
00144       // catch the error and continue, otherwise an exception will be thrown.
00145       XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
00146       image = XGetImage(fl_display, fl_window, X, Y, w, h, AllPlanes, ZPixmap);
00147       XSetErrorHandler(old_handler);
00148     } else {
00149       // image is crossing borders, determine visible region
00150       int nw, nh, noffx, noffy;
00151       noffx = fl_subimage_offsets(sx, sw, dx, w, nw);
00152       noffy = fl_subimage_offsets(sy, sh, dy, h, nh);
00153       if (nw <= 0 || nh <= 0) return 0;
00154 
00155       // allocate the image
00156       int bpp = fl_visual->depth + ((fl_visual->depth / 8) % 2) * 8;
00157       char* buf = (char*)malloc(bpp / 8 * w * h);
00158       image = XCreateImage(fl_display, fl_visual->visual,
00159           fl_visual->depth, ZPixmap, 0, buf, w, h, bpp, 0);
00160       if (!image) {
00161         if (buf) free(buf);
00162         return 0;
00163       }
00164 
00165       XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
00166       XImage *subimg = XGetSubImage(fl_display, fl_window, X + noffx, Y + noffy,
00167                                     nw, nh, AllPlanes, ZPixmap, image, noffx, noffy);
00168       XSetErrorHandler(old_handler);
00169       if (!subimg) {
00170         XDestroyImage(image);
00171         return 0;
00172       }
00173     }
00174   }
00175 
00176   if (!image) return 0;
00177 
00178 #ifdef DEBUG
00179   printf("width            = %d\n", image->width);
00180   printf("height           = %d\n", image->height);
00181   printf("xoffset          = %d\n", image->xoffset);
00182   printf("format           = %d\n", image->format);
00183   printf("data             = %p\n", image->data);
00184   printf("byte_order       = %d\n", image->byte_order);
00185   printf("bitmap_unit      = %d\n", image->bitmap_unit);
00186   printf("bitmap_bit_order = %d\n", image->bitmap_bit_order);
00187   printf("bitmap_pad       = %d\n", image->bitmap_pad);
00188   printf("depth            = %d\n", image->depth);
00189   printf("bytes_per_line   = %d\n", image->bytes_per_line);
00190   printf("bits_per_pixel   = %d\n", image->bits_per_pixel);
00191   printf("red_mask         = %08x\n", image->red_mask);
00192   printf("green_mask       = %08x\n", image->green_mask);
00193   printf("blue_mask        = %08x\n", image->blue_mask);
00194   printf("map_entries      = %d\n", fl_visual->visual->map_entries);
00195 #endif // DEBUG
00196 
00197   d = alpha ? 4 : 3;
00198 
00199   // Allocate the image data array as needed...
00200   if (!p) p = new uchar[w * h * d];
00201 
00202   // Initialize the default colors/alpha in the whole image...
00203   memset(p, alpha, w * h * d);
00204 
00205   // Check that we have valid mask/shift values...
00206   if (!image->red_mask && image->bits_per_pixel > 12) {
00207     // Greater than 12 bits must be TrueColor...
00208     image->red_mask   = fl_visual->visual->red_mask;
00209     image->green_mask = fl_visual->visual->green_mask;
00210     image->blue_mask  = fl_visual->visual->blue_mask;
00211 
00212 #ifdef DEBUG
00213     puts("\n---- UPDATED ----");
00214     printf("fl_redmask       = %08x\n", fl_redmask);
00215     printf("fl_redshift      = %d\n", fl_redshift);
00216     printf("fl_greenmask     = %08x\n", fl_greenmask);
00217     printf("fl_greenshift    = %d\n", fl_greenshift);
00218     printf("fl_bluemask      = %08x\n", fl_bluemask);
00219     printf("fl_blueshift     = %d\n", fl_blueshift);
00220     printf("red_mask         = %08x\n", image->red_mask);
00221     printf("green_mask       = %08x\n", image->green_mask);
00222     printf("blue_mask        = %08x\n", image->blue_mask);
00223 #endif // DEBUG
00224   }
00225 
00226   // Check if we have colormap image...
00227   if (!image->red_mask) {
00228     // Get the colormap entries for this window...
00229     maxindex = fl_visual->visual->map_entries;
00230 
00231     for (i = 0; i < maxindex; i ++) colors[i].pixel = i;
00232 
00233     XQueryColors(fl_display, fl_colormap, colors, maxindex);
00234 
00235     for (i = 0; i < maxindex; i ++) {
00236       cvals[i][0] = colors[i].red >> 8;
00237       cvals[i][1] = colors[i].green >> 8;
00238       cvals[i][2] = colors[i].blue >> 8;
00239     }
00240 
00241     // Read the pixels and output an RGB image...
00242     for (y = 0; y < image->height; y ++) {
00243       pixel = (unsigned char *)(image->data + y * image->bytes_per_line);
00244       line  = p + y * w * d;
00245 
00246       switch (image->bits_per_pixel) {
00247         case 1 :
00248           for (x = image->width, line_ptr = line, index_mask = 128;
00249                x > 0;
00250                x --, line_ptr += d) {
00251             if (*pixel & index_mask) {
00252               line_ptr[0] = cvals[1][0];
00253               line_ptr[1] = cvals[1][1];
00254               line_ptr[2] = cvals[1][2];
00255             } else {
00256               line_ptr[0] = cvals[0][0];
00257               line_ptr[1] = cvals[0][1];
00258               line_ptr[2] = cvals[0][2];
00259             }
00260 
00261             if (index_mask > 1) {
00262               index_mask >>= 1;
00263             } else {
00264               index_mask = 128;
00265               pixel ++;
00266             }
00267           }
00268           break;
00269 
00270         case 2 :
00271           for (x = image->width, line_ptr = line, index_shift = 6;
00272                x > 0;
00273                x --, line_ptr += d) {
00274             i = (*pixel >> index_shift) & 3;
00275 
00276             line_ptr[0] = cvals[i][0];
00277             line_ptr[1] = cvals[i][1];
00278             line_ptr[2] = cvals[i][2];
00279 
00280             if (index_shift > 0) {
00281               index_mask >>= 2;
00282               index_shift -= 2;
00283             } else {
00284               index_mask  = 192;
00285               index_shift = 6;
00286               pixel ++;
00287             }
00288           }
00289           break;
00290 
00291         case 4 :
00292           for (x = image->width, line_ptr = line, index_shift = 4;
00293                x > 0;
00294                x --, line_ptr += d) {
00295             if (index_shift == 4) i = (*pixel >> 4) & 15;
00296             else i = *pixel & 15;
00297 
00298             line_ptr[0] = cvals[i][0];
00299             line_ptr[1] = cvals[i][1];
00300             line_ptr[2] = cvals[i][2];
00301 
00302             if (index_shift > 0) {
00303               index_shift = 0;
00304             } else {
00305               index_shift = 4;
00306               pixel ++;
00307             }
00308           }
00309           break;
00310 
00311         case 8 :
00312           for (x = image->width, line_ptr = line;
00313                x > 0;
00314                x --, line_ptr += d, pixel ++) {
00315             line_ptr[0] = cvals[*pixel][0];
00316             line_ptr[1] = cvals[*pixel][1];
00317             line_ptr[2] = cvals[*pixel][2];
00318           }
00319           break;
00320 
00321         case 12 :
00322           for (x = image->width, line_ptr = line, index_shift = 0;
00323                x > 0;
00324                x --, line_ptr += d) {
00325             if (index_shift == 0) {
00326               i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095;
00327             } else {
00328               i = ((pixel[1] << 8) | pixel[2]) & 4095;
00329             }
00330 
00331             line_ptr[0] = cvals[i][0];
00332             line_ptr[1] = cvals[i][1];
00333             line_ptr[2] = cvals[i][2];
00334 
00335             if (index_shift == 0) {
00336               index_shift = 4;
00337             } else {
00338               index_shift = 0;
00339               pixel += 3;
00340             }
00341           }
00342           break;
00343       }
00344     }
00345   } else {
00346     // RGB(A) image, so figure out the shifts & masks...
00347     red_mask  = image->red_mask;
00348     red_shift = 0;
00349 
00350     while ((red_mask & 1) == 0) {
00351       red_mask >>= 1;
00352       red_shift ++;
00353     }
00354 
00355     green_mask  = image->green_mask;
00356     green_shift = 0;
00357 
00358     while ((green_mask & 1) == 0) {
00359       green_mask >>= 1;
00360       green_shift ++;
00361     }
00362 
00363     blue_mask  = image->blue_mask;
00364     blue_shift = 0;
00365 
00366     while ((blue_mask & 1) == 0) {
00367       blue_mask >>= 1;
00368       blue_shift ++;
00369     }
00370 
00371     // Read the pixels and output an RGB image...
00372     for (y = 0; y < image->height; y ++) {
00373       pixel = (unsigned char *)(image->data + y * image->bytes_per_line);
00374       line  = p + y * w * d;
00375 
00376       switch (image->bits_per_pixel) {
00377         case 8 :
00378           for (x = image->width, line_ptr = line;
00379                x > 0;
00380                x --, line_ptr += d, pixel ++) {
00381             i = *pixel;
00382 
00383             line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
00384             line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
00385             line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
00386           }
00387           break;
00388 
00389         case 12 :
00390           for (x = image->width, line_ptr = line, index_shift = 0;
00391                x > 0;
00392                x --, line_ptr += d) {
00393             if (index_shift == 0) {
00394               i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095;
00395             } else {
00396               i = ((pixel[1] << 8) | pixel[2]) & 4095;
00397             }
00398 
00399             line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
00400             line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
00401             line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
00402 
00403             if (index_shift == 0) {
00404               index_shift = 4;
00405             } else {
00406               index_shift = 0;
00407               pixel += 3;
00408             }
00409           }
00410           break;
00411 
00412         case 16 :
00413           if (image->byte_order == LSBFirst) {
00414             // Little-endian...
00415             for (x = image->width, line_ptr = line;
00416                  x > 0;
00417                  x --, line_ptr += d, pixel += 2) {
00418               i = (pixel[1] << 8) | pixel[0];
00419 
00420               line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
00421               line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
00422               line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
00423             }
00424           } else {
00425             // Big-endian...
00426             for (x = image->width, line_ptr = line;
00427                  x > 0;
00428                  x --, line_ptr += d, pixel += 2) {
00429               i = (pixel[0] << 8) | pixel[1];
00430 
00431               line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
00432               line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
00433               line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
00434             }
00435           }
00436           break;
00437 
00438         case 24 :
00439           if (image->byte_order == LSBFirst) {
00440             // Little-endian...
00441             for (x = image->width, line_ptr = line;
00442                  x > 0;
00443                  x --, line_ptr += d, pixel += 3) {
00444               i = (((pixel[2] << 8) | pixel[1]) << 8) | pixel[0];
00445 
00446               line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
00447               line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
00448               line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
00449             }
00450           } else {
00451             // Big-endian...
00452             for (x = image->width, line_ptr = line;
00453                  x > 0;
00454                  x --, line_ptr += d, pixel += 3) {
00455               i = (((pixel[0] << 8) | pixel[1]) << 8) | pixel[2];
00456 
00457               line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
00458               line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
00459               line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
00460             }
00461           }
00462           break;
00463 
00464         case 32 :
00465           if (image->byte_order == LSBFirst) {
00466             // Little-endian...
00467             for (x = image->width, line_ptr = line;
00468                  x > 0;
00469                  x --, line_ptr += d, pixel += 4) {
00470               i = (((((pixel[3] << 8) | pixel[2]) << 8) | pixel[1]) << 8) | pixel[0];
00471 
00472               line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
00473               line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
00474               line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
00475             }
00476           } else {
00477             // Big-endian...
00478             for (x = image->width, line_ptr = line;
00479                  x > 0;
00480                  x --, line_ptr += d, pixel += 4) {
00481               i = (((((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]) << 8) | pixel[3];
00482 
00483               line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask;
00484               line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask;
00485               line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask;
00486             }
00487           }
00488           break;
00489       }
00490     }
00491   }
00492 
00493   // Destroy the X image we've read and return the RGB(A) image...
00494   XDestroyImage(image);
00495 
00496   return p;
00497 }
00498 
00499 #endif
00500 
00501 //
00502 // End of "$Id: fl_read_image.cxx 7903 2010-11-28 21:06:39Z matt $".
00503 //