shutterbug 0.0.4 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +7 -1
- data/lib/shutterbug/bug_file.rb +22 -0
- data/lib/shutterbug/configuration.rb +55 -0
- data/lib/shutterbug/html_file.rb +3 -0
- data/lib/shutterbug/js_file.rb +11 -0
- data/lib/shutterbug/phantom_job.rb +70 -0
- data/lib/shutterbug/png_file.rb +3 -0
- data/lib/shutterbug/rackapp.rb +10 -26
- data/lib/shutterbug/service.rb +9 -75
- data/lib/shutterbug.rb +7 -1
- data/spec/shutterbug/rackapp_spec.rb +12 -9
- metadata +10 -4
data/README.md
CHANGED
@@ -6,7 +6,13 @@
|
|
6
6
|
A rack utility that will create and save images (pngs) from parts of your html's documents current dom. These images become available as public png resources in the rack application. Currently shutterbug supports HTML, SVG and Canvas elements.
|
7
7
|
|
8
8
|
|
9
|
-
use Shutterbug::Rackapp
|
9
|
+
use Shutterbug::Rackapp do |config|
|
10
|
+
conf.resource_dir = "/Users/npaessel/tmp"
|
11
|
+
config.uri_prefix = "http://localhost:9292"
|
12
|
+
config.path_prefix = "/shutterbug"
|
13
|
+
end
|
14
|
+
|
15
|
+
Configuration options default to reasonable defaults.
|
10
16
|
|
11
17
|
|
12
18
|
## Installation
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
class BugFile
|
3
|
+
def initialize(filename)
|
4
|
+
@filename = filename
|
5
|
+
end
|
6
|
+
|
7
|
+
def open
|
8
|
+
@stream_file = File.open(@filename, 'r')
|
9
|
+
@stream_file.rewind
|
10
|
+
end
|
11
|
+
|
12
|
+
def each(&blk)
|
13
|
+
@stream_file.each(&blk)
|
14
|
+
ensure
|
15
|
+
@stream_file.close
|
16
|
+
end
|
17
|
+
|
18
|
+
def size
|
19
|
+
@stream_file.size
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
attr_accessor :uri_prefix
|
5
|
+
attr_accessor :path_prefix
|
6
|
+
attr_accessor :resource_dir
|
7
|
+
|
8
|
+
def self.instance(opts={})
|
9
|
+
return @instance || @instance = self.new(opts)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(opts={})
|
13
|
+
self.uri_prefix = opts[:uri_prefix] || ""
|
14
|
+
self.path_prefix = opts[:path_prefix] || "/shutterbug"
|
15
|
+
self.resource_dir = opts[:resource_dir] || Dir.tmpdir
|
16
|
+
end
|
17
|
+
|
18
|
+
def js_path
|
19
|
+
"#{uri_prefix}#{path_prefix}/shutterbug.js"
|
20
|
+
end
|
21
|
+
|
22
|
+
def js_regex
|
23
|
+
/#{path_prefix}\/shutterbug.js/
|
24
|
+
end
|
25
|
+
|
26
|
+
def js_file
|
27
|
+
File.join(File.dirname(__FILE__),"shutterbug.js")
|
28
|
+
end
|
29
|
+
|
30
|
+
def convert_path
|
31
|
+
"#{uri_prefix}#{path_prefix}/make_snapshot"
|
32
|
+
end
|
33
|
+
def convert_regex
|
34
|
+
/#{path_prefix}\/make_snapshot/
|
35
|
+
end
|
36
|
+
|
37
|
+
def png_path(sha='')
|
38
|
+
"#{uri_prefix}#{path_prefix}/get_png/#{sha}"
|
39
|
+
end
|
40
|
+
def png_regex
|
41
|
+
/#{path_prefix}\/get_png\/([^\/]+)/
|
42
|
+
end
|
43
|
+
|
44
|
+
def html_path(sha='')
|
45
|
+
"#{uri_prefix}#{path_prefix}/get_html/#{sha}"
|
46
|
+
end
|
47
|
+
def html_regex
|
48
|
+
/#{path_prefix}\/get_html\/([^\/]+)/
|
49
|
+
end
|
50
|
+
|
51
|
+
def base_url(req)
|
52
|
+
req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
class JsFile < BugFile
|
3
|
+
def initialize(_config=Configuration.instance())
|
4
|
+
@config = _config
|
5
|
+
@javascript = File.read(@config.js_file).gsub(/CONVERT_PATH/,@config.convert_path)
|
6
|
+
end
|
7
|
+
def open
|
8
|
+
@stream_file = StringIO.new(@javascript)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
class PhantomJob
|
3
|
+
|
4
|
+
attr_accessor :png_file
|
5
|
+
attr_accessor :html_file
|
6
|
+
|
7
|
+
def program
|
8
|
+
'phantomjs'
|
9
|
+
end
|
10
|
+
|
11
|
+
def rasterize_js
|
12
|
+
File.join(File.dirname(__FILE__),'rasterize.js')
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(base_url, html, css="", width=1000, height=700)
|
16
|
+
@base_url = base_url
|
17
|
+
@html = html
|
18
|
+
@css = css
|
19
|
+
@width = width
|
20
|
+
@height = height
|
21
|
+
end
|
22
|
+
|
23
|
+
def cache_key
|
24
|
+
return @key || @key = Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}")[0..10]
|
25
|
+
end
|
26
|
+
|
27
|
+
def document
|
28
|
+
date = Time.now.strftime("%Y-%m-%d (%I:%M%p)")
|
29
|
+
"""
|
30
|
+
<!DOCTYPE html>
|
31
|
+
<html>
|
32
|
+
<head>
|
33
|
+
<base href='#{@base_url}'>
|
34
|
+
<meta content='text/html;charset=utf-8' http-equiv='Content-Type'>
|
35
|
+
<title>content from #{@base_url} #{date}</title>
|
36
|
+
#{@css}
|
37
|
+
</head>
|
38
|
+
<body>
|
39
|
+
#{@html}
|
40
|
+
</body>
|
41
|
+
</html>
|
42
|
+
"""
|
43
|
+
end
|
44
|
+
|
45
|
+
def base_path
|
46
|
+
Configuration.instance.resource_dir
|
47
|
+
end
|
48
|
+
|
49
|
+
def infilename
|
50
|
+
File.join(base_path,"phantom_#{cache_key}.html")
|
51
|
+
end
|
52
|
+
|
53
|
+
def outfilename
|
54
|
+
File.join(base_path,"phantom_#{cache_key}.png")
|
55
|
+
end
|
56
|
+
|
57
|
+
def rasterize_cl
|
58
|
+
%x[#{self.program} #{self.rasterize_js} #{self.infilename} #{self.outfilename} #{@width}*#{@height}]
|
59
|
+
end
|
60
|
+
|
61
|
+
def rasterize
|
62
|
+
infile = File.open(infilename, 'w') do |f|
|
63
|
+
f.write(document)
|
64
|
+
end
|
65
|
+
rasterize_cl()
|
66
|
+
self.png_file = PngFile.new(outfilename)
|
67
|
+
self.html_file = HtmlFile.new(infilename)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/shutterbug/rackapp.rb
CHANGED
@@ -2,52 +2,36 @@
|
|
2
2
|
|
3
3
|
module Shutterbug
|
4
4
|
class Rackapp
|
5
|
-
BASE_PATH = "/shutterbug"
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
PNG_PATH = "#{BASE_PATH}/get_png"
|
11
|
-
GET_PNG_REGEX = /#{PNG_PATH}\/([^\/]+)/
|
12
|
-
|
13
|
-
HTML_PATH = "#{BASE_PATH}/get_html"
|
14
|
-
GET_HTML_REGEX = /#{HTML_PATH}\/([^\/]+)/
|
15
|
-
|
16
|
-
JS_PATH = "#{BASE_PATH}/shutterbug.js"
|
17
|
-
JS_REGEX = /#{JS_PATH}$/
|
18
|
-
|
19
|
-
def initialize app
|
6
|
+
def initialize(app, &block)
|
7
|
+
@config = Configuration.instance
|
8
|
+
yield @config if block_given?
|
20
9
|
@app = app
|
21
|
-
@shutterbug = Service.new()
|
10
|
+
@shutterbug = Service.new(@config)
|
22
11
|
log "initialized"
|
23
12
|
end
|
24
13
|
|
25
|
-
def base_url(req)
|
26
|
-
req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
|
27
|
-
end
|
28
|
-
|
29
14
|
def do_convert(req)
|
30
15
|
html = req.POST()['content'] || ""
|
31
16
|
width = req.POST()['width'] || 1000
|
32
17
|
height = req.POST()['height'] || 700
|
33
18
|
css = req.POST()['css'] || ""
|
34
19
|
|
35
|
-
signature = @shutterbug.convert(base_url(req), html, css, width, height)
|
36
|
-
|
37
|
-
response_text = "<img src='#{response_url}' alt='#{signature}'>"
|
20
|
+
signature = @shutterbug.convert(@config.base_url(req), html, css, width, height)
|
21
|
+
response_text = "<img src='#{@config.png_path(signature)}' alt='#{signature}'>"
|
38
22
|
return good_response(response_text,'text/plain')
|
39
23
|
end
|
40
24
|
|
41
25
|
def call env
|
42
26
|
req = Rack::Request.new(env)
|
43
27
|
case req.path
|
44
|
-
when
|
28
|
+
when @config.convert_regex
|
45
29
|
do_convert(req)
|
46
|
-
when
|
30
|
+
when @config.png_regex
|
47
31
|
good_response(@shutterbug.get_png_file($1),'image/png')
|
48
|
-
when
|
32
|
+
when @config.html_regex
|
49
33
|
good_response(@shutterbug.get_html_file($1),'text/html')
|
50
|
-
when
|
34
|
+
when @config.js_regex
|
51
35
|
good_response(@shutterbug.get_shutterbug_file, 'application/javascript')
|
52
36
|
else
|
53
37
|
skip(env)
|
data/lib/shutterbug/service.rb
CHANGED
@@ -1,87 +1,21 @@
|
|
1
1
|
require 'stringio'
|
2
2
|
module Shutterbug
|
3
3
|
class Service
|
4
|
-
class RackFile
|
5
|
-
def initialize(file)
|
6
|
-
@stream_file = file
|
7
|
-
end
|
8
|
-
|
9
|
-
def open
|
10
|
-
@stream_file.open
|
11
|
-
@stream_file.rewind
|
12
|
-
end
|
13
|
-
|
14
|
-
def each(&blk)
|
15
|
-
@stream_file.each(&blk)
|
16
|
-
ensure
|
17
|
-
@stream_file.close
|
18
|
-
end
|
19
|
-
|
20
|
-
def size
|
21
|
-
@stream_file.size
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class PngFile < RackFile; end
|
26
|
-
class HtmlFile < RackFile; end
|
27
|
-
|
28
|
-
class JSFile < RackFile
|
29
|
-
def initialize(_filename)
|
30
|
-
@javascript = File.read(_filename).gsub(/CONVERT_PATH/,Shutterbug::Rackapp::CONVERT_PATH)
|
31
|
-
end
|
32
|
-
def open
|
33
|
-
@stream_file = StringIO.new(@javascript)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
PROGRAM = 'phantomjs'
|
39
|
-
RASTERIZE_JS = File.join(File.dirname(__FILE__),'rasterize.js')
|
40
|
-
SHUTTERBUG_JS = File.join(File.dirname(__FILE__),'shutterbug.js')
|
41
4
|
|
42
|
-
def
|
43
|
-
date = Time.now.strftime("%Y-%m-%d (%I:%M%p)")
|
44
|
-
"""
|
45
|
-
<!DOCTYPE html>
|
46
|
-
<html>
|
47
|
-
<head>
|
48
|
-
<base href='#{url_base}'>
|
49
|
-
<meta content='text/html;charset=utf-8' http-equiv='Content-Type'>
|
50
|
-
<title>png from #{url_base} #{date}</title>
|
51
|
-
#{css}
|
52
|
-
</head>
|
53
|
-
<body>
|
54
|
-
#{html}
|
55
|
-
</body>
|
56
|
-
</html>
|
57
|
-
"""
|
58
|
-
end
|
59
|
-
|
60
|
-
def initialize
|
5
|
+
def initialize(_config = Configuration.instance)
|
61
6
|
@file_cache = {}
|
62
|
-
@
|
7
|
+
@config = _config
|
8
|
+
@js_file = JsFile.new()
|
63
9
|
end
|
64
10
|
|
65
11
|
def convert(base_url, html, css="", width=1000, height=700)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
infile_name = infile.path
|
72
|
-
|
73
|
-
outfile = Tempfile.new(['phantom_render','.png'])
|
74
|
-
outfile_name = outfile.path
|
75
|
-
|
76
|
-
begin
|
77
|
-
infile.write(html_content)
|
78
|
-
infile.rewind
|
79
|
-
%x[#{PROGRAM} #{RASTERIZE_JS} #{infile_name} #{outfile_name} #{width}*#{height}]
|
80
|
-
@file_cache[signature] = {'png' => PngFile.new(outfile), 'html' => HtmlFile.new(infile) }
|
81
|
-
ensure
|
82
|
-
infile.close
|
12
|
+
job = PhantomJob.new(base_url, html, css, width, height)
|
13
|
+
key = job.cache_key
|
14
|
+
unless (@file_cache[key])
|
15
|
+
job.rasterize
|
16
|
+
@file_cache[key] = {'html' => job.html_file, 'png' => job.png_file }
|
83
17
|
end
|
84
|
-
return
|
18
|
+
return key
|
85
19
|
end
|
86
20
|
|
87
21
|
def get_png_file(sha)
|
data/lib/shutterbug.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
module Shutterbug
|
2
|
-
VERSION = "0.0.
|
2
|
+
VERSION = "0.0.6"
|
3
3
|
autoload :Service, "shutterbug/service"
|
4
4
|
autoload :Rackapp, "shutterbug/rackapp"
|
5
|
+
autoload :Configuration, "shutterbug/configuration"
|
6
|
+
autoload :BugFile, "shutterbug/bug_file"
|
7
|
+
autoload :HtmlFile, "shutterbug/html_file"
|
8
|
+
autoload :PngFile, "shutterbug/png_file"
|
9
|
+
autoload :JsFile, "shutterbug/js_file"
|
10
|
+
autoload :PhantomJob, "shutterbug/phantom_job"
|
5
11
|
end
|
@@ -6,11 +6,13 @@ RSpec::Matchers.define :be_happy_response do |filetype|
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe Shutterbug::Rackapp do
|
9
|
-
let(:sha) { "542112e"
|
10
|
-
let(:size) { 200
|
11
|
-
let(:rackfile){ mock :fackfile, :size => size
|
12
|
-
let(:service) { mock :service
|
13
|
-
let(:app) { mock :app
|
9
|
+
let(:sha) { "542112e" }
|
10
|
+
let(:size) { 200 }
|
11
|
+
let(:rackfile){ mock :fackfile, :size => size }
|
12
|
+
let(:service) { mock :service }
|
13
|
+
let(:app) { mock :app }
|
14
|
+
let(:config) { Shutterbug::Configuration.instance }
|
15
|
+
|
14
16
|
let(:post_data) do
|
15
17
|
{
|
16
18
|
'content' => "<div class='foo'>foo!</div>",
|
@@ -20,6 +22,7 @@ describe Shutterbug::Rackapp do
|
|
20
22
|
'base_url' => "http://localhost:8080/"
|
21
23
|
}
|
22
24
|
end
|
25
|
+
|
23
26
|
subject { Shutterbug::Rackapp.new(app) }
|
24
27
|
|
25
28
|
before(:each) do
|
@@ -46,7 +49,7 @@ describe Shutterbug::Rackapp do
|
|
46
49
|
end
|
47
50
|
|
48
51
|
describe "convert route" do
|
49
|
-
let(:path) {
|
52
|
+
let(:path) { config.convert_path }
|
50
53
|
let(:image_response) { mock :image_response }
|
51
54
|
it "should route #do_convert" do
|
52
55
|
subject.should_receive(:do_convert, :with => req).and_return image_response
|
@@ -55,7 +58,7 @@ describe Shutterbug::Rackapp do
|
|
55
58
|
end
|
56
59
|
|
57
60
|
describe "get png route" do
|
58
|
-
let(:path) {
|
61
|
+
let(:path) { config.png_path(sha) }
|
59
62
|
it "should route #do_get_png" do
|
60
63
|
service.should_receive(:get_png_file, :with => sha).and_return rackfile
|
61
64
|
subject.call(mock).should be_happy_response('image/png')
|
@@ -63,7 +66,7 @@ describe Shutterbug::Rackapp do
|
|
63
66
|
end
|
64
67
|
|
65
68
|
describe "get html route" do
|
66
|
-
let(:path) {
|
69
|
+
let(:path) { config.html_path(sha) }
|
67
70
|
it "should route #do_get_html" do
|
68
71
|
service.should_receive(:get_html_file, :with => sha).and_return rackfile
|
69
72
|
subject.call(mock).should be_happy_response('text/html')
|
@@ -71,7 +74,7 @@ describe Shutterbug::Rackapp do
|
|
71
74
|
end
|
72
75
|
|
73
76
|
describe "get shutterbug javascipt route" do
|
74
|
-
let(:path) {
|
77
|
+
let(:path) { config.js_path }
|
75
78
|
it "should route #do_get_shutterbug" do
|
76
79
|
service.should_receive(:get_shutterbug_file).and_return rackfile
|
77
80
|
subject.call(mock).should be_happy_response('application/javascript')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shutterbug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -112,6 +112,12 @@ files:
|
|
112
112
|
- README.md
|
113
113
|
- Rakefile
|
114
114
|
- lib/shutterbug.rb
|
115
|
+
- lib/shutterbug/bug_file.rb
|
116
|
+
- lib/shutterbug/configuration.rb
|
117
|
+
- lib/shutterbug/html_file.rb
|
118
|
+
- lib/shutterbug/js_file.rb
|
119
|
+
- lib/shutterbug/phantom_job.rb
|
120
|
+
- lib/shutterbug/png_file.rb
|
115
121
|
- lib/shutterbug/rackapp.rb
|
116
122
|
- lib/shutterbug/rasterize.js
|
117
123
|
- lib/shutterbug/service.rb
|
@@ -134,7 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
140
|
version: '0'
|
135
141
|
segments:
|
136
142
|
- 0
|
137
|
-
hash:
|
143
|
+
hash: -488192167171583670
|
138
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
145
|
none: false
|
140
146
|
requirements:
|
@@ -143,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
149
|
version: '0'
|
144
150
|
segments:
|
145
151
|
- 0
|
146
|
-
hash:
|
152
|
+
hash: -488192167171583670
|
147
153
|
requirements: []
|
148
154
|
rubyforge_project:
|
149
155
|
rubygems_version: 1.8.23
|