win32screenshot 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.rdoc +13 -0
- data/README.rdoc +19 -0
- data/VERSION +1 -1
- data/lib/win32/screenshot.rb +14 -15
- data/lib/win32/screenshot/bitmap_maker.rb +149 -149
- data/lib/win32/util.rb +40 -0
- data/spec/spec_helper.rb +16 -3
- data/spec/win32_screenshot_spec.rb +41 -36
- data/spec/win32_screenshot_util_spec.rb +38 -0
- data/win32screenshot.gemspec +69 -0
- metadata +7 -4
- data/lib/win32screenshot.rb +0 -3
data/History.rdoc
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
= 0.0.6 2010-08-07
|
2
|
+
* Trying to bring window to the foreground more aggressively (Roger Pack)
|
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)
|
13
|
+
|
1
14
|
= 0.0.5 2010-07-07
|
2
15
|
* Added method window_area for capturing specified area of the window instead of full window (Jarmo Pertman)
|
3
16
|
Usage: Win32::Screenshot.window_area(title, x1, y1, x2, y2) {|width, height, bmp|}
|
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.
|
1
|
+
0.0.6
|
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,22 +74,20 @@ 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
|
-
|
85
|
-
|
79
|
+
if coords.any? {|c| c < 0}
|
80
|
+
raise "specified coordinates (#{specified_coordinates}) are invalid - cannot be negative!"
|
81
|
+
end
|
86
82
|
x1, y1, x2, y2 = *coords
|
87
|
-
|
83
|
+
if x1 >= x2 || y1 >= y2
|
84
|
+
raise "specified coordinates (#{specified_coordinates}) are invalid - cannot have x1 > x2 or y1 > y2!"
|
85
|
+
end
|
88
86
|
|
89
|
-
|
90
|
-
|
91
|
-
|
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}!"
|
90
|
+
end
|
92
91
|
end
|
93
92
|
end
|
94
93
|
|
@@ -3,165 +3,165 @@ 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
|
-
|
76
|
-
else
|
77
|
-
true
|
6
|
+
class BitmapMaker #:nodoc:all
|
7
|
+
class << self
|
8
|
+
extend FFI::Library
|
9
|
+
|
10
|
+
ffi_lib 'user32', 'gdi32'
|
11
|
+
ffi_convention :stdcall
|
12
|
+
|
13
|
+
callback :enum_callback, [:long, :pointer], :bool
|
14
|
+
|
15
|
+
# user32.dll
|
16
|
+
attach_function :enum_windows, :EnumWindows,
|
17
|
+
[:enum_callback, :pointer], :long
|
18
|
+
attach_function :window_text, :GetWindowTextA,
|
19
|
+
[:long, :pointer, :int], :int
|
20
|
+
attach_function :window_text_length, :GetWindowTextLengthA,
|
21
|
+
[:long], :int
|
22
|
+
attach_function :window_visible, :IsWindowVisible,
|
23
|
+
[:long], :bool
|
24
|
+
attach_function :dc, :GetDC,
|
25
|
+
[:long], :long
|
26
|
+
attach_function :client_rect, :GetClientRect,
|
27
|
+
[:long, :pointer], :bool
|
28
|
+
attach_function :minimized, :IsIconic,
|
29
|
+
[:long], :bool
|
30
|
+
attach_function :show_window, :ShowWindow,
|
31
|
+
[:long, :int], :bool
|
32
|
+
attach_function :foreground_window, :GetForegroundWindow,
|
33
|
+
[], :long
|
34
|
+
attach_function :desktop_window, :GetDesktopWindow,
|
35
|
+
[], :long
|
36
|
+
attach_function :window_thread_process_id, :GetWindowThreadProcessId,
|
37
|
+
[:long, :pointer], :long
|
38
|
+
attach_function :attach_thread_input, :AttachThreadInput,
|
39
|
+
[:long, :long, :bool], :bool
|
40
|
+
attach_function :set_foreground_window, :SetForegroundWindow,
|
41
|
+
[:long], :bool
|
42
|
+
attach_function :bring_window_to_top, :BringWindowToTop,
|
43
|
+
[:long], :bool
|
44
|
+
attach_function :set_active_window, :SetActiveWindow,
|
45
|
+
[:long], :long
|
46
|
+
|
47
|
+
|
48
|
+
# gdi32.dll
|
49
|
+
attach_function :create_compatible_dc, :CreateCompatibleDC,
|
50
|
+
[:long], :long
|
51
|
+
attach_function :create_compatible_bitmap, :CreateCompatibleBitmap,
|
52
|
+
[:long, :int, :int], :long
|
53
|
+
attach_function :select_object, :SelectObject,
|
54
|
+
[:long, :long], :long
|
55
|
+
attach_function :bit_blt, :BitBlt,
|
56
|
+
[:long, :int, :int, :int, :int, :long, :int, :int, :long], :bool
|
57
|
+
attach_function :di_bits, :GetDIBits,
|
58
|
+
[:long, :long, :int, :int, :pointer, :pointer, :int], :int
|
59
|
+
attach_function :delete_object, :DeleteObject,
|
60
|
+
[:long], :bool
|
61
|
+
attach_function :delete_dc, :DeleteDC,
|
62
|
+
[:long], :bool
|
63
|
+
attach_function :release_dc, :ReleaseDC,
|
64
|
+
[:long, :long], :int
|
65
|
+
|
66
|
+
|
67
|
+
EnumWindowCallback = Proc.new do |hwnd, param|
|
68
|
+
searched_window = WindowStruct.new param
|
69
|
+
title = Util.window_title(hwnd)
|
70
|
+
if title =~ Regexp.new(searched_window[:title].read_string) && window_visible(hwnd)
|
71
|
+
searched_window[:hwnd] = hwnd
|
72
|
+
false
|
73
|
+
else
|
74
|
+
true
|
75
|
+
end
|
78
76
|
end
|
79
|
-
end
|
80
|
-
|
81
|
-
module_function
|
82
|
-
|
83
|
-
class WindowStruct < FFI::Struct
|
84
|
-
layout :title, :pointer,
|
85
|
-
:hwnd, :long
|
86
|
-
end
|
87
77
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
enum_windows(EnumWindowCallback, window.to_ptr)
|
93
|
-
window[:hwnd] == 0 ? nil : window[:hwnd]
|
94
|
-
end
|
78
|
+
class WindowStruct < FFI::Struct
|
79
|
+
layout :title, :pointer,
|
80
|
+
:hwnd, :long
|
81
|
+
end
|
95
82
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
83
|
+
def hwnd(window_title)
|
84
|
+
window = WindowStruct.new
|
85
|
+
unless window_title.is_a?(Regexp)
|
86
|
+
window_title = Regexp.escape(window_title.to_s)
|
87
|
+
else
|
88
|
+
window_title = window_title.to_s
|
89
|
+
end
|
90
|
+
window_title = FFI::MemoryPointer.from_string(window_title)
|
91
|
+
window[:title] = window_title
|
92
|
+
enum_windows(EnumWindowCallback, window.to_ptr)
|
93
|
+
window[:hwnd] == 0 ? nil : window[:hwnd]
|
94
|
+
end
|
101
95
|
|
102
|
-
|
96
|
+
def prepare_window(hwnd, pause)
|
97
|
+
restore(hwnd) if minimized(hwnd)
|
98
|
+
set_foreground(hwnd)
|
99
|
+
sleep pause
|
100
|
+
end
|
103
101
|
|
104
|
-
|
105
|
-
show_window(hwnd, SW_RESTORE)
|
106
|
-
end
|
102
|
+
SW_RESTORE = 9
|
107
103
|
|
108
|
-
|
109
|
-
|
110
|
-
foreground_thread = window_thread_process_id(current_thread_id, nil)
|
111
|
-
other_thread = window_thread_process_id(hwnd, nil)
|
112
|
-
attach_thread_input(foreground_thread, other_thread, true)
|
113
|
-
set_foreground_window(hwnd)
|
114
|
-
set_focus(hwnd)
|
115
|
-
attach_thread_input(foreground_thread, other_thread, false)
|
104
|
+
def restore(hwnd)
|
105
|
+
show_window(hwnd, SW_RESTORE)
|
116
106
|
end
|
117
|
-
end
|
118
107
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
108
|
+
def set_foreground(hwnd)
|
109
|
+
if foreground_window != hwnd
|
110
|
+
set_foreground_window(hwnd)
|
111
|
+
set_active_window(hwnd)
|
112
|
+
bring_window_to_top(hwnd)
|
113
|
+
# and just in case...
|
114
|
+
foreground_thread = window_thread_process_id(foreground_window, nil)
|
115
|
+
other_thread = window_thread_process_id(hwnd, nil)
|
116
|
+
attach_thread_input(foreground_thread, other_thread, true) unless other_thread == foreground_thread
|
117
|
+
set_foreground_window(hwnd)
|
118
|
+
set_active_window(hwnd)
|
119
|
+
bring_window_to_top(hwnd)
|
120
|
+
attach_thread_input(foreground_thread, other_thread, false) unless other_thread == foreground_thread
|
121
|
+
end
|
122
|
+
end
|
124
123
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
def capture_all(hwnd, &proc)
|
125
|
+
width, height = Util.dimensions_for(hwnd)
|
126
|
+
capture_area(hwnd, 0, 0, width, height, &proc)
|
127
|
+
end
|
129
128
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
129
|
+
SRCCOPY = 0x00CC0020
|
130
|
+
DIB_RGB_COLORS = 0
|
131
|
+
|
132
|
+
def capture_area(hwnd, x1, y1, x2, y2) # block
|
133
|
+
hScreenDC = dc(hwnd)
|
134
|
+
w = x2-x1
|
135
|
+
h = y2-y1
|
136
|
+
|
137
|
+
hmemDC = create_compatible_dc(hScreenDC)
|
138
|
+
hmemBM = create_compatible_bitmap(hScreenDC, w, h)
|
139
|
+
select_object(hmemDC, hmemBM)
|
140
|
+
bit_blt(hmemDC, 0, 0, w, h, hScreenDC, x1, y1, SRCCOPY)
|
141
|
+
bitmap_size = w * h * 3 + w % 4 * h
|
142
|
+
lpvpxldata = FFI::MemoryPointer.new(bitmap_size)
|
143
|
+
|
144
|
+
# Bitmap header
|
145
|
+
# http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
|
146
|
+
bmInfo = [40, w, h, 1, 24, 0, 0, 0, 0, 0, 0, 0].pack('L3S2L6')
|
147
|
+
di_bits(hmemDC, hmemBM, 0, h, lpvpxldata, bmInfo, DIB_RGB_COLORS)
|
148
|
+
|
149
|
+
bmFileHeader = [
|
150
|
+
19778,
|
151
|
+
bitmap_size + 40 + 14,
|
152
|
+
0,
|
153
|
+
0,
|
154
|
+
54
|
155
|
+
].pack('SLSSL')
|
156
|
+
|
157
|
+
bmp_data = bmFileHeader + bmInfo + lpvpxldata.read_string(bitmap_size)
|
158
|
+
yield(w, h, bmp_data)
|
159
|
+
ensure
|
160
|
+
lpvpxldata.free
|
161
|
+
delete_object(hmemBM)
|
162
|
+
delete_dc(hmemDC)
|
163
|
+
release_dc(0, hScreenDC)
|
164
|
+
end
|
165
165
|
end
|
166
166
|
end
|
167
167
|
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 = Proc.new 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
@@ -24,6 +24,10 @@ module SpecHelper
|
|
24
24
|
attach_function :set_window_pos, :SetWindowPos,
|
25
25
|
[:long, :long, :int, :int, :int, :int, :int], :bool
|
26
26
|
|
27
|
+
def cleanup
|
28
|
+
FileUtils.rm Dir.glob(File.join(File.dirname(__FILE__), "tmp/*"))
|
29
|
+
end
|
30
|
+
|
27
31
|
def check_image(bmp, file=nil)
|
28
32
|
temp_dir = File.join(File.dirname(__FILE__), 'tmp')
|
29
33
|
FileUtils.mkdir temp_dir unless File.exists?(temp_dir)
|
@@ -37,12 +41,21 @@ module SpecHelper
|
|
37
41
|
|
38
42
|
def wait_for_programs_to_open
|
39
43
|
until Win32::Screenshot::BitmapMaker.hwnd(/Internet Explorer/) &&
|
40
|
-
Win32::Screenshot::BitmapMaker.hwnd(/Notepad/)
|
41
|
-
|
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/)
|
42
55
|
sleep 0.1
|
43
56
|
end
|
44
57
|
# just in case of slow PC
|
45
|
-
sleep
|
58
|
+
sleep 2
|
46
59
|
end
|
47
60
|
|
48
61
|
def maximize title
|
@@ -1,25 +1,21 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Win32::Screenshot do
|
4
4
|
include SpecHelper
|
5
5
|
|
6
6
|
before :all do
|
7
|
-
PROGRAM_FILES = "c:/program files/"
|
8
|
-
FileUtils.rm Dir.glob("*.bmp")
|
9
|
-
FileUtils.rm Dir.glob("*.png")
|
10
7
|
@notepad = IO.popen("notepad").pid
|
11
|
-
@iexplore = IO.popen(
|
8
|
+
@iexplore = IO.popen("\"c:/program files/Internet Explorer/iexplore\" about:blank").pid
|
12
9
|
@calc = IO.popen("calc").pid
|
13
10
|
wait_for_programs_to_open
|
11
|
+
cleanup
|
14
12
|
end
|
15
13
|
|
16
14
|
it "captures foreground" do
|
17
15
|
Win32::Screenshot.foreground do |width, height, bmp|
|
18
16
|
check_image(bmp, 'foreground')
|
19
17
|
hwnd = Win32::Screenshot::BitmapMaker.foreground_window
|
20
|
-
|
21
|
-
width.should == dimensions[2]
|
22
|
-
height.should == dimensions[3]
|
18
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
23
19
|
end
|
24
20
|
end
|
25
21
|
|
@@ -33,16 +29,14 @@ describe "win32-screenshot" do
|
|
33
29
|
|
34
30
|
it "doesn't allow to capture area of the foreground with invalid coordinates" do
|
35
31
|
lambda {Win32::Screenshot.foreground_area(0, 0, -1, 100) {|width, height, bmp| check_image('foreground2')}}.
|
36
|
-
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid!")
|
32
|
+
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
37
33
|
end
|
38
34
|
|
39
35
|
it "captures desktop" do
|
40
36
|
Win32::Screenshot.desktop do |width, height, bmp|
|
41
37
|
check_image(bmp, 'desktop')
|
42
38
|
hwnd = Win32::Screenshot::BitmapMaker.desktop_window
|
43
|
-
|
44
|
-
width.should == dimensions[2]
|
45
|
-
height.should == dimensions[3]
|
39
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
46
40
|
end
|
47
41
|
end
|
48
42
|
|
@@ -56,7 +50,7 @@ describe "win32-screenshot" do
|
|
56
50
|
|
57
51
|
it "doesn't allow to capture area of the desktop with invalid coordinates" do
|
58
52
|
lambda {Win32::Screenshot.desktop_area(0, 0, -1, 100) {|width, height, bmp| check_image('desktop2')}}.
|
59
|
-
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid!")
|
53
|
+
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
60
54
|
end
|
61
55
|
|
62
56
|
it "captures maximized window by window title" do
|
@@ -65,9 +59,7 @@ describe "win32-screenshot" do
|
|
65
59
|
Win32::Screenshot.window(title) do |width, height, bmp|
|
66
60
|
check_image(bmp, 'iexplore')
|
67
61
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
68
|
-
|
69
|
-
width.should == dimensions[2]
|
70
|
-
height.should == dimensions[3]
|
62
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
71
63
|
end
|
72
64
|
end
|
73
65
|
|
@@ -77,9 +69,7 @@ describe "win32-screenshot" do
|
|
77
69
|
Win32::Screenshot.window(title) do |width, height, bmp|
|
78
70
|
check_image(bmp, 'calc')
|
79
71
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
80
|
-
|
81
|
-
width.should == dimensions[2]
|
82
|
-
height.should == dimensions[3]
|
72
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
83
73
|
end
|
84
74
|
end
|
85
75
|
|
@@ -92,9 +82,7 @@ describe "win32-screenshot" do
|
|
92
82
|
# screenshot doesn't include titlebar and the size
|
93
83
|
# varies between different themes and Windows versions
|
94
84
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
95
|
-
|
96
|
-
width.should == dimensions[2]
|
97
|
-
height.should == dimensions[3]
|
85
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
98
86
|
end
|
99
87
|
end
|
100
88
|
|
@@ -110,36 +98,38 @@ describe "win32-screenshot" do
|
|
110
98
|
it "captures whole window if window size is specified as coordinates" do
|
111
99
|
title = /calculator/i
|
112
100
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
113
|
-
|
114
|
-
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|
|
115
103
|
check_image(bmp, 'calc_area_full_window')
|
116
|
-
width.should ==
|
117
|
-
height.should ==
|
104
|
+
width.should == expected_width
|
105
|
+
height.should == expected_height
|
118
106
|
end
|
119
107
|
end
|
120
108
|
|
121
109
|
it "doesn't allow to capture area of the window with negative coordinates" do
|
122
110
|
title = /calculator/i
|
123
111
|
lambda {Win32::Screenshot.window_area(title, 0, 0, -1, 100) {|width, height, bmp| check_image('calc2')}}.
|
124
|
-
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid!")
|
112
|
+
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
125
113
|
end
|
126
114
|
|
127
115
|
it "doesn't allow to capture area of the window if coordinates are the same" do
|
128
116
|
title = /calculator/i
|
129
117
|
lambda {Win32::Screenshot.window_area(title, 10, 0, 10, 20) {|width, height, bmp| check_image('calc4')}}.
|
130
|
-
should raise_exception("specified coordinates (10, 0, 10, 20) are invalid!")
|
118
|
+
should raise_exception("specified coordinates (10, 0, 10, 20) are invalid - cannot have x1 > x2 or y1 > y2!")
|
131
119
|
end
|
132
120
|
|
133
121
|
it "doesn't allow to capture area of the window if second coordinate is smaller than first one" do
|
134
122
|
title = /calculator/i
|
135
123
|
lambda {Win32::Screenshot.window_area(title, 0, 10, 10, 9) {|width, height, bmp| check_image('calc5')}}.
|
136
|
-
should raise_exception("specified coordinates (0, 10, 10, 9) are invalid!")
|
124
|
+
should raise_exception("specified coordinates (0, 10, 10, 9) are invalid - cannot have x1 > x2 or y1 > y2!")
|
137
125
|
end
|
138
126
|
|
139
127
|
it "doesn't allow to capture area of the window with too big coordinates" do
|
140
128
|
title = /calculator/i
|
141
|
-
|
142
|
-
|
129
|
+
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
130
|
+
expected_width, expected_height = Win32::Screenshot::Util.dimensions_for(hwnd)
|
131
|
+
lambda {Win32::Screenshot.window_area(title, 0, 0, 10, 1000) {|width, height, bmp| check_image('calc3')}}.
|
132
|
+
should raise_exception("specified coordinates (0, 0, 10, 1000) are invalid - maximum are x2=#{expected_width} and y2=#{expected_height}!")
|
143
133
|
end
|
144
134
|
|
145
135
|
it "captures by window with handle" do
|
@@ -147,9 +137,7 @@ describe "win32-screenshot" do
|
|
147
137
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
148
138
|
Win32::Screenshot.hwnd(hwnd) do |width, height, bmp|
|
149
139
|
check_image(bmp, 'calc_hwnd')
|
150
|
-
|
151
|
-
width.should == dimensions[2]
|
152
|
-
height.should == dimensions[3]
|
140
|
+
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
153
141
|
end
|
154
142
|
end
|
155
143
|
|
@@ -165,12 +153,29 @@ describe "win32-screenshot" do
|
|
165
153
|
it "doesn't allow to capture area of the window with handle with invalid coordinates" do
|
166
154
|
hwnd = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
|
167
155
|
lambda {Win32::Screenshot.hwnd_area(hwnd, 0, 0, -1, 100) {|width, height, bmp| check_image('desktop2')}}.
|
168
|
-
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid!")
|
156
|
+
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
157
|
+
end
|
158
|
+
|
159
|
+
it "captures based on coordinates" do
|
160
|
+
hwnd = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
|
161
|
+
bmp1 = bmp2 = nil
|
162
|
+
Win32::Screenshot.hwnd_area(hwnd, 100, 100, 170, 180) do |width, height, bmp|; bmp1 = bmp; end
|
163
|
+
Win32::Screenshot.hwnd_area(hwnd, 0, 0, 70, 80) do |width, height, bmp|; bmp2 = bmp; end
|
164
|
+
bmp1.length.should == bmp2.length
|
165
|
+
bmp1.should_not == bmp2
|
166
|
+
end
|
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)
|
169
174
|
end
|
170
175
|
|
171
176
|
after :all do
|
172
177
|
Process.kill 9, @notepad
|
173
|
-
Process.kill 9, @iexplore
|
178
|
+
Process.kill 9, @iexplore rescue nil # allow for a pre-existing IE to have been used.
|
174
179
|
Process.kill 9, @calc
|
175
180
|
end
|
176
181
|
end
|
@@ -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
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 6
|
9
|
+
version: 0.0.6
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jarmo Pertman
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-08-07 00:00:00 +03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -89,10 +89,12 @@ files:
|
|
89
89
|
- VERSION
|
90
90
|
- lib/win32/screenshot.rb
|
91
91
|
- lib/win32/screenshot/bitmap_maker.rb
|
92
|
-
- lib/
|
92
|
+
- lib/win32/util.rb
|
93
93
|
- spec/spec.opts
|
94
94
|
- spec/spec_helper.rb
|
95
95
|
- spec/win32_screenshot_spec.rb
|
96
|
+
- spec/win32_screenshot_util_spec.rb
|
97
|
+
- win32screenshot.gemspec
|
96
98
|
has_rdoc: true
|
97
99
|
homepage: http://github.com/jarmo/win32screenshot
|
98
100
|
licenses: []
|
@@ -127,3 +129,4 @@ summary: Capture Screenshots on Windows with Ruby
|
|
127
129
|
test_files:
|
128
130
|
- spec/spec_helper.rb
|
129
131
|
- spec/win32_screenshot_spec.rb
|
132
|
+
- spec/win32_screenshot_util_spec.rb
|
data/lib/win32screenshot.rb
DELETED