mugshot 0.5.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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