From: Tony Cook Date: Mon, 1 Jan 2007 05:57:53 +0000 (+0000) Subject: add a readme and example for win32, convert files from Win32 to Unix X-Git-Tag: v0.008~35 X-Git-Url: http://git.imager.perl.org/imager-screenshot.git/commitdiff_plain/0ddb7051a56b5bdd401c9cc600c238b6273d0d60?hp=ff5d88f087814c0e1b16786fab6e12ba293ea6c2 add a readme and example for win32, convert files from Win32 to Unix --- diff --git a/Changes b/Changes index e894dd9..a34c6e7 100755 --- a/Changes +++ b/Changes @@ -1,2 +1,2 @@ -0.001 1 Jan 2007 - - Initial release with X11 and Win32 support +0.001 1 Jan 2007 + - Initial release with X11 and Win32 support diff --git a/MANIFEST b/MANIFEST index f1e0d0b..8639a5d 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,10 +1,11 @@ Changes History -imss.h Declarations of the functions the XS gives access to -Makefile.PL Build script MANIFEST This list of files MANIFEST.SKIP Files not to include in the MANIFEST +Makefile.PL Build script Screenshot.pm Main perl implementation Screenshot.xs Interface to C code +examples/win32_fw.pl Example - get a window by name on win32 and grab it +imss.h Declarations of the functions the XS gives access to scwin32.c Win32 implementation scx11.c X11 implementation t/00load.t Test - can we load the modules diff --git a/Makefile.PL b/Makefile.PL index f598d1d..0c59fcb 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,117 +1,117 @@ -#!perl -w -use strict; -use ExtUtils::MakeMaker; -use Imager::ExtUtils; -use Config; -use File::Spec; - -my @objs = qw/Screenshot.o/; -my @cflags; -my @lflags; -my $X11_lib = $^O eq 'cygwin' ? 'X11.dll' : 'X11'; -if (find_header("X11/Xlib.h") and find_lib($X11_lib)) { - push @objs, 'scx11.o'; - push @cflags, '-DSS_X11'; - push @lflags, '-l'.$X11_lib; - print "Found X11\n"; -} -if (find_header('windows.h') and find_lib('gdi32')) { - push @objs, 'scwin32.o'; - push @cflags, '-DSS_WIN32'; - if ($^O eq 'cygwin') { - push @lflags, '-L/usr/lib/w32api', '-lgdi32'; - } - print "Found Win32\n"; -} - -unless (@objs > 1) { - die "Sorry, I can't find headers or libraries for a supported GUI\n" -} - -my %opts = - ( - NAME => 'Imager::Screenshot', - VERSION_FROM => 'Screenshot.pm', - OBJECT => "@objs", - PREREQ_PM => { - 'Imager' => 0.54, - }, - INC => Imager::ExtUtils->includes, - TYPEMAPS => [ Imager::ExtUtils->typemap ], - ); - -$opts{LIBS} = "@lflags" if @lflags; -$opts{INC} .= " @cflags" if @cflags; - -if ($ExtUtils::MakeMaker::VERSION > 6.06) { - $opts{AUTHOR} = 'Tony Cook '; - $opts{ABSTRACT} = 'Screen/Window capture to Imager images'; -} - -WriteMakefile(%opts); - -my @incs; -sub header_search_path { - @incs and return @incs; - - push @incs, '/usr/include' - unless $^O eq 'MSWin32' && $Config{cc} =~ /\bcl\b/; - push @incs, split /\Q$Config{path_sep}/, $ENV{INCLUDE} - if $^O eq 'MSWin32' && $Config{cc} =~ /\bcl\b/ and $ENV{INCLUDE}; - push @incs, split ' ', $Config{locincpth} - if $Config{locincpth}; - push @incs, split /\Q$Config{path_sep}/, $Config{incpath} - if $Config{incpath}; - push @incs, '/usr/include/w32api', '/usr/X11R6/include' - if $^O eq 'cygwin'; - - @incs = grep -d, @incs; - - @incs; -} - -my @libs; -sub library_search_path { - @libs and return @libs; - - push @libs, '/usr/lib' - unless $^O eq 'MSWin32' && $Config{cc} =~ /\bcl\b/; - push @libs, split /\Q$Config{path_sep}/, $ENV{LIB} - if $^O eq 'MSWin32' && $Config{cc} =~ /\bcl\b/ and $ENV{LIB}; - push @libs, split ' ', $Config{loclibpth} - if $Config{loclibpth}; - push @libs, split /\Q$Config{path_sep}/, $Config{libpth} - if $Config{libpth}; - push @libs, '/usr/lib/w32api', '/usr/X11R6/lib' - if $^O eq 'cygwin'; - - @libs = grep -d, @libs; - - @libs; -} - - -sub _find_file { - my ($name, @where) = @_; - - grep -f File::Spec->catfile($_, $name), @where; -} - -sub find_header { - _find_file($_[0], header_search_path()); -} - -sub find_lib { - my $name = shift; - my @found; - if ($^O eq 'MSWin32' && $Config{_a} eq '.lib') { - @found = _find_file($name . $Config{_a}, library_search_path()); - } - else { - @found = _find_file("lib" . $name . $Config{_a}, library_search_path()); - } - if (@found) { - push @lflags, "-L$_" for @found; - } - @found; -} +#!perl -w +use strict; +use ExtUtils::MakeMaker; +use Imager::ExtUtils; +use Config; +use File::Spec; + +my @objs = qw/Screenshot.o/; +my @cflags; +my @lflags; +my $X11_lib = $^O eq 'cygwin' ? 'X11.dll' : 'X11'; +if (find_header("X11/Xlib.h") and find_lib($X11_lib)) { + push @objs, 'scx11.o'; + push @cflags, '-DSS_X11'; + push @lflags, '-l'.$X11_lib; + print "Found X11\n"; +} +if (find_header('windows.h') and find_lib('gdi32')) { + push @objs, 'scwin32.o'; + push @cflags, '-DSS_WIN32'; + if ($^O eq 'cygwin') { + push @lflags, '-L/usr/lib/w32api', '-lgdi32'; + } + print "Found Win32\n"; +} + +unless (@objs > 1) { + die "Sorry, I can't find headers or libraries for a supported GUI\n" +} + +my %opts = + ( + NAME => 'Imager::Screenshot', + VERSION_FROM => 'Screenshot.pm', + OBJECT => "@objs", + PREREQ_PM => { + 'Imager' => 0.54, + }, + INC => Imager::ExtUtils->includes, + TYPEMAPS => [ Imager::ExtUtils->typemap ], + ); + +$opts{LIBS} = "@lflags" if @lflags; +$opts{INC} .= " @cflags" if @cflags; + +if ($ExtUtils::MakeMaker::VERSION > 6.06) { + $opts{AUTHOR} = 'Tony Cook '; + $opts{ABSTRACT} = 'Screen/Window capture to Imager images'; +} + +WriteMakefile(%opts); + +my @incs; +sub header_search_path { + @incs and return @incs; + + push @incs, '/usr/include' + unless $^O eq 'MSWin32' && $Config{cc} =~ /\bcl\b/; + push @incs, split /\Q$Config{path_sep}/, $ENV{INCLUDE} + if $^O eq 'MSWin32' && $Config{cc} =~ /\bcl\b/ and $ENV{INCLUDE}; + push @incs, split ' ', $Config{locincpth} + if $Config{locincpth}; + push @incs, split /\Q$Config{path_sep}/, $Config{incpath} + if $Config{incpath}; + push @incs, '/usr/include/w32api', '/usr/X11R6/include' + if $^O eq 'cygwin'; + + @incs = grep -d, @incs; + + @incs; +} + +my @libs; +sub library_search_path { + @libs and return @libs; + + push @libs, '/usr/lib' + unless $^O eq 'MSWin32' && $Config{cc} =~ /\bcl\b/; + push @libs, split /\Q$Config{path_sep}/, $ENV{LIB} + if $^O eq 'MSWin32' && $Config{cc} =~ /\bcl\b/ and $ENV{LIB}; + push @libs, split ' ', $Config{loclibpth} + if $Config{loclibpth}; + push @libs, split /\Q$Config{path_sep}/, $Config{libpth} + if $Config{libpth}; + push @libs, '/usr/lib/w32api', '/usr/X11R6/lib' + if $^O eq 'cygwin'; + + @libs = grep -d, @libs; + + @libs; +} + + +sub _find_file { + my ($name, @where) = @_; + + grep -f File::Spec->catfile($_, $name), @where; +} + +sub find_header { + _find_file($_[0], header_search_path()); +} + +sub find_lib { + my $name = shift; + my @found; + if ($^O eq 'MSWin32' && $Config{_a} eq '.lib') { + @found = _find_file($name . $Config{_a}, library_search_path()); + } + else { + @found = _find_file("lib" . $name . $Config{_a}, library_search_path()); + } + if (@found) { + push @lflags, "-L$_" for @found; + } + @found; +} diff --git a/README b/README new file mode 100755 index 0000000..07aa8d4 --- /dev/null +++ b/README @@ -0,0 +1,26 @@ +Imager::Screenshot is a module that grabs an image from a window under +X11 or Win32. + +Requires: + Imager 0.54 or later. + SDK header files and libraries for Win32 support + X11 header files and libraries for X11 support. + A C compiler compatible with that used to build perl itself. + +Optional + Perl/Tk + +Installation: + + perl Makefile.PL + make + make test + make install + (nmake or dmake on Win32) + +Tested under: + + - Win32 (VC++ 6.0) + - Win32 (mingw) + - Win32/X11 (cygwin as of Jan 1 2007) + - X11 (Debian Linux) diff --git a/Screenshot.pm b/Screenshot.pm index 68cb958..d9192ea 100644 --- a/Screenshot.pm +++ b/Screenshot.pm @@ -204,6 +204,10 @@ Closes a display returned by Imager::Screenshot::x11_open(). =back +=head1 LICENSE + +Imager::Screenshot is licensed under the same terms as Perl itself. + =head1 AUTHOR Tony Cook diff --git a/Screenshot.xs b/Screenshot.xs index eac1afd..6d56685 100644 --- a/Screenshot.xs +++ b/Screenshot.xs @@ -1,43 +1,43 @@ -#include "EXTERN.h" -#include "perl.h" -#include "XSUB.h" -#include "imext.h" -#include "imperl.h" -#include "imss.h" - -DEFINE_IMAGER_CALLBACKS; - -#define imss__x11_open imss_x11_open - -MODULE = Imager::Screenshot PACKAGE = Imager::Screenshot PREFIX = imss - -PROTOTYPES: DISABLE - -#ifdef SS_WIN32 - -Imager -imss_win32(hwnd, include_decor = 0) - unsigned hwnd - int include_decor - -#endif - -#ifdef SS_X11 - -Imager -imss_x11(display, window_id) - unsigned long display - int window_id - -unsigned long -imss_x11_open(display_name = NULL) - const char *display_name - -void -imss_x11_close(display) - unsigned long display - -#endif - -BOOT: +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "imext.h" +#include "imperl.h" +#include "imss.h" + +DEFINE_IMAGER_CALLBACKS; + +#define imss__x11_open imss_x11_open + +MODULE = Imager::Screenshot PACKAGE = Imager::Screenshot PREFIX = imss + +PROTOTYPES: DISABLE + +#ifdef SS_WIN32 + +Imager +imss_win32(hwnd, include_decor = 0) + unsigned hwnd + int include_decor + +#endif + +#ifdef SS_X11 + +Imager +imss_x11(display, window_id) + unsigned long display + int window_id + +unsigned long +imss_x11_open(display_name = NULL) + const char *display_name + +void +imss_x11_close(display) + unsigned long display + +#endif + +BOOT: PERL_INITIALIZE_IMAGER_CALLBACKS; \ No newline at end of file diff --git a/examples/win32_fw.pl b/examples/win32_fw.pl new file mode 100755 index 0000000..18f130e --- /dev/null +++ b/examples/win32_fw.pl @@ -0,0 +1,27 @@ +#!perl -w +use strict; +use Win32::API; +use Imager; +use Imager::Screenshot 'screenshot'; + +# delay so I can bring the window to the front +sleep 2; + +# get the API +my $find_window = Win32::API->new('user32', 'FindWindowA', 'NP', 'N') + or die "Cannot import FindWindow\n"; + +# get the window, this requires an exact match on the window title +my $hwnd = $find_window->Call(0, "use Perl: All the Perl that's Practical to Extract and Report - Mozilla Firefox"); + +$hwnd + or die "Mozilla window not found"; + +# take a picture, including the border and title bar +my $img = screenshot(hwnd => $hwnd, decor=>1) + or die Imager->errstr; + +# and save it +$img->write(file=>'mozilla.ppm') + or die $img->errstr; + diff --git a/imss.h b/imss.h index fd725a4..8a0ced2 100644 --- a/imss.h +++ b/imss.h @@ -1,15 +1,15 @@ -#ifndef IMSS_H -#define IMSS_H - -extern i_img * -imss_win32(unsigned hwnd, int include_decor); - -extern i_img * -imss_x11(unsigned long display, int window_id); - -extern unsigned long -imss_x11_open(char const *display_name); -extern void -imss_x11_close(unsigned long display); - -#endif +#ifndef IMSS_H +#define IMSS_H + +extern i_img * +imss_win32(unsigned hwnd, int include_decor); + +extern i_img * +imss_x11(unsigned long display, int window_id); + +extern unsigned long +imss_x11_open(char const *display_name); +extern void +imss_x11_close(unsigned long display); + +#endif diff --git a/scwin32.c b/scwin32.c index 228d182..dad6436 100644 --- a/scwin32.c +++ b/scwin32.c @@ -1,80 +1,80 @@ -#include "imext.h" -#include -#include - -i_img * -imss_win32(unsigned hwnd_u, int include_decor) { - HWND hwnd = (HWND)hwnd_u; - HDC wdc, bmdc; - RECT rect; - HBITMAP work_bmp, old_dc_bmp; - int width, height; - BITMAPINFO bmi; - unsigned char *di_bits; - i_img *result = NULL; - - i_clear_error(); - - if (!hwnd) - hwnd = GetDesktopWindow(); - - if (include_decor) { - wdc = GetWindowDC(hwnd); - GetWindowRect(hwnd, &rect); - } - else { - wdc = GetDC(hwnd); - GetClientRect(hwnd, &rect); - } - if (!wdc) { - i_push_error(0, "Cannot get window DC - invalid hwnd?"); - return NULL; - } - - width = rect.right - rect.left; - height = rect.bottom - rect.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); - - /* make a dib */ - memset(&bmi, 0, sizeof(bmi)); - bmi.bmiHeader.biSize = sizeof(bmi); - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = -height; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - - di_bits = mymalloc(4 * width * height); - if (GetDIBits(bmdc, work_bmp, 0, height, di_bits, &bmi, DIB_RGB_COLORS)) { - i_color *line = mymalloc(sizeof(i_color) * width); - i_color *cp; - int x, y; - unsigned char *ch_pp = di_bits; - result = i_img_8_new(width, height, 3); - - for (y = 0; y < height; ++y) { - cp = line; - for (x = 0; x < width; ++x) { - cp->rgb.b = *ch_pp++; - cp->rgb.g = *ch_pp++; - cp->rgb.r = *ch_pp++; - ch_pp++; - cp++; - } - i_plin(result, 0, width, y, line); - } - myfree(line); - } - - /* clean up */ - myfree(di_bits); - SelectObject(bmdc, old_dc_bmp); - DeleteDC(bmdc); - DeleteObject(work_bmp); - ReleaseDC(hwnd, wdc); - - return result; -} +#include "imext.h" +#include +#include + +i_img * +imss_win32(unsigned hwnd_u, int include_decor) { + HWND hwnd = (HWND)hwnd_u; + HDC wdc, bmdc; + RECT rect; + HBITMAP work_bmp, old_dc_bmp; + int width, height; + BITMAPINFO bmi; + unsigned char *di_bits; + i_img *result = NULL; + + i_clear_error(); + + if (!hwnd) + hwnd = GetDesktopWindow(); + + if (include_decor) { + wdc = GetWindowDC(hwnd); + GetWindowRect(hwnd, &rect); + } + else { + wdc = GetDC(hwnd); + GetClientRect(hwnd, &rect); + } + if (!wdc) { + i_push_error(0, "Cannot get window DC - invalid hwnd?"); + return NULL; + } + + width = rect.right - rect.left; + height = rect.bottom - rect.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); + + /* make a dib */ + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(bmi); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + di_bits = mymalloc(4 * width * height); + if (GetDIBits(bmdc, work_bmp, 0, height, di_bits, &bmi, DIB_RGB_COLORS)) { + i_color *line = mymalloc(sizeof(i_color) * width); + i_color *cp; + int x, y; + unsigned char *ch_pp = di_bits; + result = i_img_8_new(width, height, 3); + + for (y = 0; y < height; ++y) { + cp = line; + for (x = 0; x < width; ++x) { + cp->rgb.b = *ch_pp++; + cp->rgb.g = *ch_pp++; + cp->rgb.r = *ch_pp++; + ch_pp++; + cp++; + } + i_plin(result, 0, width, y, line); + } + myfree(line); + } + + /* clean up */ + myfree(di_bits); + SelectObject(bmdc, old_dc_bmp); + DeleteDC(bmdc); + DeleteObject(work_bmp); + ReleaseDC(hwnd, wdc); + + return result; +} diff --git a/t/00load.t b/t/00load.t index 6b88ec6..7d40711 100644 --- a/t/00load.t +++ b/t/00load.t @@ -1,5 +1,5 @@ -#!perl -w -use strict; -use Test::More tests => 1; - -use_ok('Imager::Screenshot', 'screenshot'); +#!perl -w +use strict; +use Test::More tests => 1; + +use_ok('Imager::Screenshot', 'screenshot'); diff --git a/t/10win32.t b/t/10win32.t index ce18b87..f1db421 100644 --- a/t/10win32.t +++ b/t/10win32.t @@ -1,23 +1,23 @@ -#!perl -w -use strict; -use Test::More; - -use Imager::Screenshot 'screenshot'; - -Imager::Screenshot->have_win32 - or plan skip_all => "No Win32 support"; - -plan tests => 2; - -{ - my $im = screenshot(hwnd => 0); - - ok($im, "got a screenshot"); -} - -{ # as a method - my $im = Imager::Screenshot->screenshot(hwnd => 0); - - ok($im, "call as a method"); -} - +#!perl -w +use strict; +use Test::More; + +use Imager::Screenshot 'screenshot'; + +Imager::Screenshot->have_win32 + or plan skip_all => "No Win32 support"; + +plan tests => 2; + +{ + my $im = screenshot(hwnd => 0); + + ok($im, "got a screenshot"); +} + +{ # as a method + my $im = Imager::Screenshot->screenshot(hwnd => 0); + + ok($im, "call as a method"); +} + diff --git a/t/20x11.t b/t/20x11.t index 25c3798..80e9e97 100644 --- a/t/20x11.t +++ b/t/20x11.t @@ -1,45 +1,45 @@ -#!perl -w -use strict; -use Test::More; - -use Imager::Screenshot 'screenshot'; - -Imager::Screenshot->have_x11 - or plan skip_all => "No X11 support"; - -# can we connect to a display -my $display = Imager::Screenshot::x11_open() - or plan skip_all => "Cannot connect to a display: ".Imager->errstr; - -plan tests => 5; - -{ - # should automatically connect and grab the root window - my $im = screenshot(id => 0) - or print "# ", Imager->errstr, "\n"; - - ok($im, "got a root screenshot, no display"); -} - -{ - # use our supplied display - my $im = screenshot(display => $display, id => 0); - ok($im, "got a root screenshot, supplied display"); -} - -{ - # use our supplied display - as a method - my $im = Imager::Screenshot->screenshot(display => $display, id => 0); - ok($im, "got a root screenshot, supplied display (method)"); -} - -{ - # supply a junk window id - my $im = screenshot(display => $display, id => 0xFFFFFFF) - or print "# ", Imager->errstr, "\n"; - ok(!$im, "should fail to get screenshot"); - cmp_ok(Imager->errstr, '=~', 'BadWindow', - "check error"); -} - -Imager::Screenshot::x11_close($display); +#!perl -w +use strict; +use Test::More; + +use Imager::Screenshot 'screenshot'; + +Imager::Screenshot->have_x11 + or plan skip_all => "No X11 support"; + +# can we connect to a display +my $display = Imager::Screenshot::x11_open() + or plan skip_all => "Cannot connect to a display: ".Imager->errstr; + +plan tests => 5; + +{ + # should automatically connect and grab the root window + my $im = screenshot(id => 0) + or print "# ", Imager->errstr, "\n"; + + ok($im, "got a root screenshot, no display"); +} + +{ + # use our supplied display + my $im = screenshot(display => $display, id => 0); + ok($im, "got a root screenshot, supplied display"); +} + +{ + # use our supplied display - as a method + my $im = Imager::Screenshot->screenshot(display => $display, id => 0); + ok($im, "got a root screenshot, supplied display (method)"); +} + +{ + # supply a junk window id + my $im = screenshot(display => $display, id => 0xFFFFFFF) + or print "# ", Imager->errstr, "\n"; + ok(!$im, "should fail to get screenshot"); + cmp_ok(Imager->errstr, '=~', 'BadWindow', + "check error"); +} + +Imager::Screenshot::x11_close($display); diff --git a/t/90pod.t b/t/90pod.t index 00c66f0..45d6ef5 100644 --- a/t/90pod.t +++ b/t/90pod.t @@ -1,12 +1,12 @@ -#!perl -w -use strict; -use Test::More; -use ExtUtils::Manifest qw(maniread); -eval "use Test::Pod 1.00;"; -plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; -my $manifest = maniread(); -my @pod = grep /\.(pm|pl|pod|PL)$/, keys %$manifest; -plan tests => scalar(@pod); -for my $file (@pod) { - pod_file_ok($file, "pod ok in $file"); -} +#!perl -w +use strict; +use Test::More; +use ExtUtils::Manifest qw(maniread); +eval "use Test::Pod 1.00;"; +plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; +my $manifest = maniread(); +my @pod = grep /\.(pm|pl|pod|PL)$/, keys %$manifest; +plan tests => scalar(@pod); +for my $file (@pod) { + pod_file_ok($file, "pod ok in $file"); +} diff --git a/t/91podcover.t b/t/91podcover.t index 5203d3b..912686a 100644 --- a/t/91podcover.t +++ b/t/91podcover.t @@ -1,8 +1,8 @@ -#!perl -w -use strict; -use Test::More; -eval "use Test::Pod::Coverage;"; -plan skip_all => "Test::Pod::Coverage required for POD coverage" if $@; - -plan tests => 1; -pod_coverage_ok('Imager::Screenshot'); +#!perl -w +use strict; +use Test::More; +eval "use Test::Pod::Coverage;"; +plan skip_all => "Test::Pod::Coverage required for POD coverage" if $@; + +plan tests => 1; +pod_coverage_ok('Imager::Screenshot');