win32screenshot 0.0.8 → 1.0.0
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/.gitignore +3 -1
- data/{spec/spec.opts → .rspec} +0 -0
- data/.yardopts +6 -0
- data/History.rdoc +7 -0
- data/README.rdoc +22 -76
- data/Rakefile +8 -25
- data/VERSION +1 -1
- data/ext/CORE_RL_bzlib_.dll +0 -0
- data/ext/CORE_RL_jpeg_.dll +0 -0
- data/ext/CORE_RL_lcms_.dll +0 -0
- data/ext/CORE_RL_magick_.dll +0 -0
- data/ext/CORE_RL_png_.dll +0 -0
- data/ext/CORE_RL_ttf_.dll +0 -0
- data/ext/CORE_RL_wand_.dll +0 -0
- data/ext/CORE_RL_zlib_.dll +0 -0
- data/ext/ImageMagick-License.txt +101 -0
- data/ext/X11.dll +0 -0
- data/ext/identify.exe +0 -0
- data/ext/modules/coders/IM_MOD_RL_bmp_.dll +0 -0
- data/ext/modules/coders/IM_MOD_RL_gif_.dll +0 -0
- data/ext/modules/coders/IM_MOD_RL_jpeg_.dll +0 -0
- data/ext/modules/coders/IM_MOD_RL_png_.dll +0 -0
- data/ext/mogrify.exe +0 -0
- data/ext/msvcr100.dll +0 -0
- data/ext/vcomp100.dll +0 -0
- data/lib/win32/screenshot.rb +12 -93
- data/lib/win32/screenshot/bitmap_maker.rb +17 -119
- data/lib/win32/screenshot/extensions/rautomation/adapter/ffi/functions.rb +12 -0
- data/lib/win32/screenshot/extensions/rautomation/adapter/ffi/window.rb +17 -0
- data/lib/win32/screenshot/image.rb +43 -0
- data/lib/win32/screenshot/take.rb +102 -0
- data/spec/spec_helper.rb +13 -50
- data/spec/win32/screenshot/image_spec.rb +68 -0
- data/spec/win32/screenshot/take_spec.rb +137 -0
- data/win32screenshot.gemspec +39 -17
- metadata +50 -27
- data/lib/win32/util.rb +0 -93
- data/spec/win32_screenshot_spec.rb +0 -194
- data/spec/win32_screenshot_util_spec.rb +0 -75
data/lib/win32/util.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
module Win32
|
2
|
-
class Screenshot
|
3
|
-
class Util
|
4
|
-
class << self
|
5
|
-
|
6
|
-
def all_desktop_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
|
-
# just returns a long list of hwnd's...
|
18
|
-
# unless with_info is true
|
19
|
-
# then it will return all hwnds with full info about each window
|
20
|
-
def windows_hierarchy with_info = false
|
21
|
-
all = {}
|
22
|
-
desktop_hwnd = BitmapMaker.desktop_window
|
23
|
-
root = {:hwnd => desktop_hwnd, :children => []}
|
24
|
-
root.merge!(get_info(desktop_hwnd)) if with_info
|
25
|
-
parents = []
|
26
|
-
parents << root
|
27
|
-
window_callback = FFI::Function.new(:bool, [ :long, :pointer ], { :convention => :stdcall }) do |hwnd, param|
|
28
|
-
# this is a child of the most recent parent
|
29
|
-
myself = {:hwnd => hwnd, :children => []}
|
30
|
-
myself.merge!(get_info(hwnd)) if with_info
|
31
|
-
parents[-1][:children] << myself
|
32
|
-
parents << myself
|
33
|
-
if !all[hwnd]
|
34
|
-
all[hwnd] = true
|
35
|
-
BitmapMaker.enum_child_windows(hwnd, window_callback, nil)
|
36
|
-
end
|
37
|
-
|
38
|
-
parents.pop
|
39
|
-
true
|
40
|
-
end
|
41
|
-
BitmapMaker.enum_child_windows(desktop_hwnd, window_callback, nil)
|
42
|
-
root
|
43
|
-
end
|
44
|
-
|
45
|
-
def get_info hwnd
|
46
|
-
{:title => window_title(hwnd),
|
47
|
-
:class => window_class(hwnd),
|
48
|
-
:dimensions => dimensions_for(hwnd),
|
49
|
-
:starting_coordinates => location_of(hwnd)
|
50
|
-
}
|
51
|
-
end
|
52
|
-
|
53
|
-
def window_title hwnd
|
54
|
-
title_length = BitmapMaker.window_text_length(hwnd) + 1
|
55
|
-
title = FFI::MemoryPointer.new :char, title_length
|
56
|
-
BitmapMaker.window_text(hwnd, title, title_length)
|
57
|
-
title.read_string
|
58
|
-
end
|
59
|
-
|
60
|
-
def window_class hwnd
|
61
|
-
title = FFI::MemoryPointer.new :char, 100
|
62
|
-
BitmapMaker.class_name(hwnd, title, 99)
|
63
|
-
title.read_string
|
64
|
-
end
|
65
|
-
|
66
|
-
def window_hwnd(title_query)
|
67
|
-
hwnd = BitmapMaker.hwnd(title_query)
|
68
|
-
raise "window with title '#{title_query}' was not found!" unless hwnd
|
69
|
-
hwnd
|
70
|
-
end
|
71
|
-
|
72
|
-
def location_of(hwnd)
|
73
|
-
rect = [0, 0, 0, 0].pack('L4')
|
74
|
-
BitmapMaker.window_rect(hwnd, rect)
|
75
|
-
x, y, width, height = rect.unpack('L4')
|
76
|
-
return x, y
|
77
|
-
end
|
78
|
-
|
79
|
-
def dimensions_for(hwnd)
|
80
|
-
rect = [0, 0, 0, 0].pack('L4')
|
81
|
-
BitmapMaker.client_rect(hwnd, rect)
|
82
|
-
_, _, width, height = rect.unpack('L4')
|
83
|
-
return width, height
|
84
|
-
end
|
85
|
-
|
86
|
-
def window_process_id(hwnd)
|
87
|
-
BitmapMaker.get_process_id_from_hwnd(hwnd)
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
@@ -1,194 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe Win32::Screenshot do
|
4
|
-
include SpecHelper
|
5
|
-
|
6
|
-
before :all do
|
7
|
-
@notepad = IO.popen("notepad").pid
|
8
|
-
@iexplore = Dir.chdir("c:/program files/Internet Explorer") do; IO.popen(".\\iexplore about:blank").pid; end
|
9
|
-
@calc = IO.popen("calc").pid
|
10
|
-
wait_for_programs_to_open
|
11
|
-
cleanup
|
12
|
-
end
|
13
|
-
|
14
|
-
it "captures foreground" do
|
15
|
-
Win32::Screenshot.foreground do |width, height, bmp|
|
16
|
-
check_image(bmp, 'foreground')
|
17
|
-
hwnd = Win32::Screenshot::BitmapMaker.foreground_window
|
18
|
-
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
it "captures area of the foreground" do
|
23
|
-
Win32::Screenshot.foreground_area(30, 30, 100, 150) do |width, height, bmp|
|
24
|
-
check_image(bmp, 'foreground_area')
|
25
|
-
width.should == 70
|
26
|
-
height.should == 120
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
it "doesn't allow to capture area of the foreground with invalid coordinates" do
|
31
|
-
lambda {Win32::Screenshot.foreground_area(0, 0, -1, 100) {|width, height, bmp| check_image('foreground2')}}.
|
32
|
-
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
33
|
-
end
|
34
|
-
|
35
|
-
it "captures desktop" do
|
36
|
-
Win32::Screenshot.desktop do |width, height, bmp|
|
37
|
-
check_image(bmp, 'desktop')
|
38
|
-
hwnd = Win32::Screenshot::BitmapMaker.desktop_window
|
39
|
-
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
it "captures area of the desktop" do
|
44
|
-
Win32::Screenshot.desktop_area(30, 30, 100, 150) do |width, height, bmp|
|
45
|
-
check_image(bmp, 'desktop_area')
|
46
|
-
width.should == 70
|
47
|
-
height.should == 120
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
it "doesn't allow to capture area of the desktop with invalid coordinates" do
|
52
|
-
lambda {Win32::Screenshot.desktop_area(0, 0, -1, 100) {|width, height, bmp| check_image('desktop2')}}.
|
53
|
-
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
54
|
-
end
|
55
|
-
|
56
|
-
it "captures maximized window by window title" do
|
57
|
-
title = "Internet Explorer"
|
58
|
-
maximize(title)
|
59
|
-
Win32::Screenshot.window(title) do |width, height, bmp|
|
60
|
-
check_image(bmp, 'iexplore')
|
61
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
62
|
-
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
it "captures minimized window by window title as a regexp" do
|
67
|
-
title = /calculator/i
|
68
|
-
minimize(title)
|
69
|
-
Win32::Screenshot.window(title) do |width, height, bmp|
|
70
|
-
check_image(bmp, 'calc')
|
71
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
72
|
-
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
it "can also search by window class name" do
|
77
|
-
good_pid = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
|
78
|
-
good_pid.should_not be_nil
|
79
|
-
good_pid.should == Win32::Screenshot::BitmapMaker.hwnd(/calcframe/i, true)
|
80
|
-
end
|
81
|
-
|
82
|
-
it "can find sub windows as well" do
|
83
|
-
# search for an IE sub-window by class (doesn't have text)
|
84
|
-
Win32::Screenshot::BitmapMaker.hwnd(/CommandBarClass/i, true).should_not be_nil
|
85
|
-
end
|
86
|
-
|
87
|
-
it "captures small windows" do
|
88
|
-
title = /Notepad/
|
89
|
-
resize(title)
|
90
|
-
Win32::Screenshot.window(title) do |width, height, bmp|
|
91
|
-
check_image(bmp, 'notepad')
|
92
|
-
# we should get the size of the picture because
|
93
|
-
# screenshot doesn't include titlebar and the size
|
94
|
-
# varies between different themes and Windows versions
|
95
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
96
|
-
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
it "captures area of the window" do
|
101
|
-
title = /calculator/i
|
102
|
-
Win32::Screenshot.window_area(title, 30, 30, 100, 150) do |width, height, bmp|
|
103
|
-
check_image(bmp, 'calc_area')
|
104
|
-
width.should == 70
|
105
|
-
height.should == 120
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
it "captures whole window if window size is specified as coordinates" do
|
110
|
-
title = /calculator/i
|
111
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
112
|
-
expected_width, expected_height = Win32::Screenshot::Util.dimensions_for(hwnd)
|
113
|
-
Win32::Screenshot.window_area(title, 0, 0, expected_width, expected_height) do |width, height, bmp|
|
114
|
-
check_image(bmp, 'calc_area_full_window')
|
115
|
-
width.should == expected_width
|
116
|
-
height.should == expected_height
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
it "doesn't allow to capture area of the window with negative coordinates" do
|
121
|
-
title = /calculator/i
|
122
|
-
lambda {Win32::Screenshot.window_area(title, 0, 0, -1, 100) {|width, height, bmp| check_image('calc2')}}.
|
123
|
-
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
124
|
-
end
|
125
|
-
|
126
|
-
it "doesn't allow to capture area of the window if coordinates are the same" do
|
127
|
-
title = /calculator/i
|
128
|
-
lambda {Win32::Screenshot.window_area(title, 10, 0, 10, 20) {|width, height, bmp| check_image('calc4')}}.
|
129
|
-
should raise_exception("specified coordinates (10, 0, 10, 20) are invalid - cannot have x1 > x2 or y1 > y2!")
|
130
|
-
end
|
131
|
-
|
132
|
-
it "doesn't allow to capture area of the window if second coordinate is smaller than first one" do
|
133
|
-
title = /calculator/i
|
134
|
-
lambda {Win32::Screenshot.window_area(title, 0, 10, 10, 9) {|width, height, bmp| check_image('calc5')}}.
|
135
|
-
should raise_exception("specified coordinates (0, 10, 10, 9) are invalid - cannot have x1 > x2 or y1 > y2!")
|
136
|
-
end
|
137
|
-
|
138
|
-
it "doesn't allow to capture area of the window with too big coordinates" do
|
139
|
-
title = /calculator/i
|
140
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
141
|
-
expected_width, expected_height = Win32::Screenshot::Util.dimensions_for(hwnd)
|
142
|
-
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=#{expected_width} and y2=#{expected_height}!")
|
144
|
-
end
|
145
|
-
|
146
|
-
it "captures by window with handle" do
|
147
|
-
title = /calculator/i
|
148
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
149
|
-
Win32::Screenshot.hwnd(hwnd) do |width, height, bmp|
|
150
|
-
check_image(bmp, 'calc_hwnd')
|
151
|
-
[width, height].should == Win32::Screenshot::Util.dimensions_for(hwnd)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
it "captures area of the window with handle" do
|
156
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
|
157
|
-
Win32::Screenshot.hwnd_area(hwnd, 30, 30, 100, 150) do |width, height, bmp|
|
158
|
-
check_image(bmp, 'calc_hwnd_area')
|
159
|
-
width.should == 70
|
160
|
-
height.should == 120
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
it "doesn't allow to capture area of the window with handle with invalid coordinates" do
|
165
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
|
166
|
-
lambda {Win32::Screenshot.hwnd_area(hwnd, 0, 0, -1, 100) {|width, height, bmp| check_image('desktop2')}}.
|
167
|
-
should raise_exception("specified coordinates (0, 0, -1, 100) are invalid - cannot be negative!")
|
168
|
-
end
|
169
|
-
|
170
|
-
it "captures based on coordinates" do
|
171
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
|
172
|
-
bmp1 = bmp2 = nil
|
173
|
-
Win32::Screenshot.hwnd_area(hwnd, 100, 100, 170, 180) do |width, height, bmp|; bmp1 = bmp; end
|
174
|
-
Win32::Screenshot.hwnd_area(hwnd, 0, 0, 70, 80) do |width, height, bmp|; bmp2 = bmp; end
|
175
|
-
bmp1.length.should == bmp2.length
|
176
|
-
bmp1.should_not == bmp2
|
177
|
-
end
|
178
|
-
|
179
|
-
it "allows window titles to include regular expressions' special characters" do
|
180
|
-
lambda {Win32::Screenshot::BitmapMaker.hwnd("Window title *^$?([.")}.should_not raise_exception
|
181
|
-
end
|
182
|
-
|
183
|
-
it "raises an 'no block given' Exception if no block was given" do
|
184
|
-
lambda {Win32::Screenshot.foreground}.should raise_exception(LocalJumpError)
|
185
|
-
end
|
186
|
-
|
187
|
-
after :all do
|
188
|
-
for name in [/calculator/i, /Notepad/, /Internet Explorer/] do
|
189
|
-
# kill them in a jruby friendly way
|
190
|
-
pid = Win32::Screenshot::Util.window_process_id(Win32::Screenshot::Util.window_hwnd(name))
|
191
|
-
system("taskkill /PID #{pid}")
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
@@ -1,75 +0,0 @@
|
|
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
|
-
# should not have any running calculators yet...
|
8
|
-
proc {Win32::Screenshot::Util.window_hwnd("Calculator") }.should raise_exception("window with title 'Calculator' was not found!")
|
9
|
-
@calc = IO.popen("calc").pid
|
10
|
-
wait_for_calculator_to_open
|
11
|
-
@calc_hwnd = Win32::Screenshot::Util.window_hwnd("Calculator")
|
12
|
-
end
|
13
|
-
|
14
|
-
it ".all_desktop_windows enumerates all available windows" do
|
15
|
-
all_windows = Win32::Screenshot::Util.all_desktop_windows
|
16
|
-
all_windows.should_not be_empty
|
17
|
-
all_windows[0].should be_an(Array)
|
18
|
-
all_windows[0][0].should be_a(String)
|
19
|
-
all_windows[0][1].should be_a(Fixnum)
|
20
|
-
|
21
|
-
calculator = all_windows.find {|title, hwnd| title =~ /Calculator/}
|
22
|
-
calculator.should_not be_nil
|
23
|
-
calculator[0].should == "Calculator"
|
24
|
-
calculator[1].should == @calc_hwnd
|
25
|
-
end
|
26
|
-
|
27
|
-
it ".window_title returns title of a specified window's handle" do
|
28
|
-
Win32::Screenshot::Util.window_title(@calc_hwnd).should == "Calculator"
|
29
|
-
end
|
30
|
-
|
31
|
-
it ".dimensions_for window handle returns dimensions of the window in pixels" do
|
32
|
-
width, height = Win32::Screenshot::Util.dimensions_for(@calc_hwnd)
|
33
|
-
width.should be > 100
|
34
|
-
height.should be > 100
|
35
|
-
end
|
36
|
-
|
37
|
-
it ".window_class returns classname of a specified window's handle" do
|
38
|
-
Win32::Screenshot::Util.window_class(@calc_hwnd).should == "CalcFrame"
|
39
|
-
end
|
40
|
-
|
41
|
-
it ".get_info returns lots of info about an hwnd" do
|
42
|
-
desktop_hwnd = Win32::Screenshot::BitmapMaker.desktop_window
|
43
|
-
info = Win32::Screenshot::Util.get_info desktop_hwnd
|
44
|
-
info.should be_a(Hash)
|
45
|
-
info.keys.map {|k| k.to_s}.sort.should == ["class", "dimensions", "starting_coordinates", "title"]
|
46
|
-
end
|
47
|
-
|
48
|
-
it ".windows_hierarchy returns hwnds" do
|
49
|
-
a = Win32::Screenshot::Util.windows_hierarchy
|
50
|
-
# should have root as "desktop"
|
51
|
-
# though in reality some windows might not be descendants of the desktop
|
52
|
-
# (see the WinCheat source which discusses this further)
|
53
|
-
# but we don't worry about that edge case yet
|
54
|
-
a.should be_a(Hash)
|
55
|
-
a[:children].should be_an(Array)
|
56
|
-
a[:children].length.should be > 0
|
57
|
-
a[:children][0].should be_a(Hash)
|
58
|
-
a[:hwnd].should == Win32::Screenshot::BitmapMaker.desktop_window
|
59
|
-
end
|
60
|
-
|
61
|
-
it ".windows_hierarchy can return info" do
|
62
|
-
a = Win32::Screenshot::Util.windows_hierarchy true
|
63
|
-
# check for right structure
|
64
|
-
for hash_example in [a, a[:children][0]] do
|
65
|
-
hash_example.keys.map {|k| k.to_s}.sort.should == ["children", "class", "dimensions", "hwnd", "starting_coordinates", "title"]
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
after :all do
|
70
|
-
# tests our hwnd -> pid method, and conveniently, shuts down the calculator process
|
71
|
-
calc_pid = Win32::Screenshot::Util.window_process_id(@calc_hwnd)
|
72
|
-
system("taskkill /PID #{calc_pid}")
|
73
|
-
proc {Win32::Screenshot::Util.window_hwnd("Calculator") }.should raise_exception("window with title 'Calculator' was not found!")
|
74
|
-
end
|
75
|
-
end
|