win32screenshot 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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.5
1
+ 0.0.6
@@ -1,4 +1,5 @@
1
- require 'win32/screenshot/bitmap_maker'
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
- invalid = coords.any? {|c| c < 0}
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
- invalid ||= x1 >= x2 || y1 >= y2
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
- max_x1, max_y1, max_x2, max_y2 = BitmapMaker.dimensions_for(hwnd)
90
- invalid ||= x2 > max_x2 || y2 > max_y2
91
- raise "specified coordinates (#{specified_coordinates}) are invalid!" if invalid
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
- module BitmapMaker #:nodoc:all
7
- extend FFI::Library
8
-
9
- ffi_lib 'user32', 'kernel32', 'gdi32'
10
- ffi_convention :stdcall
11
-
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 :set_focus, :SetFocus,
42
- [:long], :bool
43
-
44
- # kernel32.dll
45
- attach_function :current_thread_id, :GetCurrentThreadId,
46
- [], :long
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_length = window_text_length(hwnd) + 1
70
- title = FFI::MemoryPointer.new :char, title_length
71
- window_text(hwnd, title, title_length)
72
- title = title.read_string
73
- if title =~ Regexp.new(searched_window[:title].read_string) && window_visible(hwnd)
74
- searched_window[:hwnd] = hwnd
75
- false
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
- def hwnd(window_title)
89
- window = WindowStruct.new
90
- window_title = FFI::MemoryPointer.from_string(window_title.to_s)
91
- window[:title] = window_title
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
- def prepare_window(hwnd, pause)
97
- restore(hwnd) if minimized(hwnd)
98
- set_foreground(hwnd)
99
- sleep pause
100
- end
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
- SW_RESTORE = 9
96
+ def prepare_window(hwnd, pause)
97
+ restore(hwnd) if minimized(hwnd)
98
+ set_foreground(hwnd)
99
+ sleep pause
100
+ end
103
101
 
104
- def restore(hwnd)
105
- show_window(hwnd, SW_RESTORE)
106
- end
102
+ SW_RESTORE = 9
107
103
 
108
- def set_foreground(hwnd)
109
- if foreground_window != hwnd
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
- def dimensions_for(hwnd)
120
- rect = [0, 0, 0, 0].pack('L4')
121
- client_rect(hwnd, rect)
122
- x1, y1, x2, y2 = rect.unpack('L4')
123
- end
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
- def capture_all(hwnd, &proc)
126
- x1, y1, x2, y2 = dimensions_for(hwnd)
127
- capture_area(hwnd, x1, y1, x2, y2, &proc)
128
- end
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
- SRCCOPY = 0x00CC0020
131
- DIB_RGB_COLORS = 0
132
-
133
- def capture_area(hwnd, x1, y1, x2, y2, &proc)
134
- hScreenDC = dc(hwnd)
135
- w = x2-x1
136
- h = y2-y1
137
-
138
- hmemDC = create_compatible_dc(hScreenDC)
139
- hmemBM = create_compatible_bitmap(hScreenDC, w, h)
140
- select_object(hmemDC, hmemBM)
141
- bit_blt(hmemDC, 0, 0, w, h, hScreenDC, 0, 0, SRCCOPY)
142
- bitmap_size = w * h * 3 + w % 4 * h
143
- lpvpxldata = FFI::MemoryPointer.new(bitmap_size)
144
-
145
- # Bitmap header
146
- # http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
147
- bmInfo = [40, w, h, 1, 24, 0, 0, 0, 0, 0, 0, 0].pack('L3S2L6')
148
- di_bits(hmemDC, hmemBM, 0, h, lpvpxldata, bmInfo, DIB_RGB_COLORS)
149
-
150
- bmFileHeader = [
151
- 19778,
152
- bitmap_size + 40 + 14,
153
- 0,
154
- 0,
155
- 54
156
- ].pack('SLSSL')
157
-
158
- bmp_data = bmFileHeader + bmInfo + lpvpxldata.read_string(bitmap_size)
159
- proc.call(w, h, bmp_data)
160
- ensure
161
- lpvpxldata.free
162
- delete_object(hmemBM)
163
- delete_dc(hmemDC)
164
- release_dc(0, hScreenDC)
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
- Win32::Screenshot::BitmapMaker.hwnd(/Calculator/)
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 10
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 "win32-screenshot" do
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(File.join(PROGRAM_FILES, "Internet Explorer", "iexplore about:blank")).pid
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
- dimensions = Win32::Screenshot::BitmapMaker.dimensions_for(hwnd)
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
- dimensions = Win32::Screenshot::BitmapMaker.dimensions_for(hwnd)
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
- dimensions = Win32::Screenshot::BitmapMaker.dimensions_for(hwnd)
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
- dimensions = Win32::Screenshot::BitmapMaker.dimensions_for(hwnd)
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
- dimensions = Win32::Screenshot::BitmapMaker.dimensions_for(hwnd)
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
- dimensions = Win32::Screenshot::BitmapMaker.dimensions_for(hwnd)
114
- Win32::Screenshot.window_area(title, 0, 0, dimensions[2], dimensions[3]) do |width, height, bmp|
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 == dimensions[2]
117
- height.should == dimensions[3]
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
- lambda {Win32::Screenshot.window_area(title, 0, 0, 10, 10000) {|width, height, bmp| check_image('calc3')}}.
142
- should raise_exception("specified coordinates (0, 0, 10, 10000) are invalid!")
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
- dimensions = Win32::Screenshot::BitmapMaker.dimensions_for(hwnd)
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
- - 5
9
- version: 0.0.5
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-07-07 00:00:00 +03:00
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/win32screenshot.rb
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
@@ -1,3 +0,0 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
- Kernel.warn %q(DEPRECATION: use "require 'win32/screenshot'" instead of "require 'win32screenshot'")
3
- require "win32/screenshot"