summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FL/Fl_Screen_Driver.H11
-rw-r--r--FL/fl_draw.H18
-rw-r--r--src/Fl_Screen_Driver.cxx126
-rw-r--r--src/Makefile4
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H1
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx45
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H1
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx100
-rw-r--r--src/drivers/X11/Fl_X11_Screen_Driver.H1
-rw-r--r--src/drivers/X11/Fl_X11_Screen_Driver.cxx456
-rw-r--r--src/fl_read_image.cxx636
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$".
//