win32-captureie 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +26 -0
- data/Manifest.txt +8 -1
- data/README.txt +28 -1
- data/TODO.txt +7 -4
- data/bin/prtie +3 -0
- data/config/hoe.rb +7 -6
- data/examples/capture-ruby-lang.rb +23 -0
- data/examples/each_ie.rb +28 -0
- data/examples/hilight-id.rb +47 -0
- data/lib/win32/capture_ie.rb +78 -9
- data/lib/win32/capture_ie/area.rb +56 -0
- data/lib/win32/capture_ie/bitmap.rb +66 -4
- data/lib/win32/capture_ie/browser.rb +194 -9
- data/lib/win32/capture_ie/cli/prt_ie.rb +6 -0
- data/lib/win32/capture_ie/commands/prt_ie.rb +3 -7
- data/lib/win32/capture_ie/feature.rb +63 -0
- data/lib/win32/capture_ie/screen_captor.rb +58 -45
- data/lib/win32/capture_ie/util.rb +45 -0
- data/lib/win32/capture_ie/version.rb +1 -1
- data/spec/dsl/behaviour_eval.rb +5 -0
- data/spec/spec.opts +0 -1
- data/spec/spec_helper.rb +8 -7
- data/spec/win32/capture_ie/area_spec.rb +19 -0
- data/spec/win32/capture_ie_spec.rb +0 -11
- data/tasks/deployment.rake +1 -1
- data/tasks/deployment2.rake +2 -1
- metadata +10 -3
- data/tasks/website.rake +0 -17
data/History.txt
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
== 0.2.0 / 2007-12-09
|
2
|
+
|
3
|
+
* Win32::CaptureIE.each
|
4
|
+
* Enumerate existing IE window.
|
5
|
+
|
6
|
+
* Capture web page as BLOB.
|
7
|
+
* Win32::CaptureIE::Browser#capture_browser_image
|
8
|
+
* Win32::CaptureIE::Browser#capture_page_image
|
9
|
+
* Win32::CaptureIE::Browser#capture_elements_image
|
10
|
+
|
11
|
+
* Support capture DOM elements.
|
12
|
+
* Win32::CaptureIE::Browser#capture_elements:
|
13
|
+
* CaptureIE specified DOM elements.
|
14
|
+
|
15
|
+
* Support RMagick.
|
16
|
+
* Win32::CaptureIE::Browser#capture_page:
|
17
|
+
* Converts the bitmap image to the format specified by the filename if RMagick available.
|
18
|
+
* If filename has ".bmp" extension, RMagick are optional.
|
19
|
+
* Win32::CaptureIE::Browser#capture_browser:
|
20
|
+
* ditto.
|
21
|
+
* Win32::CaptureIE.rmagick_available?
|
22
|
+
* Win32::CaptureIE.rmagick_enable?
|
23
|
+
* Win32::CaptureIE.enable_rmagick
|
24
|
+
* Win32::CaptureIE.disable_rmagick
|
25
|
+
|
26
|
+
|
1
27
|
== 0.1.0 / 2007-11-23
|
2
28
|
|
3
29
|
* Initial release
|
data/Manifest.txt
CHANGED
@@ -7,7 +7,11 @@ TODO.txt
|
|
7
7
|
bin/prtie
|
8
8
|
config/hoe.rb
|
9
9
|
config/requirements.rb
|
10
|
+
examples/capture-ruby-lang.rb
|
11
|
+
examples/each_ie.rb
|
12
|
+
examples/hilight-id.rb
|
10
13
|
lib/win32/capture_ie.rb
|
14
|
+
lib/win32/capture_ie/area.rb
|
11
15
|
lib/win32/capture_ie/base.rb
|
12
16
|
lib/win32/capture_ie/bitmap.rb
|
13
17
|
lib/win32/capture_ie/browser.rb
|
@@ -15,12 +19,14 @@ lib/win32/capture_ie/cli/base.rb
|
|
15
19
|
lib/win32/capture_ie/cli/prt_ie.rb
|
16
20
|
lib/win32/capture_ie/commands/base.rb
|
17
21
|
lib/win32/capture_ie/commands/prt_ie.rb
|
22
|
+
lib/win32/capture_ie/feature.rb
|
18
23
|
lib/win32/capture_ie/ffi.rb
|
19
24
|
lib/win32/capture_ie/ffi/base.rb
|
20
25
|
lib/win32/capture_ie/ffi/gdi32.rb
|
21
26
|
lib/win32/capture_ie/ffi/struct.rb
|
22
27
|
lib/win32/capture_ie/ffi/user32.rb
|
23
28
|
lib/win32/capture_ie/screen_captor.rb
|
29
|
+
lib/win32/capture_ie/util.rb
|
24
30
|
lib/win32/capture_ie/version.rb
|
25
31
|
lib/win32/capture_ie/window.rb
|
26
32
|
script/destroy
|
@@ -31,8 +37,10 @@ script/rdoc_filter.rb
|
|
31
37
|
script/txt2html
|
32
38
|
script/txt2html.cmd
|
33
39
|
setup.rb
|
40
|
+
spec/dsl/behaviour_eval.rb
|
34
41
|
spec/spec.opts
|
35
42
|
spec/spec_helper.rb
|
43
|
+
spec/win32/capture_ie/area_spec.rb
|
36
44
|
spec/win32/capture_ie_spec.rb
|
37
45
|
tasks/deployment.rake
|
38
46
|
tasks/deployment2.rake
|
@@ -42,4 +50,3 @@ tasks/helper/rake.rb
|
|
42
50
|
tasks/helper/rake_sh_filter.rb
|
43
51
|
tasks/helper/util.rb
|
44
52
|
tasks/rspec.rake
|
45
|
-
tasks/website.rake
|
data/README.txt
CHANGED
@@ -6,9 +6,29 @@
|
|
6
6
|
require "win32/capture_ie"
|
7
7
|
|
8
8
|
Win32::CaptureIE.start("http://www.ruby-lang.org/") do |ie|
|
9
|
-
ie.capture_page("ruby-lang-whole-page.bmp")
|
10
9
|
ie.capture_browser("ruby-lang-browser.bmp")
|
11
10
|
ie.capture_browser("ruby-lang-onepage.bmp", :only_drawing_area => true)
|
11
|
+
open("ruby-lang-wholepage.bmp", "wb") do |w|
|
12
|
+
ie.capture_page(w)
|
13
|
+
end
|
14
|
+
|
15
|
+
# require RMagick
|
16
|
+
ie.capture_page($stdout, :format => "jpg")
|
17
|
+
ie.capture_browser("ruby-lang-browser.png")
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
require "cgi"
|
22
|
+
Win32::CaptureIE.each do |ie|
|
23
|
+
url = ie.document.location.href
|
24
|
+
ie.capture_page("#{CGI.escape(url)}.png") do |image|
|
25
|
+
gc = Magick::Draw.new
|
26
|
+
gc.stroke = "white"
|
27
|
+
gc.text_undercolor("blue")
|
28
|
+
gc.text(5, ie.body_area.height - 5, url)
|
29
|
+
gc.draw(image)
|
30
|
+
image
|
31
|
+
end
|
12
32
|
end
|
13
33
|
|
14
34
|
|
@@ -24,6 +44,13 @@ For more details, please see {prtie}[link:files/bin/prtie.html] document.
|
|
24
44
|
gem install win32-captureie
|
25
45
|
|
26
46
|
|
47
|
+
=== REQUIREMENTS
|
48
|
+
|
49
|
+
* Internet Explorer
|
50
|
+
* win32ole (standard library)
|
51
|
+
* RMagick[http://rubyforge.org/projects/rmagick] (optional)
|
52
|
+
|
53
|
+
|
27
54
|
=== ACKNOWLEDGMENTS
|
28
55
|
|
29
56
|
Thanks to P.Smejkal author for his Perl's <tt>Win32-CaptureIE</tt>,
|
data/TODO.txt
CHANGED
@@ -2,11 +2,15 @@
|
|
2
2
|
|
3
3
|
=== lib
|
4
4
|
|
5
|
-
* RMagick
|
6
|
-
* png, jpg, ...
|
7
|
-
* capture_element
|
8
5
|
* capture_page(1)
|
6
|
+
* rcairo
|
7
|
+
* frame
|
9
8
|
* filter, effect
|
9
|
+
* xxx_image block
|
10
|
+
* animation gif
|
11
|
+
* offline mode
|
12
|
+
* font size / page encoding
|
13
|
+
|
10
14
|
|
11
15
|
=== bin/capture-ie
|
12
16
|
|
@@ -15,7 +19,6 @@
|
|
15
19
|
|
16
20
|
Usage: capture-ie [options ...] URL [ [options ...] URL ]...
|
17
21
|
|
18
|
-
-T, --type
|
19
22
|
-o, --output
|
20
23
|
--stdout
|
21
24
|
-N --worker=1
|
data/bin/prtie
CHANGED
@@ -24,6 +24,9 @@
|
|
24
24
|
# -w, --wait=SECONDS wait SECONDS between retrievals
|
25
25
|
# -d, --output-directory=DIRECTORY save capture to DIRECTORY/...
|
26
26
|
# -o, --output=FILE save capture to FILE
|
27
|
+
# -T, --output-type=TYPE save capture as image TYPE
|
28
|
+
# Default: PNG (RMagick available)
|
29
|
+
# or BMP (not available)
|
27
30
|
# -D, --output-digest=ALGORITHM use output filename as hex-encoded version
|
28
31
|
# of a given URL
|
29
32
|
# ALGORITHM: MD5, SHA1, SHA512 ...
|
data/config/hoe.rb
CHANGED
@@ -48,7 +48,7 @@ end
|
|
48
48
|
|
49
49
|
# Generate all the Rake tasks
|
50
50
|
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
51
|
-
|
51
|
+
HOE = Hoe.new(GEM_NAME, VERS) do |p|
|
52
52
|
p.author = AUTHOR
|
53
53
|
p.description = DESCRIPTION
|
54
54
|
p.email = EMAIL
|
@@ -61,12 +61,13 @@ hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
|
61
61
|
# == Optional
|
62
62
|
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
63
63
|
#p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
64
|
-
|
65
64
|
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
66
|
-
|
65
|
+
|
66
|
+
p.need_zip = true
|
67
|
+
p.need_tar = false
|
67
68
|
end
|
68
69
|
|
69
|
-
CHANGES =
|
70
|
+
CHANGES = HOE.paragraphs_of('History.txt', 0..1).join("\n\n")
|
70
71
|
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
71
|
-
|
72
|
-
|
72
|
+
HOE.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
73
|
+
HOE.rsync_args = '-av --delete --ignore-errors'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../lib")
|
5
|
+
require "win32/capture_ie"
|
6
|
+
|
7
|
+
|
8
|
+
outdir = Pathname.new(__FILE__).basename(".*")
|
9
|
+
FileUtils.mkdir_p(outdir)
|
10
|
+
|
11
|
+
Win32::CaptureIE.start("http://www.ruby-lang.org/") do |ie|
|
12
|
+
ie.capture_browser(outdir + "ruby-lang-browser.bmp")
|
13
|
+
ie.capture_browser(outdir + "ruby-lang-onepage.bmp", :only_drawing_area => true)
|
14
|
+
open(outdir + "ruby-lang-wholepage.bmp", "wb") do |w|
|
15
|
+
ie.capture_page(w)
|
16
|
+
end
|
17
|
+
|
18
|
+
# require RMagick
|
19
|
+
ie.capture_browser(outdir + "ruby-lang-browser.png")
|
20
|
+
open(outdir + "ruby-lang-wholepage.png", "wb") do |w|
|
21
|
+
ie.capture_page(w, :format => "png")
|
22
|
+
end
|
23
|
+
end
|
data/examples/each_ie.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "digest/md5"
|
2
|
+
require "fileutils"
|
3
|
+
require "pathname"
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../lib")
|
7
|
+
require "win32/capture_ie"
|
8
|
+
|
9
|
+
outdir = Pathname.new(__FILE__).basename(".*")
|
10
|
+
FileUtils.mkdir_p(outdir)
|
11
|
+
|
12
|
+
Win32::CaptureIE.reject {|ie| ie.load_error? }.each do |ie|
|
13
|
+
url = ie.document.location.href
|
14
|
+
digest = Digest::MD5.hexdigest(url)
|
15
|
+
output = outdir + "#{digest}.png"
|
16
|
+
|
17
|
+
puts url
|
18
|
+
text = "#{url} - #{Time.now.iso8601}"
|
19
|
+
ie.capture_page(output) do |image|
|
20
|
+
gc = Magick::Draw.new
|
21
|
+
gc.stroke = "white"
|
22
|
+
gc.text_undercolor("blue")
|
23
|
+
gc.text(5, ie.body_area.height - 5, text)
|
24
|
+
gc.draw(image)
|
25
|
+
image
|
26
|
+
end
|
27
|
+
puts " => #{output}"
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "digest/md5"
|
2
|
+
require "fileutils"
|
3
|
+
require "pathname"
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../lib")
|
7
|
+
require "win32/capture_ie"
|
8
|
+
|
9
|
+
if ARGV.size < 2
|
10
|
+
$stderr.puts "Usage: #{$0} URL ID..."
|
11
|
+
exit 2
|
12
|
+
end
|
13
|
+
|
14
|
+
uri = ARGV.shift
|
15
|
+
hilight_ids = ARGV
|
16
|
+
colors = %w(red green blue)
|
17
|
+
|
18
|
+
outdir = Pathname.new(__FILE__).basename(".*")
|
19
|
+
digest = Digest::MD5.hexdigest(uri)
|
20
|
+
output = outdir + "#{digest}.png"
|
21
|
+
FileUtils.mkdir_p(outdir)
|
22
|
+
|
23
|
+
FileUtils.mkdir_p(File.dirname(output))
|
24
|
+
Win32::CaptureIE.start(uri) do |b|
|
25
|
+
b.capture_page(output) do |image|
|
26
|
+
hilight_ids.each_with_index do |id, i|
|
27
|
+
color = colors[i % colors.length]
|
28
|
+
area = b.abs_element_area(id)
|
29
|
+
gc = Magick::Draw.new
|
30
|
+
gc.stroke = color
|
31
|
+
gc.fill = color
|
32
|
+
gc.stroke_width = 4
|
33
|
+
gc.stroke_opacity(0.5)
|
34
|
+
gc.fill_opacity(0.2)
|
35
|
+
gc.rectangle(*area.rect)
|
36
|
+
gc.draw(image)
|
37
|
+
|
38
|
+
gc = Magick::Draw.new
|
39
|
+
gc.stroke_width = 1
|
40
|
+
gc.stroke = "white"
|
41
|
+
gc.text_undercolor(color)
|
42
|
+
gc.text(area.x1, area.y1 + 10, id)
|
43
|
+
gc.draw(image)
|
44
|
+
end
|
45
|
+
image
|
46
|
+
end
|
47
|
+
end
|
data/lib/win32/capture_ie.rb
CHANGED
@@ -1,13 +1,75 @@
|
|
1
1
|
require "win32ole"
|
2
|
+
|
3
|
+
require "win32/capture_ie/feature"
|
2
4
|
require "win32/capture_ie/browser"
|
3
5
|
require "win32/capture_ie/version"
|
4
6
|
|
7
|
+
|
5
8
|
module Win32 #:nodoc:
|
6
9
|
|
10
|
+
#
|
11
|
+
# Ex)
|
12
|
+
#
|
13
|
+
# require "rubygems"
|
14
|
+
# require "win32/capture_ie"
|
15
|
+
#
|
16
|
+
# Win32::CaptureIE.start do |ie|
|
17
|
+
# ie.navigate("http://www.ruby-lang.org/")
|
18
|
+
# ie.capture_browser("ruby-lang.bmp")
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# ie = Win32::CaptureIE.start
|
22
|
+
# begin
|
23
|
+
# ie.navigate("http://rubyforge.org/")
|
24
|
+
# ie.capture_browser("rubyforge.bmp")
|
25
|
+
# ensure
|
26
|
+
# ie.quit
|
27
|
+
# end
|
28
|
+
#
|
7
29
|
module CaptureIE
|
30
|
+
# see Win32::CaptureIE#connect
|
31
|
+
class ConnectError < StandardError; end
|
32
|
+
|
8
33
|
class <<self
|
34
|
+
include Enumerable
|
35
|
+
include Win32::CaptureIE::Feature
|
36
|
+
|
37
|
+
# Do not load/use RMagick even if RMagick is installed.
|
38
|
+
#
|
39
|
+
# Win32::CaptureIE.connect_or_start(url) do |b|
|
40
|
+
# Win32::CaptureIE.disable_rmagick
|
41
|
+
# b.capture_browser("foo.png") #=> Win32::CaptureIE::Feature::DisabledError
|
42
|
+
# b.capture_browser("foo.bmp") #=> ok
|
43
|
+
# Win32::CaptureIE.enable_rmagick
|
44
|
+
# b.capture_browser("foo.png") #=> ok and load RMagick automatically.
|
45
|
+
# Win32::CaptureIE.disable_rmagick
|
46
|
+
# b.capture_browser("foo.png") #=> Win32::CaptureIE::Feature::DisabledError
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
def disable_rmagick
|
50
|
+
disable_feature("RMagick")
|
51
|
+
end
|
9
52
|
|
10
|
-
|
53
|
+
# enable RMagick.
|
54
|
+
#
|
55
|
+
# see disable_rmagick for more details.
|
56
|
+
def enable_rmagick
|
57
|
+
enable_feature("RMagick")
|
58
|
+
end
|
59
|
+
|
60
|
+
# RMagick is enabled?
|
61
|
+
#
|
62
|
+
# see disable_rmagick for more details.
|
63
|
+
def rmagick_enable?
|
64
|
+
feature_enable?("RMagick")
|
65
|
+
end
|
66
|
+
|
67
|
+
# RMagick is installed and enabled?
|
68
|
+
#
|
69
|
+
# This method will load RMagick (and rubygems) automatically.
|
70
|
+
def rmagick_available?
|
71
|
+
feature_available?("RMagick")
|
72
|
+
end
|
11
73
|
|
12
74
|
# call-seq:
|
13
75
|
# start(url) -> Win32::CaptureIE::Browser
|
@@ -45,9 +107,16 @@ module Win32 #:nodoc:
|
|
45
107
|
attach(url, lambda { raise ConnectError, "no such IE `#{url}'" }, opts, &block)
|
46
108
|
end
|
47
109
|
|
110
|
+
# Calls +block+ for each IE window,
|
111
|
+
# passing Win32::CaptureIE::Browser object to the supplied +block+.
|
112
|
+
def each
|
113
|
+
each_ie {|ie| yield wrap(ie) }
|
114
|
+
end
|
115
|
+
|
116
|
+
|
48
117
|
def attach(url, fallback, opts=nil, &block)
|
49
118
|
url = url.to_s
|
50
|
-
ie =
|
119
|
+
ie = each_ie {|ie| break ie if ie.LocationURL == url }
|
51
120
|
if ie
|
52
121
|
run(wrap(ie), opts, &block)
|
53
122
|
else
|
@@ -56,11 +125,14 @@ module Win32 #:nodoc:
|
|
56
125
|
end
|
57
126
|
private :attach
|
58
127
|
|
59
|
-
def
|
128
|
+
def each_ie
|
60
129
|
shell = WIN32OLE.new("Shell.Application")
|
61
|
-
w = shell.Windows
|
62
|
-
w.
|
130
|
+
w = shell.Windows
|
131
|
+
w.each do |ie|
|
132
|
+
yield ie if ie.FullName =~ /\biexplore\.exe\z/i
|
133
|
+
end
|
63
134
|
end
|
135
|
+
private :each_ie
|
64
136
|
|
65
137
|
def run(ie, opts=nil, &block)
|
66
138
|
opts ||= {}
|
@@ -68,10 +140,7 @@ module Win32 #:nodoc:
|
|
68
140
|
begin
|
69
141
|
block.call(ie)
|
70
142
|
ensure
|
71
|
-
|
72
|
-
ie.browser.Quit unless opts[:no_quit]
|
73
|
-
rescue WIN32OLERuntimeError => ignored
|
74
|
-
end
|
143
|
+
ie.quit unless opts[:no_quit]
|
75
144
|
end
|
76
145
|
end
|
77
146
|
private :run
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "win32/capture_ie/base"
|
2
|
+
|
3
|
+
module Win32::CaptureIE
|
4
|
+
|
5
|
+
class Area #:nodoc:
|
6
|
+
|
7
|
+
attr_accessor :x, :y, :w, :h
|
8
|
+
alias x1 x
|
9
|
+
alias y1 y
|
10
|
+
alias width w
|
11
|
+
alias height h
|
12
|
+
|
13
|
+
def initialize(x, y, w, h)
|
14
|
+
@x, @y, @w, @h = x, y, w, h
|
15
|
+
end
|
16
|
+
|
17
|
+
def x2
|
18
|
+
x + w
|
19
|
+
end
|
20
|
+
|
21
|
+
def y2
|
22
|
+
y + h
|
23
|
+
end
|
24
|
+
|
25
|
+
def top_left
|
26
|
+
[x1, y1]
|
27
|
+
end
|
28
|
+
|
29
|
+
def top_right
|
30
|
+
[x2, y1]
|
31
|
+
end
|
32
|
+
|
33
|
+
def bottom_left
|
34
|
+
[x1, y2]
|
35
|
+
end
|
36
|
+
|
37
|
+
def bottom_right
|
38
|
+
[x2, y2]
|
39
|
+
end
|
40
|
+
|
41
|
+
def rect
|
42
|
+
[x1, y1, x2, y2]
|
43
|
+
end
|
44
|
+
|
45
|
+
def +(other)
|
46
|
+
tl = top_left.zip(other.top_left).map{|e| e.min }
|
47
|
+
br = bottom_right.zip(other.bottom_right).map{|e| e.max }
|
48
|
+
self.class.new(tl[0], tl[1], br[0] - tl[0], br[1] - tl[1])
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
"[(%d, %d), (%d, %d)]" % rect
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require "win32/capture_ie/base"
|
2
|
+
require "win32/capture_ie/util"
|
3
|
+
require "win32/capture_ie/feature"
|
2
4
|
require "win32/capture_ie/ffi"
|
3
5
|
|
6
|
+
|
4
7
|
module Win32::CaptureIE
|
5
8
|
|
6
9
|
class BitMapSizeError < StandardError #:nodoc:
|
@@ -8,6 +11,8 @@ module Win32::CaptureIE
|
|
8
11
|
|
9
12
|
class BitMap #:nodoc:
|
10
13
|
include Win32::CaptureIE::FFI::GDI32
|
14
|
+
include Win32::CaptureIE::Util
|
15
|
+
include Win32::CaptureIE::Feature
|
11
16
|
|
12
17
|
attr_reader :width, :height
|
13
18
|
def initialize(width, height)
|
@@ -89,16 +94,60 @@ module Win32::CaptureIE
|
|
89
94
|
end
|
90
95
|
alias info create_bitmapinfo
|
91
96
|
|
92
|
-
def save(
|
93
|
-
|
94
|
-
|
97
|
+
def save(writable, format=nil, &rmagick_filter)
|
98
|
+
format ||= guess_format(writable)
|
99
|
+
begin
|
100
|
+
load_depended_library("RMagick", "save `#{format}' format")
|
101
|
+
save_magick(writable, format, &rmagick_filter)
|
102
|
+
rescue DisabledError, LoadError => e
|
103
|
+
raise e unless format == "bmp"
|
104
|
+
if rmagick_filter and $VERBOSE
|
105
|
+
at = eval("[__FILE__, __LINE__]", rmagick_filter.binding)
|
106
|
+
warn "Ignore block argument at %s:%d because RMagick is not available." % at
|
107
|
+
end
|
108
|
+
save_bmp(writable)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def save_magick(writable, format, &rmagick_filter)
|
113
|
+
img = to_magick(format)
|
114
|
+
img = run_filter(img, rmagick_filter) if rmagick_filter
|
115
|
+
with_output_stream(writable) do |w|
|
116
|
+
w.write img.to_blob
|
117
|
+
end
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
private :save_magick
|
121
|
+
|
122
|
+
def save_bmp(writable)
|
123
|
+
with_output_stream(writable) do |w|
|
124
|
+
to_blob {|data|
|
95
125
|
w.write data
|
96
126
|
}
|
97
127
|
end
|
98
128
|
nil
|
99
129
|
end
|
130
|
+
private :save_bmp
|
131
|
+
|
132
|
+
def to_image(format=nil)
|
133
|
+
format ||= "bmp"
|
134
|
+
begin
|
135
|
+
to_magick(format)
|
136
|
+
rescue DisabledError, LoadError => e
|
137
|
+
raise e unless format == "bmp"
|
138
|
+
to_blob
|
139
|
+
end
|
140
|
+
end
|
100
141
|
|
101
|
-
def
|
142
|
+
def to_magick(format=nil)
|
143
|
+
load_depended_library("RMagick", "create Magick::ImageList")
|
144
|
+
r = Magick::ImageList.new.from_blob(to_blob)
|
145
|
+
r.format = format if format
|
146
|
+
r
|
147
|
+
end
|
148
|
+
private :to_magick
|
149
|
+
|
150
|
+
def to_blob(&block)
|
102
151
|
v = [create_bitmapfileheader.pack, create_bitmapinfo.bmiHeader.pack, @data]
|
103
152
|
if block
|
104
153
|
v.each(&block)
|
@@ -106,6 +155,19 @@ module Win32::CaptureIE
|
|
106
155
|
v.join
|
107
156
|
end
|
108
157
|
end
|
158
|
+
private :to_blob
|
159
|
+
|
160
|
+
def run_filter(image, *filters)
|
161
|
+
filters.inject(image){|image,filter|
|
162
|
+
r = filter.call(image) || image
|
163
|
+
if not [Magick::ImageList, Magick::Image].any?{|k| k === r }
|
164
|
+
raise ArgumentError, "filter `#{filter.inspect}' should return " +
|
165
|
+
"Magick::ImageList, Magick::Image or nil. but was `#{r.inspect}' (#{r.class})."
|
166
|
+
end
|
167
|
+
r
|
168
|
+
}
|
169
|
+
end
|
170
|
+
private :run_filter
|
109
171
|
|
110
172
|
def inspect
|
111
173
|
"#<%s:0x%x @width=%d @height=%d @data=...>" % [self.class, self.object_id << 1, @height, @width]
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require "win32/capture_ie/base"
|
2
2
|
require "win32/capture_ie/ffi"
|
3
3
|
require "win32/capture_ie/window"
|
4
|
+
require "win32/capture_ie/area"
|
4
5
|
require "win32/capture_ie/screen_captor"
|
5
6
|
|
7
|
+
|
6
8
|
module Win32::CaptureIE
|
7
9
|
class Browser < Window
|
8
10
|
module ReadyState
|
@@ -30,6 +32,14 @@ module Win32::CaptureIE
|
|
30
32
|
@embedding_ie_hwnd = nil
|
31
33
|
end
|
32
34
|
|
35
|
+
def quit(ignore_error = true)
|
36
|
+
begin
|
37
|
+
browser.Quit
|
38
|
+
rescue WIN32OLERuntimeError => e
|
39
|
+
raise e unless ignore_error
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
33
43
|
def document
|
34
44
|
@document ||= browser.document rescue nil if browser
|
35
45
|
end
|
@@ -51,6 +61,46 @@ module Win32::CaptureIE
|
|
51
61
|
end
|
52
62
|
private :body0
|
53
63
|
|
64
|
+
def body_area
|
65
|
+
Area.new(0, 0, body.scrollWidth, body.scrollHeight) if body
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_element(id, parent=document)
|
69
|
+
r = parent.getElementById(id)
|
70
|
+
raise ArgumentError, "unknown element `##{id}'" unless r
|
71
|
+
r
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_element(id_or_element)
|
75
|
+
case id_or_element
|
76
|
+
when WIN32OLE
|
77
|
+
id_or_element
|
78
|
+
when String
|
79
|
+
get_element(id_or_element)
|
80
|
+
else
|
81
|
+
raise ArgumentError, "Invalid argument #{id_or_element.inspect}:#{id_or_element.class}," +
|
82
|
+
" expected String or WIN32OLE."
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def abs_element_area(id_or_element)
|
87
|
+
# Let's calculate the absolute position of the object on the page
|
88
|
+
elem = to_element(id_or_element)
|
89
|
+
x = y = 0
|
90
|
+
p = elem
|
91
|
+
while p
|
92
|
+
x += p.offsetLeft
|
93
|
+
y += p.offsetTop
|
94
|
+
p = p.offsetParent
|
95
|
+
end
|
96
|
+
|
97
|
+
# This is the size of the object including its border
|
98
|
+
w = elem.offsetWidth
|
99
|
+
h = elem.offsetHeight
|
100
|
+
|
101
|
+
Area.new(x, y, w, h)
|
102
|
+
end
|
103
|
+
|
54
104
|
def compatible_mode?
|
55
105
|
v = document.compatMode rescue nil
|
56
106
|
return (v.nil? or v == "BackCompat")
|
@@ -79,28 +129,163 @@ module Win32::CaptureIE
|
|
79
129
|
end
|
80
130
|
private :find_embedding_ie_hwnd
|
81
131
|
|
132
|
+
# save window scroll position.
|
82
133
|
def save_excursion
|
83
134
|
top, left = body.scrollTop, body.scrollLeft
|
84
135
|
begin
|
85
136
|
yield
|
86
137
|
ensure
|
87
|
-
|
138
|
+
begin
|
139
|
+
body.scrollTop, body.scrollLeft = top, left
|
140
|
+
rescue => ignored
|
141
|
+
end
|
88
142
|
end
|
89
143
|
end
|
90
144
|
|
91
145
|
# call-seq:
|
92
|
-
# capture_browser(
|
93
|
-
# capture_browser(
|
146
|
+
# capture_browser(writable, :format => "bmp")
|
147
|
+
# capture_browser(writable, :format => "bmp", :only_drawing_area => true)
|
148
|
+
# capture_browser(writable, :format => "bmp") {|image| ... }
|
149
|
+
# capture_browser(writable, :format => "bmp", :only_drawing_area => true) {|image| ... }
|
150
|
+
#
|
151
|
+
# capture IE window and write to +writable+.
|
152
|
+
#
|
153
|
+
# * +writable+ is String, Pathname or object that implemented #write method (Such as IO stream).
|
154
|
+
# * +format+ is image format, "GIF" or "JPG" for example.
|
155
|
+
# * You can specify optional block argument to filter Magick::ImageList.
|
156
|
+
# If RMagick is not installed, block argument will ignore.
|
157
|
+
#
|
158
|
+
# ex):
|
159
|
+
#
|
160
|
+
# Win32::CaptureIE.start do |b|
|
161
|
+
# b.capture_browser("browser.bmp")
|
162
|
+
# b.capture_browser("browser.png", :only_drawing_area => true)
|
163
|
+
# open("browser.jpg", "wb") do |w|
|
164
|
+
# b.capture_browser(w, :format => "jpg")
|
165
|
+
# end
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# RMagick example:
|
94
169
|
#
|
95
|
-
#
|
96
|
-
|
97
|
-
|
170
|
+
# url = "http://win32-captureie.rubyforge.org/html/files/README_txt.html"
|
171
|
+
# Win32::CaptureIE.start(url) do |b|
|
172
|
+
# b.capture_page("readme.jpg") do |image|
|
173
|
+
# area = b.abs_element_area("description")
|
174
|
+
# gc = Magick::Draw.new
|
175
|
+
# gc.stroke = "red"
|
176
|
+
# gc.fill = "red"
|
177
|
+
# gc.stroke_width = 4
|
178
|
+
# gc.stroke_opacity(0.6)
|
179
|
+
# gc.fill_opacity(0.3)
|
180
|
+
# gc.rectangle(*area.rect)
|
181
|
+
# gc.draw(image)
|
182
|
+
# image
|
183
|
+
# end
|
184
|
+
# end
|
185
|
+
#
|
186
|
+
def capture_browser(writable, opts=nil, &rmagick_filter)
|
187
|
+
opts = parse_opts_for_capture_xxx(opts)
|
188
|
+
captor.capture_browser(opts).save(writable, opts[:format], &rmagick_filter)
|
98
189
|
end
|
99
190
|
|
100
|
-
#
|
101
|
-
|
102
|
-
|
191
|
+
# call-seq:
|
192
|
+
# capture_browser_image(:format => "bmp")
|
193
|
+
# capture_browser_image(:format => "bmp", :only_drawing_area => true)
|
194
|
+
#
|
195
|
+
# capture IE window and return Magick::ImageList or BitMap blob as String.
|
196
|
+
#
|
197
|
+
# * +format+ is image format, "GIF" or "JPG" for example.
|
198
|
+
#
|
199
|
+
# ex):
|
200
|
+
#
|
201
|
+
# Win32::CaptureIE.start do |b|
|
202
|
+
# b.capture_browser_image.write("foo.bmp")
|
203
|
+
# b.capture_browser_image(:format => "png").write("foo.png")
|
204
|
+
# end
|
205
|
+
#
|
206
|
+
def capture_browser_image(opts=nil)
|
207
|
+
opts = parse_opts_for_capture_xxx_image(opts)
|
208
|
+
captor.capture_browser(opts).to_image(opts[:format])
|
209
|
+
end
|
210
|
+
|
211
|
+
# call-seq:
|
212
|
+
# capture_page(writable, :format => "bmp")
|
213
|
+
# capture_page(writable, :format => "bmp") {|image| ... }
|
214
|
+
#
|
215
|
+
# capture whole web page and write to +writable+.
|
216
|
+
#
|
217
|
+
# see #capture_browser for more detail.
|
218
|
+
def capture_page(writable, opts=nil, &rmagick_filter)
|
219
|
+
opts = parse_opts_for_capture_xxx(opts)
|
220
|
+
captor.capture_page.save(writable, opts[:format], &rmagick_filter)
|
221
|
+
end
|
222
|
+
|
223
|
+
# capture whole web page and return Magick::ImageList or BitMap blob as String.
|
224
|
+
#
|
225
|
+
# see #capture_browser_image for more detail.
|
226
|
+
def capture_page_image(opts=nil)
|
227
|
+
opts = parse_opts_for_capture_xxx_image(opts)
|
228
|
+
captor.capture_page.to_image(opts[:format])
|
229
|
+
end
|
230
|
+
|
231
|
+
# call-seq:
|
232
|
+
# capture_elements(writable, ["id", "id2"], :format => "bmp")
|
233
|
+
# capture_elements(writable, ["id", "id2"], :format => "bmp") {|image| ... }
|
234
|
+
#
|
235
|
+
# Captures specified elements (outer bounding box of all elements)
|
236
|
+
# and write to +writable+.
|
237
|
+
#
|
238
|
+
# * +id_or_elements+ is ID of DOM element or WIN32OLE object.
|
239
|
+
#
|
240
|
+
# see #capture_browser for more detail.
|
241
|
+
def capture_elements(writable, id_or_elements, opts=nil, &rmagick_filter)
|
242
|
+
opts = parse_opts_for_capture_xxx(opts)
|
243
|
+
captor.capture_elements(*id_or_elements).save(writable, opts[:format], &rmagick_filter)
|
244
|
+
end
|
245
|
+
|
246
|
+
# capture specified elements and return Magick::ImageList or BitMap blob as String.
|
247
|
+
#
|
248
|
+
# see #capture_browser_image for more detail.
|
249
|
+
def capture_elements_image(id_or_elements, opts=nil)
|
250
|
+
opts = parse_opts_for_capture_xxx_image(opts)
|
251
|
+
captor.capture_elements(*id_or_elements).to_image(opts[:format])
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
def parse_opts_for_capture_xxx(opts)
|
256
|
+
r = parse_opts(opts, String => :format)
|
257
|
+
r[:format] = guess_format(r[:format])
|
258
|
+
r
|
259
|
+
end
|
260
|
+
private :parse_opts_for_capture_xxx
|
261
|
+
|
262
|
+
def parse_opts_for_capture_xxx_image(opts)
|
263
|
+
r = parse_opts(opts, String => :filename)
|
264
|
+
r[:format] = guess_format(r.delete(:filename))
|
265
|
+
r
|
266
|
+
end
|
267
|
+
private :parse_opts_for_capture_xxx_image
|
268
|
+
|
269
|
+
def parse_opts(opts, fallback)
|
270
|
+
opts ||= {}
|
271
|
+
return opts if Hash === opts
|
272
|
+
if key = fallback[opts.class]
|
273
|
+
return { key => opts }
|
274
|
+
end
|
275
|
+
raise ArgumentError, "Invalid options `#{opts.inspect}:#{opts.class}' (expected Hash)."
|
276
|
+
end
|
277
|
+
private :parse_opts
|
278
|
+
|
279
|
+
def guess_format(filename_or_format)
|
280
|
+
return nil if filename_or_format.nil? or filename_or_format == ""
|
281
|
+
ext = File.extname(filename_or_format)
|
282
|
+
if ext == ""
|
283
|
+
filename_or_format
|
284
|
+
else
|
285
|
+
ext.sub(/\A\./, "") # arrow :format => File.basename("foo.png")
|
286
|
+
end
|
103
287
|
end
|
288
|
+
private :guess_format
|
104
289
|
|
105
290
|
def captor
|
106
291
|
Win32::CaptureIE::ScreenCaptor.new(self)
|
@@ -58,6 +58,12 @@ module Win32::CaptureIE::CLI
|
|
58
58
|
parser.on("-o", "--output=FILE", "save capture to FILE") {|v|
|
59
59
|
opt.output = v
|
60
60
|
}
|
61
|
+
parser.on("-T", "--output-type=TYPE",
|
62
|
+
"save capture as image TYPE",
|
63
|
+
"Default: PNG (RMagick available)",
|
64
|
+
" or BMP (not available)") {|v|
|
65
|
+
opt.output_type = v
|
66
|
+
}
|
61
67
|
parser.on("-D", "--output-digest=ALGORITHM",
|
62
68
|
"use output filename as hex-encoded version",
|
63
69
|
"of a given URL",
|
@@ -9,13 +9,8 @@ module Win32::CaptureIE::Commands
|
|
9
9
|
module PrtIE #:nodoc:
|
10
10
|
|
11
11
|
class Option < OptionBase #:nodoc:
|
12
|
-
global_option :outdir, :wait, :output_digest
|
12
|
+
global_option :outdir, :wait, :output_type, :output_digest
|
13
13
|
local_option :output, :url
|
14
|
-
attr_reader :ext
|
15
|
-
|
16
|
-
def initialize
|
17
|
-
@ext = "bmp"
|
18
|
-
end
|
19
14
|
|
20
15
|
def check_options
|
21
16
|
raise_arg_error(url, "missing url argument")
|
@@ -39,10 +34,11 @@ module Win32::CaptureIE::Commands
|
|
39
34
|
|
40
35
|
def fixup!
|
41
36
|
self.wait = 0 if wait.nil? or wait < 0
|
37
|
+
self.output_type ||= Win32::CaptureIE.rmagick_available? ? "png" : "bmp"
|
42
38
|
end
|
43
39
|
|
44
40
|
def outfile
|
45
|
-
base = output || "#{digest_url}.#{
|
41
|
+
base = output || "#{digest_url}.#{output_type}"
|
46
42
|
r = File.expand_path(base, outdir)
|
47
43
|
dir = File.dirname(r)
|
48
44
|
::FileUtils.mkdir_p(dir) unless File.exist?(dir)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "win32/capture_ie/base"
|
2
|
+
|
3
|
+
module Win32::CaptureIE
|
4
|
+
module Feature #:nodoc:
|
5
|
+
|
6
|
+
# see Win32::CaptureIE.disable_rmagick
|
7
|
+
class DisabledError < StandardError; end
|
8
|
+
|
9
|
+
DISABLED_FEATURE = []
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
def disable_feature(feature)
|
14
|
+
DISABLED_FEATURE << feature if feature_enable?(feature)
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def enable_feature(feature)
|
19
|
+
DISABLED_FEATURE.delete(feature)
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def feature_enable?(feature)
|
24
|
+
not DISABLED_FEATURE.include?(feature)
|
25
|
+
end
|
26
|
+
|
27
|
+
def feature_available?(feature)
|
28
|
+
begin
|
29
|
+
load_depended_library(feature, "test")
|
30
|
+
true
|
31
|
+
rescue LoadError, DisabledError => ignored
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def raise_if_disabled(feature, function)
|
37
|
+
if DISABLED_FEATURE.include?(feature)
|
38
|
+
raise DisabledError, "`#{feature}' is disabled. " +
|
39
|
+
"Please enable `#{feature}' to #{function}."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_feature(feature, function)
|
44
|
+
raise_if_disabled(feature, function)
|
45
|
+
require feature
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_depended_library(feature, function)
|
49
|
+
begin
|
50
|
+
load_feature feature, function
|
51
|
+
rescue LoadError
|
52
|
+
begin
|
53
|
+
load_feature "rubygems", function
|
54
|
+
load_feature feature, function
|
55
|
+
rescue LoadError
|
56
|
+
raise LoadError, "no such file to load -- `#{feature}'. " +
|
57
|
+
"Please install `#{feature}' to #{function}."
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "win32/capture_ie/base"
|
2
2
|
require "win32/capture_ie/ffi"
|
3
3
|
require "win32/capture_ie/bitmap"
|
4
|
+
require "win32/capture_ie/area"
|
4
5
|
|
5
6
|
module Win32::CaptureIE
|
6
7
|
|
@@ -19,80 +20,92 @@ module Win32::CaptureIE
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def capture_browser(opts=nil)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
capture_hwnd(h)
|
27
|
-
end
|
23
|
+
opts ||= {}
|
24
|
+
hwnd = opts[:only_drawing_area] ? browser.embedding_ie_hwnd : browser.hwnd
|
25
|
+
browser.bring_window_to_top
|
26
|
+
capture_hwnd(hwnd)
|
28
27
|
end
|
29
28
|
|
30
29
|
def capture_page
|
31
|
-
browser.
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
browser.bring_window_to_top
|
31
|
+
capture_area(browser.embedding_ie_hwnd, browser.body_area)
|
32
|
+
end
|
33
|
+
|
34
|
+
def capture_elements(*id_or_elements)
|
35
|
+
elems = id_or_elements.map{|e| [e, browser.to_element(e)] }
|
36
|
+
return capture_page if elems.find{|id, e| e.tagName.downcase == "body" }
|
37
|
+
|
38
|
+
area = elems.map {|id, e|
|
39
|
+
r = browser.abs_element_area(e)
|
40
|
+
if r.w.zero? or r.h.zero?
|
41
|
+
raise ArgumentError, "Invalid element: `#{id}' has no content. #{r}."
|
42
|
+
end
|
43
|
+
r
|
44
|
+
}.inject{|a,b| a + b }
|
45
|
+
|
46
|
+
browser.bring_window_to_top
|
47
|
+
capture_area(browser.embedding_ie_hwnd, area)
|
35
48
|
end
|
36
49
|
|
37
|
-
def capture_area(hwnd,
|
38
|
-
|
39
|
-
|
50
|
+
def capture_area(hwnd, area)
|
51
|
+
area.x = 0 if area.x < 0
|
52
|
+
area.y = 0 if area.y < 0
|
40
53
|
|
41
|
-
w = body.scrollWidth
|
42
|
-
h = body.scrollHeight -
|
54
|
+
area.w = body.scrollWidth - area.x if area.x + area.w > body.scrollWidth
|
55
|
+
area.h = body.scrollHeight - area.y if area.y + area.h > body.scrollHeight
|
43
56
|
|
44
57
|
# Scrolls the page so that top of the object is visible at the top of the window.
|
45
|
-
body.
|
46
|
-
body.
|
58
|
+
body.scrollLeft = area.x - 2
|
59
|
+
body.scrollTop = area.y - 2
|
47
60
|
|
48
61
|
# The position on the screen is different due to page scrolling and Body border
|
49
|
-
sx =
|
50
|
-
sy =
|
62
|
+
sx = area.x - body.scrollLeft + body.clientLeft
|
63
|
+
sy = area.y - body.scrollTop + body.clientTop
|
51
64
|
|
52
|
-
if sx + w < body.clientWidth && sy + h < body.clientHeight
|
65
|
+
if sx + area.w < body.clientWidth && sy + area.h < body.clientHeight
|
53
66
|
# If the whole object is visible
|
54
|
-
capture_hwnd_area(hwnd, sx, sy, w, h)
|
67
|
+
capture_hwnd_area(hwnd, Area.new(sx, sy, area.w, area.h))
|
55
68
|
else
|
56
69
|
# If only part of it is visible
|
57
|
-
capture_and_scroll(hwnd,
|
70
|
+
capture_and_scroll(hwnd, area)
|
58
71
|
end
|
59
72
|
end
|
60
73
|
|
61
|
-
def capture_and_scroll(hwnd,
|
74
|
+
def capture_and_scroll(hwnd, area)
|
62
75
|
# Captured area
|
63
76
|
result = BitMap.new(0, 0)
|
64
77
|
|
65
78
|
# We will do the screen capturing in more steps by areas of maximum dimensions maxw x maxh
|
66
|
-
maxw = body.clientWidth
|
67
|
-
maxh = body.clientHeight
|
79
|
+
maxw = body.clientWidth
|
80
|
+
maxh = body.clientHeight
|
68
81
|
|
69
82
|
cw = 0
|
70
83
|
ch = 0
|
71
84
|
cnt_x = 0
|
72
|
-
while cw < w
|
85
|
+
while cw < area.w
|
73
86
|
# Scroll to the top and right
|
74
|
-
body.scrollTop
|
75
|
-
body.scrollLeft =
|
87
|
+
body.scrollTop = area.x - 2
|
88
|
+
body.scrollLeft = area.x - 2 + cnt_x * (maxw * 0.9).to_i
|
76
89
|
|
77
|
-
ch = 0
|
90
|
+
ch = 0
|
78
91
|
cnt_y = 0
|
79
92
|
strip = BitMap.new(0, 0)
|
80
|
-
while ch < h
|
81
|
-
body.scrollTop =
|
93
|
+
while ch < area.h
|
94
|
+
body.scrollTop = area.x - 2 + cnt_y * (maxh * 0.9).to_i
|
82
95
|
|
83
96
|
# Recalculate the position on the screen
|
84
|
-
sx =
|
85
|
-
sy =
|
97
|
+
sx = area.x - body.scrollLeft + body.clientLeft + cw
|
98
|
+
sy = area.y - body.scrollTop + body.clientTop + ch
|
86
99
|
|
87
100
|
# Calculate the dimensions of the part to be captured
|
88
|
-
pw = (
|
89
|
-
pw = cw + pw > w ? w - cw : pw
|
101
|
+
pw = (area.x + cw - body.scrollLeft + maxw) > maxw ? maxw - (area.x + cw) + body.scrollLeft : maxw
|
102
|
+
pw = cw + pw > area.w ? area.w - cw : pw
|
90
103
|
|
91
|
-
ph = (
|
92
|
-
ph = ch + ph > h ? h - ch : ph
|
104
|
+
ph = (area.y + ch - body.scrollTop + maxh) > maxh ? maxh - (area.y + ch) + body.scrollTop : maxh
|
105
|
+
ph = ch + ph > area.h ? area.h - ch : ph
|
93
106
|
|
94
107
|
# Capture the part and append it to the strip
|
95
|
-
strip << capture_hwnd_area(hwnd, sx, sy, pw, ph)
|
108
|
+
strip << capture_hwnd_area(hwnd, Area.new(sx, sy, pw, ph))
|
96
109
|
ch += ph
|
97
110
|
cnt_y += 1
|
98
111
|
end
|
@@ -107,19 +120,19 @@ module Win32::CaptureIE
|
|
107
120
|
|
108
121
|
def capture_hwnd(hwnd)
|
109
122
|
left, top, right, bottom = get_window_rect(hwnd)
|
110
|
-
capture_hwnd_area(hwnd, 0, 0, right - left, bottom - top)
|
123
|
+
capture_hwnd_area(hwnd, Area.new(0, 0, right - left, bottom - top))
|
111
124
|
end
|
112
125
|
|
113
|
-
def capture_hwnd_area(hwnd,
|
126
|
+
def capture_hwnd_area(hwnd, area)
|
114
127
|
with_window_dc(hwnd) do |hdc|
|
115
128
|
with_delete_dc(CreateCompatibleDC(hdc)) do |memdc|
|
116
|
-
with_delete_object(CreateCompatibleBitmap(hdc, w, h)) do |hbmp|
|
129
|
+
with_delete_object(CreateCompatibleBitmap(hdc, area.w, area.h)) do |hbmp|
|
117
130
|
SelectObject(memdc, hbmp)
|
118
|
-
BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY)
|
131
|
+
BitBlt(memdc, 0, 0, area.w, area.h, hdc, area.x, area.y, SRCCOPY)
|
119
132
|
|
120
|
-
bmp = BitMap.new(w, h)
|
121
|
-
r = GetDIBits(memdc, hbmp, 0, h, bmp.data, bmp.info.pack, DIB_RGB_COLORS)
|
122
|
-
raise Win32APIError, "GetDIBits failed: #{r}" if r.nil? or r.zero?
|
133
|
+
bmp = BitMap.new(area.w, area.h)
|
134
|
+
r = GetDIBits(memdc, hbmp, 0, area.h, bmp.data, bmp.info.pack, DIB_RGB_COLORS)
|
135
|
+
raise Win32APIError, "GetDIBits failed: #{r}: #{[hwnd, area].inspect}" if r.nil? or r.zero?
|
123
136
|
|
124
137
|
bmp
|
125
138
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Win32::CaptureIE
|
2
|
+
module Util #:nodoc:
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def maybe_enable_binmode(obj)
|
7
|
+
obj.binmode if obj.respond_to?(:binmode)
|
8
|
+
end
|
9
|
+
|
10
|
+
def filename_type
|
11
|
+
r = []
|
12
|
+
r << ::String
|
13
|
+
r << ::Pathname if defined?(::Pathname)
|
14
|
+
r
|
15
|
+
end
|
16
|
+
|
17
|
+
def with_filename_or_writable(duck, opts)
|
18
|
+
if filename_type.any?{|t| t === duck }
|
19
|
+
maybe_enable_binmode(duck)
|
20
|
+
opts[:if_filename].call(duck)
|
21
|
+
elsif duck.respond_to?(:write)
|
22
|
+
opts[:if_writable].call(duck)
|
23
|
+
else
|
24
|
+
raise ArgumentError, "`#{duck.inspect}' (#{duck.class}) " +
|
25
|
+
"should be writable object or filename (String or Pathname)."
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def guess_format(writable, default="bmp")
|
30
|
+
r = with_filename_or_writable(writable, {
|
31
|
+
:if_writable => lambda { "" },
|
32
|
+
:if_filename => lambda { File.extname(writable).downcase.sub(/\A\./, "") },
|
33
|
+
})
|
34
|
+
(r == "") ? default : r
|
35
|
+
end
|
36
|
+
|
37
|
+
def with_output_stream(duck, &block)
|
38
|
+
with_filename_or_writable(duck, {
|
39
|
+
:if_writable => lambda { block.call(duck) },
|
40
|
+
:if_filename => lambda { open(duck, "wb", &block) },
|
41
|
+
})
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec.opts
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
--colour
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../lib")
|
2
|
+
require "win32/capture_ie"
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require "spec"
|
6
|
+
|
7
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__))
|
8
|
+
require "dsl/behaviour_eval"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "../../spec_helper.rb")
|
2
|
+
require "win32/capture_ie/area"
|
3
|
+
|
4
|
+
describe Win32::CaptureIE::Area do
|
5
|
+
|
6
|
+
it "#bottom_right" do
|
7
|
+
area = Win32::CaptureIE::Area.new(200, 300, 10, 20)
|
8
|
+
area.bottom_right == [200, 200, 210, 320]
|
9
|
+
end
|
10
|
+
|
11
|
+
it "#+" do
|
12
|
+
area1 = Win32::CaptureIE::Area.new(0, 0, 100, 100)
|
13
|
+
area2 = Win32::CaptureIE::Area.new(200, 200, 10, 10)
|
14
|
+
area3 = area1 + area2
|
15
|
+
area3.top_left.should == [0, 0]
|
16
|
+
area3.bottom_right.should == [210, 210]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/tasks/deployment.rake
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
desc 'Release the website and new gem version'
|
2
|
-
task :deploy => [:check_version, :
|
2
|
+
task :deploy => [:check_version, :publish_docs, :release] do
|
3
3
|
puts "Remember to create SVN tag:"
|
4
4
|
puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
5
5
|
"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
data/tasks/deployment2.rake
CHANGED
@@ -67,8 +67,9 @@ if ENV["SCP"] and ENV["SCP"] != "scp"
|
|
67
67
|
end
|
68
68
|
|
69
69
|
|
70
|
+
NEWS_FILE = "news.txt"
|
70
71
|
task :create_news do
|
71
|
-
subject, title, body, urls =
|
72
|
+
subject, title, body, urls = HOE.announcement
|
72
73
|
open(NEWS_FILE, "w") do |w|
|
73
74
|
w.puts subject
|
74
75
|
w.puts "#{title}\n\n#{body}\n\n"
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: win32-captureie
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-12-09 00:00:00 +09:00
|
8
8
|
summary: Win32::CaptureIE - Capture web pages using Internet Explorer
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -38,7 +38,11 @@ files:
|
|
38
38
|
- bin/prtie
|
39
39
|
- config/hoe.rb
|
40
40
|
- config/requirements.rb
|
41
|
+
- examples/capture-ruby-lang.rb
|
42
|
+
- examples/each_ie.rb
|
43
|
+
- examples/hilight-id.rb
|
41
44
|
- lib/win32/capture_ie.rb
|
45
|
+
- lib/win32/capture_ie/area.rb
|
42
46
|
- lib/win32/capture_ie/base.rb
|
43
47
|
- lib/win32/capture_ie/bitmap.rb
|
44
48
|
- lib/win32/capture_ie/browser.rb
|
@@ -46,12 +50,14 @@ files:
|
|
46
50
|
- lib/win32/capture_ie/cli/prt_ie.rb
|
47
51
|
- lib/win32/capture_ie/commands/base.rb
|
48
52
|
- lib/win32/capture_ie/commands/prt_ie.rb
|
53
|
+
- lib/win32/capture_ie/feature.rb
|
49
54
|
- lib/win32/capture_ie/ffi.rb
|
50
55
|
- lib/win32/capture_ie/ffi/base.rb
|
51
56
|
- lib/win32/capture_ie/ffi/gdi32.rb
|
52
57
|
- lib/win32/capture_ie/ffi/struct.rb
|
53
58
|
- lib/win32/capture_ie/ffi/user32.rb
|
54
59
|
- lib/win32/capture_ie/screen_captor.rb
|
60
|
+
- lib/win32/capture_ie/util.rb
|
55
61
|
- lib/win32/capture_ie/version.rb
|
56
62
|
- lib/win32/capture_ie/window.rb
|
57
63
|
- script/destroy
|
@@ -62,8 +68,10 @@ files:
|
|
62
68
|
- script/txt2html
|
63
69
|
- script/txt2html.cmd
|
64
70
|
- setup.rb
|
71
|
+
- spec/dsl/behaviour_eval.rb
|
65
72
|
- spec/spec.opts
|
66
73
|
- spec/spec_helper.rb
|
74
|
+
- spec/win32/capture_ie/area_spec.rb
|
67
75
|
- spec/win32/capture_ie_spec.rb
|
68
76
|
- tasks/deployment.rake
|
69
77
|
- tasks/deployment2.rake
|
@@ -73,7 +81,6 @@ files:
|
|
73
81
|
- tasks/helper/rake_sh_filter.rb
|
74
82
|
- tasks/helper/util.rb
|
75
83
|
- tasks/rspec.rake
|
76
|
-
- tasks/website.rake
|
77
84
|
test_files: []
|
78
85
|
|
79
86
|
rdoc_options:
|
data/tasks/website.rake
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
desc 'Generate website files'
|
2
|
-
task :website_generate => :ruby_env do
|
3
|
-
(Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
|
4
|
-
sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
|
5
|
-
end
|
6
|
-
end
|
7
|
-
|
8
|
-
desc 'Upload website files to rubyforge'
|
9
|
-
task :website_upload do
|
10
|
-
host = "#{rubyforge_username}@rubyforge.org"
|
11
|
-
remote_dir = "/var/www/gforge-projects/#{PATH}/"
|
12
|
-
local_dir = 'website'
|
13
|
-
sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
|
14
|
-
end
|
15
|
-
|
16
|
-
desc 'Generate and upload website files'
|
17
|
-
task :website => [:website_generate, :website_upload, :publish_docs]
|