Fix for STR#3142 where fl_read_image() correctly reads GL data under X11, but ignores them under MSWindows and Mac OS X.

Moreover, fl_read_image() behaves differently with and without OS virtualization for X11 and MSWindows.
The patched function reads whatever is in the rectangle transmitted in arguments, with and without GL data, with and without subwindows,
on ‘true’ OS or on virtualized OS.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10436 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy
2014-11-06 16:48:57 +00:00
parent f5e023f9c8
commit bd1446a6eb
7 changed files with 393 additions and 114 deletions
+6 -2
View File
@@ -4,7 +4,7 @@
// Definition of classes Fl_Device, Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device
// for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2012 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
@@ -558,7 +558,7 @@ public:
/**
This plugin socket allows the integration of new device drivers for special
window or screen types. It is currently used to provide an automated printing
service for OpenGL windows, if linked with fltk_gl.
service and screen capture for OpenGL windows, if linked with fltk_gl.
*/
class FL_EXPORT Fl_Device_Plugin : public Fl_Plugin {
public:
@@ -575,6 +575,10 @@ public:
\param height height of the current drawing area
*/
virtual int print(Fl_Widget* w, int x, int y, int height) = 0;
/** captures a rectangle of a widget as an image
\return The captured pixels as an RGB image
*/
virtual Fl_RGB_Image* rectangle_capture(Fl_Widget *widget, int x, int y, int w, int h) = 0;
};
#endif // Fl_Device_H
+47 -50
View File
@@ -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)
baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth);
mByteWidth = 3 * w;
#endif
#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);
}
};
+2 -7
View File
@@ -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) {
+182 -31
View File
@@ -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;
}
+4 -1
View File
@@ -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);
+149 -16
View File
@@ -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$".
+3 -7
View File
@@ -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