snapurl 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/History ADDED
@@ -0,0 +1,21 @@
1
+ === 0.0.3 / 2009-10-19
2
+
3
+ * Added install-cocoa script.
4
+ * Moved to jeweler for package/project management
5
+ (http://github.com/technicalpickles/jeweler)
6
+ * Added support for file:// urls - thanks to Joel Chippindale
7
+ (http://blog.monkeysthumb.org)
8
+ * Added dependency to thoughtbot-shoulda
9
+ (http://thoughtbot.com/projects/shoulda)
10
+ * Gem name is now jurisgalang-snapurl
11
+ * No longer uses Hoe
12
+
13
+ === 0.0.2 / 2009-04-04
14
+
15
+ * Light house-keeping.
16
+ * Merged changes by Michael Kohl (http://citizen428.net)
17
+ * Added RubyCocoa source package and installation task.
18
+
19
+ === 0.0.1 / 2009-02-08
20
+
21
+ * Birthday!
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2008, 2009 Juris Galang
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ Except as contained in this notice, the name(s) of the above
16
+ copyright holders shall not be used in advertising or otherwise to
17
+ promote the sale, use or other dealings in this Software without
18
+ prior written authorization.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,106 @@
1
+ = snapurl
2
+
3
+ Take snapshots of web pages. This is a Ruby/RubyCocoa port of the webkit2png.py script by Paul Hammond (http://www.paulhammond.org/webkit2png/) with some minor modifications.
4
+
5
+ See also: http://www.jurisgalang.com/articles/show/SnapUrl
6
+
7
+
8
+ == Requirements:
9
+
10
+ * OS X only.
11
+ * RubyCocoa (Leopard and Snow Leopard will already have this installed)
12
+ * Ruby 1.8.7 (Ruby 1.9.x wont play with RubyCocoa)
13
+
14
+ If you intend to work with the source and do your own builds, the project expects that you have the following gems installed:
15
+
16
+ * gemcutter
17
+ * jeweler
18
+ * rcov
19
+ * thoughtbot-shoulda
20
+
21
+
22
+ == Installation
23
+
24
+ $ sudo gem install snapurl
25
+
26
+ This gem is published at gemcutter (http://gemcutter.org), so you'll need to add it as a gem source (unless you already have):
27
+
28
+ $ gem sources -a http://gemcutter.org
29
+
30
+ Alternatively you can build the gem from source and install:
31
+
32
+ $ git clone git://github.com/jurisgalang/snapurl.git
33
+ $ cd snapurl
34
+ $ rake gemspec install
35
+
36
+ To build and install a specific tag:
37
+
38
+ $ git clone git://github.com/jurisgalang/snapurl.git
39
+ $ cd snapurl
40
+ $ git checkout -f -b `whoami`-snapurl v0.0.3
41
+ $ rake gemspec install
42
+
43
+
44
+ == Install RubyCocoa
45
+
46
+ If you have a custom Ruby installation then you'll also need to do a custom build and install of RubyCocoa. I've bundled the latest release source and a script to do this for you:
47
+
48
+ $ cd snapurl
49
+ $ ./thirdparty/install-cocoa
50
+
51
+ NOTE: Your custom Ruby installation must have had --enable-shared flag on when you built it.
52
+
53
+
54
+ == Usage
55
+
56
+ Just pass a list of URLs to the snapurl script and it will take a snapshot of the pages found in those URLs:
57
+
58
+ $ snapurl http://artists.gawker.com/ # takes a snapshot of gawker artists
59
+ $ snapurl http://io9.com/ http://artists.gawker.com/ # ... and io9 websites.
60
+
61
+ By default snapurl generates a set of files per URL that it processes: thumbnail, clipped, and full-sized view of the web pages in PNG format.
62
+
63
+
64
+ == Note on Patches/Pull Requests
65
+
66
+ * Fork the project.
67
+ * Make your feature addition or bug fix.
68
+ * Add tests for it. This is important so I don't break it in a
69
+ future version unintentionally.
70
+ * Commit, do not mess with rakefile, version, or history.
71
+ (if you want to have your own version, that is fine but
72
+ bump version in a commit by itself I can ignore when I pull)
73
+ * Send me a pull request. Bonus points for topic branches.
74
+
75
+
76
+ == License
77
+
78
+ (The MIT License)
79
+
80
+ Copyright (c) 2008, 2009 Juris Galang
81
+
82
+ Permission is hereby granted, free of charge, to any person
83
+ obtaining a copy of this software and associated documentation
84
+ files (the "Software"), to deal in the Software without
85
+ restriction, including without limitation the rights to use,
86
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
87
+ copies of the Software, and to permit persons to whom the
88
+ Software is furnished to do so, subject to the following
89
+ conditions:
90
+
91
+ The above copyright notice and this permission notice shall be
92
+ included in all copies or substantial portions of the Software.
93
+
94
+ Except as contained in this notice, the name(s) of the above
95
+ copyright holders shall not be used in advertising or otherwise to
96
+ promote the sale, use or other dealings in this Software without
97
+ prior written authorization.
98
+
99
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
100
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
101
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
102
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
103
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
104
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
105
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
106
+ OTHER DEALINGS IN THE SOFTWARE.
data/bin/snapurl ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File::join(File::dirname(__FILE__), '..', 'lib')
4
+ require 'rubygems'
5
+ require 'snapurl'
6
+
7
+ SnapUrl::Application::run(ARGV)
@@ -0,0 +1,96 @@
1
+ =begin
2
+ * Name: SnapUrl
3
+ * Description:
4
+ * This is a Ruby/RubyCocoa port of the webkit2png.py script by Paul Hammond
5
+ * (http://www.paulhammond.org/webkit2png/) with some minor modifications.
6
+ * Author: Juris Galang (http://www.JurisGalang.com)
7
+ * Date: 09/15/08
8
+ * License:
9
+ =end
10
+ module SnapUrl
11
+ class Application
12
+ def Application::run(args)
13
+ config = Application.parse(args)
14
+ Camera::snap(config[:urls], config[:options])
15
+ end
16
+
17
+ # TODO: add option to control log-level
18
+ # TODO: add implementation for verbose run
19
+ # TODO: set --include-format = true if more than one format
20
+ def Application::parse(args)
21
+ options = Camera::DEFAULT_OPTIONS
22
+ begin
23
+ opts = OptionParser.new do |opts|
24
+ opts.banner = <<-EOF
25
+ Usage: #{opts.program_name} url0 [url1] [url2]... [options]
26
+
27
+ #{opts.program_name} is a command line tool that creates PNG screenshots of webpages.
28
+ With tall or wide pages that would normally require scrolling, it takes
29
+ screenshots of the whole webpage, not just the area that would be visible
30
+ in a browser window.
31
+
32
+ It is a Ruby/RubyCocoa port of the webkit2png.py script by Paul Hammond
33
+ (http://www.paulhammond.org/webkit2png/)
34
+ EOF
35
+ opts.banner.gsub!(/ /, '')
36
+
37
+ opts.separator ' '
38
+ opts.separator 'Specific Options:'
39
+ opts.on('--width [WIDTH]', Float, "initial and minimum browser width (default: #{options[:browser][:width].to_i})") { |n| options[:browser][:width] = n }
40
+ opts.on('--height [HEIGHT]', Float, "initial and minimum browser height (default: #{options[:browser][:height].to_i})") { |n| options[:browser][:height] = n }
41
+
42
+ opts.separator ' '
43
+ opts.on('--[no-]fullsize', "create fullsize screenshot") { |n| n ? options[:snapFormat] << :fullsize : options[:snapFormat].delete(:fullsize) }
44
+ opts.on('--[no-]thumbnail', "create thumbnail") { |n| n ? options[:snapFormat] << :thumbnail : options[:snapFormat].delete(:thumbnail) }
45
+ opts.on('--[no-]clip', "create clip of thumbnail") { |n| n ? options[:snapFormat] << :clip : options[:snapFormat].delete(:clip) }
46
+
47
+ opts.separator ' '
48
+ opts.on('--scale [SCALE]', Float, "scale factor for thumbnails (default: #{options[:scaleFactor]})") { |n| options[:scaleFactor] = n }
49
+
50
+ opts.separator ' '
51
+ opts.on('--clipwidth [WIDTH]', Float, "width of clipped thumbnail (default: #{options[:clip][:width].to_i})") { |n| options[:clip][:width] = n }
52
+ opts.on('--clipheight [HEIGHT]', Float, "height of clipped thumbnail (default: #{options[:clip][:height].to_i})") { |n| options[:clip][:height] = n }
53
+
54
+ opts.separator ' '
55
+ opts.on('-f', '--filename [NAME]', "use NAME as part of filename (derived from url if not specified)") { |n| options[:filename] = n }
56
+
57
+ opts.on('--use-md5hash', "use md5 hash for filename (overriden by --filename)") { |n| options[:useHashForFilename?] = n }
58
+ opts.on('--include-datestamp', "include date in filename") { |n| options[:datestampInFilename?] = n }
59
+ opts.on('--include-timestamp', "include time in filename") { |n| options[:timestampInFilename?] = n }
60
+ opts.on('--include-size', "include image size in filename") { |n| options[:sizeInFilename?] = n }
61
+ opts.on('--include-format', "include image format in filename") { |n| options[:snapFormatInFilename?] = n }
62
+
63
+ opts.separator ' '
64
+ opts.on('-d', '--output-dir [DIRNAME]', "directory to place images into (default: #{options[:outputDirectory]})") { |n| options[:outputDirectory] = n }
65
+
66
+ opts.separator ' '
67
+ opts.separator 'Common Options:'
68
+ opts.on('-v', "--[no-]verbose", "Run verbosely") { |n| options[:verbose?] = n }
69
+ opts.on_tail("-h", "--help", "Show this message") do
70
+ puts opts.help
71
+ exit
72
+ end
73
+
74
+ opts.on_tail("--version", "Show version") do
75
+ puts opts.ver
76
+ exit
77
+ end
78
+ end
79
+
80
+ urls = opts.permute!(args)
81
+
82
+ raise OptionParser::MissingArgument.new('you need to supply at least one URL') if urls.empty?
83
+ raise OptionParser::InvalidArgument.new('you can only use the filename option if there is only one URL') if (urls.size > 1) && !options[:filename].empty?
84
+ raise OptionParser::InvalidArgument.new('scale cannot be zero') if options[:scaleFactor] < 0.0
85
+ # width and height cannot be zero or less than minimum
86
+ # clipwidth and clipheight cannot be zero or less than minimum
87
+ raise OptionParser::AmbiguousArgument.new('you need to allow at least one format') if options[:snapFormat].empty?
88
+
89
+ return { :urls => urls, :options => options }
90
+ rescue OptionParser::ParseError => e
91
+ puts "#{e.message.capitalize}"
92
+ exit(1)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,225 @@
1
+ =begin
2
+ * Name: SnapUrl
3
+ * Description:
4
+ * This is a Ruby/RubyCocoa port of the webkit2png.py script by Paul Hammond
5
+ * (http://www.paulhammond.org/webkit2png/) with some minor modifications.
6
+ * Author: Juris Galang (http://www.JurisGalang.com)
7
+ * Date: 09/15/08
8
+ * License:
9
+ =end
10
+
11
+ module SnapUrl
12
+ module Camera
13
+ DEFAULT_OPTIONS = {
14
+ :browser => {:width => 800.0, :height => 600.0},
15
+ :clip => {:width => 200.0, :height => 150.0},
16
+ :snapFormat => [:fullsize, :thumbnail, :clip],
17
+ :scaleFactor => 0.25,
18
+ :filename => '',
19
+ :datestampInFilename? => false,
20
+ :timestampInFilename? => false,
21
+ :sizeInFilename? => false,
22
+ :snapFormatInFilename? => false,
23
+ :useHashForFilename? => false,
24
+ :outputDirectory => Dir.pwd,
25
+ :verbose? => false
26
+ }
27
+
28
+ def Camera::snap(urls, options = {})
29
+ # create context
30
+ OSX::NSApplication.sharedApplication
31
+
32
+ # create an app delegate
33
+ delegate = AppDelegate.alloc.init
34
+ OSX::NSApp.setDelegate(delegate)
35
+
36
+ # create a webview object
37
+ rect = OSX::NSMakeRect(-16000, -16000, 100, 100)
38
+ webview = OSX::WebView.alloc.initWithFrame(rect)
39
+ webview.setMediaStyle('screen')
40
+ webview.mainFrame.frameView.setAllowsScrolling(false)
41
+
42
+ # make sure we don't save any of the prefs that we change.
43
+ webview.preferences.setAutosaves(false)
44
+ webview.preferences.setShouldPrintBackgrounds(true)
45
+ webview.preferences.setJavaScriptCanOpenWindowsAutomatically(false)
46
+ webview.preferences.setAllowsAnimatedImages(false)
47
+
48
+ # create a window and set view
49
+ win = OSX::NSWindow.alloc
50
+ win.initWithContentRect_styleMask_backing_defer(rect, OSX::NSBorderlessWindowMask, OSX::NSBackingStoreBuffered, false)
51
+ win.setContentView(webview)
52
+
53
+ # create load delegate
54
+ loader = LoadDelegate.alloc.init
55
+ loader.urls = urls
56
+ loader.options = DEFAULT_OPTIONS.merge(options)
57
+ webview.setFrameLoadDelegate(loader)
58
+
59
+ # now run
60
+ OSX::NSApp.run
61
+ end
62
+
63
+ class AppDelegate < OSX::NSObject
64
+ def applicationDidFinishLaunching(aNotification)
65
+ webview = aNotification.object.windows.objectAtIndex(0).contentView
66
+ webview.frameLoadDelegate.fetchUrl(webview)
67
+ end
68
+ end
69
+
70
+ class LoadDelegate < OSX::NSObject
71
+ attr_accessor :options, :urls, :logger
72
+
73
+ def urls=(urls)
74
+ @urls = urls.to_a
75
+ end
76
+
77
+ def options=(options)
78
+ # adjust configs
79
+ options[:snapFormatInFilename?] = true if (options[:snapFormat].size > 1) && !options[:snapFormatInFilename?]
80
+
81
+ w = options[:clip][:width] / options[:scaleFactor]
82
+ h = options[:clip][:height] / options[:scaleFactor]
83
+ options[:browser][:width] = w unless w < options[:browser][:width]
84
+ options[:browser][:height] = h unless h < options[:browser][:height]
85
+
86
+ @options = options
87
+ end
88
+
89
+ def init
90
+ @logger = Logger.new(STDOUT)
91
+ self
92
+ end
93
+
94
+ def webView_didFailLoadWithError_forFrame(webview, error, frame)
95
+ @logger.warn "#{error.localizedDescription}"
96
+ fetchUrl(webview)
97
+ end
98
+
99
+ def webView_didFailProvisionalLoadWithError_forFrame(webview, error, frame)
100
+ @logger.warn "#{error.localizedDescription}"
101
+ fetchUrl(webview)
102
+ end
103
+
104
+ def webView_didFinishLoadForFrame(webview, frame)
105
+ # don't care about subframes
106
+ return unless (frame == webview.mainFrame)
107
+ docview = frame.frameView.documentView
108
+ resizeWebView(docview)
109
+
110
+ @logger.info "Capturing..."
111
+ url = frame.dataSource.initialRequest.URL.absoluteString
112
+ bitmap = captureView(docview)
113
+ saveImages(url, bitmap)
114
+
115
+ @logger.info "Done!"
116
+ fetchUrl(webview)
117
+ end
118
+
119
+ def resetWebView(view)
120
+ rect = OSX::NSMakeRect(0, 0, browser[:width], browser[:height])
121
+ view.window.setContentSize([browser[:width], browser[:height]])
122
+ view.setFrame(rect)
123
+ end
124
+
125
+ def resizeWebView(view)
126
+ view.setNeedsDisplay(true)
127
+ view.displayIfNeeded
128
+ view.window.setContentSize(view.bounds.size)
129
+ view.setFrame(view.bounds)
130
+ end
131
+
132
+ def captureView(view)
133
+ view.lockFocus
134
+ bitmap = OSX::NSBitmapImageRep.alloc
135
+ bitmap.initWithFocusedViewRect(view.bounds)
136
+ view.unlockFocus
137
+ bitmap
138
+ end
139
+
140
+ def fetchUrl(webview)
141
+ OSX::NSApplication.sharedApplication.terminate(self) if @urls.empty?
142
+
143
+ url = String.new(@urls.shift)
144
+
145
+ url.gsub!(/^/, "http:\/\/") unless url =~ /^(http(s)?|file):\/\//
146
+ @logger.info "Fetching #{url}..."
147
+
148
+ resetWebView(webview)
149
+ webview.mainFrame.loadRequest(OSX::NSURLRequest.requestWithURL(OSX::NSURL.URLWithString(url)))
150
+
151
+ return if webview.mainFrame.provisionalDataSource
152
+ fetchUrl(webview)
153
+ end
154
+
155
+ def makeFilename(url, bitmap, format)
156
+ if !filename.empty?
157
+ name = filename
158
+
159
+ elsif useHashForFilename?
160
+ name = Digest::MD5.new.hexdigest(url)
161
+
162
+ else
163
+ name = String.new(url)
164
+ name.gsub!(/\W/, '');
165
+ name.gsub!(/^http(s)?/i, '');
166
+ name.gsub!(/\//, '.');
167
+ end
168
+
169
+ name = "#{Time.now.strftime('%H%M%S')}-#{name}" if timestampInFilename?
170
+ name = "#{Time.now.strftime('%Y%m%d')}-#{name}" if datestampInFilename?
171
+ name = "#{name}-#{bitmap.pixelsWide}x#{bitmap.pixelsHigh}" if sizeInFilename?
172
+ name = "#{name}-#{format}" if snapFormatInFilename?
173
+
174
+ name = "#{name}.png"
175
+
176
+ name = File.join(File.expand_path(outputDirectory), name) unless outputDirectory.empty?
177
+ name
178
+ end
179
+
180
+ def saveImages(url, bitmap)
181
+ writeToFile(url, bitmap, :fullsize) if snapFormat.include?(:fullsize)
182
+
183
+ if snapFormat.include?(:thumbnail) || snapFormat.include?(:clip)
184
+ # work out how big the thumbnail is
185
+ thumbWidth = bitmap.pixelsWide * scaleFactor
186
+ thumbHeight = bitmap.pixelsHigh * scaleFactor
187
+
188
+ # make the thumbnails in a scratch image
189
+ scratch = OSX::NSImage.alloc.initWithSize(OSX::NSMakeSize(thumbWidth, thumbHeight))
190
+ scratch.lockFocus
191
+ OSX::NSGraphicsContext.currentContext.setImageInterpolation(OSX::NSImageInterpolationHigh)
192
+ thumbRect = OSX::NSMakeRect(0.0, 0.0, thumbWidth, thumbHeight)
193
+ clipRect = OSX::NSMakeRect(0.0, thumbHeight - clip[:height], clip[:width], clip[:height])
194
+ bitmap.drawInRect(thumbRect)
195
+ thumbnail = OSX::NSBitmapImageRep.alloc.initWithFocusedViewRect(thumbRect)
196
+ clipping = OSX::NSBitmapImageRep.alloc.initWithFocusedViewRect(clipRect)
197
+ scratch.unlockFocus
198
+
199
+ # save the thumbnails as pngs
200
+ writeToFile(url, thumbnail, :thumbnail) if snapFormat.include?(:thumbnail)
201
+ writeToFile(url, clipping, :clip) if snapFormat.include?(:clip)
202
+ end
203
+ end
204
+
205
+ def writeToFile(url, bitmap, format)
206
+ name = makeFilename(url, bitmap, format)
207
+ FileUtils.mkdir_p File.dirname(name)
208
+ bitmap.representationUsingType_properties(OSX::NSPNGFileType, nil).writeToFile_atomically(name, true)
209
+ end
210
+
211
+ def ping(url)
212
+ open(url) rescue nil
213
+ end
214
+
215
+ def method_missing(name, *args)
216
+ if args.empty?
217
+ k = name.to_sym
218
+ super(name, args) unless @options.keys.include?(k)
219
+ return @options[k]
220
+ end
221
+ super(name, args)
222
+ end
223
+ end
224
+ end
225
+ end
data/lib/snapurl.rb ADDED
@@ -0,0 +1,28 @@
1
+ =begin
2
+ * Name: SnapUrl
3
+ * Description:
4
+ * This is a Ruby/RubyCocoa port of the webkit2png.py script by Paul Hammond
5
+ * (http://www.paulhammond.org/webkit2png/) with some minor modifications.
6
+ * Author: Juris Galang (http://www.JurisGalang.com)
7
+ * Date: 09/15/08
8
+ * License:
9
+ =end
10
+ require 'digest/md5'
11
+ require 'fileutils'
12
+ require 'logger'
13
+ require 'optparse'
14
+ require 'ostruct'
15
+ require 'open-uri'
16
+
17
+ require 'osx/cocoa'
18
+ OSX.require_framework 'WebKit'
19
+
20
+ require 'core/camera'
21
+ require 'core/application'
22
+
23
+ Version = "0.0.2"
24
+ Release = "alpha"
25
+
26
+ module SnapUrl
27
+ VERSION = Version
28
+ end
File without changes
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snapurl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Juris Galang
8
+ - Michael Kohl
9
+ - Joel Chippindale
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-10-20 00:00:00 -07:00
15
+ default_executable: snapurl
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: thoughtbot-shoulda
19
+ type: :development
20
+ version_requirement:
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: "0"
26
+ version:
27
+ description: "\n Take snapshots of websites. This is a Ruby/RubyCocoa port of the \n webkit2png.py script by Paul Hammond \n (http://www.paulhammond.org/webkit2png/) with some minor modifications -\n Generates a set of image files representing the thumbnail, clipped, \n and full-sized view of a web page in PNG format. "
28
+ email: jurisgalang@gmail.com
29
+ executables:
30
+ - snapurl
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - LICENSE
35
+ - README.rdoc
36
+ files:
37
+ - History
38
+ - README.rdoc
39
+ - bin/snapurl
40
+ - lib/core/application.rb
41
+ - lib/core/camera.rb
42
+ - lib/snapurl.rb
43
+ - test/test_snapurl.rb
44
+ - LICENSE
45
+ has_rdoc: true
46
+ homepage: http://github.com/jurisgalang/snapurl
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --charset=UTF-8
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.5
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Take snapshots of websites.
73
+ test_files:
74
+ - test/test_snapurl.rb