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 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
- This project is pretty new. There are definitely some improvements that can be/need to be made. Suggestions and pull requests are welcome.
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, but this implementation was quite a bit easier :)
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 [David Hall](https://github.com/moonhouse) for code contributions.
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
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.1"
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-07-24"
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 = [
@@ -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
@@ -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
- execute_command(curl options.overlay, :user_agent => user_agent, :timeout => timeout, :output => @overlay_file.path)
19
- execute_command curl(options.source, :user_agent => user_agent, :timeout => timeout) +
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
- execute_command %'#{curl options.source, :user_agent => user_agent, :timeout => timeout} | convert - #{convert_options} #{new_format}#{file.path}'
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(%'curl -L -s -A "imageproxy" "http://example.com/dog.jpg" | convert - -resize 10x20 png:/mock/file/path')
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.1
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-07-24 00:00:00.000000000 Z
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: 3458948603279650035
211
+ hash: 1087416563410215419
212
212
  required_rubygems_version: !ruby/object:Gem::Requirement
213
213
  none: false
214
214
  requirements: