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 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"