Browse files

Improvements to testing, gravity and cropping, now uses Mapel, not Mi…

…ni::Magick
  • Loading branch information...
1 parent 5fc8437 commit a2b5028059a838de5ba22a9d5b1e5c3ef7d25cea @leehambley committed Feb 22, 2012
Showing with 113 additions and 18 deletions.
  1. +6 −0 example/config.ru
  2. +90 −11 lib/rack-thumb-proxy.rb
  3. +3 −3 rack-thumb-proxy.gemspec
  4. +1 −1 test/test_helper.rb
  5. +13 −3 test/test_rack_thumb_proxy.rb
View
6 example/config.ru
@@ -0,0 +1,6 @@
+require 'rubygems'
+require 'bundler/setup'
+
+require 'rack-thumb-proxy'
+
+run Rack::Thumb::Proxy
View
101 lib/rack-thumb-proxy.rb
@@ -42,7 +42,7 @@ def call
format_response!
response.finish
else
- [404, {'Content-Length' => 9}, ['Not Found']]
+ [404, {'Content-Length' => 9.to_s, 'Content-Type' => 'text/plain'}, ['Not Found']]
end
end
@@ -55,6 +55,7 @@ def validate_signature!
def retreive_upstream!
begin
open(request_url, 'rb') do |f|
+ tempfile.binmode
tempfile.write(f.read)
tempfile.flush
end
@@ -67,7 +68,8 @@ def retreive_upstream!
def format_response!
response.status = 200
- response.headers["Content-Length"] = transformed_image_file_size_in_bytes
+ response.headers["Content-Type"] = mime_type_from_request_url
+ response.headers["Content-Length"] = transformed_image_file_size_in_bytes.to_s
response.body << read_tempfile
true
end
@@ -78,23 +80,57 @@ def read_tempfile
end
def tempfile
- @_tempfile ||= Tempfile.new(escaped_request_url)
+ @_tempfile ||= Tempfile.new('rack_thumb_proxy')
+ end
+
+ def tempfile_path
+ tempfile.path
end
def transform_image!
- return true if request_options.empty?
+
+ return true unless should_resize?
+
begin
- require 'mini_magick'
- mmi = MiniMagick::Image.open(tempfile.path)
- mmi.resize(request_options)
- mmi.write tempfile.path
+ require 'mapel'
+
+ width, height = dimensions_from_request_options
+ owidth, oheight = dimensions_from_tempfile
+
+ width = [width, owidth].min if width
+ height = [height, oheight].min if height
+
+ cmd = Mapel(tempfile_path)
+
+ if should_apply_gravity?
+ cmd.gravity(request_gravity)
+ end
+
+ if width && height
+ cmd.resize!(width, height)
+ else
+ cmd.resize(width, height, 0, 0, '>')
+ end
+
+ cmd.to(tempfile_path).run
+
rescue
+ puts $!, $@
write_error_to_response!
return false
end
+
true
end
+ def should_resize?
+ !request_options.empty?
+ end
+
+ def should_apply_gravity?
+ !!request_gravity_shorthand
+ end
+
def should_verify_hash_signature?
configuration.hash_signatures_in_use?
end
@@ -122,11 +158,12 @@ def request_gravity
'sw' => :southwest,
's' => :south,
'se' => :southeast
- }.fetch(request_gravity_shorthand, nil) if request_gravity_shorthand
+ }.fetch(request_gravity_shorthand).to_s if request_gravity_shorthand
end
def request_gravity_shorthand
- @_request_match_data["gravity"]
+ g = @_request_match_data["gravity"]
+ g.empty? ? nil : g
end
def request_url
@@ -141,8 +178,34 @@ def request_matches?
@_request_match_data = @path.match(routing_pattern)
end
+ def witdh_from_tempfile
+ dimensions_from_tempfile.first
+ end
+
+ def height_from_tempfile
+ dimensions_from_tempfile.last
+ end
+
+ def dimensions_from_tempfile
+ require 'mapel' unless defined?(Mapel)
+ Mapel.info(tempfile_path)[:dimensions]
+ end
+
+ def width_from_request_options
+ dimensions_from_request_options.first
+ end
+
+ def height_from_request_options
+ dimensions_from_request_options.last
+ end
+
+ def dimensions_from_request_options
+ width, height = request_options.split('x').map(&:to_i).collect { |dim| dim == 0 ? nil : dim }
+ [width, height]
+ end
+
def transformed_image_file_size_in_bytes
- ::File.size(tempfile.path)
+ ::File.size(tempfile_path)
end
# Examples: http://rubular.com/r/oPRK1t31yv
@@ -156,7 +219,23 @@ def response
def write_error_to_response!
response.status = 500
+ response.headers['Content-Type'] = 'text/plain'
response.body << $!.message
+ response.body << "\n\n"
+ response.body << $!.backtrace.join("\n")
+ end
+
+ def request_url_file_extension
+ ::File.extname(request_url)
+ end
+
+ def mime_type_from_request_url
+ {
+ '.png' => 'image/png',
+ '.gif' => 'image/gif',
+ '.jpg' => 'image/jpg',
+ '.jpeg' => 'image/jpeg'
+ }.fetch(request_url_file_extension)
end
end
View
6 rack-thumb-proxy.gemspec
@@ -5,8 +5,8 @@ Gem::Specification.new do |gem|
gem.authors = ["Lee Hambley"]
gem.email = ["lee.hambley@gmail.com"]
- gem.description = %q{TODO: Write a gem description}
- gem.summary = %q{TODO: Write a gem summary}
+ gem.description = %q{ Rack middleware for resizing proxied requests for images which don't reside on your own servers. }
+ gem.summary = %q{ For more information see https://github.com/leehambley/rack-thumb-proxy }
gem.homepage = ""
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -22,7 +22,7 @@ Gem::Specification.new do |gem|
gem.add_development_dependency 'minitest', '~> 2.11'
gem.add_development_dependency 'webmock', '~> 1.8.0'
gem.add_development_dependency 'rack-test', '~> 0.6.1'
+ gem.add_development_dependency 'mapel'
gem.add_development_dependency 'dimensions'
- gem.add_development_dependency 'mini_magick'
end
View
2 test/test_helper.rb
@@ -20,4 +20,4 @@
WebMock.disable_net_connect!
require 'ruby-debug'
-require 'mini_magick'
+require 'mapel'
View
16 test/test_rack_thumb_proxy.rb
@@ -14,8 +14,8 @@ def test_it_should_repond_with_not_found_when_the_upstream_url_is_bunk
end
def test_it_should_return_success_with_the_correct_content_length_when_a_matching_url_is_found_for_a_noop_image
- stub_image_request!('250x.gif', 'http://www.example.com/images/kittens.gif')
- get '/' + escape('http://www.example.com/images/kittens.gif')
+ stub_image_request!('250x.gif', 'http://www.example.com/images/noop-kittens.gif')
+ get '/' + escape('http://www.example.com/images/noop-kittens.gif')
assert last_response.ok?
assert_equal file_size_for_fixture('250x.gif').to_s, last_response.headers.fetch('Content-Length')
assert_equal file_hash_for_fixture('250x.gif'), file_hash_from_string(last_response.body)
@@ -29,6 +29,13 @@ def test_it_should_return_a_smaller_image_when_resizing_with_minimagick
assert_dimensions last_response.body, 50, 50
end
+ def test_it_should_crop_when_the_ratio_cannot_be_maintained
+ stub_image_request!('200x100.gif', 'http://www.example.com/images/sharkjumping.gif')
+ get '/50x50/' + escape('http://www.example.com/images/sharkjumping.gif')
+ assert last_response.ok?
+ assert_dimensions last_response.body, 50, 50
+ end
+
def test_it_should_retain_the_aspec_ratio
stub_image_request!('200x100.gif', 'http://www.example.com/images/sharkjumping.gif')
get '/50x/' + escape('http://www.example.com/images/sharkjumping.gif')
@@ -37,7 +44,6 @@ def test_it_should_retain_the_aspec_ratio
end
def test_it_should_accept_the_gravity_setting_without_breaking_the_resize
- skip
stub_image_request!('200x100.gif', 'http://www.example.com/images/sharkjumping.gif')
get '/50x50e/' + escape('http://www.example.com/images/sharkjumping.gif')
assert last_response.ok?
@@ -48,6 +54,10 @@ def test_it_should_accept_the_gravity_setting_without_breaking_the_resize
refute_equal file_hash_from_string(east), file_hash_from_string(west)
end
+ def test_should_respond_with_the_proper_mimetype
+
+ end
+
private
def stub_image_request!(file, url)

0 comments on commit a2b5028

Please sign in to comment.