rdp-win32screenshot 0.0.6.2 → 0.0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +11 -2
- data/README.rdoc +19 -0
- data/VERSION +1 -1
- data/lib/win32/screenshot/bitmap_maker.rb +147 -169
- data/lib/win32/screenshot.rb +7 -12
- data/lib/win32/util.rb +40 -0
- data/spec/spec_helper.rb +12 -3
- data/spec/win32_screenshot_spec.rb +24 -39
- data/spec/win32_screenshot_util_spec.rb +38 -0
- data/win32screenshot.gemspec +69 -0
- metadata +7 -11
- data/lib/win32screenshot.rb +0 -3
data/History.rdoc
CHANGED
@@ -1,6 +1,15 @@
|
|
1
|
-
= 0.0.6 2010-
|
1
|
+
= 0.0.6 2010-08-07
|
2
2
|
* Trying to bring window to the foreground more aggressively (Roger Pack)
|
3
|
-
*
|
3
|
+
* Added utility class Win32::Screenshot.Util with some helper methods not related directly with taking of the screenshots:
|
4
|
+
- all_windows - enumerates all windows and returns their titles and window handles as an Array (Roger Pack)
|
5
|
+
- window_title(hwnd) - returns title of the window for specified handle (Jarmo Pertman)
|
6
|
+
- window_hwnd(title_query) - returns handle of the window for specified title (Jarmo Pertman)
|
7
|
+
- dimensions_for(hwnd) - returns a width and height for a window with specified handle (Jarmo Pertman)
|
8
|
+
* Removed a file 'win32screenshot.rb' which was solely used for displaying deprecation warnings for versions older than 0.0.4. Make sure than from now on all require statements require 'win32/screenshot'!
|
9
|
+
|
10
|
+
== Bug Fixes:
|
11
|
+
* Fixed usages of gdi32.dll BitBlt (Roger Pack)
|
12
|
+
* It was impossible to specify correctly window titles with regular expressions special characters in them (Roger Pack)
|
4
13
|
|
5
14
|
= 0.0.5 2010-07-07
|
6
15
|
* Added method window_area for capturing specified area of the window instead of full window (Jarmo Pertman)
|
data/README.rdoc
CHANGED
@@ -71,6 +71,25 @@ other formats like png.
|
|
71
71
|
File.open("picture10.png", "wb") {|file| file.puts png}
|
72
72
|
end
|
73
73
|
|
74
|
+
#
|
75
|
+
# Win32::Screenshot has also some utility methods which can be used for various needs
|
76
|
+
|
77
|
+
# enumerate all windows and return their titles and handles
|
78
|
+
Win32::Screenshot::Util.all_windows # => [["title1", 2345], ["title2", 3456]]
|
79
|
+
|
80
|
+
# retrieve window title for the specified window handle
|
81
|
+
Win32::Screenshot::Util.window_title(2345) # => "title1"
|
82
|
+
|
83
|
+
# retrieve window handle for the specified title
|
84
|
+
Win32::Screenshot::Util.window_hwnd("title1") # => 2345
|
85
|
+
|
86
|
+
# title can be also a regular expression with first matching window retrieved
|
87
|
+
Win32::Screenshot::Util.window_hwnd(/tit.*1/) # => 2345
|
88
|
+
|
89
|
+
# retrive dimensions of a window with specified handle in an Array of [width, height]
|
90
|
+
# might be useful for using with different capture_area methods
|
91
|
+
Win32::Screenshot::Util.dimensions_for(2345) # => [100, 200]
|
92
|
+
|
74
93
|
== Copyright
|
75
94
|
|
76
95
|
Copyright (c) 2010 Jarmo Pertman, Aslak Hellesøy. See LICENSE for details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.6.
|
1
|
+
0.0.6.3
|
@@ -3,186 +3,164 @@ require 'ffi'
|
|
3
3
|
module Win32
|
4
4
|
class Screenshot
|
5
5
|
# internal methods
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
else
|
76
|
-
true
|
6
|
+
class BitmapMaker #:nodoc:all
|
7
|
+
class << self
|
8
|
+
extend FFI::Library
|
9
|
+
|
10
|
+
ffi_lib 'user32', 'gdi32'
|
11
|
+
ffi_convention :stdcall
|
12
|
+
callback :enum_callback, [:long, :pointer], :bool
|
13
|
+
|
14
|
+
# user32.dll
|
15
|
+
attach_function :enum_windows, :EnumWindows,
|
16
|
+
[:enum_callback, :pointer], :long
|
17
|
+
attach_function :window_text, :GetWindowTextA,
|
18
|
+
[:long, :pointer, :int], :int
|
19
|
+
attach_function :window_text_length, :GetWindowTextLengthA,
|
20
|
+
[:long], :int
|
21
|
+
attach_function :window_visible, :IsWindowVisible,
|
22
|
+
[:long], :bool
|
23
|
+
attach_function :dc, :GetDC,
|
24
|
+
[:long], :long
|
25
|
+
attach_function :client_rect, :GetClientRect,
|
26
|
+
[:long, :pointer], :bool
|
27
|
+
attach_function :minimized, :IsIconic,
|
28
|
+
[:long], :bool
|
29
|
+
attach_function :show_window, :ShowWindow,
|
30
|
+
[:long, :int], :bool
|
31
|
+
attach_function :foreground_window, :GetForegroundWindow,
|
32
|
+
[], :long
|
33
|
+
attach_function :desktop_window, :GetDesktopWindow,
|
34
|
+
[], :long
|
35
|
+
attach_function :window_thread_process_id, :GetWindowThreadProcessId,
|
36
|
+
[:long, :pointer], :long
|
37
|
+
attach_function :attach_thread_input, :AttachThreadInput,
|
38
|
+
[:long, :long, :bool], :bool
|
39
|
+
attach_function :set_foreground_window, :SetForegroundWindow,
|
40
|
+
[:long], :bool
|
41
|
+
attach_function :bring_window_to_top, :BringWindowToTop,
|
42
|
+
[:long], :bool
|
43
|
+
attach_function :set_active_window, :SetActiveWindow,
|
44
|
+
[:long], :long
|
45
|
+
|
46
|
+
|
47
|
+
# gdi32.dll
|
48
|
+
attach_function :create_compatible_dc, :CreateCompatibleDC,
|
49
|
+
[:long], :long
|
50
|
+
attach_function :create_compatible_bitmap, :CreateCompatibleBitmap,
|
51
|
+
[:long, :int, :int], :long
|
52
|
+
attach_function :select_object, :SelectObject,
|
53
|
+
[:long, :long], :long
|
54
|
+
attach_function :bit_blt, :BitBlt,
|
55
|
+
[:long, :int, :int, :int, :int, :long, :int, :int, :long], :bool
|
56
|
+
attach_function :di_bits, :GetDIBits,
|
57
|
+
[:long, :long, :int, :int, :pointer, :pointer, :int], :int
|
58
|
+
attach_function :delete_object, :DeleteObject,
|
59
|
+
[:long], :bool
|
60
|
+
attach_function :delete_dc, :DeleteDC,
|
61
|
+
[:long], :bool
|
62
|
+
attach_function :release_dc, :ReleaseDC,
|
63
|
+
[:long, :long], :int
|
64
|
+
|
65
|
+
|
66
|
+
EnumWindowCallback = FFI::Function.new(:bool, [ :long, :pointer ], { :convention => :stdcall }) do |hwnd, param|
|
67
|
+
searched_window = WindowStruct.new param
|
68
|
+
title = Util.window_title(hwnd)
|
69
|
+
if title =~ Regexp.new(searched_window[:title].read_string) && window_visible(hwnd)
|
70
|
+
searched_window[:hwnd] = hwnd
|
71
|
+
false
|
72
|
+
else
|
73
|
+
true
|
74
|
+
end
|
77
75
|
end
|
78
|
-
end
|
79
|
-
|
80
|
-
module_function
|
81
|
-
|
82
|
-
class WindowStruct < FFI::Struct
|
83
|
-
layout :title, :pointer,
|
84
|
-
:hwnd, :long
|
85
|
-
end
|
86
76
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
window_title = Regexp.escape(window_title.to_s)
|
91
|
-
end
|
92
|
-
window_title = FFI::MemoryPointer.from_string(window_title.to_s)
|
93
|
-
window[:title] = window_title
|
94
|
-
enum_windows(EnumWindowCallback, window.to_ptr)
|
95
|
-
window[:hwnd] == 0 ? nil : window[:hwnd]
|
96
|
-
end
|
97
|
-
|
98
|
-
def list_window_titles
|
99
|
-
out = []
|
100
|
-
out_proc = Proc.new do |hwnd, param|
|
101
|
-
title_length = window_text_length(hwnd) + 1
|
102
|
-
title = FFI::MemoryPointer.new :char, title_length
|
103
|
-
window_text(hwnd, title, title_length)
|
104
|
-
out << title.read_string
|
105
|
-
true
|
77
|
+
class WindowStruct < FFI::Struct
|
78
|
+
layout :title, :pointer,
|
79
|
+
:hwnd, :long
|
106
80
|
end
|
107
|
-
|
108
|
-
enum_windows(out_proc, nil)
|
109
|
-
out
|
110
|
-
end
|
111
81
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
82
|
+
def hwnd(window_title)
|
83
|
+
window = WindowStruct.new
|
84
|
+
unless window_title.is_a?(Regexp)
|
85
|
+
window_title = Regexp.escape(window_title.to_s)
|
86
|
+
else
|
87
|
+
window_title = window_title.to_s
|
88
|
+
end
|
89
|
+
window_title = FFI::MemoryPointer.from_string(window_title)
|
90
|
+
window[:title] = window_title
|
91
|
+
enum_windows(EnumWindowCallback, window.to_ptr)
|
92
|
+
window[:hwnd] == 0 ? nil : window[:hwnd]
|
93
|
+
end
|
117
94
|
|
118
|
-
|
95
|
+
def prepare_window(hwnd, pause)
|
96
|
+
restore(hwnd) if minimized(hwnd)
|
97
|
+
set_foreground(hwnd)
|
98
|
+
sleep pause
|
99
|
+
end
|
119
100
|
|
120
|
-
|
121
|
-
show_window(hwnd, SW_RESTORE)
|
122
|
-
end
|
101
|
+
SW_RESTORE = 9
|
123
102
|
|
124
|
-
|
125
|
-
|
126
|
-
set_foreground_window(hwnd)
|
127
|
-
set_active_window(hwnd)
|
128
|
-
bring_window_to_top(hwnd)
|
129
|
-
# and just in case...
|
130
|
-
foreground_thread = window_thread_process_id(foreground_window, nil)
|
131
|
-
other_thread = window_thread_process_id(hwnd, nil)
|
132
|
-
attach_thread_input(foreground_thread, other_thread, true) unless other_thread == foreground_thread
|
133
|
-
set_foreground_window(hwnd)
|
134
|
-
set_active_window(hwnd)
|
135
|
-
bring_window_to_top(hwnd)
|
136
|
-
attach_thread_input(foreground_thread, other_thread, false) unless other_thread == foreground_thread
|
103
|
+
def restore(hwnd)
|
104
|
+
show_window(hwnd, SW_RESTORE)
|
137
105
|
end
|
138
|
-
end
|
139
106
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
107
|
+
def set_foreground(hwnd)
|
108
|
+
if foreground_window != hwnd
|
109
|
+
set_foreground_window(hwnd)
|
110
|
+
set_active_window(hwnd)
|
111
|
+
bring_window_to_top(hwnd)
|
112
|
+
# and just in case...
|
113
|
+
foreground_thread = window_thread_process_id(foreground_window, nil)
|
114
|
+
other_thread = window_thread_process_id(hwnd, nil)
|
115
|
+
attach_thread_input(foreground_thread, other_thread, true) unless other_thread == foreground_thread
|
116
|
+
set_foreground_window(hwnd)
|
117
|
+
set_active_window(hwnd)
|
118
|
+
bring_window_to_top(hwnd)
|
119
|
+
attach_thread_input(foreground_thread, other_thread, false) unless other_thread == foreground_thread
|
120
|
+
end
|
121
|
+
end
|
145
122
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
123
|
+
def capture_all(hwnd, &proc)
|
124
|
+
width, height = Util.dimensions_for(hwnd)
|
125
|
+
capture_area(hwnd, 0, 0, width, height, &proc)
|
126
|
+
end
|
150
127
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
128
|
+
SRCCOPY = 0x00CC0020
|
129
|
+
DIB_RGB_COLORS = 0
|
130
|
+
|
131
|
+
def capture_area(hwnd, x1, y1, x2, y2) # block
|
132
|
+
hScreenDC = dc(hwnd)
|
133
|
+
w = x2-x1
|
134
|
+
h = y2-y1
|
135
|
+
|
136
|
+
hmemDC = create_compatible_dc(hScreenDC)
|
137
|
+
hmemBM = create_compatible_bitmap(hScreenDC, w, h)
|
138
|
+
select_object(hmemDC, hmemBM)
|
139
|
+
bit_blt(hmemDC, 0, 0, w, h, hScreenDC, x1, y1, SRCCOPY)
|
140
|
+
bitmap_size = w * h * 3 + w % 4 * h
|
141
|
+
lpvpxldata = FFI::MemoryPointer.new(bitmap_size)
|
142
|
+
|
143
|
+
# Bitmap header
|
144
|
+
# http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
|
145
|
+
bmInfo = [40, w, h, 1, 24, 0, 0, 0, 0, 0, 0, 0].pack('L3S2L6')
|
146
|
+
di_bits(hmemDC, hmemBM, 0, h, lpvpxldata, bmInfo, DIB_RGB_COLORS)
|
147
|
+
|
148
|
+
bmFileHeader = [
|
149
|
+
19778,
|
150
|
+
bitmap_size + 40 + 14,
|
151
|
+
0,
|
152
|
+
0,
|
153
|
+
54
|
154
|
+
].pack('SLSSL')
|
155
|
+
|
156
|
+
bmp_data = bmFileHeader + bmInfo + lpvpxldata.read_string(bitmap_size)
|
157
|
+
yield(w, h, bmp_data)
|
158
|
+
ensure
|
159
|
+
lpvpxldata.free
|
160
|
+
delete_object(hmemBM)
|
161
|
+
delete_dc(hmemDC)
|
162
|
+
release_dc(0, hScreenDC)
|
163
|
+
end
|
186
164
|
end
|
187
165
|
end
|
188
166
|
end
|
data/lib/win32/screenshot.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require File.dirname(__FILE__) + '/screenshot/bitmap_maker'
|
2
|
+
require File.dirname(__FILE__) + '/util'
|
2
3
|
|
3
4
|
module Win32
|
4
5
|
# Captures screenshots with Ruby on Windows
|
@@ -44,7 +45,7 @@ module Win32
|
|
44
45
|
# captures window with a *title_query* and waits *pause* (by default is 0.5)
|
45
46
|
# seconds after trying to set window to the foreground
|
46
47
|
def window(title_query, pause=0.5, &proc)
|
47
|
-
hwnd = window_hwnd(title_query)
|
48
|
+
hwnd = Util.window_hwnd(title_query)
|
48
49
|
hwnd(hwnd, pause, &proc)
|
49
50
|
end
|
50
51
|
|
@@ -52,7 +53,7 @@ module Win32
|
|
52
53
|
# where *x1* and *y1* are 0 in the upper left corner and
|
53
54
|
# *x2* specifies the width and *y2* the height of the area to be captured
|
54
55
|
def window_area(title_query, x1, y1, x2, y2, pause=0.5, &proc)
|
55
|
-
hwnd = window_hwnd(title_query)
|
56
|
+
hwnd = Util.window_hwnd(title_query)
|
56
57
|
hwnd_area(hwnd, x1, y1, x2, y2, pause, &proc)
|
57
58
|
end
|
58
59
|
|
@@ -73,12 +74,6 @@ module Win32
|
|
73
74
|
|
74
75
|
private
|
75
76
|
|
76
|
-
def window_hwnd(title_query)
|
77
|
-
hwnd = BitmapMaker.hwnd(title_query)
|
78
|
-
raise "window with title '#{title_query}' was not found!" unless hwnd
|
79
|
-
hwnd
|
80
|
-
end
|
81
|
-
|
82
77
|
def validate_coordinates(hwnd, *coords)
|
83
78
|
specified_coordinates = coords.join(', ')
|
84
79
|
if coords.any? {|c| c < 0}
|
@@ -89,9 +84,9 @@ module Win32
|
|
89
84
|
raise "specified coordinates (#{specified_coordinates}) are invalid - cannot have x1 > x2 or y1 > y2!"
|
90
85
|
end
|
91
86
|
|
92
|
-
|
93
|
-
if x2 >
|
94
|
-
raise "specified coordinates (#{specified_coordinates}) are invalid - maximum are x2=#{
|
87
|
+
max_width, max_height = Util.dimensions_for(hwnd)
|
88
|
+
if x2 > max_width || y2 > max_height
|
89
|
+
raise "specified coordinates (#{specified_coordinates}) are invalid - maximum are x2=#{max_width} and y2=#{max_height}!"
|
95
90
|
end
|
96
91
|
end
|
97
92
|
end
|
data/lib/win32/util.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Win32
|
2
|
+
class Screenshot
|
3
|
+
class Util
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def all_windows
|
7
|
+
titles = []
|
8
|
+
window_callback = FFI::Function.new(:bool, [ :long, :pointer ], { :convention => :stdcall }) do |hwnd, param|
|
9
|
+
titles << [window_title(hwnd), hwnd]
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
BitmapMaker.enum_windows(window_callback, nil)
|
14
|
+
titles
|
15
|
+
end
|
16
|
+
|
17
|
+
def window_title hwnd
|
18
|
+
title_length = BitmapMaker.window_text_length(hwnd) + 1
|
19
|
+
title = FFI::MemoryPointer.new :char, title_length
|
20
|
+
BitmapMaker.window_text(hwnd, title, title_length)
|
21
|
+
title.read_string
|
22
|
+
end
|
23
|
+
|
24
|
+
def window_hwnd(title_query)
|
25
|
+
hwnd = BitmapMaker.hwnd(title_query)
|
26
|
+
raise "window with title '#{title_query}' was not found!" unless hwnd
|
27
|
+
hwnd
|
28
|
+
end
|
29
|
+
|
30
|
+
def dimensions_for(hwnd)
|
31
|
+
rect = [0, 0, 0, 0].pack('L4')
|
32
|
+
BitmapMaker.client_rect(hwnd, rect)
|
33
|
+
_, _, width, height = rect.unpack('L4')
|
34
|
+
return width, height
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -41,12 +41,21 @@ module SpecHelper
|
|
41
41
|
|
42
42
|
def wait_for_programs_to_open
|
43
43
|
until Win32::Screenshot::BitmapMaker.hwnd(/Internet Explorer/) &&
|
44
|
-
Win32::Screenshot::BitmapMaker.hwnd(/Notepad/)
|
45
|
-
|
44
|
+
Win32::Screenshot::BitmapMaker.hwnd(/Notepad/)
|
45
|
+
sleep 0.1
|
46
|
+
end
|
47
|
+
wait_for_calculator_to_open
|
48
|
+
|
49
|
+
# just in case of slow PC
|
50
|
+
sleep 8
|
51
|
+
end
|
52
|
+
|
53
|
+
def wait_for_calculator_to_open
|
54
|
+
until Win32::Screenshot::BitmapMaker.hwnd(/Calculator/)
|
46
55
|
sleep 0.1
|
47
56
|
end
|
48
57
|
# just in case of slow PC
|
49
|
-
sleep
|
58
|
+
sleep 2
|
50
59
|
end
|
51
60
|
|
52
61
|
def maximize title
|
@@ -1,12 +1,11 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
describe
|
4
|
-
include SpecHelper
|
5
|
-
|
3
|
+
describe Win32::Screenshot do
|
4
|
+
include SpecHelper
|
5
|
+
|
6
6
|
before :all do
|
7
|
-
PROGRAM_FILES = "c:/program files/"
|
8
7
|
@notepad = IO.popen("notepad").pid
|
9
|
-
@iexplore =
|
8
|
+
@iexplore = Dir.chdir("c:/program files/Internet Explorer") do; IO.popen(".\\iexplore about:blank").pid; end
|
10
9
|
@calc = IO.popen("calc").pid
|
11
10
|
wait_for_programs_to_open
|
12
11
|
cleanup
|
@@ -16,9 +15,7 @@ describe "win32-screenshot" do
|
|
16
15
|
Win32::Screenshot.foreground do |width, height, bmp|
|
17
16
|
check_image(bmp, 'foreground')
|
18
17
|
hwnd = Win32::Screenshot::BitmapMaker.foreground_window
|
19
|
-
|
20
|
-
width.should == dimensions[2]
|
21
|
-
height.should == dimensions[3]
|
18
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
22
19
|
end
|
23
20
|
end
|
24
21
|
|
@@ -39,9 +36,7 @@ describe "win32-screenshot" do
|
|
39
36
|
Win32::Screenshot.desktop do |width, height, bmp|
|
40
37
|
check_image(bmp, 'desktop')
|
41
38
|
hwnd = Win32::Screenshot::BitmapMaker.desktop_window
|
42
|
-
|
43
|
-
width.should == dimensions[2]
|
44
|
-
height.should == dimensions[3]
|
39
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
@@ -64,9 +59,7 @@ describe "win32-screenshot" do
|
|
64
59
|
Win32::Screenshot.window(title) do |width, height, bmp|
|
65
60
|
check_image(bmp, 'iexplore')
|
66
61
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
67
|
-
|
68
|
-
width.should == dimensions[2]
|
69
|
-
height.should == dimensions[3]
|
62
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
70
63
|
end
|
71
64
|
end
|
72
65
|
|
@@ -76,9 +69,7 @@ describe "win32-screenshot" do
|
|
76
69
|
Win32::Screenshot.window(title) do |width, height, bmp|
|
77
70
|
check_image(bmp, 'calc')
|
78
71
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
79
|
-
|
80
|
-
width.should == dimensions[2]
|
81
|
-
height.should == dimensions[3]
|
72
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
82
73
|
end
|
83
74
|
end
|
84
75
|
|
@@ -91,9 +82,7 @@ describe "win32-screenshot" do
|
|
91
82
|
# screenshot doesn't include titlebar and the size
|
92
83
|
# varies between different themes and Windows versions
|
93
84
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
94
|
-
|
95
|
-
width.should == dimensions[2]
|
96
|
-
height.should == dimensions[3]
|
85
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
97
86
|
end
|
98
87
|
end
|
99
88
|
|
@@ -109,11 +98,11 @@ describe "win32-screenshot" do
|
|
109
98
|
it "captures whole window if window size is specified as coordinates" do
|
110
99
|
title = /calculator/i
|
111
100
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
112
|
-
|
113
|
-
Win32::Screenshot.window_area(title, 0, 0,
|
101
|
+
expected_width, expected_height = Win32::Screenshot::Util.dimensions_for(hwnd)
|
102
|
+
Win32::Screenshot.window_area(title, 0, 0, expected_width, expected_height) do |width, height, bmp|
|
114
103
|
check_image(bmp, 'calc_area_full_window')
|
115
|
-
width.should ==
|
116
|
-
height.should ==
|
104
|
+
width.should == expected_width
|
105
|
+
height.should == expected_height
|
117
106
|
end
|
118
107
|
end
|
119
108
|
|
@@ -138,9 +127,9 @@ describe "win32-screenshot" do
|
|
138
127
|
it "doesn't allow to capture area of the window with too big coordinates" do
|
139
128
|
title = /calculator/i
|
140
129
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
141
|
-
|
130
|
+
expected_width, expected_height = Win32::Screenshot::Util.dimensions_for(hwnd)
|
142
131
|
lambda {Win32::Screenshot.window_area(title, 0, 0, 10, 1000) {|width, height, bmp| check_image('calc3')}}.
|
143
|
-
should raise_exception("specified coordinates (0, 0, 10, 1000) are invalid - maximum are x2=#{
|
132
|
+
should raise_exception("specified coordinates (0, 0, 10, 1000) are invalid - maximum are x2=#{expected_width} and y2=#{expected_height}!")
|
144
133
|
end
|
145
134
|
|
146
135
|
it "captures by window with handle" do
|
@@ -148,9 +137,7 @@ describe "win32-screenshot" do
|
|
148
137
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
149
138
|
Win32::Screenshot.hwnd(hwnd) do |width, height, bmp|
|
150
139
|
check_image(bmp, 'calc_hwnd')
|
151
|
-
|
152
|
-
width.should == dimensions[2]
|
153
|
-
height.should == dimensions[3]
|
140
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
154
141
|
end
|
155
142
|
end
|
156
143
|
|
@@ -168,7 +155,7 @@ describe "win32-screenshot" do
|
|
168
155
|
lambda {Win32::Screenshot.hwnd_area(hwnd, 0, 0, -1, 100) {|width, height, bmp| check_image('desktop2')}}.
|
169
156
|
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
170
157
|
end
|
171
|
-
|
158
|
+
|
172
159
|
it "captures based on coordinates" do
|
173
160
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
|
174
161
|
bmp1 = bmp2 = nil
|
@@ -177,15 +164,13 @@ describe "win32-screenshot" do
|
|
177
164
|
bmp1.length.should == bmp2.length
|
178
165
|
bmp1.should_not == bmp2
|
179
166
|
end
|
180
|
-
|
181
|
-
it "
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
it "allow for parentheses in window names" do
|
188
|
-
Win32::Screenshot::BitmapMaker.hwnd("VLC (Direct")
|
167
|
+
|
168
|
+
it "allows window titles to include regular expressions' special characters" do
|
169
|
+
lambda {Win32::Screenshot::BitmapMaker.hwnd("Window title *^$?([.")}.should_not raise_exception
|
170
|
+
end
|
171
|
+
|
172
|
+
it "raises an 'no block given' Exception if no block was given" do
|
173
|
+
lambda {Win32::Screenshot.foreground}.should raise_exception(LocalJumpError)
|
189
174
|
end
|
190
175
|
|
191
176
|
after :all do
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Win32::Screenshot::Util do
|
4
|
+
include SpecHelper
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
@calc = IO.popen("calc").pid
|
8
|
+
wait_for_calculator_to_open
|
9
|
+
@calc_hwnd = Win32::Screenshot::Util.window_hwnd("Calculator")
|
10
|
+
end
|
11
|
+
|
12
|
+
it ".all_windows enumerates all available windows" do
|
13
|
+
all_windows = Win32::Screenshot::Util.all_windows
|
14
|
+
all_windows.should_not be_empty
|
15
|
+
all_windows[0].should be_an(Array)
|
16
|
+
all_windows[0][0].should be_a(String)
|
17
|
+
all_windows[0][1].should be_a(Fixnum)
|
18
|
+
|
19
|
+
calculator = all_windows.find {|title, hwnd| title =~ /Calculator/}
|
20
|
+
calculator.should_not be_nil
|
21
|
+
calculator[0].should == "Calculator"
|
22
|
+
calculator[1].should == @calc_hwnd
|
23
|
+
end
|
24
|
+
|
25
|
+
it ".window_title returns title of a specified window's handle" do
|
26
|
+
Win32::Screenshot::Util.window_title(@calc_hwnd).should == "Calculator"
|
27
|
+
end
|
28
|
+
|
29
|
+
it ".dimensions_for window handle returns dimensions of the window in pixels" do
|
30
|
+
width, height = Win32::Screenshot::Util.dimensions_for(@calc_hwnd)
|
31
|
+
width.should be > 100
|
32
|
+
height.should be > 100
|
33
|
+
end
|
34
|
+
|
35
|
+
after :all do
|
36
|
+
Process.kill 9, @calc
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{win32screenshot}
|
8
|
+
s.version = "0.0.6"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jarmo Pertman", "Aslak Helles\303\270y"]
|
12
|
+
s.date = %q{2010-08-07}
|
13
|
+
s.description = %q{Capture Screenshots on Windows with Ruby}
|
14
|
+
s.email = ["jarmo.p@gmail.com", "aslak.hellesoy@gmail.com"]
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"History.rdoc",
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/win32/screenshot.rb",
|
28
|
+
"lib/win32/screenshot/bitmap_maker.rb",
|
29
|
+
"lib/win32/util.rb",
|
30
|
+
"spec/spec.opts",
|
31
|
+
"spec/spec_helper.rb",
|
32
|
+
"spec/win32_screenshot_spec.rb",
|
33
|
+
"spec/win32_screenshot_util_spec.rb",
|
34
|
+
"win32screenshot.gemspec"
|
35
|
+
]
|
36
|
+
s.homepage = %q{http://github.com/jarmo/win32screenshot}
|
37
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = %q{1.3.6}
|
40
|
+
s.summary = %q{Capture Screenshots on Windows with Ruby}
|
41
|
+
s.test_files = [
|
42
|
+
"spec/spec_helper.rb",
|
43
|
+
"spec/win32_screenshot_spec.rb",
|
44
|
+
"spec/win32_screenshot_util_spec.rb"
|
45
|
+
]
|
46
|
+
|
47
|
+
if s.respond_to? :specification_version then
|
48
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_runtime_dependency(%q<ffi>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
54
|
+
s.add_development_dependency(%q<os>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<rmagick>, [">= 0"])
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<ffi>, [">= 0"])
|
58
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
59
|
+
s.add_dependency(%q<os>, [">= 0"])
|
60
|
+
s.add_dependency(%q<rmagick>, [">= 0"])
|
61
|
+
end
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<ffi>, [">= 0"])
|
64
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
65
|
+
s.add_dependency(%q<os>, [">= 0"])
|
66
|
+
s.add_dependency(%q<rmagick>, [">= 0"])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdp-win32screenshot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 83
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
7
|
- 0
|
9
8
|
- 6
|
10
|
-
-
|
11
|
-
version: 0.0.6.
|
9
|
+
- 3
|
10
|
+
version: 0.0.6.3
|
12
11
|
platform: ruby
|
13
12
|
authors:
|
14
13
|
- Jarmo Pertman
|
@@ -17,7 +16,7 @@ autorequire:
|
|
17
16
|
bindir: bin
|
18
17
|
cert_chain: []
|
19
18
|
|
20
|
-
date: 2010-
|
19
|
+
date: 2010-08-16 00:00:00 -06:00
|
21
20
|
default_executable:
|
22
21
|
dependencies:
|
23
22
|
- !ruby/object:Gem::Dependency
|
@@ -28,7 +27,6 @@ dependencies:
|
|
28
27
|
requirements:
|
29
28
|
- - ">="
|
30
29
|
- !ruby/object:Gem::Version
|
31
|
-
hash: 3
|
32
30
|
segments:
|
33
31
|
- 0
|
34
32
|
version: "0"
|
@@ -42,7 +40,6 @@ dependencies:
|
|
42
40
|
requirements:
|
43
41
|
- - ">="
|
44
42
|
- !ruby/object:Gem::Version
|
45
|
-
hash: 13
|
46
43
|
segments:
|
47
44
|
- 1
|
48
45
|
- 2
|
@@ -58,7 +55,6 @@ dependencies:
|
|
58
55
|
requirements:
|
59
56
|
- - ">="
|
60
57
|
- !ruby/object:Gem::Version
|
61
|
-
hash: 3
|
62
58
|
segments:
|
63
59
|
- 0
|
64
60
|
version: "0"
|
@@ -72,7 +68,6 @@ dependencies:
|
|
72
68
|
requirements:
|
73
69
|
- - ">="
|
74
70
|
- !ruby/object:Gem::Version
|
75
|
-
hash: 3
|
76
71
|
segments:
|
77
72
|
- 0
|
78
73
|
version: "0"
|
@@ -99,10 +94,12 @@ files:
|
|
99
94
|
- VERSION
|
100
95
|
- lib/win32/screenshot.rb
|
101
96
|
- lib/win32/screenshot/bitmap_maker.rb
|
102
|
-
- lib/
|
97
|
+
- lib/win32/util.rb
|
103
98
|
- spec/spec.opts
|
104
99
|
- spec/spec_helper.rb
|
105
100
|
- spec/win32_screenshot_spec.rb
|
101
|
+
- spec/win32_screenshot_util_spec.rb
|
102
|
+
- win32screenshot.gemspec
|
106
103
|
has_rdoc: true
|
107
104
|
homepage: http://github.com/jarmo/win32screenshot
|
108
105
|
licenses: []
|
@@ -118,7 +115,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
118
115
|
requirements:
|
119
116
|
- - ">="
|
120
117
|
- !ruby/object:Gem::Version
|
121
|
-
hash: 3
|
122
118
|
segments:
|
123
119
|
- 0
|
124
120
|
version: "0"
|
@@ -127,7 +123,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
123
|
requirements:
|
128
124
|
- - ">="
|
129
125
|
- !ruby/object:Gem::Version
|
130
|
-
hash: 3
|
131
126
|
segments:
|
132
127
|
- 0
|
133
128
|
version: "0"
|
@@ -141,3 +136,4 @@ summary: Capture Screenshots on Windows with Ruby
|
|
141
136
|
test_files:
|
142
137
|
- spec/spec_helper.rb
|
143
138
|
- spec/win32_screenshot_spec.rb
|
139
|
+
- spec/win32_screenshot_util_spec.rb
|
data/lib/win32screenshot.rb
DELETED