imgkit 0.9.2
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/.document +5 -0
- data/.gitignore +22 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +35 -0
- data/LICENSE +22 -0
- data/POST_INSTALL +8 -0
- data/README.md +82 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/imgkit +72 -0
- data/imgkit.gemspec +84 -0
- data/lib/imgkit.rb +5 -0
- data/lib/imgkit/configuration.rb +33 -0
- data/lib/imgkit/imgkit.rb +147 -0
- data/lib/imgkit/source.rb +27 -0
- data/spec/fixtures/example.css +1 -0
- data/spec/fixtures/example.html +5 -0
- data/spec/imgkit_spec.rb +182 -0
- data/spec/source_spec.rb +73 -0
- data/spec/spec_helper.rb +19 -0
- metadata +143 -0
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2@imgkit_devel
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
gemcutter (0.6.1)
|
6
|
+
git (1.2.5)
|
7
|
+
jeweler (1.4.0)
|
8
|
+
gemcutter (>= 0.1.0)
|
9
|
+
git (>= 1.2.5)
|
10
|
+
rubyforge (>= 2.0.0)
|
11
|
+
json_pure (1.4.3)
|
12
|
+
mocha (0.9.8)
|
13
|
+
rake
|
14
|
+
rack (1.2.1)
|
15
|
+
rake (0.8.7)
|
16
|
+
rspec (2.0.0.beta.19)
|
17
|
+
rspec-core (= 2.0.0.beta.19)
|
18
|
+
rspec-expectations (= 2.0.0.beta.19)
|
19
|
+
rspec-mocks (= 2.0.0.beta.19)
|
20
|
+
rspec-core (2.0.0.beta.19)
|
21
|
+
rspec-expectations (2.0.0.beta.19)
|
22
|
+
diff-lcs (>= 1.1.2)
|
23
|
+
rspec-mocks (2.0.0.beta.19)
|
24
|
+
rubyforge (2.0.4)
|
25
|
+
json_pure (>= 1.1.7)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
jeweler
|
32
|
+
mocha
|
33
|
+
rack
|
34
|
+
rspec (~> 2.0.0.beta.8)
|
35
|
+
rspec-core (~> 2.0.0.beta.8)
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
This is a derivative work.
|
2
|
+
|
3
|
+
Original Copyright (c) 2009 jdpace
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/POST_INSTALL
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
******************************************************************
|
2
|
+
|
3
|
+
Now install wkhtmltoimage binaries:
|
4
|
+
Global: sudo `which imgkit` --install-wkhtmltoimage
|
5
|
+
or inside RVM folder: export TO=`which imgkit | sed 's:/imgkit:/wkhtmltoimage:'` && imgkit --install-wkhtmltoimage
|
6
|
+
(run imgkit --help to see more options)
|
7
|
+
|
8
|
+
******************************************************************
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# IMGKit
|
2
|
+
|
3
|
+
Create JPGs using plain old HTML+CSS. Uses [wkhtmltoimage](http://github.com/antialize/wkhtmltopdf) on the backend which renders HTML using Webkit.
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
### IMGKit
|
8
|
+
|
9
|
+
gem install imgkit
|
10
|
+
|
11
|
+
### wkhtmltoimage
|
12
|
+
* **Automatic**: `sudo imgkit --install-wkhtmltoimage`
|
13
|
+
install latest version into /usr/local/bin
|
14
|
+
(overwrite defaults with e.g. ARCHITECTURE=amd64 TO=/home/foo/bin)
|
15
|
+
* By hand: http://code.google.com/p/wkhtmltopdf/downloads/list
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
# IMGKit.new takes the HTML and any options for wkhtmltoimage
|
20
|
+
# run `wkhtmltoimage --extended-help` for a full list of options
|
21
|
+
kit = IMGKit.new(html, :quality => 50)
|
22
|
+
kit.stylesheets << '/path/to/css/file'
|
23
|
+
|
24
|
+
# Get an inline image
|
25
|
+
img = kit.to_img
|
26
|
+
|
27
|
+
# Save the PDF to a file
|
28
|
+
file = kit.to_file('/path/to/save/file.jpg')
|
29
|
+
|
30
|
+
# IMGKit.new can optionally accept a URL or a File.
|
31
|
+
# Stylesheets can not be added when source is provided as a URL of File.
|
32
|
+
kit = IMGKit.new('http://google.com')
|
33
|
+
kit = IMGKit.new(File.new('/path/to/html'))
|
34
|
+
|
35
|
+
# Add any kind of option through meta tags
|
36
|
+
IMGKit.new('<html><head><meta name="imgkit-quality" content="75")
|
37
|
+
|
38
|
+
## Configuration
|
39
|
+
|
40
|
+
If you're on Windows or you installed wkhtmltopdf by hand to a location other than /usr/local/bin you will need to tell PDFKit where the binary is. You can configure PDFKit like so:
|
41
|
+
|
42
|
+
# config/initializers/imgkit.rb
|
43
|
+
IMGKit.configure do |config|
|
44
|
+
config.wkhtmltoimage = '/path/to/wkhtmltoimage'
|
45
|
+
config.default_options = {
|
46
|
+
:quality => 60
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
## Mime Types
|
52
|
+
register a .jpg mime type in:
|
53
|
+
|
54
|
+
#config/initializers/mime_type.rb
|
55
|
+
Mime::Type.register "image/jpeg", :jpg
|
56
|
+
|
57
|
+
## Controllers
|
58
|
+
You can then send JPGs with
|
59
|
+
|
60
|
+
format.jpg do
|
61
|
+
send_data(@kit.to_img, :type => "image/jpeg", :disposition => 'inline')
|
62
|
+
end
|
63
|
+
|
64
|
+
This allows you to take advantage of rails page caching so you only generate the
|
65
|
+
image when you need to.
|
66
|
+
|
67
|
+
## Note on Patches/Pull Requests
|
68
|
+
|
69
|
+
* Fork the project.
|
70
|
+
* Setup your development environment with: gem install bundler; bundle install
|
71
|
+
* Make your feature addition or bug fix.
|
72
|
+
* Add tests for it. This is important so I don't break it in a
|
73
|
+
future version unintentionally.
|
74
|
+
* Commit, do not mess with rakefile, version, or history.
|
75
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
76
|
+
* Send me a pull request. Bonus points for topic branches.
|
77
|
+
|
78
|
+
## Copyright
|
79
|
+
|
80
|
+
Copyright (c) 2010 Chris Continanza
|
81
|
+
Based on work by Jared Pace
|
82
|
+
See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.require(:development)
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = "imgkit"
|
10
|
+
gem.summary = %Q{HTML+CSS -> JPG}
|
11
|
+
gem.description = %Q{Uses wkhtmltoimage to create Images using HTML}
|
12
|
+
gem.email = "christopher.continanza@gmail.com"
|
13
|
+
gem.homepage = "http://github.com/csquared/IMGKit"
|
14
|
+
gem.authors = ["csquared"]
|
15
|
+
gem.add_development_dependency "rspec", "~> 2.0.0.beta.8"
|
16
|
+
gem.add_development_dependency "rspec-core", "~> 2.0.0.beta.8"
|
17
|
+
gem.add_development_dependency 'mocha'
|
18
|
+
gem.post_install_message = File.read('POST_INSTALL')
|
19
|
+
end
|
20
|
+
Jeweler::GemcutterTasks.new
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rspec/core/rake_task'
|
26
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
27
|
+
end
|
28
|
+
|
29
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
40
|
+
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
42
|
+
rdoc.title = "IMGKit #{version}"
|
43
|
+
rdoc.rdoc_files.include('README*')
|
44
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.9.2
|
data/bin/imgkit
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'optparse'
|
4
|
+
require 'rbconfig'
|
5
|
+
require 'open-uri'
|
6
|
+
require 'imgkit/configuration'
|
7
|
+
|
8
|
+
def detect_architecture
|
9
|
+
case Config::CONFIG['host_os']
|
10
|
+
when /x86_64-linux/i
|
11
|
+
'amd64'
|
12
|
+
when /linux/i
|
13
|
+
'i386'
|
14
|
+
when /darwin/i
|
15
|
+
'OS-X.i386'
|
16
|
+
else
|
17
|
+
raise "No binaries found for your system. Please install wkhtmltoimage by hand."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def cleanup(install_to)
|
22
|
+
`rm -rf wkhtmltoimage*`
|
23
|
+
`rm #{install_to}`
|
24
|
+
end
|
25
|
+
|
26
|
+
def download_wkhtmltoimage(arch)
|
27
|
+
page = open("http://code.google.com/p/wkhtmltopdf/downloads/list").read
|
28
|
+
download = page.match(/href=".*name=(.*wkhtmltoimage-.*#{arch}.*?)&/) || raise("File not found..")
|
29
|
+
download = download[1]
|
30
|
+
url = "http://wkhtmltopdf.googlecode.com/files/#{download}"
|
31
|
+
puts "Downloading #{download} from #{url}"
|
32
|
+
|
33
|
+
`curl #{url} > #{download}`
|
34
|
+
download
|
35
|
+
end
|
36
|
+
|
37
|
+
def install(download, arch, install_to)
|
38
|
+
puts "Installing #{download} to #{install_to}"
|
39
|
+
if download =~ /.tar.bz2$/
|
40
|
+
`tar xjvf #{download}`
|
41
|
+
`mv wkhtmltoimage-#{arch} #{install_to}`
|
42
|
+
elsif download =~ /.tar.lzma$/
|
43
|
+
raise "couldn't extract archive: lzcat not found" unless system("which lzcat > /dev/null 2>/dev/null")
|
44
|
+
`lzcat #{download} | tar x`
|
45
|
+
`mv wkhtmltoimage-#{arch} #{install_to}`
|
46
|
+
else
|
47
|
+
`mv #{download} #{install_to}`
|
48
|
+
end
|
49
|
+
`sudo chmod +x #{install_to}`
|
50
|
+
end
|
51
|
+
|
52
|
+
OptionParser.new do |parser|
|
53
|
+
parser.banner = "IMGKit\n\nOptions are:"
|
54
|
+
|
55
|
+
parser.on("--install-wkhtmltoimage", "Install wkhtmltoimage binaries (TO=/usr/local/bin ARCHITECTURE=i386)") do
|
56
|
+
architecture = ENV['ARCHITECTURE'] || detect_architecture
|
57
|
+
install_to = ENV['TO'] || IMGKit.configuration.wkhtmltoimage
|
58
|
+
|
59
|
+
Dir.chdir '/tmp'
|
60
|
+
|
61
|
+
cleanup(install_to)
|
62
|
+
download = download_wkhtmltoimage(architecture)
|
63
|
+
install(download, architecture, install_to)
|
64
|
+
end
|
65
|
+
|
66
|
+
parser.on("--version", "Show Version.") do
|
67
|
+
root = File.dirname(File.dirname(__FILE__))
|
68
|
+
puts File.read(File.join(root, 'VERSION'))
|
69
|
+
end
|
70
|
+
|
71
|
+
parser.on("-h", "--help", "Show this.") { puts parser; exit }
|
72
|
+
end.parse!
|
data/imgkit.gemspec
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{imgkit}
|
8
|
+
s.version = "0.9.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["csquared"]
|
12
|
+
s.date = %q{2010-12-12}
|
13
|
+
s.default_executable = %q{imgkit}
|
14
|
+
s.description = %q{Uses wkhtmltoimage to create Images using HTML}
|
15
|
+
s.email = %q{christopher.continanza@gmail.com}
|
16
|
+
s.executables = ["imgkit"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.md"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".gitignore",
|
24
|
+
".rspec",
|
25
|
+
".rvmrc",
|
26
|
+
"Gemfile",
|
27
|
+
"Gemfile.lock",
|
28
|
+
"LICENSE",
|
29
|
+
"POST_INSTALL",
|
30
|
+
"README.md",
|
31
|
+
"Rakefile",
|
32
|
+
"VERSION",
|
33
|
+
"bin/imgkit",
|
34
|
+
"imgkit.gemspec",
|
35
|
+
"lib/imgkit.rb",
|
36
|
+
"lib/imgkit/configuration.rb",
|
37
|
+
"lib/imgkit/imgkit.rb",
|
38
|
+
"lib/imgkit/source.rb",
|
39
|
+
"spec/fixtures/example.css",
|
40
|
+
"spec/fixtures/example.html",
|
41
|
+
"spec/imgkit_spec.rb",
|
42
|
+
"spec/source_spec.rb",
|
43
|
+
"spec/spec_helper.rb"
|
44
|
+
]
|
45
|
+
s.homepage = %q{http://github.com/csquared/IMGKit}
|
46
|
+
s.post_install_message = %q{******************************************************************
|
47
|
+
|
48
|
+
Now install wkhtmltoimage binaries:
|
49
|
+
Global: sudo `which imgkit` --install-wkhtmltoimage
|
50
|
+
or inside RVM folder: export TO=`which imgkit | sed 's:/imgkit:/wkhtmltoimage:'` && imgkit --install-wkhtmltoimage
|
51
|
+
(run imgkit --help to see more options)
|
52
|
+
|
53
|
+
******************************************************************
|
54
|
+
}
|
55
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
56
|
+
s.require_paths = ["lib"]
|
57
|
+
s.rubygems_version = %q{1.3.7}
|
58
|
+
s.summary = %q{HTML+CSS -> JPG}
|
59
|
+
s.test_files = [
|
60
|
+
"spec/imgkit_spec.rb",
|
61
|
+
"spec/source_spec.rb",
|
62
|
+
"spec/spec_helper.rb"
|
63
|
+
]
|
64
|
+
|
65
|
+
if s.respond_to? :specification_version then
|
66
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
67
|
+
s.specification_version = 3
|
68
|
+
|
69
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
70
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.0.0.beta.8"])
|
71
|
+
s.add_development_dependency(%q<rspec-core>, ["~> 2.0.0.beta.8"])
|
72
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
73
|
+
else
|
74
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.0.beta.8"])
|
75
|
+
s.add_dependency(%q<rspec-core>, ["~> 2.0.0.beta.8"])
|
76
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
77
|
+
end
|
78
|
+
else
|
79
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.0.beta.8"])
|
80
|
+
s.add_dependency(%q<rspec-core>, ["~> 2.0.0.beta.8"])
|
81
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
data/lib/imgkit.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class IMGKit
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :meta_tag_prefix, :wkhtmltoimage, :default_options
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@meta_tag_prefix = 'imgkit-'
|
7
|
+
@wkhtmltoimage = '/usr/local/bin/wkhtmltoimage'
|
8
|
+
@default_options = {}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
# Configure IMGKit someplace sensible,
|
17
|
+
# like config/initializers/imgkit.rb
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# IMGKit.configure do |config|
|
21
|
+
# config.wkhtmltoimage = '/usr/bin/wkhtmltoimage'
|
22
|
+
# end
|
23
|
+
|
24
|
+
def self.configuration
|
25
|
+
@configuration ||= Configuration.new
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def self.configure
|
30
|
+
self.configuration
|
31
|
+
yield(configuration)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
class IMGKit
|
2
|
+
|
3
|
+
class NoExecutableError < StandardError
|
4
|
+
def initialize
|
5
|
+
msg = "No wkhtmltoimage executable found at #{IMGKit.configuration.wkhtmltoimage}\n"
|
6
|
+
msg << ">> Install wkhtmltoimage by hand or try running `imgkit --install-wkhtmltoimage`"
|
7
|
+
super(msg)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ImproperSourceError < StandardError
|
12
|
+
def initialize(msg)
|
13
|
+
super("Improper Source: #{msg}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_accessor :source, :stylesheets
|
18
|
+
attr_reader :options
|
19
|
+
|
20
|
+
def initialize(url_file_or_html, options = {})
|
21
|
+
@source = Source.new(url_file_or_html)
|
22
|
+
|
23
|
+
@stylesheets = []
|
24
|
+
|
25
|
+
@options = IMGKit.configuration.default_options.merge(options)
|
26
|
+
@options.merge! find_options_in_meta(url_file_or_html) unless source.url?
|
27
|
+
@options = normalize_options(@options)
|
28
|
+
|
29
|
+
raise NoExecutableError.new unless File.exists?(IMGKit.configuration.wkhtmltoimage)
|
30
|
+
end
|
31
|
+
|
32
|
+
def command
|
33
|
+
args = [executable]
|
34
|
+
args += @options.to_a.flatten.compact
|
35
|
+
|
36
|
+
if @source.html?
|
37
|
+
args << '-' # Get HTML from stdin
|
38
|
+
else
|
39
|
+
args << @source.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
args << '-' # Read IMG from stdout
|
43
|
+
args
|
44
|
+
end
|
45
|
+
|
46
|
+
def executable
|
47
|
+
default = IMGKit.configuration.wkhtmltoimage
|
48
|
+
return default if default !~ /^\// # its not a path, so nothing we can do
|
49
|
+
if File.exist?(default)
|
50
|
+
default
|
51
|
+
else
|
52
|
+
default.split('/').last
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_img
|
57
|
+
append_stylesheets
|
58
|
+
|
59
|
+
=begin Need to use Open3 b.c wkhtmltoimage has to --quiet option
|
60
|
+
and we need to slience $stderr
|
61
|
+
image = Kernel.open('|-', "w+")
|
62
|
+
exec(*command) if image.nil?
|
63
|
+
image.puts(@source.to_s) if @source.html?
|
64
|
+
image.close_write
|
65
|
+
result = image.gets(nil)
|
66
|
+
image.close_read
|
67
|
+
=end
|
68
|
+
|
69
|
+
result = nil
|
70
|
+
Open3.popen3(*command) do |stdin,stdout,stderr|
|
71
|
+
stdin << (@source.to_s) if @source.html?
|
72
|
+
stdin.close
|
73
|
+
result = stdout.gets(nil)
|
74
|
+
stdout.close
|
75
|
+
stderr.close
|
76
|
+
end
|
77
|
+
|
78
|
+
raise "command failed: #{command.join(' ')}" unless result
|
79
|
+
return result
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_file(path)
|
83
|
+
File.open(path,'w') {|file| file << self.to_img}
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def find_options_in_meta(body)
|
89
|
+
imgkit_meta_tags(body).inject({}) do |found, tag|
|
90
|
+
name = tag.attributes["name"].sub(/^#{IMGKit.configuration.meta_tag_prefix}/, '').to_sym
|
91
|
+
found.merge(name => tag.attributes["content"])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def imgkit_meta_tags(body)
|
96
|
+
require 'rexml/document'
|
97
|
+
xml_body = REXML::Document.new(body)
|
98
|
+
found = []
|
99
|
+
xml_body.elements.each("html/head/meta") do |tag|
|
100
|
+
found << tag if tag.attributes['name'].to_s =~ /^#{IMGKit.configuration.meta_tag_prefix}/
|
101
|
+
end
|
102
|
+
found
|
103
|
+
rescue # rexml random crash on invalid xml
|
104
|
+
[]
|
105
|
+
end
|
106
|
+
|
107
|
+
def style_tag_for(stylesheet)
|
108
|
+
"<style>#{File.read(stylesheet)}</style>"
|
109
|
+
end
|
110
|
+
|
111
|
+
def append_stylesheets
|
112
|
+
raise ImproperSourceError.new('Stylesheets may only be added to an HTML source') if stylesheets.any? && !@source.html?
|
113
|
+
|
114
|
+
stylesheets.each do |stylesheet|
|
115
|
+
if @source.to_s.match(/<\/head>/)
|
116
|
+
@source.to_s.gsub!(/(<\/head>)/, style_tag_for(stylesheet)+'\1')
|
117
|
+
else
|
118
|
+
@source.to_s.insert(0, style_tag_for(stylesheet))
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def normalize_options(options)
|
124
|
+
normalized_options = {}
|
125
|
+
|
126
|
+
options.each do |key, value|
|
127
|
+
next if !value
|
128
|
+
normalized_key = "--#{normalize_arg key}"
|
129
|
+
normalized_options[normalized_key] = normalize_value(value)
|
130
|
+
end
|
131
|
+
normalized_options
|
132
|
+
end
|
133
|
+
|
134
|
+
def normalize_arg(arg)
|
135
|
+
arg.to_s.downcase.gsub(/[^a-z0-9]/,'-')
|
136
|
+
end
|
137
|
+
|
138
|
+
def normalize_value(value)
|
139
|
+
case value
|
140
|
+
when TrueClass
|
141
|
+
nil
|
142
|
+
else
|
143
|
+
value.to_s
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class IMGKit
|
2
|
+
|
3
|
+
class Source
|
4
|
+
|
5
|
+
def initialize(url_file_or_html)
|
6
|
+
@source = url_file_or_html
|
7
|
+
end
|
8
|
+
|
9
|
+
def url?
|
10
|
+
@source.is_a?(String) && @source.match(/^http/)
|
11
|
+
end
|
12
|
+
|
13
|
+
def file?
|
14
|
+
@source.kind_of?(File)
|
15
|
+
end
|
16
|
+
|
17
|
+
def html?
|
18
|
+
!(url? || file?)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
file? ? @source.path : @source
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
body { font-size: 20px; }
|
data/spec/imgkit_spec.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe IMGKit do
|
4
|
+
context "initialization" do
|
5
|
+
it "should accept HTML as the source" do
|
6
|
+
imgkit = IMGKit.new('<h1>Oh Hai</h1>')
|
7
|
+
imgkit.source.should be_html
|
8
|
+
imgkit.source.to_s.should == '<h1>Oh Hai</h1>'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should accept a URL as the source" do
|
12
|
+
imgkit = IMGKit.new('http://google.com')
|
13
|
+
imgkit.source.should be_url
|
14
|
+
imgkit.source.to_s.should == 'http://google.com'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should accept a File as the source" do
|
18
|
+
file_path = File.join(SPEC_ROOT,'fixtures','example.html')
|
19
|
+
imgkit = IMGKit.new(File.new(file_path))
|
20
|
+
imgkit.source.should be_file
|
21
|
+
imgkit.source.to_s.should == file_path
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should parse the options into a cmd line friedly format" do
|
25
|
+
imgkit = IMGKit.new('html', :quality => 75)
|
26
|
+
imgkit.options.should have_key('--quality')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should provide no default options" do
|
30
|
+
imgkit = IMGKit.new('<h1>Oh Hai</h1>')
|
31
|
+
imgkit.options.should be_empty
|
32
|
+
end
|
33
|
+
|
34
|
+
=begin
|
35
|
+
it "should default to 'UTF-8' encoding" do
|
36
|
+
imgkit = IMGKit.new('Captación')
|
37
|
+
end
|
38
|
+
=end
|
39
|
+
|
40
|
+
it "should not have any stylesheedt by default" do
|
41
|
+
imgkit = IMGKit.new('<h1>Oh Hai</h1>')
|
42
|
+
imgkit.stylesheets.should be_empty
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "command" do
|
47
|
+
it "should contstruct the correct command" do
|
48
|
+
imgkit = IMGKit.new('html')
|
49
|
+
imgkit.command[0].should include('wkhtmltoimage')
|
50
|
+
imgkit.command.should include('-')
|
51
|
+
end
|
52
|
+
|
53
|
+
it "will not include default options it is told to omit" do
|
54
|
+
imgkit = IMGKit.new('html')
|
55
|
+
imgkit = IMGKit.new('html', :disable_smart_shrinking => false)
|
56
|
+
imgkit.command.should_not include('--disable-smart-shrinking')
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should encapsulate string arguments in quotes" do
|
60
|
+
imgkit = IMGKit.new('html', :header_center => "foo [page]")
|
61
|
+
imgkit.command[imgkit.command.index('--header-center') + 1].should == 'foo [page]'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "read the source from stdin if it is html" do
|
65
|
+
imgkit = IMGKit.new('html')
|
66
|
+
imgkit.command[-2..-1].should == ['-', '-']
|
67
|
+
end
|
68
|
+
|
69
|
+
it "specify the URL to the source if it is a url" do
|
70
|
+
imgkit = IMGKit.new('http://google.com')
|
71
|
+
imgkit.command[-2..-1].should == ['http://google.com', '-']
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should specify the path to the source if it is a file" do
|
75
|
+
file_path = File.join(SPEC_ROOT,'fixtures','example.html')
|
76
|
+
imgkit = IMGKit.new(File.new(file_path))
|
77
|
+
imgkit.command[-2..-1].should == [file_path, '-']
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should detect special imgkit meta tags" do
|
81
|
+
body = %{
|
82
|
+
<html>
|
83
|
+
<head>
|
84
|
+
<meta name="imgkit-page_size" content="Legal"/>
|
85
|
+
<meta name="imgkit-orientation" content="Landscape"/>
|
86
|
+
</head>
|
87
|
+
</html>
|
88
|
+
}
|
89
|
+
imgkit = IMGKit.new(body)
|
90
|
+
imgkit.command[imgkit.command.index('--page-size') + 1].should == 'Legal'
|
91
|
+
imgkit.command[imgkit.command.index('--orientation') + 1].should == 'Landscape'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "#to_img" do
|
96
|
+
def filetype_of(img)
|
97
|
+
result = nil
|
98
|
+
tmpfile = Tempfile.new('imgkit')
|
99
|
+
File.open(tmpfile.path, 'w') { |f| f << img }
|
100
|
+
result = `file #{tmpfile.path}`
|
101
|
+
tmpfile.unlink()
|
102
|
+
result
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should generate a IMG of the HTML" do
|
106
|
+
imgkit = IMGKit.new('html')
|
107
|
+
img = imgkit.to_img
|
108
|
+
filetype_of(img).should include('JPEG')
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should generate an Image with a numerical parameter" do
|
112
|
+
imgkit = IMGKit.new('html', :quality => 50)
|
113
|
+
img = imgkit.to_img
|
114
|
+
filetype_of(img).should include('JPEG')
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should generate an Image with a symbol parameter" do
|
118
|
+
imgkit = IMGKit.new('html', :username => 'chris')
|
119
|
+
img = imgkit.to_img
|
120
|
+
filetype_of(img).should include('JPEG')
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should have the stylesheet added to the head if it has one" do
|
124
|
+
imgkit = IMGKit.new("<html><head></head><body>Hai!</body></html>")
|
125
|
+
css = File.join(SPEC_ROOT,'fixtures','example.css')
|
126
|
+
imgkit.stylesheets << css
|
127
|
+
imgkit.to_img
|
128
|
+
imgkit.source.to_s.should include("<style>#{File.read(css)}</style>")
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should prepend style tags if the HTML doesn't have a head tag" do
|
132
|
+
imgkit = IMGKit.new("<html><body>Hai!</body></html>")
|
133
|
+
css = File.join(SPEC_ROOT,'fixtures','example.css')
|
134
|
+
imgkit.stylesheets << css
|
135
|
+
imgkit.to_img
|
136
|
+
imgkit.source.to_s.should include("<style>#{File.read(css)}</style><html>")
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should throw an error if the source is not html and stylesheets have been added" do
|
140
|
+
imgkit = IMGKit.new('http://google.com')
|
141
|
+
css = File.join(SPEC_ROOT,'fixtures','example.css')
|
142
|
+
imgkit.stylesheets << css
|
143
|
+
lambda { imgkit.to_img }.should raise_error(IMGKit::ImproperSourceError)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "#to_file" do
|
148
|
+
before do
|
149
|
+
@file_path = File.join(SPEC_ROOT,'fixtures','test.jpg')
|
150
|
+
File.delete(@file_path) if File.exist?(@file_path)
|
151
|
+
end
|
152
|
+
|
153
|
+
after do
|
154
|
+
File.delete(@file_path)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should create a file with the result of :to_img as content" do
|
158
|
+
imgkit = IMGKit.new('html', :quality => 50)
|
159
|
+
imgkit.expects(:to_img).returns('CONTENT')
|
160
|
+
file = imgkit.to_file(@file_path)
|
161
|
+
file.should be_instance_of(File)
|
162
|
+
File.read(file.path).should == 'CONTENT'
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "security" do
|
167
|
+
before do
|
168
|
+
@test_path = File.join(SPEC_ROOT,'fixtures','security-oops')
|
169
|
+
File.delete(@test_path) if File.exist?(@test_path)
|
170
|
+
end
|
171
|
+
|
172
|
+
after do
|
173
|
+
File.delete(@test_path) if File.exist?(@test_path)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should not allow shell injection in options" do
|
177
|
+
imgkit = IMGKit.new('html', :password => "blah\"; touch #{@test_path} #")
|
178
|
+
imgkit.to_img
|
179
|
+
File.exist?(@test_path).should be_false
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/spec/source_spec.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe IMGKit::Source do
|
4
|
+
|
5
|
+
describe "#url?" do
|
6
|
+
it "should return true if passed a url like string" do
|
7
|
+
source = IMGKit::Source.new('http://google.com')
|
8
|
+
source.should be_url
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return false if passed a file" do
|
12
|
+
source = IMGKit::Source.new(File.new(__FILE__))
|
13
|
+
source.should_not be_url
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should return false if passed HTML" do
|
17
|
+
source = IMGKit::Source.new('<blink>Oh Hai!</blink>')
|
18
|
+
source.should_not be_url
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#file?" do
|
23
|
+
it "should return true if passed a file" do
|
24
|
+
source = IMGKit::Source.new(File.new(__FILE__))
|
25
|
+
source.should be_file
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return false if passed a url like string" do
|
29
|
+
source = IMGKit::Source.new('http://google.com')
|
30
|
+
source.should_not be_file
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return false if passed HTML" do
|
34
|
+
source = IMGKit::Source.new('<blink>Oh Hai!</blink>')
|
35
|
+
source.should_not be_file
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#html?" do
|
40
|
+
it "should return true if passed HTML" do
|
41
|
+
source = IMGKit::Source.new('<blink>Oh Hai!</blink>')
|
42
|
+
source.should be_html
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return false if passed a file" do
|
46
|
+
source = IMGKit::Source.new(File.new(__FILE__))
|
47
|
+
source.should_not be_html
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return false if passed a url like string" do
|
51
|
+
source = IMGKit::Source.new('http://google.com')
|
52
|
+
source.should_not be_html
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#to_s" do
|
57
|
+
it "should return the HTML if passed HTML" do
|
58
|
+
source = IMGKit::Source.new('<blink>Oh Hai!</blink>')
|
59
|
+
source.to_s.should == '<blink>Oh Hai!</blink>'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return a path if passed a file" do
|
63
|
+
source = IMGKit::Source.new(File.new(__FILE__))
|
64
|
+
source.to_s.should == __FILE__
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return the url if passed a url like string" do
|
68
|
+
source = IMGKit::Source.new('http://google.com')
|
69
|
+
source.to_s.should == 'http://google.com'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
SPEC_ROOT = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift(SPEC_ROOT)
|
3
|
+
$LOAD_PATH.unshift(File.join(SPEC_ROOT, '..', 'lib'))
|
4
|
+
require 'imgkit'
|
5
|
+
require 'rspec'
|
6
|
+
require 'rspec/autorun'
|
7
|
+
require 'mocha'
|
8
|
+
require 'rack'
|
9
|
+
require 'tempfile'
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
|
13
|
+
config.before do
|
14
|
+
IMGKit.any_instance.stubs(:wkhtmltoimage).returns(
|
15
|
+
File.join(SPEC_ROOT,'..','bin','wkhtmltoimage-proxy')
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: imgkit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 9
|
8
|
+
- 2
|
9
|
+
version: 0.9.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- csquared
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-12 00:00:00 -06:00
|
18
|
+
default_executable: imgkit
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 2
|
30
|
+
- 0
|
31
|
+
- 0
|
32
|
+
- beta
|
33
|
+
- 8
|
34
|
+
version: 2.0.0.beta.8
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec-core
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
segments:
|
46
|
+
- 2
|
47
|
+
- 0
|
48
|
+
- 0
|
49
|
+
- beta
|
50
|
+
- 8
|
51
|
+
version: 2.0.0.beta.8
|
52
|
+
type: :development
|
53
|
+
version_requirements: *id002
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: mocha
|
56
|
+
prerelease: false
|
57
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
type: :development
|
66
|
+
version_requirements: *id003
|
67
|
+
description: Uses wkhtmltoimage to create Images using HTML
|
68
|
+
email: christopher.continanza@gmail.com
|
69
|
+
executables:
|
70
|
+
- imgkit
|
71
|
+
extensions: []
|
72
|
+
|
73
|
+
extra_rdoc_files:
|
74
|
+
- LICENSE
|
75
|
+
- README.md
|
76
|
+
files:
|
77
|
+
- .document
|
78
|
+
- .gitignore
|
79
|
+
- .rspec
|
80
|
+
- .rvmrc
|
81
|
+
- Gemfile
|
82
|
+
- Gemfile.lock
|
83
|
+
- LICENSE
|
84
|
+
- POST_INSTALL
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- VERSION
|
88
|
+
- bin/imgkit
|
89
|
+
- imgkit.gemspec
|
90
|
+
- lib/imgkit.rb
|
91
|
+
- lib/imgkit/configuration.rb
|
92
|
+
- lib/imgkit/imgkit.rb
|
93
|
+
- lib/imgkit/source.rb
|
94
|
+
- spec/fixtures/example.css
|
95
|
+
- spec/fixtures/example.html
|
96
|
+
- spec/imgkit_spec.rb
|
97
|
+
- spec/source_spec.rb
|
98
|
+
- spec/spec_helper.rb
|
99
|
+
has_rdoc: true
|
100
|
+
homepage: http://github.com/csquared/IMGKit
|
101
|
+
licenses: []
|
102
|
+
|
103
|
+
post_install_message: |
|
104
|
+
******************************************************************
|
105
|
+
|
106
|
+
Now install wkhtmltoimage binaries:
|
107
|
+
Global: sudo `which imgkit` --install-wkhtmltoimage
|
108
|
+
or inside RVM folder: export TO=`which imgkit | sed 's:/imgkit:/wkhtmltoimage:'` && imgkit --install-wkhtmltoimage
|
109
|
+
(run imgkit --help to see more options)
|
110
|
+
|
111
|
+
******************************************************************
|
112
|
+
|
113
|
+
rdoc_options:
|
114
|
+
- --charset=UTF-8
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
version: "0"
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
segments:
|
131
|
+
- 0
|
132
|
+
version: "0"
|
133
|
+
requirements: []
|
134
|
+
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 1.3.7
|
137
|
+
signing_key:
|
138
|
+
specification_version: 3
|
139
|
+
summary: HTML+CSS -> JPG
|
140
|
+
test_files:
|
141
|
+
- spec/imgkit_spec.rb
|
142
|
+
- spec/source_spec.rb
|
143
|
+
- spec/spec_helper.rb
|