Rewrite fl_read_image.cxx under the driver model.

Files fl_read_image_mac.cxx and fl_read_image_win32.cxx are no longer used;
their content is now in Fl_XXX_Screen_Driver.cxx

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11516 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2016-04-03 06:51:09 +00:00
parent c88af210e7
commit f1ffe2f1fe
11 changed files with 757 additions and 644 deletions

View File

@ -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);
};

View File

@ -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:

View File

@ -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$".
//

View File

@ -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

View File

@ -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);
};

View File

@ -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$".
//

View File

@ -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);
};

View File

@ -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$".
//

View File

@ -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);
};

View File

@ -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
@ -665,6 +676,451 @@ void Fl_Screen_Driver::font_name(int num, const char *name) {
s->first = 0;
}
//
// '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$".
//

View File

@ -17,629 +17,29 @@
//
#include <FL/Fl.H>
#include <FL/x.H>
#include <FL/fl_draw.H>
#include "flstring.h"
#include <FL/Fl_Screen_Driver.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".
/**
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.
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.
*/
{
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;
}
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);
}
/* 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);
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;
}
#endif // !WIN32
#endif // !__APPLE__ // PORTME: Fl_Screen_Driver - platform screenshots
//
// End of "$Id$".
//