Skip to content

Commit

Permalink
update /info to give a JSON response
Browse files Browse the repository at this point in the history
includes a boolean for if the image is animated (or likely to be)
  • Loading branch information
jweir committed Apr 8, 2013
1 parent 7cf6acb commit 5a3c666
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 60 deletions.
46 changes: 33 additions & 13 deletions README.md
Expand Up @@ -9,12 +9,14 @@ ScaleDown
So you want to scale an image?
------------------------------

You have an image on `example.com`. It has a public path of `/images/john/picture.png`.
You want it scaled to fit in a 400x400 pixel box. ScaleDown is running on the subdomain `images`.
You have an image on `example.com`. It has a public path of
`/images/john/picture.png`. You want it scaled to fit in a 400x400 pixel box.
ScaleDown is running on the subdomain `images`.

http://server/images/john/scaled/400x400/picture.png?HMAC_SIGNATURE

The scaled file is saved in a public path identical to the request. It will be statically served on the next request.
The scaled file is saved in a public path identical to the request. It will be
statically served on the next request.

Geometry, Labels and Cropping
==============================
Expand Down Expand Up @@ -52,10 +54,11 @@ A geometry defines a box the image must fit within: `WIDTHxHEIGHT`.
```sh
# scale to a 300 pixel width box by 900 pixel high box
http://server/images/john/scaled/300x900/picture.png?HMAC_SIGNATURE
^^^^^^^
^^^^^^^
```

Either, but not both, dimensions may use the keyword `auto`. This will scale the image to fit the defined dimension.
Either, but not both, dimensions may use the keyword `auto`. This will scale
the image to fit the defined dimension.

```sh
# scale to a 500 pixel wide box, of any height
Expand All @@ -68,7 +71,9 @@ When using a geometry an HMAC is required (see below).
Crop
----

To crop an image include the `-crop` option. The image will be scaled and cropped to fit the geometry. This is a simple crop positioned on the center and top of the image.
To crop an image include the `-crop` option. The image will be scaled and
cropped to fit the geometry. This is a simple crop positioned on the center and
top of the image.

Both geometry and labels accept the `-crop` option.

Expand All @@ -79,7 +84,9 @@ http://server/images/john/scaled/100x100-crop/picture.png

Info
----
There is a very simple `/info` function for getting image dimensions. It just returns a string with the WIDTHxHEIGHT of the original image.
There is a simple `/info` function for getting image dimensions. It just
returns a json response the width, height and additional details of the
original file.

http://server/images/logo.png/info

Expand Down Expand Up @@ -183,7 +190,8 @@ Dependencies
* RMagick
* Ruby-HMAC

RMagick can be a bit tricky to install, these links http://www.google.com/search?q=install+rmagick might help.
RMagick can be a bit tricky to install, these links
http://www.google.com/search?q=install+rmagick might help.

LICENSE
=======
Expand All @@ -192,8 +200,20 @@ LICENSE

Copyright © 2011 John Weir & Fame Driver LLC

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the ‘Software’), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
1 change: 1 addition & 0 deletions lib/scale_down.rb
Expand Up @@ -13,6 +13,7 @@ module ScaleDown
require 'scale_down/controller'
require 'scale_down/dispatcher'
require 'scale_down/image'
require 'scale_down/info'

class InvalidGeometry < Exception; end
class FileSizeTooLarge < Exception; end
Expand Down
6 changes: 3 additions & 3 deletions lib/scale_down/controller.rb
Expand Up @@ -13,9 +13,9 @@ class ScaleDown::Controller < Sinatra::Application
end

get '/*/info' do
info = ScaleDown::Dispatcher.info(params[:splat].join("/"))
if info
[200, info]
info = ScaleDown::Info.new(params[:splat].join("/"))
if ! info.missing?
[200, info.to_json]
else
[404, "Image not found"]
end
Expand Down
11 changes: 0 additions & 11 deletions lib/scale_down/dispatcher.rb
Expand Up @@ -19,17 +19,6 @@ def process(params)
[dispatcher.redirect_path, dispatcher.redirect_code]
end

# TODO return a JSON response with a full set of image details
def info(relative_path)
path = [ScaleDown.public_folder, relative_path].join("/")
if File.exists?(path)
GC.start
image = Magick::Image.read(path).first
[image.columns, image.rows].join('x')
else
nil
end
end
end

def initialize(params)
Expand Down
33 changes: 33 additions & 0 deletions lib/scale_down/info.rb
@@ -0,0 +1,33 @@
require 'json'

# Returns a json object with the height, width attributes
class ScaleDown::Info

def initialize(relative_path)
path = [ScaleDown.public_folder, relative_path].join("/")
if File.exists?(path)
GC.start
@image_list = Magick::Image.read(path)
@image = @image_list.first
else
@missing = true
end
end

def missing?
@missing == true
end

def hash
{
height: @image.rows,
width: @image.columns,
# is this an animated GIF or other file
animated: @image_list.size > 1
}
end

def to_json
JSON hash
end
end
2 changes: 1 addition & 1 deletion lib/scale_down/version.rb
@@ -1,3 +1,3 @@
module ScaleDown
VERSION = "0.7.3"
VERSION = "0.8.1"
end
1 change: 1 addition & 0 deletions scale_down.gemspec
Expand Up @@ -17,6 +17,7 @@ Gem::Specification.new do |s|
s.add_dependency "rmagick", ">= 2.1"
s.add_dependency "sinatra", ">= 1.0"
s.add_dependency "ruby-hmac", ">= 0.4.0"
s.add_dependency "json", "~> 1.7.7"

s.add_development_dependency "contest", ">= 0.1.2"
s.add_development_dependency "rake", ">= 0.9.2.2"
Expand Down
Binary file added test/files/animated.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions test/scale_down/controller_test.rb
Expand Up @@ -52,20 +52,20 @@ def app
context "get dimensions" do
context "for image which exists" do
setup do
ScaleDown::Dispatcher.expects(:info).with("image/path/image.jpg").returns "400x300"
ScaleDown::Info.expects(:new).with("image/path/image.jpg").returns mock(missing?: false, to_json: 'json_blob')
end

should "return the width and height as json" do
get "/image/path/image.jpg/info"

assert_equal 200, last_response.status
assert_equal "400x300", last_response.body
assert_equal "json_blob", last_response.body
end
end

context "for a non-existant image" do
setup do
ScaleDown::Dispatcher.expects(:info).with("image/path/image.jpg").returns nil
ScaleDown::Info.expects(:new).with("image/path/image.jpg").returns mock(missing?: true)
end

should "respond with a 404" do
Expand Down
15 changes: 0 additions & 15 deletions test/scale_down/dispatcher_test.rb
Expand Up @@ -167,19 +167,4 @@ class ScaleDown::Dispatcher::Test < Test::Unit::TestCase
end
end
end

context "#info" do
setup do
ScaleDown.public_folder = File.join(File.expand_path(File.dirname(__FILE__)), "..")
end

should "return the width x height for an image" do
assert_equal "200x400", ScaleDown::Dispatcher.info("files/graphic.png")
end

should "return nil for a non-existant image" do
assert_equal nil, ScaleDown::Dispatcher.info("files/notthere.jpg")
end
end

end
34 changes: 34 additions & 0 deletions test/scale_down/info_test.rb
@@ -0,0 +1,34 @@
require File.expand_path(File.dirname(__FILE__))+'/../test_helper'

class ScaleDown::Info::Test < Test::Unit::TestCase
context "#new" do
setup do
ScaleDown.public_folder = File.join(File.expand_path(File.dirname(__FILE__)), "..")
end

should "be missing? a non-existant image" do
assert ScaleDown::Info.new("files/notthere.jpg").missing?
end

should "generate json" do
info = ScaleDown::Info.new("files/graphic.png")
assert info.to_json
end
end

context "properties" do
should "have dimentions" do
info = ScaleDown::Info.new("files/graphic.png")
assert_equal 200, info.hash[:width]
assert_equal 400, info.hash[:height]
end

should "set the animation flag for animated gifs" do
info = ScaleDown::Info.new("files/graphic.png")
assert_equal false, info.hash[:animated]

info = ScaleDown::Info.new("files/animated.gif")
assert_equal true, info.hash[:animated]
end
end
end
29 changes: 15 additions & 14 deletions test/scale_down_test.rb
Expand Up @@ -55,27 +55,28 @@ def copy(f, to, num)
FileUtils.rm_r("/tmp/scale_down")
end

context "homepage" do
should "show the version" do
get "/"
assert_match ScaleDown::VERSION, last_response.body
end
should "show the version on the homepage" do
get "/"
assert_match ScaleDown::VERSION, last_response.body
end

should "show the labels" do
ScaleDown.labels = {
:medium => "100x100"
}
should "show the labels on the homepage" do
ScaleDown.labels = {
:medium => "100x100"
}

get "/"
assert_match "medium", last_response.body
assert_match "100x100", last_response.body
end
get "/"
assert_match "medium", last_response.body
assert_match "100x100", last_response.body
end

should "get image info" do
copy 'cmyk.tif', 'long-name.tiff', 1
get "/test_images/example_1/#{CGI.escape 'long-name.tiff'}/info"
assert_equal "300x500", last_response.body

result = JSON(last_response.body)
assert_equal 300, result["width"]
assert_equal 500, result["height"]
end

should "get an image with a geometry and scale it" do
Expand Down

0 comments on commit 5a3c666

Please sign in to comment.