win32screenshot 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,5 +2,4 @@ coverage
2
2
  rdoc
3
3
  pkg
4
4
  .idea
5
- *.bmp
6
- *.png
5
+ spec/tmp
data/History.rdoc CHANGED
@@ -1,3 +1,17 @@
1
+ = 0.0.5 2010-07-07
2
+ * Added method window_area for capturing specified area of the window instead of full window (Jarmo Pertman)
3
+ Usage: Win32::Screenshot.window_area(title, x1, y1, x2, y2) {|width, height, bmp|}
4
+ * Added method foreground_area for capturing area of the foreground (Jarmo Pertman)
5
+ Usage: Win32::Screenshot.foreground_area(x1, y1, x2, y2) {|width, height, bmp|}
6
+ * Added method desktop_area for capturing area of the visible view (Jarmo Pertman)
7
+ Usage: Win32::Screenshot.desktop_area(x1, y1, x2, y2) {|width, height, bmp|}
8
+ * Added method hwnd_area for capturing area of the window with specified handle (Jarmo Pertman)
9
+ Usage: Win32::Screenshot.hwnd_area(hwnd, x1, y1, x2, y2) {|width, height, bmp|}
10
+
11
+ == Internal changes
12
+ * Removed usage of ShowWindow with parameter SW_SHOW when trying to bring window to front due it's behaviour of resizing window if it was maximized (Jarmo Pertman)
13
+ * Using FFI::Struct when searching window handle (Roger Pack)
14
+
1
15
  = 0.0.4 2010-05-27 - A Complete Overhaul
2
16
  * Fixed a bug where taking of screenshots failed on some sizes of windows (thanks for the tip from Tony Popiel)
3
17
  * Blocks should be used when taking screenshots for cleaning up resources after usage (Aslak Hellesøy)
data/README.rdoc CHANGED
@@ -16,25 +16,50 @@ other formats like png.
16
16
  Win32::Screenshot.foreground do |width, height, bmp|
17
17
  File.open("picture1.bmp", "wb") {|file| file.puts bmp}
18
18
  end
19
-
19
+
20
+ # take a screenshot of the area of the foreground where upper left x and y
21
+ # coordinates are 0 and 10, width is 100 and height is 200
22
+ Win32::Screenshot.foreground_area(0, 10, 100, 200) do |width, height, bmp|
23
+ File.open("picture2.bmp", "wb") {|file| file.puts bmp}
24
+ end
25
+
20
26
  # take a screenshot of the screen
21
27
  Win32::Screenshot.desktop do |width, height, bmp|
22
- File.open("picture2.bmp", "wb") {|file| file.puts bmp}
28
+ File.open("picture3.bmp", "wb") {|file| file.puts bmp}
29
+ end
30
+
31
+ # take a screenshot of the area of the desktop where upper left x and y
32
+ # coordinates are 0 and 10, width is 100 and height is 200
33
+ Win32::Screenshot.desktop_area(0, 10, 100, 200) do |width, height, bmp|
34
+ File.open("picture4.bmp", "wb") {|file| file.puts bmp}
23
35
  end
24
36
 
25
37
  # take a screenshot of the window, which has a text part of it's title
26
38
  Win32::Screenshot.window("Internet Explorer") do |width, height, bmp|
27
- File.open("picture3.bmp", "wb") {|file| file.puts bmp}
39
+ File.open("picture5.bmp", "wb") {|file| file.puts bmp}
28
40
  end
29
41
 
30
42
  # take a screenshot of the window, which matches regexp against it's title
31
43
  Win32::Screenshot.window(/Internet Explorer/) do |width, height, bmp|
32
- File.open("picture4.bmp", "wb") {|file| file.puts bmp}
44
+ File.open("picture6.bmp", "wb") {|file| file.puts bmp}
45
+ end
46
+
47
+ # take a screenshot of the area of the window where upper left x and y
48
+ # coordinates are 0 and 10, width is 100 and height is 200
49
+ Win32::Screenshot.window_area("Internet Explorer", 0, 10, 100, 200) do |width, height, bmp|
50
+ File.open("picture7.bmp", "wb") {|file| file.puts bmp}
33
51
  end
34
52
 
35
53
  # take a screenshot of the window with specified window handle
36
54
  Win32::Screenshot.hwnd(window_handle) do |width, height, bmp|
37
- File.open("picture5.bmp", "wb") {|file| file.puts bmp}
55
+ File.open("picture8.bmp", "wb") {|file| file.puts bmp}
56
+ end
57
+
58
+ # take a screenshot of the area of the window with a window handle
59
+ # where upper left x and y
60
+ # coordinates are 0 and 10, width is 100 and height is 200
61
+ Win32::Screenshot.hwnd_area(window_handle, 0, 10, 100, 200) do |width, height, bmp|
62
+ File.open("picture9.bmp", "wb") {|file| file.puts bmp}
38
63
  end
39
64
 
40
65
  # convert a screenshot to the png format with RMagick
@@ -43,7 +68,7 @@ other formats like png.
43
68
  Win32::Screenshot.hwnd(window_handle) do |width, height, bmp|
44
69
  img = Magick::Image.from_blob(bmp)
45
70
  png = img[0].to_blob {self.format = 'PNG'}
46
- File.open("picture6.png", "wb") {|file| file.puts png}
71
+ File.open("picture10.png", "wb") {|file| file.puts png}
47
72
  end
48
73
 
49
74
  == Copyright
data/Rakefile CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'rake'
5
+ require 'os'
5
6
 
6
7
  begin
7
8
  require 'jeweler'
@@ -18,7 +19,12 @@ begin
18
19
  gem.add_dependency "ffi"
19
20
 
20
21
  gem.add_development_dependency "rspec", ">= 1.2.9"
21
- gem.add_development_dependency "rmagick"
22
+ gem.add_development_dependency 'os'
23
+ if OS.java?
24
+ gem.add_development_dependency "rmagick4j"
25
+ else
26
+ gem.add_development_dependency "rmagick"
27
+ end
22
28
  end
23
29
  Jeweler::GemcutterTasks.new
24
30
  rescue LoadError
@@ -50,3 +56,8 @@ Rake::RDocTask.new do |rdoc|
50
56
  rdoc.rdoc_files.include('README*')
51
57
  rdoc.rdoc_files.include('lib/**/*.rb')
52
58
  end
59
+
60
+ desc "Remove all temporary files"
61
+ task :clobber => [:clobber_rdoc, :clobber_rcov] do
62
+ rm_r "spec/tmp"
63
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.5
@@ -8,27 +8,87 @@ module Win32
8
8
  # captures foreground
9
9
  def foreground(&proc)
10
10
  hwnd = BitmapMaker.foreground_window
11
- BitmapMaker.capture(hwnd, &proc)
11
+ BitmapMaker.capture_all(hwnd, &proc)
12
12
  end
13
13
 
14
- # captures desktop
14
+ # captures area of the foreground
15
+ # where *x1* and *y1* are 0 in the upper left corner and
16
+ # *x2* specifies the width and *y2* the height of the area to be captured
17
+ def foreground_area(x1, y1, x2, y2, &proc)
18
+ hwnd = BitmapMaker.foreground_window
19
+ validate_coordinates(hwnd, x1, y1, x2, y2)
20
+ BitmapMaker.capture_area(hwnd, x1, y1, x2, y2, &proc)
21
+ end
22
+
23
+ # captures visible view of the screen
24
+ #
25
+ # to make screenshot of the real desktop, all
26
+ # windows must be minimized before
15
27
  def desktop(&proc)
16
28
  hwnd = BitmapMaker.desktop_window
17
- BitmapMaker.capture(hwnd, &proc)
29
+ BitmapMaker.capture_all(hwnd, &proc)
30
+ end
31
+
32
+ # captures area of the visible view of the screen
33
+ # where *x1* and *y1* are 0 in the upper left corner and
34
+ # *x2* specifies the width and *y2* the height of the area to be captured
35
+ #
36
+ # to make screenshot of the real desktop, all
37
+ # windows must be minimized before
38
+ def desktop_area(x1, y1, x2, y2, &proc)
39
+ hwnd = BitmapMaker.desktop_window
40
+ validate_coordinates(hwnd, x1, y1, x2, y2)
41
+ BitmapMaker.capture_area(hwnd, x1, y1, x2, y2, &proc)
18
42
  end
19
43
 
20
44
  # captures window with a *title_query* and waits *pause* (by default is 0.5)
21
45
  # seconds after trying to set window to the foreground
22
46
  def window(title_query, pause=0.5, &proc)
23
- hwnd = BitmapMaker.hwnd(title_query)
24
- raise "window with title '#{title_query}' was not found!" unless hwnd
47
+ hwnd = window_hwnd(title_query)
25
48
  hwnd(hwnd, pause, &proc)
26
49
  end
27
50
 
51
+ # captures area of the window with a *title_query*
52
+ # where *x1* and *y1* are 0 in the upper left corner and
53
+ # *x2* specifies the width and *y2* the height of the area to be captured
54
+ def window_area(title_query, x1, y1, x2, y2, pause=0.5, &proc)
55
+ hwnd = window_hwnd(title_query)
56
+ hwnd_area(hwnd, x1, y1, x2, y2, pause, &proc)
57
+ end
58
+
28
59
  # captures by window handle
29
60
  def hwnd(hwnd, pause=0.5, &proc)
30
61
  BitmapMaker.prepare_window(hwnd, pause)
31
- BitmapMaker.capture(hwnd, &proc)
62
+ BitmapMaker.capture_all(hwnd, &proc)
63
+ end
64
+
65
+ # captures area of the window with a handle of *hwnd*
66
+ # where *x1* and *y1* are 0 in the upper left corner and
67
+ # *x2* specifies the width and *y2* the height of the area to be captured
68
+ def hwnd_area(hwnd, x1, y1, x2, y2, pause=0.5, &proc)
69
+ validate_coordinates(hwnd, x1, y1, x2, y2)
70
+ BitmapMaker.prepare_window(hwnd, pause)
71
+ BitmapMaker.capture_area(hwnd, x1, y1, x2, y2, &proc)
72
+ end
73
+
74
+ private
75
+
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
+ def validate_coordinates(hwnd, *coords)
83
+ specified_coordinates = coords.join(', ')
84
+ invalid = coords.any? {|c| c < 0}
85
+
86
+ x1, y1, x2, y2 = *coords
87
+ invalid ||= x1 >= x2 || y1 >= y2
88
+
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
32
92
  end
33
93
  end
34
94
 
@@ -63,13 +63,15 @@ module Win32
63
63
  attach_function :release_dc, :ReleaseDC,
64
64
  [:long, :long], :int
65
65
 
66
+
66
67
  EnumWindowCallback = Proc.new do |hwnd, param|
68
+ searched_window = WindowStruct.new param
67
69
  title_length = window_text_length(hwnd) + 1
68
70
  title = FFI::MemoryPointer.new :char, title_length
69
71
  window_text(hwnd, title, title_length)
70
72
  title = title.read_string
71
- if title =~ Regexp.new(param.read_string) && window_visible(hwnd)
72
- param.write_long hwnd
73
+ if title =~ Regexp.new(searched_window[:title].read_string) && window_visible(hwnd)
74
+ searched_window[:hwnd] = hwnd
73
75
  false
74
76
  else
75
77
  true
@@ -78,24 +80,22 @@ module Win32
78
80
 
79
81
  module_function
80
82
 
81
- def hwnd(window_title)
82
- window_title = window_title.to_s
83
- window_params = FFI::MemoryPointer.from_string(window_title)
84
- enum_windows(EnumWindowCallback, window_params)
85
- if window_title != window_params.read_string
86
- # hwnd found
87
- window_params.read_long
88
- else
89
- nil
90
- end
83
+ class WindowStruct < FFI::Struct
84
+ layout :title, :pointer,
85
+ :hwnd, :long
91
86
  end
92
87
 
93
- SW_SHOW = 5
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
94
95
 
95
96
  def prepare_window(hwnd, pause)
96
97
  restore(hwnd) if minimized(hwnd)
97
98
  set_foreground(hwnd)
98
- show_window(hwnd, SW_SHOW)
99
99
  sleep pause
100
100
  end
101
101
 
@@ -122,16 +122,16 @@ module Win32
122
122
  x1, y1, x2, y2 = rect.unpack('L4')
123
123
  end
124
124
 
125
- def capture(hwnd, &proc)
126
- hScreenDC = dc(hwnd)
125
+ def capture_all(hwnd, &proc)
127
126
  x1, y1, x2, y2 = dimensions_for(hwnd)
128
- __capture(hScreenDC, x1, y1, x2, y2, &proc)
127
+ capture_area(hwnd, x1, y1, x2, y2, &proc)
129
128
  end
130
129
 
131
130
  SRCCOPY = 0x00CC0020
132
131
  DIB_RGB_COLORS = 0
133
132
 
134
- def __capture(hScreenDC, x1, y1, x2, y2, &proc)
133
+ def capture_area(hwnd, x1, y1, x2, y2, &proc)
134
+ hScreenDC = dc(hwnd)
135
135
  w = x2-x1
136
136
  h = y2-y1
137
137
 
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,11 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'win32/screenshot'
4
+ require 'rubygems'
4
5
  require 'spec'
5
6
  require 'spec/autorun'
6
- require 'rmagick'
7
+ require 'RMagick'
8
+ require 'fileutils'
7
9
 
8
10
  module SpecHelper
9
11
  SW_MAXIMIZE = 3
@@ -23,12 +25,14 @@ module SpecHelper
23
25
  [:long, :long, :int, :int, :int, :int, :int], :bool
24
26
 
25
27
  def check_image(bmp, file=nil)
26
- File.open("#{file}.bmp", "wb") {|io| io.write(bmp)} unless file.nil?
28
+ temp_dir = File.join(File.dirname(__FILE__), 'tmp')
29
+ FileUtils.mkdir temp_dir unless File.exists?(temp_dir)
30
+ File.open(File.join(temp_dir, "#{file}.bmp"), "wb") {|io| io.write(bmp)} unless file.nil?
27
31
  bmp[0..1].should == 'BM'
28
32
  img = Magick::Image.from_blob(bmp)
29
33
  png = img[0].to_blob {self.format = 'PNG'}
30
34
  png[0..3].should == "\211PNG"
31
- File.open("#{file}.png", "wb") {|io| io.puts(png)} unless file.nil?
35
+ File.open(File.join(temp_dir, "#{file}.png"), "wb") {|io| io.puts(png)} unless file.nil?
32
36
  end
33
37
 
34
38
  def wait_for_programs_to_open
@@ -23,6 +23,19 @@ describe "win32-screenshot" do
23
23
  end
24
24
  end
25
25
 
26
+ it "captures area of the foreground" do
27
+ Win32::Screenshot.foreground_area(30, 30, 100, 150) do |width, height, bmp|
28
+ check_image(bmp, 'foreground_area')
29
+ width.should == 70
30
+ height.should == 120
31
+ end
32
+ end
33
+
34
+ it "doesn't allow to capture area of the foreground with invalid coordinates" do
35
+ 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!")
37
+ end
38
+
26
39
  it "captures desktop" do
27
40
  Win32::Screenshot.desktop do |width, height, bmp|
28
41
  check_image(bmp, 'desktop')
@@ -33,6 +46,19 @@ describe "win32-screenshot" do
33
46
  end
34
47
  end
35
48
 
49
+ it "captures area of the desktop" do
50
+ Win32::Screenshot.desktop_area(30, 30, 100, 150) do |width, height, bmp|
51
+ check_image(bmp, 'desktop_area')
52
+ width.should == 70
53
+ height.should == 120
54
+ end
55
+ end
56
+
57
+ it "doesn't allow to capture area of the desktop with invalid coordinates" do
58
+ 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!")
60
+ end
61
+
36
62
  it "captures maximized window by window title" do
37
63
  title = "Internet Explorer"
38
64
  maximize(title)
@@ -72,7 +98,51 @@ describe "win32-screenshot" do
72
98
  end
73
99
  end
74
100
 
75
- it "captures by hwnd" do
101
+ it "captures area of the window" do
102
+ title = /calculator/i
103
+ Win32::Screenshot.window_area(title, 30, 30, 100, 150) do |width, height, bmp|
104
+ check_image(bmp, 'calc_area')
105
+ width.should == 70
106
+ height.should == 120
107
+ end
108
+ end
109
+
110
+ it "captures whole window if window size is specified as coordinates" do
111
+ title = /calculator/i
112
+ 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|
115
+ check_image(bmp, 'calc_area_full_window')
116
+ width.should == dimensions[2]
117
+ height.should == dimensions[3]
118
+ end
119
+ end
120
+
121
+ it "doesn't allow to capture area of the window with negative coordinates" do
122
+ title = /calculator/i
123
+ 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!")
125
+ end
126
+
127
+ it "doesn't allow to capture area of the window if coordinates are the same" do
128
+ title = /calculator/i
129
+ 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!")
131
+ end
132
+
133
+ it "doesn't allow to capture area of the window if second coordinate is smaller than first one" do
134
+ title = /calculator/i
135
+ 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!")
137
+ end
138
+
139
+ it "doesn't allow to capture area of the window with too big coordinates" do
140
+ 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!")
143
+ end
144
+
145
+ it "captures by window with handle" do
76
146
  title = /calculator/i
77
147
  hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
78
148
  Win32::Screenshot.hwnd(hwnd) do |width, height, bmp|
@@ -83,6 +153,21 @@ describe "win32-screenshot" do
83
153
  end
84
154
  end
85
155
 
156
+ it "captures area of the window with handle" do
157
+ hwnd = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
158
+ Win32::Screenshot.hwnd_area(hwnd, 30, 30, 100, 150) do |width, height, bmp|
159
+ check_image(bmp, 'calc_hwnd_area')
160
+ width.should == 70
161
+ height.should == 120
162
+ end
163
+ end
164
+
165
+ it "doesn't allow to capture area of the window with handle with invalid coordinates" do
166
+ hwnd = Win32::Screenshot::BitmapMaker.hwnd(/calculator/i)
167
+ 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!")
169
+ end
170
+
86
171
  after :all do
87
172
  Process.kill 9, @notepad
88
173
  Process.kill 9, @iexplore
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 4
9
- version: 0.0.4
8
+ - 5
9
+ version: 0.0.5
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-05-27 00:00:00 +03:00
18
+ date: 2010-07-07 00:00:00 +03:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -45,7 +45,7 @@ dependencies:
45
45
  type: :development
46
46
  version_requirements: *id002
47
47
  - !ruby/object:Gem::Dependency
48
- name: rmagick
48
+ name: os
49
49
  prerelease: false
50
50
  requirement: &id003 !ruby/object:Gem::Requirement
51
51
  requirements:
@@ -56,6 +56,18 @@ dependencies:
56
56
  version: "0"
57
57
  type: :development
58
58
  version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
60
+ name: rmagick
61
+ prerelease: false
62
+ requirement: &id004 !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ type: :development
70
+ version_requirements: *id004
59
71
  description: Capture Screenshots on Windows with Ruby
60
72
  email:
61
73
  - jarmo.p@gmail.com