+0.004
+ - add support for getting a subimage of the window
+ - include the interface header in the implementations so we
+ get errors when they don't match (doh!)
+ - return something from the X11 error handler
+ - add X11/Xutil.h include for XDestroyImage()
+ - handle the default (no id or hwnd) case correctly
+
0.003 12 Jan 2007
- 0.003 release
- ignore some VC++ generated junk in MANIFEST.SKIP
# lose the class if called as a method
@_ % 2 == 1 and shift;
- my %opts = (decor => 0, display => 0, @_);
+ my %opts =
+ (
+ decor => 0,
+ display => 0,
+ left => 0,
+ top => 0,
+ right => 0,
+ bottom => 0,
+ @_);
my $result;
- if (!@_) {
- my $result =
- defined &_win32 ? _win32(0) :
- defined &_x11 ? _x11($opts{display}, 0) :
- die "No drivers enabled\n";
- }
if (defined $opts{hwnd}) {
defined &_win32
or die "Win32 driver not enabled\n";
- $result = _win32($opts{hwnd}, $opts{decor});
+ $result = _win32($opts{hwnd}, $opts{decor}, $opts{left}, $opts{top},
+ $opts{right}, $opts{bottom});
}
elsif (defined $opts{id}) { # X11 window id
defined &_x11
or die "X11 driver not enabled\n";
- $result = _x11($opts{display}, $opts{id});
+ $result = _x11($opts{display}, $opts{id}, $opts{left}, $opts{top},
+ $opts{right}, $opts{bottom});
}
elsif ($opts{widget}) {
# Perl/Tk widget
Imager->_set_error("Win32 Tk and Win32 support not built");
return;
}
- $result = _win32(hex($opts{widget}->id));
+ $result = _win32(hex($opts{widget}->id), $opts{decor},
+ $opts{left}, $opts{top}, $opts{right}, $opts{bottom});
}
elsif ($sys eq 'x11') {
unless (defined &_x11) {
and $id_hex = $opts{widget}->frame;
# is there a way to get the display pointer from Tk?
- $result = _x11(0, hex($id_hex));
+ $result = _x11($opts{display}, hex($id_hex), $opts{left}, $opts{top},
+ $opts{right}, $opts{bottom});
}
else {
Imager->_set_error("Unsupported windowing system '$sys'");
return;
}
}
+ else {
+ $result =
+ defined &_win32 ? _win32(0, $opts{decor}, $opts{left}, $opts{top},
+ $opts{right}, $opts{bottom}) :
+ defined &_x11 ? _x11($opts{display}, 0, $opts{left}, $opts{top},
+ $opts{right}, $opts{bottom}) :
+ die "No drivers enabled\n";
+ }
unless ($result) {
Imager->_set_error(Imager->_error_as_msg());
=item screenshot
-If no parameters are supplied:
+If no C<id> or C<hwnd> parameter is supplied:
=over
=back
+You can also supply the following parameters to retrieve a subset of
+the window:
+
+=over
+
+=item *
+
+left
+
+=item *
+
+top
+
+=item *
+
+right
+
+=item *
+
+bottom
+
+=back
+
+If left or top is negative, then treat that as from the right/bottom
+edge of the window.
+
+If right ot bottom is zero or negative then treat as from the
+right/bottom edge of the window.
+
+So setting all 4 values to 0 retrieves the whole window.
+
+ # a 10-pixel wide right edge of the window
+ my $right_10 = screenshot(left => -10, ...);
+
+ # the top-left 100x100 portion of the window
+ my $topleft_100 = screenshot(right => 100, bottom => 100, ...);
+
+ # 10x10 pixel at the bottom right corner
+ my $bott_right_10 = screenshot(left => -10, top => -10, ...);
+
=item have_win32
Returns true if Win32 support is available.
=back
+=head1 CAVEATS
+
+It's possible to have more than one grab driver available, for
+example, Win32 and X11, and which is used can have an effect on the
+result.
+
+Under Win32, if there's a screesaver running, then you grab the
+results of the screensaver.
+
+Grabbing the root window on a rootless server (eg. Cygwin/X) may not
+grab the background. In fact, when I tested under Cygwin/X I got the
+xterm window contents even when the Windows screensaver was running.
+
=head1 LICENSE
Imager::Screenshot is licensed under the same terms as Perl itself.
#ifdef SS_WIN32
Imager
-imss_win32(hwnd, include_decor = 0)
+imss_win32(hwnd, include_decor = 0, left = 0, top = 0, right = 0, bottom = 0)
unsigned hwnd
int include_decor
+ int left
+ int top
+ int right
+ int bottom
#endif
#ifdef SS_X11
Imager
-imss_x11(display, window_id)
+imss_x11(display, window_id, left = 0, top = 0, right = 0, bottom = 0)
unsigned long display
int window_id
+ int left
+ int top
+ int right
+ int bottom
unsigned long
imss_x11_open(display_name = NULL)
#define IMSS_H
extern i_img *
-imss_win32(unsigned hwnd, int include_decor);
+imss_win32(unsigned hwnd, int include_decor, int left, int top, int right, int bottom);
extern i_img *
-imss_x11(unsigned long display, int window_id);
+imss_x11(unsigned long display, int window_id, int left, int top, int right, int bottom);
extern unsigned long
imss_x11_open(char const *display_name);
#include "imext.h"
#include <windows.h>
#include <string.h>
+#include "imss.h"
i_img *
-imss_win32(unsigned hwnd_u, int include_decor) {
+imss_win32(unsigned hwnd_u, int include_decor, int left, int top,
+ int right, int bottom) {
HWND hwnd = (HWND)hwnd_u;
HDC wdc, bmdc;
RECT rect;
HBITMAP work_bmp, old_dc_bmp;
- int width, height;
+ int window_width, window_height;
BITMAPINFO bmi;
unsigned char *di_bits;
i_img *result = NULL;
+ int width, height;
i_clear_error();
return NULL;
}
- width = rect.right - rect.left;
- height = rect.bottom - rect.top;
+ window_width = rect.right - rect.left;
+ window_height = rect.bottom - rect.top;
+
+ /* adjust negative/zero values to window size */
+ if (left < 0)
+ left += window_width;
+ if (top < 0)
+ top += window_height;
+ if (right <= 0)
+ right += window_width;
+ if (bottom <= 0)
+ bottom += window_height;
+
+ /* clamp */
+ if (left < 0)
+ left = 0;
+ if (right > window_width)
+ right = window_width;
+ if (top < 0)
+ top = 0;
+ if (bottom > window_height)
+ bottom = window_height;
+
+ /* validate */
+ if (right <= left || bottom <= top) {
+ i_push_error(0, "image would be empty");
+ return NULL;
+ }
+ width = right - left;
+ height = bottom - top;
+
work_bmp = CreateCompatibleBitmap(wdc, width, height);
bmdc = CreateCompatibleDC(wdc);
old_dc_bmp = SelectObject(bmdc, work_bmp);
- BitBlt(bmdc, 0, 0, width, height, wdc, 0, 0, SRCCOPY);
+ BitBlt(bmdc, 0, 0, width, height, wdc, left, top, SRCCOPY);
/* make a dib */
memset(&bmi, 0, sizeof(bmi));
#include "imext.h"
#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "imss.h"
static
int
XGetErrorText(display, error->error_code, buffer, sizeof(buffer));
i_push_error(error->error_code, buffer);
+
+ return 0;
}
i_img *
-imss_x11(unsigned long display_ul, unsigned long window_id) {
+imss_x11(unsigned long display_ul, int window_id,
+ int left, int top, int right, int bottom) {
Display *display = (Display *)display_ul;
int own_display = 0; /* non-zero if we connect */
GC gc;
int x, y;
XColor *colors;
XErrorHandler old_handler;
+ int width, height;
i_clear_error();
return NULL;
}
- image = XGetImage(display, window_id, 0, 0, attr.width, attr.height,
+ /* adjust negative/zero values to window size */
+ if (left < 0)
+ left += attr.width;
+ if (top < 0)
+ top += attr.height;
+ if (right <= 0)
+ right += attr.width;
+ if (bottom <= 0)
+ bottom += attr.height;
+
+ /* clamp */
+ if (left < 0)
+ left = 0;
+ if (right > attr.width)
+ right = attr.width;
+ if (top < 0)
+ top = 0;
+ if (bottom > attr.height)
+ bottom = attr.height;
+
+ /* validate */
+ if (right <= left || bottom <= top) {
+ XSetErrorHandler(old_handler);
+ if (own_display)
+ XCloseDisplay(display);
+ i_push_error(0, "image would be empty");
+ return NULL;
+ }
+ width = right - left;
+ height = bottom - top;
+ image = XGetImage(display, window_id, left, top, width, height,
-1, ZPixmap);
if (!image) {
XSetErrorHandler(old_handler);
return NULL;
}
- result = i_img_8_new(attr.width, attr.height, 3);
- line = mymalloc(sizeof(i_color) * attr.width);
- colors = mymalloc(sizeof(XColor) * attr.width);
- for (y = 0; y < attr.height; ++y) {
+ result = i_img_8_new(width, height, 3);
+ line = mymalloc(sizeof(i_color) * width);
+ colors = mymalloc(sizeof(XColor) * width);
+ for (y = 0; y < height; ++y) {
cp = line;
/* XQueryColors seems to be a round-trip, so do one big request
instead of one per pixel */
- for (x = 0; x < attr.width; ++x) {
+ for (x = 0; x < width; ++x) {
colors[x].pixel = XGetPixel(image, x, y);
}
- XQueryColors(display, attr.colormap, colors, attr.width);
- for (x = 0; x < attr.width; ++x) {
+ XQueryColors(display, attr.colormap, colors, width);
+ for (x = 0; x < width; ++x) {
cp->rgb.r = colors[x].red >> 8;
cp->rgb.g = colors[x].green >> 8;
cp->rgb.b = colors[x].blue >> 8;
++cp;
}
- i_plin(result, 0, attr.width, y, line);
+ i_plin(result, 0, width, y, line);
}
myfree(line);
myfree(colors);