summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Fl_Gl_Device_Plugin.cxx97
-rw-r--r--src/Fl_Paged_Device.cxx9
-rw-r--r--src/Fl_cocoa.mm213
-rw-r--r--src/Fl_win32.cxx5
-rw-r--r--src/fl_read_image.cxx165
-rw-r--r--src/fl_read_image_win32.cxx10
6 files changed, 387 insertions, 112 deletions
diff --git a/src/Fl_Gl_Device_Plugin.cxx b/src/Fl_Gl_Device_Plugin.cxx
index fbcb2f613..ed2889dbe 100644
--- a/src/Fl_Gl_Device_Plugin.cxx
+++ b/src/Fl_Gl_Device_Plugin.cxx
@@ -3,7 +3,7 @@
//
// implementation of class Fl_Gl_Device_Plugin for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2010 by Bill Spitzak and others.
+// Copyright 2010-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -20,19 +20,36 @@
#include <FL/Fl_Printer.H>
#include <FL/Fl_Gl_Window.H>
#include "Fl_Gl_Choice.H"
+#include <FL/Fl_RGB_Image.H>
#include "FL/Fl.H"
-#ifndef __APPLE__
-#include "FL/fl_draw.H"
-#endif
#if defined(__APPLE__)
-static void imgProviderReleaseData (void *info, const void *data, size_t size)
+uchar *convert_BGRA_to_RGB(uchar *baseAddress, int w, int h, int mByteWidth)
{
- free((void *)data);
+ uchar *newimg = new uchar[3*w*h];
+ uchar *to = newimg;
+ for (int i = 0; i < h; i++) {
+ uchar *from = baseAddress + i * mByteWidth;
+ for (int j = 0; j < w; j++, from += 4) {
+#if __ppc__
+ memcpy(to, from + 1, 3);
+ to += 3;
+#else
+ *(to++) = *(from+2);
+ *(to++) = *(from+1);
+ *(to++) = *from;
+#endif
+ }
+ }
+ delete[] baseAddress;
+ return newimg;
}
#endif
-static void print_gl_window(Fl_Gl_Window *glw, int x, int y, int height)
+static Fl_RGB_Image* capture_gl_rectangle(Fl_Gl_Window *glw, int x, int y, int w, int h)
+/* captures a rectangle of a Fl_Gl_Window window, and returns it as a RGB image
+ stored from bottom to top.
+ */
{
#if defined(__APPLE__)
const int bytesperpixel = 4;
@@ -48,66 +65,46 @@ static void print_gl_window(Fl_Gl_Window *glw, int x, int y, int height)
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
// Read a block of pixels from the frame buffer
- int mByteWidth = glw->w() * bytesperpixel;
+ int mByteWidth = w * bytesperpixel;
mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes
- uchar *baseAddress = (uchar*)malloc(mByteWidth * glw->h());
- glReadPixels(0, 0, glw->w(), glw->h(),
+ uchar *baseAddress = new uchar[mByteWidth * h];
+ glReadPixels(x, glw->h() - (y+h), w, h,
#if defined(__APPLE__)
- GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
#else
- GL_RGB, GL_UNSIGNED_BYTE,
+ GL_RGB, GL_UNSIGNED_BYTE,
#endif
- baseAddress);
+ baseAddress);
glPopClientAttrib();
#if defined(__APPLE__)
-// kCGBitmapByteOrder32Host and CGBitmapInfo are supposed to arrive with 10.4
-// but some 10.4 don't have kCGBitmapByteOrder32Host, so we play a little #define game
-#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
-#define kCGBitmapByteOrder32Host 0
-#define CGBitmapInfo CGImageAlphaInfo
-#elif ! defined(kCGBitmapByteOrder32Host)
-#ifdef __BIG_ENDIAN__
-#define kCGBitmapByteOrder32Host (4 << 12)
-#else /* Little endian. */
-#define kCGBitmapByteOrder32Host (2 << 12)
-#endif
+ baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth);
+ mByteWidth = 3 * w;
#endif
- CGColorSpaceRef cSpace = CGColorSpaceCreateDeviceRGB();
- CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, mByteWidth * glw->h(), imgProviderReleaseData);
- CGImageRef image = CGImageCreate(glw->w(), glw->h(), 8, 8*bytesperpixel, mByteWidth, cSpace,
- (CGBitmapInfo)(kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host),
- provider, NULL, false, kCGRenderingIntentDefault);
- if(image == NULL) return;
- CGContextSaveGState(fl_gc);
- CGContextTranslateCTM(fl_gc, 0, height);
- CGContextScaleCTM(fl_gc, 1.0f, -1.0f);
- CGRect rect = { { x, height - y - glw->h() }, { glw->w(), glw->h() } };
- Fl_X::q_begin_image(rect, 0, 0, glw->w(), glw->h());
- CGContextDrawImage(fl_gc, rect, image);
- Fl_X::q_end_image();
- CGContextRestoreGState(fl_gc);
- CGImageRelease(image);
- CGColorSpaceRelease(cSpace);
- CGDataProviderRelease(provider);
-#else
- fl_draw_image(baseAddress + (glw->h() - 1) * mByteWidth, x, y , glw->w(), glw->h(), bytesperpixel, - mByteWidth);
- free(baseAddress);
-#endif // __APPLE__
+ Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, mByteWidth);
+ img->alloc_array = 1;
+ return img;
}
/**
- This class will make sure that OpenGL printing is available if fltk_gl
- was linked to the program.
+ This class will make sure that OpenGL printing/screen capture is available if fltk_gl
+ was linked to the program
*/
class Fl_Gl_Device_Plugin : public Fl_Device_Plugin {
public:
Fl_Gl_Device_Plugin() : Fl_Device_Plugin(name()) { }
virtual const char *name() { return "opengl.device.fltk.org"; }
- virtual int print(Fl_Widget *w, int x, int y, int height) {
+ virtual int print(Fl_Widget *w, int x, int y, int height /*useless*/) {
Fl_Gl_Window *glw = w->as_gl_window();
if (!glw) return 0;
- print_gl_window(glw, x, y, height);
- return 1;
+ Fl_RGB_Image *img = capture_gl_rectangle(glw, 0, 0, glw->w(), glw->h());
+ fl_draw_image(img->array + (glw->h() - 1) * img->ld(), x, y , glw->w(), glw->h(), 3, - img->ld());
+ delete img;
+ return 1;
+ }
+ virtual Fl_RGB_Image* rectangle_capture(Fl_Widget *widget, int x, int y, int w, int h) {
+ Fl_Gl_Window *glw = widget->as_gl_window();
+ if (!glw) return NULL;
+ return capture_gl_rectangle(glw, x, y, w, h);
}
};
diff --git a/src/Fl_Paged_Device.cxx b/src/Fl_Paged_Device.cxx
index fcc18eab2..7f4d9d1a6 100644
--- a/src/Fl_Paged_Device.cxx
+++ b/src/Fl_Paged_Device.cxx
@@ -3,7 +3,7 @@
//
// implementation of Fl_Paged_Device class for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2010-2011 by Bill Spitzak and others.
+// Copyright 2010-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -63,12 +63,7 @@ void Fl_Paged_Device::print_widget(Fl_Widget* widget, int delta_x, int delta_y)
Fl_Plugin_Manager pm("fltk:device");
Fl_Device_Plugin *pi = (Fl_Device_Plugin*)pm.plugin("opengl.device.fltk.org");
if (pi) {
- int height = 0;
-#ifdef __APPLE__
- int width;
- this->printable_rect(&width, &height);
-#endif
- drawn_by_plugin = pi->print(widget, 0, 0, height);
+ drawn_by_plugin = pi->print(widget, 0, 0, 0);
}
}
if (!drawn_by_plugin) {
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm
index 61e327c55..abb568cde 100644
--- a/src/Fl_cocoa.mm
+++ b/src/Fl_cocoa.mm
@@ -3837,29 +3837,176 @@ int Fl::dnd(void)
return true;
}
-static NSBitmapImageRep* rect_to_NSBitmapImageRep(Fl_Window *win, int x, int y, int w, int h)
-// the returned value is autoreleased
+static void write_bitmap_inside(NSBitmapImageRep *to, int to_width, NSBitmapImageRep *from,
+ int to_x, int to_y)
+/* Copies in bitmap "to" the bitmap "from" with its top-left angle at coordinates to_x, to_y
+ On retina displays both bitmaps have double width and height
+ to_width is the width in screen units of "to". On retina, its pixel width is twice that.
+ */
{
- NSRect rect;
- NSView *winview = nil;
+ int to_w = (int)[to pixelsWide]; // pixel width of "to"
+ int from_w = (int)[from pixelsWide]; // pixel width of "from"
+ int from_h = [from pixelsHigh]; // pixel height of "from"
+ int to_depth = [to samplesPerPixel], from_depth = [from samplesPerPixel];
+ int depth = 0;
+ if (to_depth > from_depth) depth = from_depth;
+ else if (from_depth > to_depth) depth = to_depth;
+ float factor = to_w / (float)to_width; // scaling factor is 1 for classic displays and 2 for retina
+ to_x = factor*to_x; // transform offset from screen unit to pixels
+ to_y = factor*to_y;
+ // perform the copy
+ uchar *tobytes = [to bitmapData] + to_y * to_w * to_depth + to_x * to_depth;
+ uchar *frombytes = [from bitmapData];
+ for (int i = 0; i < from_h; i++) {
+ if (depth == 0) memcpy(tobytes, frombytes, from_w * from_depth);
+ else {
+ for (int j = 0; j < from_w; j++) {
+ memcpy(tobytes + j * to_depth, frombytes + j * from_depth, depth);
+ }
+ }
+ tobytes += to_w * to_depth;
+ frombytes += from_w * from_depth;
+ }
+}
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+static CGImageRef GL_rect_to_CGImage(Fl_Window *win, int x, int y, int w, int h)
+// to be used with Mac OS ≥ 10.6 to support retina displays
+// captures a rectangle from a GL window and returns it as a CGImageRef
+// with retina the image dimensions are 2*w,2*h
+// win is really a Fl_Gl_Window*
+{
+ CGRect rect;
while (win->window()) {
x += win->x();
y += win->y();
win = win->window();
}
- if ( through_drawRect ) {
- CGFloat epsilon = 0;
- if (fl_mac_os_version >= 100600) epsilon = 0.5; // STR #2887
- rect = NSMakeRect(x - epsilon, y - epsilon, w, h);
+ NSRect r = [fl_xid(win) frame];
+ rect = CGRectMake(r.origin.x + x, r.origin.y + win->h() - (y + h), w, h); // rect is target rect in window coordinates
+ // convert r to global display coordinates
+ rect.origin.y = CGDisplayPixelsHigh(CGMainDisplayID()) - (rect.origin.y + rect.size.height);
+ uint32_t count;
+ CGDirectDisplayID win_display;
+ CGGetDisplaysWithPoint(rect.origin, 1, &win_display, &count); // find display containing the window
+ CGRect bounds = CGDisplayBounds(win_display);
+ rect.origin.x -= bounds.origin.x; // rect is now in local display coordinates
+ rect.origin.y -= bounds.origin.y;
+ return CGDisplayCreateImageForRect(win_display, rect); // Mac OS 10.6
+}
+#endif
+
+
+static void imgProviderReleaseData (void *info, const void *data, size_t size)
+{
+ delete (Fl_RGB_Image *)info;
+}
+
+
+CGImageRef GL_rect_to_CGImage_10_5(Fl_Window *win, int x, int y, int w, int h)
+// captures a rectangle from a GL window and returns it as a CGImageRef
+// used with Mac OS X 10.5 and before
+// win is really a Fl_Gl_Window*
+{
+ Fl_Plugin_Manager pm("fltk:device");
+ Fl_Device_Plugin *pi = (Fl_Device_Plugin*)pm.plugin("opengl.device.fltk.org");
+ if (!pi) return NULL;
+ Fl_RGB_Image *img = pi->rectangle_capture(win, x, y, w, h);
+ CGColorSpaceRef cSpace = CGColorSpaceCreateDeviceRGB();
+ CGDataProviderRef provider = CGDataProviderCreateWithData(img, img->array, img->ld() * h, imgProviderReleaseData);
+ CGImageRef image = CGImageCreate(img->w(), img->h(), 8, 24, img->ld(), cSpace,
+ (CGBitmapInfo)(kCGImageAlphaNone),
+ provider, NULL, false, kCGRenderingIntentDefault);
+ CGColorSpaceRelease(cSpace);
+ CGDataProviderRelease(provider);
+ if (image == NULL) delete img;
+ return image;
+}
+
+
+static NSBitmapImageRep* GL_rect_to_nsbitmap(Fl_Window *win, int x, int y, int w, int h)
+// captures a rectangle from a GL window and returns it as an allocated NSBitmapImageRep
+{
+ CGImageRef image;
+ BOOL toflip = YES;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+ if (fl_mac_os_version >= 100600) {
+ image = GL_rect_to_CGImage(win, x, y, w, h); // BGRA top to bottom
+ toflip = NO;
+ }
+ else
+#endif
+ image = GL_rect_to_CGImage_10_5(win, x, y, w, h); // RGB bottom to top
+ if (!image) return nil;
+ w = CGImageGetWidth(image);
+ h = CGImageGetHeight(image);
+ // convert image to RGBA writing it to a bitmap context
+ Fl_Offscreen offscreen = fl_create_offscreen(w, h);
+ fl_begin_offscreen(offscreen);
+ if (toflip) {
+ CGContextTranslateCTM(fl_gc, 0, h);
+ CGContextScaleCTM(fl_gc, 1.0f, -1.0f);
+ }
+ CGRect rect = CGRectMake(0, 0, w, h);
+ Fl_X::q_begin_image(rect, 0, 0, w, h);
+ CGContextDrawImage(fl_gc, rect, image);
+ Fl_X::q_end_image();
+ CGImageRelease(image);
+ fl_end_offscreen();
+ NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:w pixelsHigh:h bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:4*w bitsPerPixel:32];
+ memcpy([bitmap bitmapData], CGBitmapContextGetData(offscreen), CGBitmapContextGetBytesPerRow(offscreen)*CGBitmapContextGetHeight(offscreen));
+ fl_delete_offscreen(offscreen);
+ return bitmap;
+}
+
+static NSBitmapImageRep* rect_to_NSBitmapImageRep(Fl_Window *win, int x, int y, int w, int h)
+/* Captures a rectangle from a mapped window.
+ On retina displays, the resulting bitmap has 2 pixels per screen unit.
+ The returned value is to be released after use
+ */
+{
+ NSBitmapImageRep *bitmap = nil;
+ NSRect rect;
+ if (win->as_gl_window() && y >= 0) {
+ bitmap = GL_rect_to_nsbitmap(win, x, y, w, h);
+ } else {
+ while (win->window()) {
+ x += win->x();
+ y += win->y();
+ win = win->window();
+ }
+ NSView *winview = nil;
+ if ( through_drawRect && Fl_Window::current() == win ) {
+ CGFloat epsilon = 0;
+ if (fl_mac_os_version >= 100600) epsilon = 0.5; // STR #2887
+ rect = NSMakeRect(x - epsilon, y - epsilon, w, h);
}
- else {
- rect = NSMakeRect(x, win->h()-(y+h), w, h);
- // lock focus to win's view
- winview = [fl_xid(win) contentView];
- [winview lockFocus];
+ else {
+ rect = NSMakeRect(x, win->h()-(y+h), w, h);
+ // lock focus to win's view
+ winview = [fl_xid(win) contentView];
+ [winview lockFocus];
}
- NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:rect] autorelease];
- if ( !through_drawRect ) [winview unlockFocus];
+ // The image depth is 3 until 10.5 and 4 with 10.6 and above
+ bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:rect];
+ if ( !( through_drawRect && Fl_Window::current() == win) ) [winview unlockFocus];
+ if (!bitmap) return nil;
+ }
+
+ // it's necessary to capture also GL subwindows
+ for (Fl_X *flx = Fl_X::i(win)->xidChildren; flx; flx = flx->xidNext) {
+ Fl_Window *sub = flx->w;
+ if (!sub->as_gl_window() ) continue;
+ CGRect rsub = CGRectMake(sub->x(), win->h() -(sub->y()+sub->h()), sub->w(), sub->h());
+ CGRect clip = CGRectMake(x, win->h()-(y+h), w, h);
+ clip = CGRectIntersection(rsub, clip);
+ if (CGRectIsNull(clip)) continue;
+ NSBitmapImageRep *childbitmap = rect_to_NSBitmapImageRep(sub, clip.origin.x - sub->x(),
+ win->h() - clip.origin.y - sub->y() - clip.size.height, clip.size.width, clip.size.height);
+ if (childbitmap) write_bitmap_inside(bitmap, w, childbitmap,
+ clip.origin.x - x, win->h() - clip.origin.y - clip.size.height - y );
+ [childbitmap release];
+ }
return bitmap;
}
@@ -3904,35 +4051,39 @@ unsigned char *Fl_X::bitmap_from_window_rect(Fl_Window *win, int x, int y, int w
}
}
}
+ [bitmap release];
return data;
}
-static void imgProviderReleaseData (void *info, const void *data, size_t size)
+static void nsbitmapProviderReleaseData (void *info, const void *data, size_t size)
{
- delete[] (unsigned char *)data;
+ [(NSBitmapImageRep*)info release];
}
CGImageRef Fl_X::CGImage_from_window_rect(Fl_Window *win, int x, int y, int w, int h)
-// CFRelease the returned CGImageRef after use
+/* Returns a capture of a rectangle of a mapped window as a CGImage.
+ With retina displays, the returned image has twice the width and height.
+ CFRelease the returned CGImageRef after use
+ */
{
CGImageRef img;
+ NSBitmapImageRep *bitmap = rect_to_NSBitmapImageRep(win, x, y, w, h);
if (fl_mac_os_version >= 100500) {
- NSBitmapImageRep *bitmap = rect_to_NSBitmapImageRep(win, x, y, w, h);
img = (CGImageRef)[bitmap performSelector:@selector(CGImage)]; // requires Mac OS 10.5
CGImageRetain(img);
- }
- else {
- int bpp;
- unsigned char *bitmap = bitmap_from_window_rect(win, x, y, w, h, &bpp);
- if (!bitmap) return NULL;
- CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
- CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bitmap, w*h*bpp, imgProviderReleaseData);
- img = CGImageCreate(w, h, 8, 8*bpp, w*bpp, lut,
- bpp == 3 ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast,
- provider, NULL, false, kCGRenderingIntentDefault);
- CGColorSpaceRelease(lut);
+ [bitmap release];
+ } else {
+ CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
+ CGDataProviderRef provider = CGDataProviderCreateWithData(bitmap, [bitmap bitmapData],
+ [bitmap bytesPerRow]*[bitmap pixelsHigh],
+ nsbitmapProviderReleaseData);
+ img = CGImageCreate([bitmap pixelsWide], [bitmap pixelsHigh], 8, [bitmap bitsPerPixel], [bitmap bytesPerRow],
+ cspace,
+ [bitmap bitsPerPixel] == 32 ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNone,
+ provider, NULL, false, kCGRenderingIntentDefault);
+ CGColorSpaceRelease(cspace);
CGDataProviderRelease(provider);
- }
+ }
return img;
}
diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx
index df86652d2..ea2f352ea 100644
--- a/src/Fl_win32.cxx
+++ b/src/Fl_win32.cxx
@@ -2683,11 +2683,14 @@ void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
fl_gc = GetDC(NULL); // get the screen device context
// capture the 4 window sides from screen
RECT r; GetWindowRect(fl_window, &r);
+ Window save_win = fl_window;
+ fl_window = NULL; // force use of read_win_rectangle() by fl_read_image()
uchar *top_image = fl_read_image(NULL, r.left, r.top, ww, bt + by);
uchar *left_image = fl_read_image(NULL, r.left, r.top, bx, wh);
uchar *right_image = fl_read_image(NULL, r.right - bx, r.top, bx, wh);
uchar *bottom_image = fl_read_image(NULL, r.left, r.bottom-by, ww, by);
- ReleaseDC(NULL, fl_gc); fl_gc = save_gc;
+ fl_window = save_win;
+ ReleaseDC(NULL, fl_gc); fl_gc = save_gc;
this->set_current();
// print the 4 window sides
fl_draw_image(top_image, x_offset, y_offset, ww, bt + by, 3);
diff --git a/src/fl_read_image.cxx b/src/fl_read_image.cxx
index f253c2aa8..89ff3e49e 100644
--- a/src/fl_read_image.cxx
+++ b/src/fl_read_image.cxx
@@ -3,7 +3,7 @@
//
// X11 image reading routines for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2010 by Bill Spitzak and others.
+// Copyright 1998-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -25,11 +25,151 @@
# include <stdio.h>
#endif // DEBUG
-#ifdef WIN32
-# include "fl_read_image_win32.cxx"
-#elif defined(__APPLE__)
+#if defined(__APPLE__)
# 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.
+ Also, exchange top and bottom of "from". 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 + (from->h() - 1) * from_ld;
+ for (int i = from->h() - 1; i >= 0; 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.
+ */
+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); // bottom to top image
+ if (full_img) full_img = img; // top and bottom will be exchanged later
+ else { // exchange top and bottom to get a proper FLTK image
+ 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__
+ // 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()
+#else
# include <X11/Xutil.h>
# ifdef __sgi
# include <X11/extensions/readdisplay.h>
@@ -76,18 +216,9 @@ extern "C" {
}
}
-//
-// 'fl_read_image()' - Read an image from the current window.
-//
-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
- int h, // I - Height of area to read
- int alpha) { // I - Alpha value for image (0 for none)
+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
@@ -495,7 +626,9 @@ fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate
return p;
}
-#endif
+#endif // !WIN32
+
+#endif // !__APPLE__
//
// End of "$Id$".
diff --git a/src/fl_read_image_win32.cxx b/src/fl_read_image_win32.cxx
index a811248aa..28f83017a 100644
--- a/src/fl_read_image_win32.cxx
+++ b/src/fl_read_image_win32.cxx
@@ -3,7 +3,7 @@
//
// WIN32 image reading routines for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2010 by Bill Spitzak and others.
+// Copyright 1998-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -16,12 +16,8 @@
// http://www.fltk.org/str.php
//
-//
-// 'fl_read_image()' - Read an image from the current window.
-//
-
-uchar * // O - Pixel buffer or NULL if failed
-fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate
+static uchar * // O - Pixel buffer or NULL if failed
+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