photograph 0.0.2 → 0.0.4
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.
- checksums.yaml +7 -0
- data/README.md +19 -27
- data/lib/photograph/artist.rb +61 -28
- data/lib/photograph/service.rb +7 -4
- data/lib/photograph/version.rb +1 -1
- data/photograph.gemspec +3 -1
- data/spec/photograph/artist_spec.rb +59 -25
- metadata +23 -44
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ea0a5dcbf3a353549a0009a793780daeeed56e2a
|
4
|
+
data.tar.gz: 648222a1f1475cc98c87c7ae1ab2efd67204cc1c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f54b2bbc8a8fb484674a6b646458dfd690da18c670b8f2244473bcdaa292e23420c940f93b752c84e525223c5a69ac2d7790765d6626763067d8f267fc6bf871
|
7
|
+
data.tar.gz: 091f1490bd3c72f2a2bd243c2dc2a734ee68fc3f563ab1e8c8c4f96556786cee5e3513c249bf4354b7b59e6b293c6324e302c3b4082df7c3c5104bd2d371fc65
|
data/README.md
CHANGED
@@ -1,20 +1,13 @@
|
|
1
1
|
# Photograph
|
2
2
|
|
3
|
-
Photograph
|
4
|
-
|
5
|
-
Spreadsheet. As a such document is dom based, it may be difficult to get a preview
|
6
|
-
that truly reflects the original content.
|
3
|
+
Photograph allows to take screenshots of webpages, the rendering being
|
4
|
+
done by Chrome.
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
your needs.
|
6
|
+
Typically, this can be used to generate screenshots for DOM based
|
7
|
+
documents.
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
Please remind that having a chrome instance, even if it is being reused
|
15
|
-
by all requests is still taking some time, aroung 600ms after the first
|
16
|
-
request on my development machine. *Consider using photograph only if
|
17
|
-
you expect the same exact rendering of your 'web documents'*.
|
9
|
+
Please remind that having a chrome instance doing the rendering, even if it is launched only once,
|
10
|
+
is slow, around 600ms.
|
18
11
|
|
19
12
|
## Installation
|
20
13
|
|
@@ -32,14 +25,19 @@ Or install it yourself as:
|
|
32
25
|
|
33
26
|
## Usage
|
34
27
|
|
28
|
+
**Using `Artist.shoot!` without a block had been deprecated in 0.3 and
|
29
|
+
will raise an exception.**
|
30
|
+
|
35
31
|
Photograph can be used either directly through the Photograph::Artist
|
36
|
-
class or by its little
|
32
|
+
class or by its little sinatra app.
|
37
33
|
|
38
|
-
@artist = Photograph::Artist.new("http://github.com")
|
39
|
-
@artist.shoot!
|
34
|
+
@artist = Photograph::Artist.new(:url => "http://github.com")
|
35
|
+
@artist.shoot! do |image|
|
36
|
+
image # => MiniMagick instance you can toy with
|
40
37
|
|
41
|
-
|
42
|
-
|
38
|
+
send_file image.path,
|
39
|
+
:type => :png
|
40
|
+
end
|
43
41
|
|
44
42
|
Or
|
45
43
|
|
@@ -53,17 +51,11 @@ Or
|
|
53
51
|
4. Push to the branch (`git push origin my-new-feature`)
|
54
52
|
5. Create new Pull Request
|
55
53
|
|
56
|
-
##
|
57
|
-
|
58
|
-
|
59
|
-
Photograph is maintained and funded by Tactilize.
|
60
|
-
|
61
|
-
Contributors :
|
54
|
+
## Authors
|
62
55
|
|
63
56
|
* Jean-Hadrien Chabran
|
64
|
-
|
65
|
-
The names and logos for Tactilize are trademarks of Tactilize.
|
57
|
+
* Danial Pearce
|
66
58
|
|
67
59
|
## License
|
68
60
|
|
69
|
-
Photograph is Copyright ©
|
61
|
+
Photograph is Copyright © 2013 JHCHABRAN. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
|
data/lib/photograph/artist.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'capybara/poltergeist'
|
2
2
|
require 'mini_magick'
|
3
3
|
|
4
|
-
|
5
4
|
Capybara.default_wait_time = 15
|
6
5
|
|
7
6
|
module Photograph
|
@@ -9,45 +8,77 @@ module Photograph
|
|
9
8
|
attr_accessor :options
|
10
9
|
attr_reader :image
|
11
10
|
|
12
|
-
MissingUrlError
|
11
|
+
class MissingUrlError < ArgumentError; end
|
12
|
+
class DeprecationError < RuntimeError; end
|
13
|
+
|
13
14
|
DefaultOptions = {
|
14
15
|
:x => 0, # top left position
|
15
16
|
:y => 0,
|
16
|
-
:w => 1280, #
|
17
|
-
:h => 1024,
|
17
|
+
:w => 1280, # width
|
18
|
+
:h => 1024, # height
|
18
19
|
|
19
20
|
:wait => 0.5, # if selector is nil, wait 1 seconds before taking the screenshot
|
20
21
|
:selector => nil # wait until the selector matches to take the screenshot
|
21
22
|
}
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
##
|
25
|
+
# Instanciate a browser instance.
|
26
|
+
#
|
27
|
+
# Typically it's used to supply a Photograph instance your own browser session,
|
28
|
+
# allowing you to reuse it if you're using multiples +Photograph::Artist+
|
29
|
+
# instances.
|
30
|
+
def self.create_browser
|
31
|
+
Capybara::Session.new :poltergeist
|
25
32
|
end
|
26
33
|
|
34
|
+
##
|
35
|
+
# Returns current browser instance.
|
36
|
+
#
|
37
|
+
# If none had been supplied, it creates a new one.
|
27
38
|
def browser
|
28
|
-
self.class.
|
39
|
+
@options[:browser] ||= self.class.create_browser
|
29
40
|
end
|
30
41
|
|
42
|
+
##
|
43
|
+
# Normalize urls, allowing you to use "google.com" instead of "http://google.com"
|
44
|
+
def normalize_url url
|
45
|
+
unless url.match(/https?:\/\//)
|
46
|
+
url = "http://#{url}"
|
47
|
+
end
|
48
|
+
|
49
|
+
url
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Creates a new +Photograph::Artist+ and configures it through +options+.
|
54
|
+
#
|
55
|
+
# Cropping is supported through the +x+, +y+, +w+ and +h+ options.
|
56
|
+
#
|
57
|
+
# Options:
|
58
|
+
# * +url+ mandatory, location you want to screenshot
|
59
|
+
# * +wait+ wait amount of seconds before screenshotting. *this is option is ignored if +selector+ is provided.
|
60
|
+
# * +selector+ wait until the provided +selector+ matches a dom node before screenshotting. Typically faster than an arbritrary +wait+ amount, used when your page has some dynamically inserted nodes.
|
61
|
+
# * +x+ top coordinate of the screenshot, default to 0
|
62
|
+
# * +y+ left coordinate of the screenshot, default to 0
|
63
|
+
# * +w+ width of the screenshot, default to 1280
|
64
|
+
# * +h+ height of the screenshot, default to 1024
|
65
|
+
# * +browser+ Capybara instance to use, typically instanciated by +Artist.create_browser+
|
31
66
|
def initialize options={}
|
32
|
-
raise MissingUrlError unless options[:url]
|
67
|
+
raise MissingUrlError.new('missing argument :url') unless options[:url]
|
33
68
|
|
34
69
|
@options = DefaultOptions.merge(options)
|
70
|
+
@options[:url] = normalize_url(options[:url])
|
35
71
|
end
|
36
72
|
|
73
|
+
##
|
74
|
+
# Takes a screenshot and yield the resulting image.
|
37
75
|
def shoot! &block
|
38
|
-
|
76
|
+
raise DeprecationError.new('Using Artist#shoot! without a block had been deprecated') unless block_given?
|
39
77
|
|
40
|
-
if block_given?
|
41
|
-
yield @image
|
42
|
-
clean!
|
43
|
-
else
|
44
|
-
@image
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def capture
|
49
78
|
browser.visit @options[:url]
|
50
79
|
|
80
|
+
@before_hook.call(browser) if @before_hook
|
81
|
+
|
51
82
|
if @options[:selector]
|
52
83
|
browser.wait_until do
|
53
84
|
browser.has_css? @options[:selector]
|
@@ -56,30 +87,32 @@ module Photograph
|
|
56
87
|
sleep @options[:wait]
|
57
88
|
end
|
58
89
|
|
59
|
-
|
90
|
+
tempfile = Tempfile.new(['photograph','.png'])
|
60
91
|
|
61
|
-
browser.driver.render
|
92
|
+
browser.driver.render tempfile.path,
|
62
93
|
:width => options[:w] + options[:x],
|
63
94
|
:height => options[:h] + options[:y]
|
64
95
|
|
65
|
-
|
96
|
+
yield adjust_image(tempfile)
|
97
|
+
ensure
|
98
|
+
tempfile.unlink if tempfile
|
66
99
|
end
|
67
100
|
|
68
|
-
|
69
|
-
|
101
|
+
##
|
102
|
+
# Crops a given +tempfile+ according to initially given +options+
|
103
|
+
def adjust_image tempfile
|
104
|
+
image = MiniMagick::Image.read tempfile
|
70
105
|
|
71
106
|
if options[:h] && options[:w]
|
72
107
|
image.crop "#{options[:w]}x#{options[:h]}+#{options[:x]}+#{options[:y]}"
|
73
|
-
|
74
|
-
image.write @tempfile
|
75
|
-
|
108
|
+
image.write tempfile
|
76
109
|
end
|
77
110
|
|
78
111
|
image
|
79
112
|
end
|
80
113
|
|
81
|
-
def
|
82
|
-
@
|
114
|
+
def before &block
|
115
|
+
@before_hook = block
|
83
116
|
end
|
84
117
|
end
|
85
118
|
end
|
data/lib/photograph/service.rb
CHANGED
@@ -2,12 +2,14 @@ require 'sinatra/base'
|
|
2
2
|
require 'sinatra/json'
|
3
3
|
|
4
4
|
module Photograph
|
5
|
-
# Preload the chrome instance
|
6
|
-
Artist.browser
|
7
|
-
|
8
5
|
class Service < ::Sinatra::Base
|
9
6
|
helpers Sinatra::JSON
|
10
7
|
|
8
|
+
# Reuse the same browser instance between requests.
|
9
|
+
def browser
|
10
|
+
@browser ||= Artist.create_browser
|
11
|
+
end
|
12
|
+
|
11
13
|
get '/' do
|
12
14
|
json :version => Photograph::VERSION
|
13
15
|
end
|
@@ -19,7 +21,8 @@ module Photograph
|
|
19
21
|
:w => params["w"].to_i,
|
20
22
|
:h => params["h"].to_i,
|
21
23
|
:wait => params["wait"].to_f,
|
22
|
-
:selector => params["selector"]
|
24
|
+
:selector => params["selector"],
|
25
|
+
:browser => browser
|
23
26
|
|
24
27
|
artist.shoot! do |image|
|
25
28
|
send_file image.path,
|
data/lib/photograph/version.rb
CHANGED
data/photograph.gemspec
CHANGED
@@ -21,6 +21,8 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_dependency 'sinatra-contrib'
|
22
22
|
gem.add_dependency 'thin'
|
23
23
|
|
24
|
-
gem.add_development_dependency 'rspec', '~> 2.
|
24
|
+
gem.add_development_dependency 'rspec', '~> 2.14'
|
25
25
|
gem.add_development_dependency 'rake'
|
26
|
+
|
27
|
+
gem.post_install_message = 'DEPRECATION: Artist#shoot! cannot be used without a block anymore. Please check your code, thank you.'
|
26
28
|
end
|
@@ -2,47 +2,81 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Photograph
|
4
4
|
describe Artist do
|
5
|
-
|
5
|
+
let(:url) { 'http://rubygems.org' }
|
6
|
+
subject { Artist.new :url => url }
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
describe '.new' do
|
9
|
+
it { expect(subject).to be_kind_of(Artist) }
|
10
|
+
|
11
|
+
it('raises an error when not given a url') do
|
12
|
+
expect{ Artist.new }.to raise_error(Artist::MissingUrlError)
|
13
|
+
end
|
14
|
+
|
15
|
+
it('should leave http version of url untouched as it is already valid') do
|
16
|
+
expect(subject.options[:url]).to eq(url)
|
17
|
+
end
|
18
|
+
|
19
|
+
it('should leave https version of url untouched as it is already valid') do
|
20
|
+
expect(Artist.new(:url => 'https://rubygems.org').options[:url]).to eq('https://rubygems.org')
|
21
|
+
end
|
10
22
|
|
11
|
-
|
12
|
-
|
13
|
-
image.should respond_to(:path)
|
23
|
+
it('should prepend http:// to the url if protocol is not present') do
|
24
|
+
expect(Artist.new(:url => 'github.com').options[:url]).to eq('http://github.com')
|
14
25
|
end
|
15
26
|
end
|
16
27
|
|
17
|
-
|
18
|
-
|
28
|
+
describe '#options' do
|
29
|
+
it('should have default value for x') { expect(subject.options[:x]).to eq(0) }
|
30
|
+
it('should have default value for y') { expect(subject.options[:y]).to eq(0) }
|
31
|
+
it('should have default value for w') { expect(subject.options[:w]).to eq(1280) }
|
32
|
+
it('should have default value for h') { expect(subject.options[:h]).to eq(1024) }
|
19
33
|
end
|
20
34
|
|
21
|
-
describe
|
22
|
-
|
35
|
+
describe '#shoot!' do
|
36
|
+
context 'when browser has been provided' do
|
37
|
+
let(:browser) { Capybara::Session.new(:poltergeist) }
|
38
|
+
subject { Artist.new(:url => url, :browser => browser) }
|
23
39
|
|
24
|
-
|
25
|
-
|
26
|
-
|
40
|
+
it 're-uses the browser provided to Artist#new' do
|
41
|
+
browser.should_receive(:visit)
|
42
|
+
subject.shoot! {}
|
43
|
+
end
|
27
44
|
end
|
28
45
|
|
29
|
-
it
|
30
|
-
|
31
|
-
|
46
|
+
it('should accept a block when shooting') do
|
47
|
+
subject.shoot!{|image| image.should respond_to(:path) }
|
48
|
+
end
|
49
|
+
|
50
|
+
it('should raise an exception if no block was given when shooting') do
|
51
|
+
expect{ subject.shoot! }.to raise_error(Artist::DeprecationError)
|
32
52
|
end
|
33
|
-
end
|
34
53
|
|
35
|
-
|
36
|
-
|
54
|
+
describe 'Cropping' do
|
55
|
+
subject { Artist.new :url => url, :x => 200, :y => 100, :h => 400, :w => 400 }
|
56
|
+
before { subject.browser.driver.stub(:render) }
|
37
57
|
|
38
|
-
|
39
|
-
|
58
|
+
xit 'should take a screenshot large enough to crop later' do
|
59
|
+
subject.shoot!
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
40
63
|
|
41
|
-
|
64
|
+
describe "#before" do
|
65
|
+
subject { Artist.new :url => url }
|
66
|
+
before do
|
67
|
+
subject.browser.driver.stub(:visit)
|
68
|
+
subject.browser.driver.stub(:click_link)
|
69
|
+
subject.browser.driver.stub(:render)
|
70
|
+
subject.stub(:adjust_image)
|
71
|
+
end
|
42
72
|
|
43
|
-
|
73
|
+
it('should call the before hook before shooting') do
|
74
|
+
subject.before do |browser|
|
75
|
+
browser.click_link "Use the API"
|
76
|
+
end
|
44
77
|
|
45
|
-
|
78
|
+
allow(subject.browser).to receive(:click_link)
|
79
|
+
subject.shoot! {}
|
46
80
|
end
|
47
81
|
end
|
48
82
|
end
|
metadata
CHANGED
@@ -1,126 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: photograph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.4
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- JH. Chabran
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-12-28 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: poltergeist
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: mini_magick
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: sinatra
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: sinatra-contrib
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: thin
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: '0'
|
86
76
|
type: :runtime
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - '>='
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: '0'
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: rspec
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - ~>
|
100
88
|
- !ruby/object:Gem::Version
|
101
|
-
version: '2.
|
89
|
+
version: '2.14'
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - ~>
|
108
95
|
- !ruby/object:Gem::Version
|
109
|
-
version: '2.
|
96
|
+
version: '2.14'
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: rake
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
|
-
- -
|
101
|
+
- - '>='
|
116
102
|
- !ruby/object:Gem::Version
|
117
103
|
version: '0'
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
|
-
- -
|
108
|
+
- - '>='
|
124
109
|
- !ruby/object:Gem::Version
|
125
110
|
version: '0'
|
126
111
|
description: Webservice that screenshots any url
|
@@ -149,33 +134,27 @@ files:
|
|
149
134
|
- spec/spec_helper.rb
|
150
135
|
homepage: https://github.com/jhchabran/photograph
|
151
136
|
licenses: []
|
152
|
-
|
137
|
+
metadata: {}
|
138
|
+
post_install_message: 'DEPRECATION: Artist#shoot! cannot be used without a block anymore.
|
139
|
+
Please check your code, thank you.'
|
153
140
|
rdoc_options: []
|
154
141
|
require_paths:
|
155
142
|
- lib
|
156
143
|
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
-
none: false
|
158
144
|
requirements:
|
159
|
-
- -
|
145
|
+
- - '>='
|
160
146
|
- !ruby/object:Gem::Version
|
161
147
|
version: '0'
|
162
|
-
segments:
|
163
|
-
- 0
|
164
|
-
hash: -3056213331410753270
|
165
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
-
none: false
|
167
149
|
requirements:
|
168
|
-
- -
|
150
|
+
- - '>='
|
169
151
|
- !ruby/object:Gem::Version
|
170
152
|
version: '0'
|
171
|
-
segments:
|
172
|
-
- 0
|
173
|
-
hash: -3056213331410753270
|
174
153
|
requirements: []
|
175
154
|
rubyforge_project:
|
176
|
-
rubygems_version:
|
155
|
+
rubygems_version: 2.0.3
|
177
156
|
signing_key:
|
178
|
-
specification_version:
|
157
|
+
specification_version: 4
|
179
158
|
summary: Webservice that screenshots any url
|
180
159
|
test_files:
|
181
160
|
- spec/photograph/artist_spec.rb
|