httpthumbnailer 0.2.0 → 0.3.0
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/VERSION +1 -1
- data/bin/httpthumbnailer +7 -7
- data/features/httpthumbnailer.feature +24 -2
- data/httpthumbnailer.gemspec +2 -2
- data/lib/httpthumbnailer/thumbnail_specs.rb +52 -22
- data/lib/httpthumbnailer/thumbnailer.rb +12 -25
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/bin/httpthumbnailer
CHANGED
@@ -50,18 +50,18 @@ sinatra.before do
|
|
50
50
|
if $thumbnailer.nil?
|
51
51
|
$thumbnailer = Thumbnailer.new(:logger => logger, :limit_memory => settings.limit_memory, :limit_map => settings.limit_map, :limit_disk => settings.limit_disk)
|
52
52
|
|
53
|
-
$thumbnailer.method('crop') do |image,
|
54
|
-
image.resize_to_fill!(
|
53
|
+
$thumbnailer.method('crop') do |image, width, height, options|
|
54
|
+
image.resize_to_fill!(width, height)
|
55
55
|
end
|
56
56
|
|
57
|
-
$thumbnailer.method('fit') do |image,
|
58
|
-
image.resize_to_fit!(
|
57
|
+
$thumbnailer.method('fit') do |image, width, height, options|
|
58
|
+
image.resize_to_fit!(width, height)
|
59
59
|
end
|
60
60
|
|
61
|
-
$thumbnailer.method('pad') do |image,
|
62
|
-
image.resize_to_fit!(
|
61
|
+
$thumbnailer.method('pad') do |image, width, height, options|
|
62
|
+
image.resize_to_fit!(width, height)
|
63
63
|
|
64
|
-
out = Magick::Image.new(
|
64
|
+
out = Magick::Image.new(width, height) {
|
65
65
|
self.background_color = Magick::Pixel.new(Magick::MaxRGB, Magick::MaxRGB, Magick::MaxRGB, Magick::MaxRGB) # transparent
|
66
66
|
}.composite!(image, Magick::CenterGravity, Magick::OverCompositeOp)
|
67
67
|
|
@@ -63,6 +63,18 @@ Feature: Generating set of thumbnails with single PUT request
|
|
63
63
|
Then third part will contain PNG image of size 16x32
|
64
64
|
And third part mime type will be image/png
|
65
65
|
|
66
|
+
Scenario: Thumbnails of width or height INPUT will have input image width or height
|
67
|
+
Given test.jpg file content as request body
|
68
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,INPUT,16,JPEG/crop,4,INPUT,PNG/crop,INPUT,INPUT,PNG
|
69
|
+
Then response status will be 200
|
70
|
+
And I will get multipart response
|
71
|
+
Then first part will contain JPEG image of size 509x16
|
72
|
+
And first part mime type will be image/jpeg
|
73
|
+
Then second part will contain PNG image of size 4x719
|
74
|
+
And second part mime type will be image/png
|
75
|
+
Then third part will contain PNG image of size 509x719
|
76
|
+
And third part mime type will be image/png
|
77
|
+
|
66
78
|
Scenario: Fit thumbnailing method
|
67
79
|
Given test.jpg file content as request body
|
68
80
|
When I do PUT request http://localhost:3100/thumbnail/fit,128,128,PNG
|
@@ -129,6 +141,16 @@ Feature: Generating set of thumbnails with single PUT request
|
|
129
141
|
Error: Thumbnailer::UnsupportedMediaTypeError: Magick::ImageMagickError:
|
130
142
|
"""
|
131
143
|
|
144
|
+
Scenario: Reporitng of bad thumbanil spec format - bad dimmension value
|
145
|
+
Given test.txt file content as request body
|
146
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,128,bogous,PNG
|
147
|
+
Then response status will be 500
|
148
|
+
And response content type will be text/plain
|
149
|
+
And response body will be CRLF endend lines
|
150
|
+
"""
|
151
|
+
Error: ThumbnailSpecs::BadThubnailSpecError::BadDimmensionValueError: bad dimmension value: bogous
|
152
|
+
"""
|
153
|
+
|
132
154
|
Scenario: Reporitng of bad thumbanil spec format - missing param
|
133
155
|
Given test.txt file content as request body
|
134
156
|
When I do PUT request http://localhost:3100/thumbnail/crop,128,PNG
|
@@ -136,7 +158,7 @@ Feature: Generating set of thumbnails with single PUT request
|
|
136
158
|
And response content type will be text/plain
|
137
159
|
And response body will be CRLF endend lines
|
138
160
|
"""
|
139
|
-
Error: ThumbnailSpecs::
|
161
|
+
Error: ThumbnailSpecs::BadThubnailSpecError::MissingArgumentError: missing argument in: crop,128,PNG
|
140
162
|
"""
|
141
163
|
|
142
164
|
Scenario: Reporitng of bad thumbanil spec format - bad options format
|
@@ -146,7 +168,7 @@ Feature: Generating set of thumbnails with single PUT request
|
|
146
168
|
And response content type will be text/plain
|
147
169
|
And response body will be CRLF endend lines
|
148
170
|
"""
|
149
|
-
Error: ThumbnailSpecs::
|
171
|
+
Error: ThumbnailSpecs::BadThubnailSpecError::MissingOptionKeyOrValueError: missing option key or value in: fas-fda
|
150
172
|
"""
|
151
173
|
|
152
174
|
Scenario: Reporitng of image thumbnailing errors
|
data/httpthumbnailer.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "httpthumbnailer"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jakub Pastuszek"]
|
12
|
-
s.date = "2012-01-
|
12
|
+
s.date = "2012-01-16"
|
13
13
|
s.description = "Provides HTTP API for thumbnailing images"
|
14
14
|
s.email = "jpastuszek@gmail.com"
|
15
15
|
s.executables = ["httpthumbnailer"]
|
@@ -1,22 +1,60 @@
|
|
1
1
|
require 'httpthumbnailer/thumbnailer'
|
2
2
|
|
3
3
|
class ThumbnailSpecs < Array
|
4
|
-
class
|
4
|
+
class BadThubnailSpecError < ArgumentError
|
5
|
+
class MissingArgumentError < BadThubnailSpecError
|
6
|
+
def initialize(spec)
|
7
|
+
super "missing argument in: #{spec}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class MissingOptionKeyOrValueError < BadThubnailSpecError
|
12
|
+
def initialize(option)
|
13
|
+
super "missing option key or value in: #{option}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class BadDimmensionValueError < BadThubnailSpecError
|
18
|
+
def initialize(value)
|
19
|
+
super "bad dimmension value: #{value}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class ThumbnailSpec
|
25
|
+
def initialize(method, width, height, format, options = {})
|
26
|
+
@method = method
|
27
|
+
@width = cast_dimmension(width)
|
28
|
+
@height = cast_dimmension(height)
|
29
|
+
@format = (format == 'INPUT' ? :input : format.upcase)
|
30
|
+
@options = options
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :method, :width, :height, :format, :options
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
"#{method} #{width}x#{height} (#{format}) #{options.inspect}"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def cast_dimmension(string)
|
42
|
+
return :input if string == 'INPUT'
|
43
|
+
raise BadThubnailSpecError::BadDimmensionValueError.new(string) unless string =~ /^\d+$/
|
44
|
+
string.to_i
|
45
|
+
end
|
5
46
|
end
|
6
47
|
|
7
48
|
def self.from_uri(specs)
|
8
49
|
ts = ThumbnailSpecs.new
|
9
50
|
specs.split('/').each do |spec|
|
10
51
|
method, width, height, format, *options = *spec.split(',')
|
11
|
-
raise
|
12
|
-
|
13
|
-
width = width.to_i
|
14
|
-
height = height.to_i
|
52
|
+
raise BadThubnailSpecError::MissingArgumentError.new(spec) unless method and width and height and format
|
15
53
|
|
16
54
|
opts = {}
|
17
55
|
options.each do |option|
|
18
56
|
key, value = option.split(':')
|
19
|
-
raise
|
57
|
+
raise BadThubnailSpecError::MissingOptionKeyOrValueError.new(option) unless key and value
|
20
58
|
opts[key] = value
|
21
59
|
end
|
22
60
|
|
@@ -26,25 +64,17 @@ class ThumbnailSpecs < Array
|
|
26
64
|
end
|
27
65
|
|
28
66
|
def max_width
|
29
|
-
map
|
67
|
+
map do |spec|
|
68
|
+
return nil unless spec.width.is_a? Integer
|
69
|
+
spec.width
|
70
|
+
end.max
|
30
71
|
end
|
31
72
|
|
32
73
|
def max_height
|
33
|
-
map
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
max_field = -1
|
38
|
-
max_spec = nil
|
39
|
-
each do |spec|
|
40
|
-
field = spec.width * spec.height
|
41
|
-
if max_field < field
|
42
|
-
max_field = field
|
43
|
-
max_spec = spec
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
max_spec
|
74
|
+
map do |spec|
|
75
|
+
return nil unless spec.height.is_a? Integer
|
76
|
+
spec.height
|
77
|
+
end.max
|
48
78
|
end
|
49
79
|
end
|
50
80
|
|
@@ -12,23 +12,6 @@ class Magick::Image
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
class ThumbnailSpec
|
17
|
-
def initialize(method, width, height, format, options = {})
|
18
|
-
@method = method
|
19
|
-
@width = width
|
20
|
-
@height = height
|
21
|
-
@format = format.upcase
|
22
|
-
@options = options
|
23
|
-
end
|
24
|
-
|
25
|
-
attr_reader :method, :width, :height, :format, :options
|
26
|
-
|
27
|
-
def to_s
|
28
|
-
"#{method} #{width}x#{height} (#{format}) #{options.inspect}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
15
|
class Thumbnailer
|
33
16
|
class UnsupportedMethodError < ArgumentError
|
34
17
|
def initialize(method)
|
@@ -92,7 +75,6 @@ class Thumbnailer
|
|
92
75
|
@options = options
|
93
76
|
@logger = (options[:logger] or Logger.new('/dev/null'))
|
94
77
|
|
95
|
-
|
96
78
|
mw = options['max-width']
|
97
79
|
mh = options['max-height']
|
98
80
|
if mw and mh
|
@@ -132,9 +114,14 @@ class Thumbnailer
|
|
132
114
|
def thumbnail(spec)
|
133
115
|
begin
|
134
116
|
ImageHandler.new do
|
135
|
-
|
117
|
+
width = spec.width == :input ? @image.columns : spec.width
|
118
|
+
height = spec.height == :input ? @image.rows : spec.height
|
119
|
+
|
120
|
+
process_image(@image, spec.method, width, height, spec.options).render_on_background!((spec.options['background-color'] or 'white').sub(/^0x/, '#'))
|
136
121
|
end.use do |image|
|
137
|
-
|
122
|
+
format = spec.format == :input ? @image.format : spec.format
|
123
|
+
|
124
|
+
yield Thumbnail.new(image, format, spec.options)
|
138
125
|
end
|
139
126
|
rescue Magick::ImageMagickError => e
|
140
127
|
raise ImageTooLargeError, e if e.message =~ /cache resources exhausted/
|
@@ -161,11 +148,11 @@ class Thumbnailer
|
|
161
148
|
end
|
162
149
|
end
|
163
150
|
|
164
|
-
def process_image(image,
|
165
|
-
impl = @methods[
|
151
|
+
def process_image(image, method, width, height, options)
|
152
|
+
impl = @methods[method] or raise UnsupportedMethodError.new(method)
|
166
153
|
copy = image.copy
|
167
154
|
begin
|
168
|
-
impl.call(copy,
|
155
|
+
impl.call(copy, width, height, options)
|
169
156
|
rescue
|
170
157
|
copy.destroy!
|
171
158
|
raise
|
@@ -174,10 +161,10 @@ class Thumbnailer
|
|
174
161
|
end
|
175
162
|
|
176
163
|
class Thumbnail
|
177
|
-
def initialize(image, format,
|
164
|
+
def initialize(image, format, options = {})
|
178
165
|
@image = image
|
179
166
|
@format = format
|
180
|
-
@quality = (quality or default_quality(format))
|
167
|
+
@quality = (options['quality'] or default_quality(format))
|
181
168
|
@quality &&= @quality.to_i
|
182
169
|
end
|
183
170
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpthumbnailer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jakub Pastuszek
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-01-
|
18
|
+
date: 2012-01-16 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
type: :runtime
|