diff options
| -rw-r--r-- | FL/Fl_Screen_Driver.H | 11 | ||||
| -rw-r--r-- | FL/fl_draw.H | 18 | ||||
| -rw-r--r-- | src/Fl_Screen_Driver.cxx | 126 | ||||
| -rw-r--r-- | src/Makefile | 4 | ||||
| -rw-r--r-- | src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H | 1 | ||||
| -rw-r--r-- | src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx | 45 | ||||
| -rw-r--r-- | src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H | 1 | ||||
| -rw-r--r-- | src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx | 100 | ||||
| -rw-r--r-- | src/drivers/X11/Fl_X11_Screen_Driver.H | 1 | ||||
| -rw-r--r-- | src/drivers/X11/Fl_X11_Screen_Driver.cxx | 456 | ||||
| -rw-r--r-- | src/fl_read_image.cxx | 636 |
11 files changed, 756 insertions, 643 deletions
diff --git a/FL/Fl_Screen_Driver.H b/FL/Fl_Screen_Driver.H index 87ef0261a..d13dbaafe 100644 --- a/FL/Fl_Screen_Driver.H +++ b/FL/Fl_Screen_Driver.H @@ -37,6 +37,8 @@ // TODO: application shortcuts class Fl_Window; +class Fl_RGB_Image; +class Fl_Group; class FL_EXPORT Fl_Screen_Driver { @@ -118,6 +120,15 @@ public: static unsigned font_desc_size(); static const char *font_name(int num); static void font_name(int num, const char *name); + // read raw image from a window or an offscreen buffer +#if defined(FL_PORTING) +# pragma message "FL_PORTING: implement code to read RGB data from screen" +#endif + virtual uchar *read_image(uchar *p, int x, int y, int w, int h, int alpha); + virtual uchar *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha) {return NULL;} + static void write_image_inside(Fl_RGB_Image *to, Fl_RGB_Image *from, int to_x, int to_y); + static Fl_RGB_Image *traverse_to_gl_subwindows(Fl_Group *g, uchar *p, int x, int y, int w, int h, int alpha, + Fl_RGB_Image *full_img); }; diff --git a/FL/fl_draw.H b/FL/fl_draw.H index f5adcb21c..05019a311 100644 --- a/FL/fl_draw.H +++ b/FL/fl_draw.H @@ -756,24 +756,6 @@ inline void fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int */ inline char fl_can_do_alpha_blending() {return Fl_Display_Device::display_device()->driver()->can_do_alpha_blending();} -/** - Reads an RGB(A) image from the current window or off-screen buffer. - \param[in] p pixel buffer, or NULL to allocate one - \param[in] X,Y position of top-left of image to read - \param[in] W,H width and height of image to read - \param[in] alpha alpha value for image (0 for none) - \returns pointer to pixel buffer, or NULL if allocation failed. - - The \p p argument points to a buffer that can hold the image and must - be at least \p W*H*3 bytes when reading RGB images, or \p W*H*4 bytes - when reading RGBA images. If NULL, fl_read_image() will create an - array of the proper size which can be freed using <tt>delete[]</tt>. - - The \p alpha parameter controls whether an alpha channel is created - and the value that is placed in the alpha channel. If 0, no alpha - channel is generated. - */ -/* note: doxygen comment here to avoid triplication in os-speciic files */ FL_EXPORT uchar *fl_read_image(uchar *p,int X,int Y,int W,int H,int alpha=0); // pixmaps: diff --git a/src/Fl_Screen_Driver.cxx b/src/Fl_Screen_Driver.cxx index 083922c89..f2071d3cc 100644 --- a/src/Fl_Screen_Driver.cxx +++ b/src/Fl_Screen_Driver.cxx @@ -16,11 +16,13 @@ // http://www.fltk.org/str.php // - -#include "config_lib.h" #include <FL/Fl_Screen_Driver.H> +#include <FL/Fl_Image.H> #include <FL/Fl.H> - +#include <FL/x.H> // for fl_window +#include <FL/Fl_Plugin.H> +#include <FL/Fl_Group.H> +#include <FL/Fl_Window.H> char Fl_Screen_Driver::bg_set = 0; char Fl_Screen_Driver::bg2_set = 0; @@ -149,6 +151,124 @@ void Fl_Screen_Driver::compose_reset() { Fl::compose_state = 0; } +uchar *Fl_Screen_Driver::read_image(uchar *p, int X, int Y, int w, int h, int alpha) { + if (w < 0 || fl_find(fl_window) == 0) { // read from off_screen buffer or title bar and frame + return read_win_rectangle(p, X, Y, w, h, alpha); + } + Fl_RGB_Image *img = traverse_to_gl_subwindows(Fl_Window::current(), p, X, Y, w, h, alpha, NULL); + uchar *image_data = (uchar*)img->array; + img->alloc_array = 0; + delete img; + return image_data; +} + +void Fl_Screen_Driver::write_image_inside(Fl_RGB_Image *to, Fl_RGB_Image *from, int to_x, int to_y) +/* Copy the image "from" inside image "to" with its top-left angle at coordinates to_x, to_y. +Image depth can differ between "to" and "from". +*/ +{ + int to_ld = (to->ld() == 0? to->w() * to->d() : to->ld()); + int from_ld = (from->ld() == 0? from->w() * from->d() : from->ld()); + uchar *tobytes = (uchar*)to->array + to_y * to_ld + to_x * to->d(); + const uchar *frombytes = from->array; + for (int i = 0; i < from->h(); i++) { + if (from->d() == to->d()) memcpy(tobytes, frombytes, from->w() * from->d()); + else { + for (int j = 0; j < from->w(); j++) { + memcpy(tobytes + j * to->d(), frombytes + j * from->d(), from->d()); + } + } + tobytes += to_ld; + frombytes += from_ld; + } +} + + +/* Captures rectangle x,y,w,h from a mapped window or GL window. + All sub-GL-windows that intersect x,y,w,h, and their subwindows, are also captured. + + Arguments when this function is initially called: + g: a window or GL window + p: as in fl_read_image() + x,y,w,h: a rectangle in window g's coordinates + alpha: as in fl_read_image() + full_img: NULL + + Arguments when this function recursively calls itself: + g: an Fl_Group + p: as above + x,y,w,h: a rectangle in g's coordinates if g is a window, or in g's parent window coords if g is a group + alpha: as above + full_img: NULL, or a previously captured image that encompasses the x,y,w,h rectangle and that + will be partially overwritten with the new capture + + Return value: + An Fl_RGB_Image* of depth 4 if alpha>0 or 3 if alpha = 0 containing the captured pixels. + */ +Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, uchar *p, int x, int y, int w, int h, int alpha, + Fl_RGB_Image *full_img) +{ + if ( g->as_gl_window() ) { + Fl_Plugin_Manager pm("fltk:device"); + Fl_Device_Plugin *pi = (Fl_Device_Plugin*)pm.plugin("opengl.device.fltk.org"); + if (!pi) return full_img; + Fl_RGB_Image *img = pi->rectangle_capture(g, x, y, w, h); + if (full_img) full_img = img; + else { + uchar *data = ( p ? p : new uchar[img->w() * img->h() * (alpha?4:3)] ); + full_img = new Fl_RGB_Image(data, img->w(), img->h(), alpha?4:3); + if (!p) full_img->alloc_array = 1; + if (alpha) memset(data, alpha, img->w() * img->h() * 4); + write_image_inside(full_img, img, 0, 0); + delete img; + } + } + else if ( g->as_window() && (!full_img || (g->window() && g->window()->as_gl_window())) ) { + // the starting window or one inside a GL window + if (full_img) g->as_window()->make_current(); + uchar *image_data; + int alloc_img = (full_img != NULL || p == NULL); // false means use p, don't alloc new memory for image + // on Darwin + X11, read_win_rectangle() sometimes returns NULL when there are subwindows, + // thus the call is repeated + do image_data = Fl::screen_driver()->read_win_rectangle( (alloc_img ? NULL : p), x, y, w, h, alpha); while (!image_data); + full_img = new Fl_RGB_Image(image_data, w, h, alpha?4:3); + if (alloc_img) full_img->alloc_array = 1; + } + int n = g->children(); + for (int i = 0; i < n; i++) { + Fl_Widget *c = g->child(i); + if ( !c->visible() || !c->as_group()) continue; + if ( c->as_window() ) { + int origin_x = x; // compute intersection of x,y,w,h and the c window + if (x < c->x()) origin_x = c->x(); + int origin_y = y; + if (y < c->y()) origin_y = c->y(); + int width = c->w(); + if (origin_x + width > c->x() + c->w()) width = c->x() + c->w() - origin_x; + if (origin_x + width > x + w) width = x + w - origin_x; + int height = c->w(); + if (origin_y + height > c->y() + c->h()) height = c->y() + c->h() - origin_y; + if (origin_y + height > y + h) height = y + h - origin_y; + if (width > 0 && height > 0) { + Fl_RGB_Image *img = traverse_to_gl_subwindows(c->as_window(), p, origin_x - c->x(), + origin_y - c->y(), width, height, alpha, full_img); + if (img == full_img) continue; + int top; + if (c->as_gl_window()) { + top = origin_y - y; + } else { + top = full_img->h() - (origin_y - y + img->h()); + } + write_image_inside(full_img, img, origin_x - x, top); + delete img; + } + } + else traverse_to_gl_subwindows(c->as_group(), p, x, y, w, h, alpha, full_img); + } + return full_img; +} + + // // End of "$Id$". // diff --git a/src/Makefile b/src/Makefile index 77ac0191d..632b0570a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -583,7 +583,6 @@ Fl_win32.o: Fl_win32.cxx Fl_cocoa.o: Fl_cocoa.mm fl_color.o: fl_dnd.o: fl_dnd_win32.cxx fl_dnd_x.cxx -fl_read_image.o: fl_read_image_mac.cxx fl_read_image_win32.cxx Fl_Printer.o: ../src/drivers/PostScript/Fl_PostScript.cxx Fl_Quartz_Printer.o: Fl_Quartz_Printer.mm fl_arci.o: ../FL/mac.H ../FL/win32.H @@ -616,9 +615,6 @@ Fl_Overlay_Window.o: ../FL/mac.H ../FL/win32.H Fl_own_colormap.o: ../FL/mac.H ../FL/win32.H Fl_Pixmap.o: ../FL/mac.H ../FL/win32.H Fl_Printer.o: ../FL/mac.H ../FL/win32.H -fl_read_image.o: ../FL/mac.H ../FL/win32.H -fl_read_image_mac.o: ../FL/mac.H ../FL/win32.H -fl_read_image_win32.o: ../FL/mac.H ../FL/win32.H fl_rect.o: ../FL/mac.H ../FL/win32.H fl_scroll_area.o: ../FL/mac.H ../FL/win32.H fl_set_font.o: ../FL/mac.H ../FL/win32.H diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H index 59cd6ce1e..3f475a637 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H @@ -86,6 +86,7 @@ public: int insertion_point_location(int *px, int *py, int *pheight); virtual int dnd(int use_selection); virtual int compose(int &del); + virtual uchar *read_image(uchar *p, int x, int y, int w, int h, int alpha); }; diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx index 2c9f693fc..c23046e30 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx @@ -325,6 +325,51 @@ void Fl_Screen_Driver::font_name(int num, const char *name) { s->first = 0; } +uchar * // O - Pixel buffer or NULL if failed +Fl_Cocoa_Screen_Driver::read_image(uchar *p, // I - Pixel buffer or NULL to allocate + int x, // I - Left position + int y, // I - Top position + int w, // I - Width of area to read + int h, // I - Height of area to read + int alpha) // I - Alpha value for image (0 for none) +{ + uchar *base; + int rowBytes, delta; + if (fl_window == NULL) { // reading from an offscreen buffer + CGContextRef src = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); // get bitmap context + base = (uchar *)CGBitmapContextGetData(src); // get data + if(!base) return NULL; + int sw = CGBitmapContextGetWidth(src); + int sh = CGBitmapContextGetHeight(src); + rowBytes = CGBitmapContextGetBytesPerRow(src); + delta = CGBitmapContextGetBitsPerPixel(src)/8; + if( (sw - x < w) || (sh - y < h) ) return NULL; + } + else { // reading from current window + base = Fl_X::bitmap_from_window_rect(Fl_Window::current(),x,y,w,h,&delta); + if (!base) return NULL; + rowBytes = delta*w; + x = y = 0; + } + // Allocate the image data array as needed... + int d = alpha ? 4 : 3; + if (!p) p = new uchar[w * h * d]; + // Initialize the default colors/alpha in the whole image... + memset(p, alpha, w * h * d); + // Copy the image from the off-screen buffer to the memory buffer. + int idx, idy; // Current X & Y in image + uchar *pdst, *psrc; + for (idy = y, pdst = p; idy < h + y; idy ++) { + for (idx = 0, psrc = base + idy * rowBytes + x * delta; idx < w; idx ++, psrc += delta, pdst += d) { + pdst[0] = psrc[0]; // R + pdst[1] = psrc[1]; // G + pdst[2] = psrc[2]; // B + } + } + if(fl_window != NULL) delete[] base; + return p; +} + // // End of "$Id$". // diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H index f874750a7..a8c530fbe 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H @@ -71,6 +71,7 @@ public: virtual void remove_timeout(Fl_Timeout_Handler cb, void *argp); virtual int dnd(int unused); virtual int compose(int &del); + virtual uchar *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha); }; diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 7dd7df843..bf49eebd8 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -553,6 +553,106 @@ void Fl_Screen_Driver::font_name(int num, const char *name) { s->first = 0; } + +uchar * // O - Pixel buffer or NULL if failed +Fl_WinAPI_Screen_Driver::read_win_rectangle(uchar *p, // I - Pixel buffer or NULL to allocate + int X, // I - Left position + int Y, // I - Top position + int w, // I - Width of area to read + int h, // I - Height of area to read + int alpha) // I - Alpha value for image (0 for none) +{ + int d; // Depth of image + + // Allocate the image data array as needed... + d = alpha ? 4 : 3; + + if (!p) p = new uchar[w * h * d]; + + // Initialize the default colors/alpha in the whole image... + memset(p, alpha, w * h * d); + + // Grab all of the pixels in the image... + + // Assure that we are not trying to read non-existing data. If it is so, the + // function should still work, but the out-of-bounds part of the image is + // untouched (initialized with the alpha value or 0 (black), resp.). + + int ww = w; // We need the original width for output data line size + + int shift_x = 0; // X target shift if X modified + int shift_y = 0; // Y target shift if X modified + + if (X < 0) { + shift_x = -X; + w += X; + X = 0; + } + if (Y < 0) { + shift_y = -Y; + h += Y; + Y = 0; + } + + if (h < 1 || w < 1) return p; // nothing to copy + + int line_size = ((3*w+3)/4) * 4; // each line is aligned on a DWORD (4 bytes) + uchar *dib = new uchar[line_size*h]; // create temporary buffer to read DIB + + // fill in bitmap info for GetDIBits + + BITMAPINFO bi; + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = w; + bi.bmiHeader.biHeight = -h; // negative => top-down DIB + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 24; // 24 bits RGB + bi.bmiHeader.biCompression = BI_RGB; + bi.bmiHeader.biSizeImage = 0; + bi.bmiHeader.biXPelsPerMeter = 0; + bi.bmiHeader.biYPelsPerMeter = 0; + bi.bmiHeader.biClrUsed = 0; + bi.bmiHeader.biClrImportant = 0; + + // copy bitmap from original DC (Window, Fl_Offscreen, ...) + HDC gc = (HDC)fl_graphics_driver->gc(); + HDC hdc = CreateCompatibleDC(gc); + HBITMAP hbm = CreateCompatibleBitmap(gc,w,h); + + int save_dc = SaveDC(hdc); // save context for cleanup + SelectObject(hdc,hbm); // select bitmap + BitBlt(hdc,0,0,w,h,gc,X,Y,SRCCOPY); // copy image section to DDB + + // copy RGB image data to the allocated DIB + + GetDIBits(hdc, hbm, 0, h, dib, (BITMAPINFO *)&bi, DIB_RGB_COLORS); + + // finally copy the image data to the user buffer + + for (int j = 0; j<h; j++) { + const uchar *src = dib + j * line_size; // source line + uchar *tg = p + (j + shift_y) * d * ww + shift_x * d; // target line + for (int i = 0; i<w; i++) { + uchar b = *src++; + uchar g = *src++; + *tg++ = *src++; // R + *tg++ = g; // G + *tg++ = b; // B + if (alpha) + *tg++ = alpha; // alpha + } + } + + // free used GDI and other structures + + RestoreDC(hdc,save_dc); // reset DC + DeleteDC(hdc); + DeleteObject(hbm); + delete[] dib; // delete DIB temporary buffer + + return p; +} + // // End of "$Id$". //
\ No newline at end of file diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.H b/src/drivers/X11/Fl_X11_Screen_Driver.H index 2f89eaabf..f639fd6cb 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.H +++ b/src/drivers/X11/Fl_X11_Screen_Driver.H @@ -77,6 +77,7 @@ public: virtual int compose(int &del); virtual void compose_reset(); virtual int text_display_can_leak(); + virtual uchar *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha); }; diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.cxx b/src/drivers/X11/Fl_X11_Screen_Driver.cxx index 50623664e..9e7c68af4 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Screen_Driver.cxx @@ -34,6 +34,17 @@ #include <X11/extensions/Xdbe.h> #endif +# include <X11/Xutil.h> +# ifdef __sgi +# include <X11/extensions/readdisplay.h> +# else +# include <stdlib.h> +# endif // __sgi + +#ifdef DEBUG +# include <stdio.h> +#endif // DEBUG + extern Atom fl_NET_WORKAREA; extern XIC fl_xim_ic; // in Fl_x.cxx @@ -666,5 +677,450 @@ void Fl_Screen_Driver::font_name(int num, const char *name) { } // +// 'fl_subimage_offsets()' - Calculate subimage offsets for an axis +static inline int +fl_subimage_offsets(int a, int aw, int b, int bw, int &obw) +{ + int off; + int ob; + + if (b >= a) { + ob = b; + off = 0; + } else { + ob = a; + off = a - b; + } + + bw -= off; + + if (ob + bw <= a + aw) { + obw = bw; + } else { + obw = (a + aw) - ob; + } + + return off; +} + +// this handler will catch and ignore exceptions during XGetImage +// to avoid an application crash +extern "C" { + static int xgetimageerrhandler(Display *display, XErrorEvent *error) { + return 0; + } +} + +uchar *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha) +{ + XImage *image; // Captured image + int i, maxindex; // Looping vars + int x, y; // Current X & Y in image + int d; // Depth of image + unsigned char *line, // Array to hold image row + *line_ptr; // Pointer to current line image + unsigned char *pixel; // Current color value + XColor colors[4096]; // Colors from the colormap... + unsigned char cvals[4096][3]; // Color values from the colormap... + unsigned index_mask, + index_shift, + red_mask, + red_shift, + green_mask, + green_shift, + blue_mask, + blue_shift; + // + // Under X11 we have the option of the XGetImage() interface or SGI's + // ReadDisplay extension which does all of the really hard work for + // us... + // + int allow_outside = w < 0; // negative w allows negative X or Y, that is, window frame + if (w < 0) w = - w; + +# ifdef __sgi + if (XReadDisplayQueryExtension(fl_display, &i, &i)) { + image = XReadDisplay(fl_display, fl_window, X, Y, w, h, 0, NULL); + } else +# else + image = 0; +# endif // __sgi + + if (!image) { + // fetch absolute coordinates + int dx, dy, sx, sy, sw, sh; + Window child_win; + + Fl_Window *win; + if (allow_outside) win = (Fl_Window*)1; + else win = fl_find(fl_window); + if (win) { + XTranslateCoordinates(fl_display, fl_window, + RootWindow(fl_display, fl_screen), X, Y, &dx, &dy, &child_win); + // screen dimensions + Fl::screen_xywh(sx, sy, sw, sh, fl_screen); + } + if (!win || (dx >= sx && dy >= sy && dx + w <= sx+sw && dy + h <= sy+sh)) { + // the image is fully contained, we can use the traditional method + // however, if the window is obscured etc. the function will still fail. Make sure we + // catch the error and continue, otherwise an exception will be thrown. + XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler); + image = XGetImage(fl_display, fl_window, X, Y, w, h, AllPlanes, ZPixmap); + XSetErrorHandler(old_handler); + } else { + // image is crossing borders, determine visible region + int nw, nh, noffx, noffy; + noffx = fl_subimage_offsets(sx, sw, dx, w, nw); + noffy = fl_subimage_offsets(sy, sh, dy, h, nh); + if (nw <= 0 || nh <= 0) return 0; + + // allocate the image + int bpp = fl_visual->depth + ((fl_visual->depth / 8) % 2) * 8; + char* buf = (char*)malloc(bpp / 8 * w * h); + image = XCreateImage(fl_display, fl_visual->visual, + fl_visual->depth, ZPixmap, 0, buf, w, h, bpp, 0); + if (!image) { + if (buf) free(buf); + return 0; + } + + XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler); + XImage *subimg = XGetSubImage(fl_display, fl_window, X + noffx, Y + noffy, + nw, nh, AllPlanes, ZPixmap, image, noffx, noffy); + XSetErrorHandler(old_handler); + if (!subimg) { + XDestroyImage(image); + return 0; + } + } + } + + if (!image) return 0; + +#ifdef DEBUG + printf("width = %d\n", image->width); + printf("height = %d\n", image->height); + printf("xoffset = %d\n", image->xoffset); + printf("format = %d\n", image->format); + printf("data = %p\n", image->data); + printf("byte_order = %d\n", image->byte_order); + printf("bitmap_unit = %d\n", image->bitmap_unit); + printf("bitmap_bit_order = %d\n", image->bitmap_bit_order); + printf("bitmap_pad = %d\n", image->bitmap_pad); + printf("depth = %d\n", image->depth); + printf("bytes_per_line = %d\n", image->bytes_per_line); + printf("bits_per_pixel = %d\n", image->bits_per_pixel); + printf("red_mask = %08x\n", image->red_mask); + printf("green_mask = %08x\n", image->green_mask); + printf("blue_mask = %08x\n", image->blue_mask); + printf("map_entries = %d\n", fl_visual->visual->map_entries); +#endif // DEBUG + + d = alpha ? 4 : 3; + + // Allocate the image data array as needed... + if (!p) p = new uchar[w * h * d]; + + // Initialize the default colors/alpha in the whole image... + memset(p, alpha, w * h * d); + + // Check that we have valid mask/shift values... + if (!image->red_mask && image->bits_per_pixel > 12) { + // Greater than 12 bits must be TrueColor... + image->red_mask = fl_visual->visual->red_mask; + image->green_mask = fl_visual->visual->green_mask; + image->blue_mask = fl_visual->visual->blue_mask; + +#ifdef DEBUG + // Defined in Fl_Xlib_Graphics_Driver_color.cxx + extern uchar fl_redmask, fl_greenmask, fl_bluemask; + extern int fl_redshift, fl_greenshift, fl_blueshift; + puts("\n---- UPDATED ----"); + printf("fl_redmask = %08x\n", fl_redmask); + printf("fl_redshift = %d\n", fl_redshift); + printf("fl_greenmask = %08x\n", fl_greenmask); + printf("fl_greenshift = %d\n", fl_greenshift); + printf("fl_bluemask = %08x\n", fl_bluemask); + printf("fl_blueshift = %d\n", fl_blueshift); + printf("red_mask = %08x\n", image->red_mask); + printf("green_mask = %08x\n", image->green_mask); + printf("blue_mask = %08x\n", image->blue_mask); +#endif // DEBUG + } + + // Check if we have colormap image... + if (!image->red_mask) { + // Get the colormap entries for this window... + maxindex = fl_visual->visual->map_entries; + + for (i = 0; i < maxindex; i ++) colors[i].pixel = i; + + XQueryColors(fl_display, fl_colormap, colors, maxindex); + + for (i = 0; i < maxindex; i ++) { + cvals[i][0] = colors[i].red >> 8; + cvals[i][1] = colors[i].green >> 8; + cvals[i][2] = colors[i].blue >> 8; + } + + // Read the pixels and output an RGB image... + for (y = 0; y < image->height; y ++) { + pixel = (unsigned char *)(image->data + y * image->bytes_per_line); + line = p + y * w * d; + + switch (image->bits_per_pixel) { + case 1 : + for (x = image->width, line_ptr = line, index_mask = 128; + x > 0; + x --, line_ptr += d) { + if (*pixel & index_mask) { + line_ptr[0] = cvals[1][0]; + line_ptr[1] = cvals[1][1]; + line_ptr[2] = cvals[1][2]; + } else { + line_ptr[0] = cvals[0][0]; + line_ptr[1] = cvals[0][1]; + line_ptr[2] = cvals[0][2]; + } + + if (index_mask > 1) { + index_mask >>= 1; + } else { + index_mask = 128; + pixel ++; + } + } + break; + + case 2 : + for (x = image->width, line_ptr = line, index_shift = 6; + x > 0; + x --, line_ptr += d) { + i = (*pixel >> index_shift) & 3; + + line_ptr[0] = cvals[i][0]; + line_ptr[1] = cvals[i][1]; + line_ptr[2] = cvals[i][2]; + + if (index_shift > 0) { + index_mask >>= 2; + index_shift -= 2; + } else { + index_mask = 192; + index_shift = 6; + pixel ++; + } + } + break; + + case 4 : + for (x = image->width, line_ptr = line, index_shift = 4; + x > 0; + x --, line_ptr += d) { + if (index_shift == 4) i = (*pixel >> 4) & 15; + else i = *pixel & 15; + + line_ptr[0] = cvals[i][0]; + line_ptr[1] = cvals[i][1]; + line_ptr[2] = cvals[i][2]; + + if (index_shift > 0) { + index_shift = 0; + } else { + index_shift = 4; + pixel ++; + } + } + break; + + case 8 : + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel ++) { + line_ptr[0] = cvals[*pixel][0]; + line_ptr[1] = cvals[*pixel][1]; + line_ptr[2] = cvals[*pixel][2]; + } + break; + + case 12 : + for (x = image->width, line_ptr = line, index_shift = 0; + x > 0; + x --, line_ptr += d) { + if (index_shift == 0) { + i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095; + } else { + i = ((pixel[1] << 8) | pixel[2]) & 4095; + } + + line_ptr[0] = cvals[i][0]; + line_ptr[1] = cvals[i][1]; + line_ptr[2] = cvals[i][2]; + + if (index_shift == 0) { + index_shift = 4; + } else { + index_shift = 0; + pixel += 3; + } + } + break; + } + } + } else { + // RGB(A) image, so figure out the shifts & masks... + red_mask = image->red_mask; + red_shift = 0; + + while ((red_mask & 1) == 0) { + red_mask >>= 1; + red_shift ++; + } + + green_mask = image->green_mask; + green_shift = 0; + + while ((green_mask & 1) == 0) { + green_mask >>= 1; + green_shift ++; + } + + blue_mask = image->blue_mask; + blue_shift = 0; + + while ((blue_mask & 1) == 0) { + blue_mask >>= 1; + blue_shift ++; + } + + // Read the pixels and output an RGB image... + for (y = 0; y < image->height; y ++) { + pixel = (unsigned char *)(image->data + y * image->bytes_per_line); + line = p + y * w * d; + + switch (image->bits_per_pixel) { + case 8 : + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel ++) { + i = *pixel; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + break; + + case 12 : + for (x = image->width, line_ptr = line, index_shift = 0; + x > 0; + x --, line_ptr += d) { + if (index_shift == 0) { + i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095; + } else { + i = ((pixel[1] << 8) | pixel[2]) & 4095; + } + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + + if (index_shift == 0) { + index_shift = 4; + } else { + index_shift = 0; + pixel += 3; + } + } + break; + + case 16 : + if (image->byte_order == LSBFirst) { + // Little-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 2) { + i = (pixel[1] << 8) | pixel[0]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } else { + // Big-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 2) { + i = (pixel[0] << 8) | pixel[1]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } + break; + + case 24 : + if (image->byte_order == LSBFirst) { + // Little-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 3) { + i = (((pixel[2] << 8) | pixel[1]) << 8) | pixel[0]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } else { + // Big-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 3) { + i = (((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } + break; + + case 32 : + if (image->byte_order == LSBFirst) { + // Little-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 4) { + i = (((((pixel[3] << 8) | pixel[2]) << 8) | pixel[1]) << 8) | pixel[0]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } else { + // Big-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 4) { + i = (((((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]) << 8) | pixel[3]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } + break; + } + } + } + + // Destroy the X image we've read and return the RGB(A) image... + XDestroyImage(image); + + return p; +} + +// // End of "$Id$". // diff --git a/src/fl_read_image.cxx b/src/fl_read_image.cxx index 114704f85..64161384e 100644 --- a/src/fl_read_image.cxx +++ b/src/fl_read_image.cxx @@ -17,629 +17,29 @@ // #include <FL/Fl.H> -#include <FL/x.H> -#include <FL/fl_draw.H> -#include "flstring.h" - -#ifdef DEBUG -# include <stdio.h> -#endif // DEBUG - -#if defined(WIN32) || defined(__APPLE__) // PORTME: Fl_Screen_Driver - platform screenshots -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: implement code to read RGB data from screen" -static uchar *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha) { } -#else -#endif - -#if defined(__APPLE__) // PORTME: Fl_Screen_Driver - platform screenshots -# include "fl_read_image_mac.cxx" -#else -# include <FL/Fl_RGB_Image.H> -# include <FL/Fl_Window.H> -# include <FL/Fl_Plugin.H> -# include <FL/Fl_Device.H> - -static uchar *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha); - - -static void write_image_inside(Fl_RGB_Image *to, Fl_RGB_Image *from, int to_x, int to_y) -/* Copy the image "from" inside image "to" with its top-left angle at coordinates to_x, to_y. - Image depth can differ between "to" and "from". - */ -{ - int to_ld = (to->ld() == 0? to->w() * to->d() : to->ld()); - int from_ld = (from->ld() == 0? from->w() * from->d() : from->ld()); - uchar *tobytes = (uchar*)to->array + to_y * to_ld + to_x * to->d(); - const uchar *frombytes = from->array; - for (int i = 0; i < from->h(); i++) { - if (from->d() == to->d()) memcpy(tobytes, frombytes, from->w() * from->d()); - else { - for (int j = 0; j < from->w(); j++) { - memcpy(tobytes + j * to->d(), frombytes + j * from->d(), from->d()); - } - } - tobytes += to_ld; - frombytes += from_ld; - } -} - -/* Captures rectangle x,y,w,h from a mapped window or GL window. - All sub-GL-windows that intersect x,y,w,h, and their subwindows, are also captured. +#include <FL/Fl_Screen_Driver.H> + +/** + Reads an RGB(A) image from the current window or off-screen buffer (if fl_window is null). + \param[in] p pixel buffer, or NULL to allocate one + \param[in] X,Y position of top-left of image to read + \param[in] W,H width and height of image to read + \param[in] alpha alpha value for image (0 for none) + \returns pointer to pixel buffer, or NULL if allocation failed. - Arguments when this function is initially called: - g: a window or GL window - p: as in fl_read_image() - x,y,w,h: a rectangle in window g's coordinates - alpha: as in fl_read_image() - full_img: NULL + The \p p argument points to a buffer that can hold the image and must + be at least \p W*H*3 bytes when reading RGB images, or \p W*H*4 bytes + when reading RGBA images. If NULL, fl_read_image() will create an + array of the proper size which can be freed using <tt>delete[]</tt>. - Arguments when this function recursively calls itself: - g: an Fl_Group - p: as above - x,y,w,h: a rectangle in g's coordinates if g is a window, or in g's parent window coords if g is a group - alpha: as above - full_img: NULL, or a previously captured image that encompasses the x,y,w,h rectangle and that - will be partially overwritten with the new capture - - Return value: - An Fl_RGB_Image* of depth 4 if alpha>0 or 3 if alpha = 0 containing the captured pixels. + The \p alpha parameter controls whether an alpha channel is created + and the value that is placed in the alpha channel. If 0, no alpha + channel is generated. */ -static Fl_RGB_Image *traverse_to_gl_subwindows(Fl_Group *g, uchar *p, int x, int y, int w, int h, int alpha, - Fl_RGB_Image *full_img) -{ - if ( g->as_gl_window() ) { - Fl_Plugin_Manager pm("fltk:device"); - Fl_Device_Plugin *pi = (Fl_Device_Plugin*)pm.plugin("opengl.device.fltk.org"); - if (!pi) return full_img; - Fl_RGB_Image *img = pi->rectangle_capture(g, x, y, w, h); - if (full_img) full_img = img; - else { - uchar *data = ( p ? p : new uchar[img->w() * img->h() * (alpha?4:3)] ); - full_img = new Fl_RGB_Image(data, img->w(), img->h(), alpha?4:3); - if (!p) full_img->alloc_array = 1; - if (alpha) memset(data, alpha, img->w() * img->h() * 4); - write_image_inside(full_img, img, 0, 0); - delete img; - } - } - else if ( g->as_window() && (!full_img || (g->window() && g->window()->as_gl_window())) ) { - // the starting window or one inside a GL window - if (full_img) g->as_window()->make_current(); - uchar *image_data; - int alloc_img = (full_img != NULL || p == NULL); // false means use p, don't alloc new memory for image -#ifdef __APPLE_CC__ // PORTME: Fl_Screen_Driver - platform screenshots - // on Darwin + X11, read_win_rectangle() sometimes returns NULL when there are subwindows - do image_data = read_win_rectangle( (alloc_img ? NULL : p), x, y, w, h, alpha); while (!image_data); -#else - image_data = read_win_rectangle( (alloc_img ? NULL : p), x, y, w, h, alpha); -#endif - full_img = new Fl_RGB_Image(image_data, w, h, alpha?4:3); - if (alloc_img) full_img->alloc_array = 1; - } - int n = g->children(); - for (int i = 0; i < n; i++) { - Fl_Widget *c = g->child(i); - if ( !c->visible() || !c->as_group()) continue; - if ( c->as_window() ) { - int origin_x = x; // compute intersection of x,y,w,h and the c window - if (x < c->x()) origin_x = c->x(); - int origin_y = y; - if (y < c->y()) origin_y = c->y(); - int width = c->w(); - if (origin_x + width > c->x() + c->w()) width = c->x() + c->w() - origin_x; - if (origin_x + width > x + w) width = x + w - origin_x; - int height = c->w(); - if (origin_y + height > c->y() + c->h()) height = c->y() + c->h() - origin_y; - if (origin_y + height > y + h) height = y + h - origin_y; - if (width > 0 && height > 0) { - Fl_RGB_Image *img = traverse_to_gl_subwindows(c->as_window(), p, origin_x - c->x(), - origin_y - c->y(), width, height, alpha, full_img); - if (img == full_img) continue; - int top; - if (c->as_gl_window()) { - top = origin_y - y; - } else { - top = full_img->h() - (origin_y - y + img->h()); - } - write_image_inside(full_img, img, origin_x - x, top); - delete img; - } - } - else traverse_to_gl_subwindows(c->as_group(), p, x, y, w, h, alpha, full_img); - } - return full_img; -} - -// -// 'fl_read_image()' - Read an image from the current window or off-screen buffer -// this is the version for X11 and WIN32. The mac version is in fl_read_image_mac.cxx - -uchar * // O - Pixel buffer or NULL if failed -fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate - int X, // I - Left position - int Y, // I - Top position - int w, // I - Width of area to read - // negative allows capture of window title bar and frame (X11 only) - int h, // I - Height of area to read - int alpha)// I - Alpha value for image (0 for none) -{ - if (w < 0 || fl_find(fl_window) == 0) { // read from off_screen buffer or title bar and frame - return read_win_rectangle(p, X, Y, w, h, alpha); // this function has an X11 and a WIN32 version - } - Fl_RGB_Image *img = traverse_to_gl_subwindows(Fl_Window::current(), p, X, Y, w, h, alpha, NULL); - uchar *image_data = (uchar*)img->array; - img->alloc_array = 0; - delete img; - return image_data; -} - -#ifdef WIN32 -# include "fl_read_image_win32.cxx" // gives the WIN32 version of read_win_rectangle() -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: create your own version of fl_read_image.cxx" -# include "fl_read_image_porting.cxx" -#else -# include <X11/Xutil.h> -# ifdef __sgi -# include <X11/extensions/readdisplay.h> -# else -# include <stdlib.h> -# endif // __sgi - -// Defined in fl_color.cxx -extern uchar fl_redmask, fl_greenmask, fl_bluemask; -extern int fl_redshift, fl_greenshift, fl_blueshift, fl_extrashift; - -// -// 'fl_subimage_offsets()' - Calculate subimage offsets for an axis -static inline int -fl_subimage_offsets(int a, int aw, int b, int bw, int &obw) -{ - int off; - int ob; - - if (b >= a) { - ob = b; - off = 0; - } else { - ob = a; - off = a - b; - } - - bw -= off; - - if (ob + bw <= a + aw) { - obw = bw; - } else { - obw = (a + aw) - ob; - } - - return off; -} - -// this handler will catch and ignore exceptions during XGetImage -// to avoid an application crash -extern "C" { - static int xgetimageerrhandler(Display *display, XErrorEvent *error) { - return 0; - } -} - - -static uchar *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha) -{ - XImage *image; // Captured image - int i, maxindex; // Looping vars - int x, y; // Current X & Y in image - int d; // Depth of image - unsigned char *line, // Array to hold image row - *line_ptr; // Pointer to current line image - unsigned char *pixel; // Current color value - XColor colors[4096]; // Colors from the colormap... - unsigned char cvals[4096][3]; // Color values from the colormap... - unsigned index_mask, - index_shift, - red_mask, - red_shift, - green_mask, - green_shift, - blue_mask, - blue_shift; - - - // - // Under X11 we have the option of the XGetImage() interface or SGI's - // ReadDisplay extension which does all of the really hard work for - // us... - // - int allow_outside = w < 0; // negative w allows negative X or Y, that is, window frame - if (w < 0) w = - w; - -# ifdef __sgi - if (XReadDisplayQueryExtension(fl_display, &i, &i)) { - image = XReadDisplay(fl_display, fl_window, X, Y, w, h, 0, NULL); - } else -# else - image = 0; -# endif // __sgi - - if (!image) { - // fetch absolute coordinates - int dx, dy, sx, sy, sw, sh; - Window child_win; - - Fl_Window *win; - if (allow_outside) win = (Fl_Window*)1; - else win = fl_find(fl_window); - if (win) { - XTranslateCoordinates(fl_display, fl_window, - RootWindow(fl_display, fl_screen), X, Y, &dx, &dy, &child_win); - // screen dimensions - Fl::screen_xywh(sx, sy, sw, sh, fl_screen); - } - if (!win || (dx >= sx && dy >= sy && dx + w <= sx+sw && dy + h <= sy+sh)) { - // the image is fully contained, we can use the traditional method - // however, if the window is obscured etc. the function will still fail. Make sure we - // catch the error and continue, otherwise an exception will be thrown. - XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler); - image = XGetImage(fl_display, fl_window, X, Y, w, h, AllPlanes, ZPixmap); - XSetErrorHandler(old_handler); - } else { - // image is crossing borders, determine visible region - int nw, nh, noffx, noffy; - noffx = fl_subimage_offsets(sx, sw, dx, w, nw); - noffy = fl_subimage_offsets(sy, sh, dy, h, nh); - if (nw <= 0 || nh <= 0) return 0; - - // allocate the image - int bpp = fl_visual->depth + ((fl_visual->depth / 8) % 2) * 8; - char* buf = (char*)malloc(bpp / 8 * w * h); - image = XCreateImage(fl_display, fl_visual->visual, - fl_visual->depth, ZPixmap, 0, buf, w, h, bpp, 0); - if (!image) { - if (buf) free(buf); - return 0; - } - - XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler); - XImage *subimg = XGetSubImage(fl_display, fl_window, X + noffx, Y + noffy, - nw, nh, AllPlanes, ZPixmap, image, noffx, noffy); - XSetErrorHandler(old_handler); - if (!subimg) { - XDestroyImage(image); - return 0; - } - } - } - - if (!image) return 0; - -#ifdef DEBUG - printf("width = %d\n", image->width); - printf("height = %d\n", image->height); - printf("xoffset = %d\n", image->xoffset); - printf("format = %d\n", image->format); - printf("data = %p\n", image->data); - printf("byte_order = %d\n", image->byte_order); - printf("bitmap_unit = %d\n", image->bitmap_unit); - printf("bitmap_bit_order = %d\n", image->bitmap_bit_order); - printf("bitmap_pad = %d\n", image->bitmap_pad); - printf("depth = %d\n", image->depth); - printf("bytes_per_line = %d\n", image->bytes_per_line); - printf("bits_per_pixel = %d\n", image->bits_per_pixel); - printf("red_mask = %08x\n", image->red_mask); - printf("green_mask = %08x\n", image->green_mask); - printf("blue_mask = %08x\n", image->blue_mask); - printf("map_entries = %d\n", fl_visual->visual->map_entries); -#endif // DEBUG - - d = alpha ? 4 : 3; - - // Allocate the image data array as needed... - if (!p) p = new uchar[w * h * d]; - - // Initialize the default colors/alpha in the whole image... - memset(p, alpha, w * h * d); - - // Check that we have valid mask/shift values... - if (!image->red_mask && image->bits_per_pixel > 12) { - // Greater than 12 bits must be TrueColor... - image->red_mask = fl_visual->visual->red_mask; - image->green_mask = fl_visual->visual->green_mask; - image->blue_mask = fl_visual->visual->blue_mask; - -#ifdef DEBUG - puts("\n---- UPDATED ----"); - printf("fl_redmask = %08x\n", fl_redmask); - printf("fl_redshift = %d\n", fl_redshift); - printf("fl_greenmask = %08x\n", fl_greenmask); - printf("fl_greenshift = %d\n", fl_greenshift); - printf("fl_bluemask = %08x\n", fl_bluemask); - printf("fl_blueshift = %d\n", fl_blueshift); - printf("red_mask = %08x\n", image->red_mask); - printf("green_mask = %08x\n", image->green_mask); - printf("blue_mask = %08x\n", image->blue_mask); -#endif // DEBUG - } - - // Check if we have colormap image... - if (!image->red_mask) { - // Get the colormap entries for this window... - maxindex = fl_visual->visual->map_entries; - - for (i = 0; i < maxindex; i ++) colors[i].pixel = i; - - XQueryColors(fl_display, fl_colormap, colors, maxindex); - - for (i = 0; i < maxindex; i ++) { - cvals[i][0] = colors[i].red >> 8; - cvals[i][1] = colors[i].green >> 8; - cvals[i][2] = colors[i].blue >> 8; - } - - // Read the pixels and output an RGB image... - for (y = 0; y < image->height; y ++) { - pixel = (unsigned char *)(image->data + y * image->bytes_per_line); - line = p + y * w * d; - - switch (image->bits_per_pixel) { - case 1 : - for (x = image->width, line_ptr = line, index_mask = 128; - x > 0; - x --, line_ptr += d) { - if (*pixel & index_mask) { - line_ptr[0] = cvals[1][0]; - line_ptr[1] = cvals[1][1]; - line_ptr[2] = cvals[1][2]; - } else { - line_ptr[0] = cvals[0][0]; - line_ptr[1] = cvals[0][1]; - line_ptr[2] = cvals[0][2]; - } - - if (index_mask > 1) { - index_mask >>= 1; - } else { - index_mask = 128; - pixel ++; - } - } - break; - - case 2 : - for (x = image->width, line_ptr = line, index_shift = 6; - x > 0; - x --, line_ptr += d) { - i = (*pixel >> index_shift) & 3; - - line_ptr[0] = cvals[i][0]; - line_ptr[1] = cvals[i][1]; - line_ptr[2] = cvals[i][2]; - - if (index_shift > 0) { - index_mask >>= 2; - index_shift -= 2; - } else { - index_mask = 192; - index_shift = 6; - pixel ++; - } - } - break; - - case 4 : - for (x = image->width, line_ptr = line, index_shift = 4; - x > 0; - x --, line_ptr += d) { - if (index_shift == 4) i = (*pixel >> 4) & 15; - else i = *pixel & 15; - - line_ptr[0] = cvals[i][0]; - line_ptr[1] = cvals[i][1]; - line_ptr[2] = cvals[i][2]; - - if (index_shift > 0) { - index_shift = 0; - } else { - index_shift = 4; - pixel ++; - } - } - break; - - case 8 : - for (x = image->width, line_ptr = line; - x > 0; - x --, line_ptr += d, pixel ++) { - line_ptr[0] = cvals[*pixel][0]; - line_ptr[1] = cvals[*pixel][1]; - line_ptr[2] = cvals[*pixel][2]; - } - break; - - case 12 : - for (x = image->width, line_ptr = line, index_shift = 0; - x > 0; - x --, line_ptr += d) { - if (index_shift == 0) { - i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095; - } else { - i = ((pixel[1] << 8) | pixel[2]) & 4095; - } - - line_ptr[0] = cvals[i][0]; - line_ptr[1] = cvals[i][1]; - line_ptr[2] = cvals[i][2]; - - if (index_shift == 0) { - index_shift = 4; - } else { - index_shift = 0; - pixel += 3; - } - } - break; - } - } - } else { - // RGB(A) image, so figure out the shifts & masks... - red_mask = image->red_mask; - red_shift = 0; - - while ((red_mask & 1) == 0) { - red_mask >>= 1; - red_shift ++; - } - - green_mask = image->green_mask; - green_shift = 0; - - while ((green_mask & 1) == 0) { - green_mask >>= 1; - green_shift ++; - } - - blue_mask = image->blue_mask; - blue_shift = 0; - - while ((blue_mask & 1) == 0) { - blue_mask >>= 1; - blue_shift ++; - } - - // Read the pixels and output an RGB image... - for (y = 0; y < image->height; y ++) { - pixel = (unsigned char *)(image->data + y * image->bytes_per_line); - line = p + y * w * d; - - switch (image->bits_per_pixel) { - case 8 : - for (x = image->width, line_ptr = line; - x > 0; - x --, line_ptr += d, pixel ++) { - i = *pixel; - - line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; - line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; - line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; - } - break; - - case 12 : - for (x = image->width, line_ptr = line, index_shift = 0; - x > 0; - x --, line_ptr += d) { - if (index_shift == 0) { - i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095; - } else { - i = ((pixel[1] << 8) | pixel[2]) & 4095; - } - - line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; - line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; - line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; - - if (index_shift == 0) { - index_shift = 4; - } else { - index_shift = 0; - pixel += 3; - } - } - break; - - case 16 : - if (image->byte_order == LSBFirst) { - // Little-endian... - for (x = image->width, line_ptr = line; - x > 0; - x --, line_ptr += d, pixel += 2) { - i = (pixel[1] << 8) | pixel[0]; - - line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; - line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; - line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; - } - } else { - // Big-endian... - for (x = image->width, line_ptr = line; - x > 0; - x --, line_ptr += d, pixel += 2) { - i = (pixel[0] << 8) | pixel[1]; - - line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; - line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; - line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; - } - } - break; - - case 24 : - if (image->byte_order == LSBFirst) { - // Little-endian... - for (x = image->width, line_ptr = line; - x > 0; - x --, line_ptr += d, pixel += 3) { - i = (((pixel[2] << 8) | pixel[1]) << 8) | pixel[0]; - - line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; - line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; - line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; - } - } else { - // Big-endian... - for (x = image->width, line_ptr = line; - x > 0; - x --, line_ptr += d, pixel += 3) { - i = (((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]; - - line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; - line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; - line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; - } - } - break; - - case 32 : - if (image->byte_order == LSBFirst) { - // Little-endian... - for (x = image->width, line_ptr = line; - x > 0; - x --, line_ptr += d, pixel += 4) { - i = (((((pixel[3] << 8) | pixel[2]) << 8) | pixel[1]) << 8) | pixel[0]; - - line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; - line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; - line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; - } - } else { - // Big-endian... - for (x = image->width, line_ptr = line; - x > 0; - x --, line_ptr += d, pixel += 4) { - i = (((((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]) << 8) | pixel[3]; - - line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; - line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; - line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; - } - } - break; - } - } - } - - // Destroy the X image we've read and return the RGB(A) image... - XDestroyImage(image); - - return p; +uchar *fl_read_image(uchar *p, int X, int Y, int w, int h, int alpha) { + return Fl::screen_driver()->read_image(p, X, Y, w, h, alpha); } -#endif // !WIN32 - -#endif // !__APPLE__ // PORTME: Fl_Screen_Driver - platform screenshots - // // End of "$Id$". // |
