mugshot 0.5.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -25,71 +25,49 @@ Using
25
25
 
26
26
  Mugshot provides you with a Sinatra application. You can create a **config.ru** file with these contents to start using Mugshot:
27
27
 
28
- <pre>
29
- # -*- encoding: utf-8 -*-
30
- require "rubygems"
31
- require "mugshot"
32
-
33
- run Mugshot::Application.new(:storage => Mugshot::FSStorage.new("/tmp/mugshot"))
34
- </pre>
35
28
 
29
+ Using activeresource (3.0.6)
36
30
  Then you can run it with:
37
31
 
38
- <pre>
39
- $ rackup config.ru
40
- </pre>
32
+ $ rackup config.ru
41
33
 
42
34
  And access in your browser:
43
35
 
44
- <pre>
45
- http://localhost:9292/myimg/some-name.jpg
46
- </pre>
36
+ http://localhost:9292/myimg/some-name.jpg
47
37
 
48
38
  This would simply return the image located at /tmp/mugshot/myimg, converting it to a JPEG. Additionaly you can pass some operations to be performed over the image:
49
39
 
50
- <pre>
51
40
  http://localhost:9292/resize/100x100/myimg/some-name.jpg # resizing to 100x100 pixels
52
41
  http://localhost:9292/resize/100x/myimg/some-name.jpg # resizing to 100 pixels in width maintaining aspect ratio
53
42
  http://localhost:9292/resize/x100/myimg/some-name.jpg # resizing to 100 pixels in height maintaining aspect ratio
54
43
  http://localhost:9292/crop/200x150/myimg/some-name.jpg # resize and crop image to 200x150
55
44
  http://localhost:9292/quality/70/crop/200x150/myimg/some-name.jpg # convert it to JPEG with quality of 70% and resize and crop image to 200x150
56
45
  http://localhost:9292/background/red/crop/200x150/myimg/some-name.jpg # convert it to JPEG with red background and resize and crop image to 200x150
57
- </pre>
58
46
 
59
47
  Supported operations
60
48
  --------------------
61
49
 
62
50
  ### Resize
63
51
 
64
- <pre>
65
- /resize/WIDTHxHEIGHT/id/name.jpg (ex: http://mugshot.ws/resize/200x100/myid/thumb.jpg)
66
- </pre>
52
+ /resize/WIDTHxHEIGHT/id/name.jpg (ex: http://mugshot.ws/resize/200x100/myid/thumb.jpg)
67
53
 
68
54
  ### Resize keeping aspect ratio
69
55
 
70
- <pre>
71
- /resize/WIDTHx/id/name.jpg (ex: http://mugshot.ws/resize/200x/myid/thumb.jpg)
56
+ /resize/WIDTHx/id/name.jpg (ex: http://mugshot.ws/resize/200x/myid/thumb.jpg)
72
57
 
73
- /resize/xHEIGHT/id/name.jpg (ex: http://mugshot.ws/resize/x100/myid/thumb.jpg)
74
- </pre>
58
+ /resize/xHEIGHT/id/name.jpg (ex: http://mugshot.ws/resize/x100/myid/thumb.jpg)
75
59
 
76
60
  ### Crop
77
61
 
78
- <pre>
79
- /crop/WIDTHxHEIGHT/id/name.jpg (ex: http://mugshot.ws/crop/200x100/myid/thumb.jpg)
80
- </pre>
62
+ /crop/WIDTHxHEIGHT/id/name.jpg (ex: http://mugshot.ws/crop/200x100/myid/thumb.jpg)
81
63
 
82
64
  ### Quality
83
65
 
84
- <pre>
85
- /quality/QUALITY/id/name.jpg (ex: http://mugshot.ws/quality/70/myid/thumb.jpg)
86
- </pre>
66
+ /quality/QUALITY/id/name.jpg (ex: http://mugshot.ws/quality/70/myid/thumb.jpg)
87
67
 
88
68
  ### Background
89
69
 
90
- <pre>
91
- /background/COLOR/id/name.jpg (ex: http://mugshot.ws/background/red/myid/thumb.jpg)
92
- </pre>
70
+ /background/COLOR/id/name.jpg (ex: http://mugshot.ws/background/red/myid/thumb.jpg)
93
71
 
94
72
 
95
73
  Configuration
@@ -97,21 +75,19 @@ Configuration
97
75
 
98
76
  You can further configure your Mugshot::Application when creating it, like so:
99
77
 
100
- <pre>
101
- # -*- encoding: utf-8 -*-
102
- require "rubygems"
103
- require "mugshot"
104
-
105
- run Mugshot::Application.new(
106
- :storage => Mugshot::FSStorage.new("/tmp/mugshot"),
107
- :cache_duration => 7.days.to_i, # duration set in cache header (in seconds)
108
- :allowed_sizes => ['640x360', '480x360', '320x240'], # an array with valid sizes for resize and crop operations
109
- :allowed_formats => [:jpg, :png], # an array with the allowed formats
110
- :allowed_names => ['thumb', 'img'], # an array with the allowed names in the URL
111
- :quality_range => 1..100, # the range of allowed values for quality operations
112
- :valid_operations => [:crop, :resize, :quality] # an array with the valid operations
113
- )
114
- </pre>
78
+ # -*- encoding: utf-8 -*-
79
+ require "rubygems"
80
+ require "mugshot"
81
+
82
+ run Mugshot::Application.new(
83
+ :storage => Mugshot::FSStorage.new("/tmp/mugshot"),
84
+ :cache_duration => 7.days.to_i, # duration set in cache header (in seconds)
85
+ :allowed_sizes => ['640x360', '480x360', '320x240'], # an array with valid sizes for resize and crop operations
86
+ :allowed_formats => [:jpg, :png], # an array with the allowed formats
87
+ :allowed_names => ['thumb', 'img'], # an array with the allowed names in the URL
88
+ :quality_range => 1..100, # the range of allowed values for quality operations
89
+ :valid_operations => [:crop, :resize, :quality] # an array with the valid operations
90
+ )
115
91
 
116
92
  When using the restrictive configurations any value other than the ones allowed will result in a 400 status code being returned. If no restriction is set then any value can be given, which can lead to DOS attacks. Be careful!
117
93
 
@@ -120,19 +96,10 @@ Development
120
96
 
121
97
  Clone the repository and run:
122
98
 
123
- <pre>
124
- $ bundle install
125
- </pre>
99
+ $ bundle
126
100
 
127
101
  This will install all dependencies for you. Then you can run the specs and features:
128
102
 
129
- <pre>
130
- $ rake spec
131
- $ rake cucumber
132
- </pre>
133
-
134
-
135
- Who's using
136
- -----------
103
+ $ rake spec
104
+ $ rake cucumber
137
105
 
138
- We currently use Mugshot with Varnish on [Baixatudo](http://www.baixatudo.com.br).
@@ -11,7 +11,7 @@ class Mugshot::Application < Sinatra::Base
11
11
  before do
12
12
  response['Cache-Control'] = "public, max-age=#{@cache_duration}"
13
13
  end
14
-
14
+
15
15
  get '/?' do
16
16
  'ok'
17
17
  end
@@ -28,7 +28,7 @@ class Mugshot::Application < Sinatra::Base
28
28
  check_name(name)
29
29
  check_operations
30
30
  end
31
-
31
+
32
32
  get '/*/?:id/:name.:format' do |splat, id, _, format|
33
33
  image = @storage.read(id)
34
34
  halt 404 if image.blank?
@@ -42,7 +42,7 @@ class Mugshot::Application < Sinatra::Base
42
42
  end
43
43
  end
44
44
 
45
- protected
45
+ protected
46
46
 
47
47
  def initialize(opts)
48
48
  opts = {:storage => opts} if opts.kind_of?(Mugshot::Storage)
@@ -57,11 +57,11 @@ class Mugshot::Application < Sinatra::Base
57
57
  @allowed_names = opts.delete(:allowed_names)
58
58
 
59
59
  @default_operations = opts
60
-
60
+
61
61
  super(opts)
62
62
  end
63
63
 
64
- private
64
+ private
65
65
 
66
66
  def operations_from_splat(splat)
67
67
  operations = []
@@ -73,19 +73,19 @@ class Mugshot::Application < Sinatra::Base
73
73
  end
74
74
  operations
75
75
  end
76
-
76
+
77
77
  def check_format(format)
78
78
  halt 400 unless valid_format?(format)
79
79
  end
80
-
80
+
81
81
  def valid_format?(format)
82
82
  @allowed_formats.blank? || @allowed_formats.map(&:to_s).include?(format)
83
83
  end
84
-
84
+
85
85
  def check_name(name)
86
86
  halt 400 unless valid_name?(name)
87
87
  end
88
-
88
+
89
89
  def valid_name?(name)
90
90
  @allowed_names.blank? || @allowed_names.map(&:to_s).include?(name)
91
91
  end
@@ -93,19 +93,19 @@ class Mugshot::Application < Sinatra::Base
93
93
  def check_operations
94
94
  halt 400 unless valid_quality_operation? && valid_resize_operation? && valid_crop_operation?
95
95
  end
96
-
96
+
97
97
  def valid_quality_operation?
98
98
  !@operations.has_key?("quality") || @quality_range.blank? || @quality_range.include?(@operations["quality"].to_i)
99
99
  end
100
-
100
+
101
101
  def valid_resize_operation?
102
102
  valid_operation?("resize", @allowed_sizes)
103
103
  end
104
-
104
+
105
105
  def valid_crop_operation?
106
106
  valid_operation?("crop", @allowed_sizes)
107
107
  end
108
-
108
+
109
109
  def valid_operation?(operation, range_or_array)
110
110
  !@operations.has_key?(operation) || range_or_array.blank? || range_or_array.include?(@operations[operation])
111
111
  end
@@ -115,7 +115,7 @@ class Mugshot::Application < Sinatra::Base
115
115
  image.send("#{op}!", op_params.to_s)
116
116
  end
117
117
  end
118
-
118
+
119
119
  def send_image(image, format)
120
120
  content_type format
121
121
  response['Content-Disposition'] = 'inline'
@@ -2,15 +2,18 @@
2
2
  require 'fileutils'
3
3
  class Mugshot::FSStorage < Mugshot::Storage
4
4
  def write(bin)
5
- asset_id.tap do |id|
6
- File.open(File.join(@root_path, id), "w") do |fw|
7
- fw.write(bin)
8
- end
5
+ id = asset_id
6
+ path = id_to_path(id)
7
+ FileUtils.mkdir_p(File.dirname(File.join(@root_path, path)))
8
+ File.open(File.join(@root_path, path), "w") do |fw|
9
+ fw.write(bin)
9
10
  end
11
+ id
10
12
  end
11
13
 
12
14
  def read(id)
13
- file = File.join(@root_path, id)
15
+ path = id_to_path(id)
16
+ file = File.join(@root_path, path)
14
17
  return nil unless File.exist? file
15
18
  Mugshot::Image.new File.open(file)
16
19
  end
@@ -21,4 +24,13 @@ class Mugshot::FSStorage < Mugshot::Storage
21
24
  @root_path = root_path
22
25
  FileUtils.mkdir_p(root_path)
23
26
  end
27
+
28
+ def id_to_path(id)
29
+ path = id.to_s.clone
30
+ 4.times do |i|
31
+ path = path.insert(3 + (i * 3) + i, '/')
32
+ end
33
+ path
34
+ end
24
35
  end
36
+
@@ -1,12 +1,8 @@
1
1
  # -*- encoding: utf-8 -*-
2
-
3
2
  require 'fileutils'
4
3
  require 'net/http'
5
4
 
6
5
  class Mugshot::HTTPStorage < Mugshot::Storage
7
- def write(bin)
8
- nil
9
- end
10
6
 
11
7
  def read(id)
12
8
  url = URI.parse(@url_resolver.call(id))
@@ -17,9 +13,10 @@ class Mugshot::HTTPStorage < Mugshot::Storage
17
13
  Mugshot::Image.new(res.body)
18
14
  end
19
15
 
20
- protected
16
+ protected
21
17
 
22
18
  def initialize(&block)
23
19
  @url_resolver = block
24
20
  end
21
+
25
22
  end
data/lib/mugshot/image.rb CHANGED
@@ -45,19 +45,21 @@ class Mugshot::Image
45
45
  end
46
46
  end
47
47
 
48
- protected
48
+ protected
49
+
49
50
  def initialize(file_or_blob)
50
51
  if file_or_blob.is_a?(File)
51
52
  @image = Magick::Image.read(file_or_blob).first
52
53
  else
53
54
  @image = Magick::Image.from_blob(file_or_blob).first
54
55
  end
55
-
56
+
56
57
  # initialize attrs
57
58
  @background_color = @quality = nil
58
59
  end
59
60
 
60
- private
61
+ private
62
+
61
63
  def parse_size(size)
62
64
  size.to_s.split("x").map{|i| i.blank? ? nil : i.to_i}
63
65
  end
@@ -67,4 +69,5 @@ class Mugshot::Image
67
69
  create_canvas(@image.columns, @image.rows, color).
68
70
  composite(@image, Magick::NorthWestGravity, Magick::OverCompositeOp)
69
71
  end
72
+
70
73
  end
@@ -2,11 +2,7 @@
2
2
  require 'RMagick'
3
3
 
4
4
  class Mugshot::MagickFactory
5
- class << self
6
-
7
- def create_canvas(columns, rows, color)
8
- Magick::Image.new(columns, rows){ self.background_color = color }
9
- end
10
-
5
+ def self.create_canvas(columns, rows, color)
6
+ Magick::Image.new(columns, rows){ self.background_color = color }
11
7
  end
12
8
  end
@@ -1,8 +1,15 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  require 'uuid'
3
3
  class Mugshot::Storage
4
- protected
4
+
5
+ def write(bin)
6
+ nil
7
+ end
8
+
9
+ protected
10
+
5
11
  def asset_id
6
12
  UUID.generate :compact
7
13
  end
14
+
8
15
  end
@@ -1,3 +1,4 @@
1
1
  module Mugshot
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.2"
3
3
  end
4
+
@@ -0,0 +1 @@
1
+ image
@@ -37,10 +37,9 @@ describe Mugshot::Application do
37
37
  describe "POST /" do
38
38
  it "should create image" do
39
39
  file_read = nil
40
- File.open("spec/files/test.jpg") {|f| file_read = f.read}
40
+ File.open("spec/files/test-upload.jpg") {|f| file_read = f.read}
41
41
  @storage.should_receive(:write).with(file_read).and_return("batata")
42
-
43
- post "/", "file" => Rack::Test::UploadedFile.new("spec/files/test.jpg", "image/jpeg")
42
+ post "/", "file" => Rack::Test::UploadedFile.new("spec/files/test-upload.jpg", "image/jpeg")
44
43
 
45
44
  last_response.status.should == 200
46
45
  end
@@ -8,7 +8,7 @@ describe Mugshot::FSStorage do
8
8
 
9
9
  after :each do
10
10
  require 'fileutils'
11
- FileUtils.rm_rf("/tmp/mugshot/spec")
11
+ #FileUtils.rm_rf("/tmp/mugshot/spec")
12
12
  end
13
13
 
14
14
  it "should write an image to the filesystem and read it back" do
@@ -18,12 +18,16 @@ describe Mugshot::FSStorage do
18
18
  Mugshot::Image.stub!(:new).and_return(image)
19
19
 
20
20
  id = @fs.write(bin)
21
- image2 = @fs.read(id)
22
21
 
22
+ image2 = @fs.read(id)
23
23
  image2.should == image
24
24
  end
25
25
 
26
26
  it "should return nil when an image with the given id doesn't exist on the filesystem" do
27
27
  @fs.read('nonexistant-id').should be_nil
28
28
  end
29
+
30
+ it "should convert an id to path with 4r levels of directories" do
31
+ @fs.send(:id_to_path, "a9657a30c7df012c736512313b021ce1").should == "a96/57a/30c/7df/012c736512313b021ce1"
32
+ end
29
33
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mugshot
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
5
- prerelease: false
4
+ hash: 3
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
- - 5
9
- - 1
10
- version: 0.5.1
8
+ - 6
9
+ - 2
10
+ version: 0.6.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Cain\xC3\xA3 Nunes"
@@ -15,11 +15,12 @@ authors:
15
15
  - Guilherme Cirne
16
16
  - Jose Peleteiro
17
17
  - Vicente Mundim
18
+ - Anselmo Alves
18
19
  autorequire:
19
20
  bindir: bin
20
21
  cert_chain: []
21
22
 
22
- date: 2010-12-28 00:00:00 -02:00
23
+ date: 2011-04-25 00:00:00 -03:00
23
24
  default_executable:
24
25
  dependencies:
25
26
  - !ruby/object:Gem::Dependency
@@ -39,9 +40,25 @@ dependencies:
39
40
  type: :runtime
40
41
  version_requirements: *id001
41
42
  - !ruby/object:Gem::Dependency
42
- name: rmagick
43
+ name: i18n
43
44
  prerelease: false
44
45
  requirement: &id002 !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ hash: 11
51
+ segments:
52
+ - 0
53
+ - 5
54
+ - 0
55
+ version: 0.5.0
56
+ type: :runtime
57
+ version_requirements: *id002
58
+ - !ruby/object:Gem::Dependency
59
+ name: rmagick
60
+ prerelease: false
61
+ requirement: &id003 !ruby/object:Gem::Requirement
45
62
  none: false
46
63
  requirements:
47
64
  - - ">="
@@ -53,11 +70,11 @@ dependencies:
53
70
  - 2
54
71
  version: 2.12.2
55
72
  type: :runtime
56
- version_requirements: *id002
73
+ version_requirements: *id003
57
74
  - !ruby/object:Gem::Dependency
58
75
  name: uuid
59
76
  prerelease: false
60
- requirement: &id003 !ruby/object:Gem::Requirement
77
+ requirement: &id004 !ruby/object:Gem::Requirement
61
78
  none: false
62
79
  requirements:
63
80
  - - ">="
@@ -69,11 +86,11 @@ dependencies:
69
86
  - 2
70
87
  version: 2.0.2
71
88
  type: :runtime
72
- version_requirements: *id003
89
+ version_requirements: *id004
73
90
  - !ruby/object:Gem::Dependency
74
91
  name: blankslate
75
92
  prerelease: false
76
- requirement: &id004 !ruby/object:Gem::Requirement
93
+ requirement: &id005 !ruby/object:Gem::Requirement
77
94
  none: false
78
95
  requirements:
79
96
  - - ">="
@@ -86,11 +103,11 @@ dependencies:
86
103
  - 3
87
104
  version: 2.1.2.3
88
105
  type: :runtime
89
- version_requirements: *id004
106
+ version_requirements: *id005
90
107
  - !ruby/object:Gem::Dependency
91
108
  name: sinatra
92
109
  prerelease: false
93
- requirement: &id005 !ruby/object:Gem::Requirement
110
+ requirement: &id006 !ruby/object:Gem::Requirement
94
111
  none: false
95
112
  requirements:
96
113
  - - ">="
@@ -102,11 +119,11 @@ dependencies:
102
119
  - 4
103
120
  version: 0.9.4
104
121
  type: :runtime
105
- version_requirements: *id005
122
+ version_requirements: *id006
106
123
  - !ruby/object:Gem::Dependency
107
124
  name: fakeweb
108
125
  prerelease: false
109
- requirement: &id006 !ruby/object:Gem::Requirement
126
+ requirement: &id007 !ruby/object:Gem::Requirement
110
127
  none: false
111
128
  requirements:
112
129
  - - ">="
@@ -116,11 +133,11 @@ dependencies:
116
133
  - 0
117
134
  version: "0"
118
135
  type: :development
119
- version_requirements: *id006
136
+ version_requirements: *id007
120
137
  - !ruby/object:Gem::Dependency
121
138
  name: rspec
122
139
  prerelease: false
123
- requirement: &id007 !ruby/object:Gem::Requirement
140
+ requirement: &id008 !ruby/object:Gem::Requirement
124
141
  none: false
125
142
  requirements:
126
143
  - - ">="
@@ -132,22 +149,6 @@ dependencies:
132
149
  - 0
133
150
  version: 2.3.0
134
151
  type: :development
135
- version_requirements: *id007
136
- - !ruby/object:Gem::Dependency
137
- name: rcov
138
- prerelease: false
139
- requirement: &id008 !ruby/object:Gem::Requirement
140
- none: false
141
- requirements:
142
- - - ">="
143
- - !ruby/object:Gem::Version
144
- hash: 43
145
- segments:
146
- - 0
147
- - 9
148
- - 8
149
- version: 0.9.8
150
- type: :development
151
152
  version_requirements: *id008
152
153
  - !ruby/object:Gem::Dependency
153
154
  name: cucumber
@@ -188,6 +189,7 @@ email:
188
189
  - gcirne@gmail.com
189
190
  - jose@peleteiro.net
190
191
  - vicente.mundim@gmail.com
192
+ - me@anselmoalves.com
191
193
  executables: []
192
194
 
193
195
  extensions: []
@@ -227,6 +229,7 @@ files:
227
229
  - features/support/files/with_alpha_channel.png
228
230
  - features/upload_image.feature
229
231
  - spec/files/firefox_png.png
232
+ - spec/files/test-upload.jpg
230
233
  - spec/files/test.jpg
231
234
  - spec/files/test_png.png
232
235
  - spec/mugshot/application_spec.rb
@@ -266,7 +269,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
266
269
  requirements: []
267
270
 
268
271
  rubyforge_project: mugshot
269
- rubygems_version: 1.3.7
272
+ rubygems_version: 1.5.2
270
273
  signing_key:
271
274
  specification_version: 3
272
275
  summary: Dead simple image server
@@ -291,6 +294,7 @@ test_files:
291
294
  - features/support/files/with_alpha_channel.png
292
295
  - features/upload_image.feature
293
296
  - spec/files/firefox_png.png
297
+ - spec/files/test-upload.jpg
294
298
  - spec/files/test.jpg
295
299
  - spec/files/test_png.png
296
300
  - spec/mugshot/application_spec.rb