win32screenshot 0.0.4 → 0.0.5

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