imageproxy 0.4.1 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mdown +26 -7
- data/VERSION +1 -1
- data/imageproxy.gemspec +2 -2
- data/lib/imageproxy/command.rb +4 -2
- data/lib/imageproxy/convert.rb +10 -3
- data/spec/command_spec.rb +8 -3
- data/spec/convert_spec.rb +4 -3
- data/spec/server_spec.rb +10 -0
- data/spec/spec_helper.rb +12 -0
- metadata +3 -3
data/README.mdown
CHANGED
@@ -16,7 +16,7 @@ See http://imageproxy.heroku.com/selftest for some examples (it's running on Her
|
|
16
16
|
Status
|
17
17
|
------
|
18
18
|
|
19
|
-
|
19
|
+
imageproxy is being used in production on at least one commercial website, keeping two big EC2 servers busy. There are definitely some feature and performance improvements that can be/need to be made. Suggestions and pull requests are welcome.
|
20
20
|
|
21
21
|
### Current Features
|
22
22
|
|
@@ -47,7 +47,16 @@ PERFORMANCE
|
|
47
47
|
|
48
48
|
imageproxy doesn't do any sort of caching. That kind of thing is better left up to CDNs (like Amazon CloudFront or VoxCast CDN) or to caching proxies such as Varnish.
|
49
49
|
|
50
|
-
Also, imageproxy itself isn't nearly as fast as it could be. It's written in an interpreted language, and it shells out to curl and ImageMagick to do its work. Presumably, it would be way faster written in C as an Apache module
|
50
|
+
Also, imageproxy itself isn't nearly as fast as it could be. It's written in an interpreted language, and it shells out to curl and ImageMagick to do its work. Presumably, it would be way faster written in C as an Apache module or something.
|
51
|
+
|
52
|
+
|
53
|
+
REQUIREMENTS
|
54
|
+
------------
|
55
|
+
|
56
|
+
* [Ruby](http://www.ruby-lang.org/)
|
57
|
+
* [Rack](http://rack.github.com)
|
58
|
+
* [Imagemagick](http://www.imagemagick.org/)
|
59
|
+
* [Curl](http://curl.haxx.se)
|
51
60
|
|
52
61
|
|
53
62
|
INSTALLING
|
@@ -83,7 +92,7 @@ There are two major functions: `identify` and `convert`, plus a helpful `selftes
|
|
83
92
|
|
84
93
|
`thumbnail` The new size of the image, in "WxH" format (e.g., `20x30`). Thumbnailing assumes the resulting image will be pretty small and makes some optimizations.
|
85
94
|
|
86
|
-
`shape` The shape of the image, when `resize`ing or `thumbnail`ing to a different aspect ratio. The value can be `preserve` which will preserve the original aspect ratio, `pad` which will add padding to keep the proper aspect ratio (you can supply a `background` parameter to choose the background color to pad with, or leave blank to pad with transparent color if the image format allows it), and `cut` which will cut the image to fit the new size.
|
95
|
+
`shape` The shape of the image, when `resize`ing or `thumbnail`ing to a different aspect ratio. The value can be `preserve` which will preserve the original aspect ratio, `pad` which will add padding to keep the proper aspect ratio (you can supply a `background` parameter to choose the background color to pad with, or leave blank to pad with transparent color if the image format allows it), and `cut` which will cut the image to fit the new size. The default is `preserve`.
|
87
96
|
|
88
97
|
`flip` Flip the image. The value can be `horizontal` or `vertical`.
|
89
98
|
|
@@ -91,9 +100,9 @@ There are two major functions: `identify` and `convert`, plus a helpful `selftes
|
|
91
100
|
|
92
101
|
`format` Change the format. Possible formats include `gif`, `jpg`, `png`, `png8`, etc.
|
93
102
|
|
94
|
-
`quality` Choose the compression quality for formats that support lossy compression. The value can be any number from 0 to 100.
|
103
|
+
`quality` Choose the compression quality for formats that support lossy compression. The value can be any number from 0 to 100. The default is to use [Imagemagick's default quality settings](http://www.imagemagick.org/script/command-line-options.php#quality).
|
95
104
|
|
96
|
-
`progressive` Choose whether a JPEG image should be a progressive JPEG or not. Possible values are `true` and `false`.
|
105
|
+
`progressive` Choose whether a JPEG image should be a progressive JPEG or not. Possible values are `true` and `false`. The default is `false`.
|
97
106
|
|
98
107
|
`background` Some operations allow for a background color to be provided. The format is hex (e.g., `#ff00ff`) or rgba (e.g., `rgba(20,30,19,0.4)`)
|
99
108
|
|
@@ -111,6 +120,8 @@ Or, the parameters can be Amazon CloudFront-compatible URLs, like this:
|
|
111
120
|
|
112
121
|
http://example.com/convert/resize/100x100/shape/cut
|
113
122
|
|
123
|
+
(Note that CloudFront now optionally support query parameters.)
|
124
|
+
|
114
125
|
You can also mix the parameters if you like. This doesn't make much sense except for the case of the `signature` parameter which must be a query param:
|
115
126
|
|
116
127
|
http://example.com/convert/resize/100x100?signature=szFGj470w%2ByhJYJfTRryFLF9msA%3D
|
@@ -280,6 +291,9 @@ Clone the imageproxy code:
|
|
280
291
|
|
281
292
|
Set up Heroku:
|
282
293
|
|
294
|
+
As of Aug 2012 cedar does not work out of the box but bamboo does (specify bamboo as
|
295
|
+
an option to the heroku create command).
|
296
|
+
|
283
297
|
http://devcenter.heroku.com/articles/quickstart
|
284
298
|
|
285
299
|
Deploy:
|
@@ -305,9 +319,14 @@ To run the specs
|
|
305
319
|
Thanks
|
306
320
|
------
|
307
321
|
|
308
|
-
Thanks to
|
322
|
+
Thanks to the following for code contributions:
|
323
|
+
|
324
|
+
* [David Hall](https://github.com/moonhouse)
|
325
|
+
* [Andy Blyler](https://github.com/ablyler)
|
326
|
+
* [NeedFeed](https://github.com/needfeed)
|
327
|
+
* [Daniel Szmulewicz](https://github.com/danielsz)
|
309
328
|
|
310
329
|
License
|
311
330
|
-------
|
312
331
|
|
313
|
-
Licensed under the MIT license. See LICENSE.txt.
|
332
|
+
Licensed under the MIT license. See LICENSE.txt.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.3
|
data/imageproxy.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "imageproxy"
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Erik Hanson"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-11-26"
|
13
13
|
s.description = "A image processing proxy server, written in Ruby as a Rack application. Requires ImageMagick."
|
14
14
|
s.email = "erik@eahanson.com"
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/imageproxy/command.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
1
3
|
module Imageproxy
|
2
4
|
class Command
|
3
5
|
protected
|
@@ -15,7 +17,7 @@ module Imageproxy
|
|
15
17
|
user_agent = options[:user_agent] || "imageproxy"
|
16
18
|
timeout = options[:timeout] ? "-m #{options[:timeout]} " : ""
|
17
19
|
output = options[:output]
|
18
|
-
%|curl #{timeout}-L -s -A "#{user_agent}" #{output ? "-o #{output} ": ""}"#{url}"|
|
20
|
+
%|curl #{timeout}-L -f -s -S -A "#{user_agent}" #{output ? "-o #{output} ": ""}"#{url}"|
|
19
21
|
end
|
20
22
|
|
21
23
|
def to_path(obj)
|
@@ -26,4 +28,4 @@ module Imageproxy
|
|
26
28
|
output.readlines.join("").chomp
|
27
29
|
end
|
28
30
|
end
|
29
|
-
end
|
31
|
+
end
|
data/lib/imageproxy/convert.rb
CHANGED
@@ -15,16 +15,23 @@ module Imageproxy
|
|
15
15
|
def execute(user_agent=nil, timeout=nil)
|
16
16
|
if options.overlay
|
17
17
|
@overlay_file ||= Tempfile.new("imageproxy").tap(&:close)
|
18
|
-
|
19
|
-
|
18
|
+
try_command_with_timeout(curl options.overlay, :user_agent => user_agent, :timeout => timeout, :output => @overlay_file.path)
|
19
|
+
try_command_with_timeout curl(options.source, :user_agent => user_agent, :timeout => timeout) +
|
20
20
|
"| composite #{@overlay_file.path} - - | convert - #{convert_options} #{new_format}#{file.path}"
|
21
21
|
file
|
22
22
|
else
|
23
|
-
|
23
|
+
try_command_with_timeout %'#{curl options.source, :user_agent => user_agent, :timeout => timeout} | convert - #{convert_options} #{new_format}#{file.path}'
|
24
24
|
file
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
def try_command_with_timeout cmd
|
29
|
+
Timeout::timeout(10) { execute_command cmd }
|
30
|
+
rescue Timeout::Error => e
|
31
|
+
puts "Command timed out after 10 seconds, retrying >#{cmd}<"
|
32
|
+
execute_command cmd
|
33
|
+
puts "SUCCESS " * 20
|
34
|
+
end
|
28
35
|
|
29
36
|
def convert_options
|
30
37
|
convert_options = []
|
data/spec/command_spec.rb
CHANGED
@@ -5,24 +5,29 @@ describe Imageproxy::Command do
|
|
5
5
|
context "when a user agent is supplied" do
|
6
6
|
it "should send that user agent" do
|
7
7
|
Imageproxy::Command.new.send(:curl, "http://example.com/dog.jpg", :user_agent => "some user agent").should ==
|
8
|
-
%|curl -L -s -A "some user agent" "http://example.com/dog.jpg"|
|
8
|
+
%|curl -L -f -s -S -A "some user agent" "http://example.com/dog.jpg"|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
context "when no user agent is supplied" do
|
13
13
|
it "should send a default user agent" do
|
14
14
|
Imageproxy::Command.new.send(:curl, "http://example.com/dog.jpg").should ==
|
15
|
-
%|curl -L -s -A "imageproxy" "http://example.com/dog.jpg"|
|
15
|
+
%|curl -L -f -s -S -A "imageproxy" "http://example.com/dog.jpg"|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
context "when a timeout is supplied" do
|
20
20
|
it "should set the timeout" do
|
21
21
|
Imageproxy::Command.new.send(:curl, "http://example.com/dog.jpg", :timeout => "2").should ==
|
22
|
-
%|curl -m 2 -L -s -A "imageproxy" "http://example.com/dog.jpg"|
|
22
|
+
%|curl -m 2 -L -f -s -S -A "imageproxy" "http://example.com/dog.jpg"|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
it "should have curl report errors on stderr" do
|
27
|
+
curl_command = Imageproxy::Command.new.send(:curl, "http://example.com/dog.jpg")
|
28
|
+
curl_command.should match(/curl .*-f -s -S .*/)
|
29
|
+
end
|
30
|
+
|
26
31
|
context "when the command exits with a non-zero status" do
|
27
32
|
it "should raise an exception" do
|
28
33
|
ruby_19 = RUBY_VERSION.split(".").map(&:to_i)[1] == 9
|
data/spec/convert_spec.rb
CHANGED
@@ -21,7 +21,8 @@ describe Imageproxy::Convert do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should generate the proper command-line" do
|
24
|
-
@command.should_receive(:execute_command).with(
|
24
|
+
@command.should_receive(:execute_command).with(
|
25
|
+
%'curl -L -f -s -S -A "imageproxy" "http://example.com/dog.jpg" | convert - -resize 10x20 png:/mock/file/path')
|
25
26
|
@command.execute
|
26
27
|
end
|
27
28
|
|
@@ -157,9 +158,9 @@ describe Imageproxy::Convert do
|
|
157
158
|
end
|
158
159
|
|
159
160
|
it "should fetch both the overlay and the source, and call the composite command to composit the overlay on top of the source" do
|
160
|
-
@command.should_receive(:execute_command).with(%r|curl -L -s -A "imageproxy" -o [^ ]+ "http://example.com/frame.jpg"|)
|
161
|
+
@command.should_receive(:execute_command).with(%r|curl -L -f -s -S -A "imageproxy" -o [^ ]+ "http://example.com/frame.jpg"|)
|
161
162
|
@command.should_receive(:execute_command).with(
|
162
|
-
%r{curl -L -s -A "imageproxy" "http://example.com/dog.jpg" | composite [^ ]+ - - | convert - png:/mock/file/path})
|
163
|
+
%r{curl -L -f -s -S -A "imageproxy" "http://example.com/dog.jpg" | composite [^ ]+ - - | convert - png:/mock/file/path})
|
163
164
|
@command.execute
|
164
165
|
end
|
165
166
|
|
data/spec/server_spec.rb
CHANGED
@@ -121,6 +121,16 @@ describe "Server" do
|
|
121
121
|
|
122
122
|
end
|
123
123
|
|
124
|
+
context "error handling on errors from curl" do
|
125
|
+
it "should fail if curl can't load from that URL" do
|
126
|
+
get("/convert/flip/vertical/source/#{escaped_test_broken_image_url}").should fail
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should succeed if curl can load from that URL" do
|
130
|
+
get("/convert/flip/vertical/source/#{escaped_test_image_url}").should succeed
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
124
134
|
describe "#content_type" do
|
125
135
|
before do
|
126
136
|
@options = Imageproxy::Options.new("/", {})
|
data/spec/spec_helper.rb
CHANGED
@@ -21,3 +21,15 @@ end
|
|
21
21
|
def escaped_test_image_url
|
22
22
|
CGI.escape test_image_url
|
23
23
|
end
|
24
|
+
|
25
|
+
def test_broken_image_path
|
26
|
+
File.expand_path(File.dirname(__FILE__) + "/../public/does-not-exist.png")
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_broken_image_url
|
30
|
+
"file://#{test_broken_image_path}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def escaped_test_broken_image_url
|
34
|
+
CGI.escape test_broken_image_url
|
35
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imageproxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
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: 2012-
|
12
|
+
date: 2012-11-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -208,7 +208,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
208
208
|
version: '0'
|
209
209
|
segments:
|
210
210
|
- 0
|
211
|
-
hash:
|
211
|
+
hash: 1087416563410215419
|
212
212
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
213
213
|
none: false
|
214
214
|
requirements:
|