httpthumbnailer 0.0.3 → 0.0.4
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 +59 -42
- data/features/httpthumbnailer.feature +92 -14
- data/features/step_definitions/httpthumbnailer_steps.rb +36 -0
- data/features/support/test.txt +1 -0
- data/httpthumbnailer.gemspec +3 -2
- data/lib/httpthumbnailer/thumbnail_specs.rb +6 -0
- data/lib/httpthumbnailer/thumbnailer.rb +110 -32
- metadata +5 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.4
|
data/bin/httpthumbnailer
CHANGED
@@ -17,30 +17,42 @@ sinatra.set :server, ['mongrel']
|
|
17
17
|
sinatra.set :lock, true
|
18
18
|
sinatra.set :boundary, "thumnail image data"
|
19
19
|
sinatra.set :logging, true
|
20
|
+
sinatra.set :debug, true
|
20
21
|
|
21
22
|
sinatra.before do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
logger.level = Logger::DEBUG if settings.debug == true
|
24
|
+
if $thumbnailer.nil?
|
25
|
+
$thumbnailer = Thumbnailer.new(:logger => logger)
|
26
|
+
|
27
|
+
$thumbnailer.method('crop') do |image, spec|
|
28
|
+
image.resize_to_fill!(spec.width, spec.height)
|
26
29
|
end
|
27
30
|
|
28
|
-
|
29
|
-
image.resize_to_fit(spec.width, spec.height)
|
31
|
+
$thumbnailer.method('fit') do |image, spec|
|
32
|
+
image.resize_to_fit!(spec.width, spec.height)
|
30
33
|
end
|
31
34
|
|
32
|
-
|
33
|
-
|
35
|
+
$thumbnailer.method('pad') do |image, spec|
|
36
|
+
image.resize_to_fit!(spec.width, spec.height)
|
37
|
+
|
38
|
+
out = Magick::Image.new(spec.width, spec.height) {
|
34
39
|
self.background_color = Magick::Pixel.new(Magick::MaxRGB, Magick::MaxRGB, Magick::MaxRGB, Magick::MaxRGB) # transparent
|
35
|
-
}.composite!(image
|
40
|
+
}.composite!(image, Magick::CenterGravity, Magick::OverCompositeOp)
|
41
|
+
|
42
|
+
image.destroy!
|
43
|
+
out
|
36
44
|
end
|
37
45
|
end
|
38
46
|
end
|
39
47
|
|
40
48
|
sinatra.helpers do
|
41
|
-
def
|
49
|
+
def plain_response(msg)
|
42
50
|
headers "Content-Type" => "text/plain"
|
43
|
-
body "
|
51
|
+
body msg.gsub("\n", "\r\n") + "\r\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
def plain_exception(exception)
|
55
|
+
plain_response("Error: #{exception.class.name}: #{exception}")
|
44
56
|
end
|
45
57
|
end
|
46
58
|
|
@@ -48,45 +60,50 @@ sinatra.get '/' do
|
|
48
60
|
logger.info 'hello'
|
49
61
|
end
|
50
62
|
|
51
|
-
sinatra.
|
52
|
-
|
53
|
-
|
54
|
-
rescue => e
|
55
|
-
plain_exception(e)
|
56
|
-
halt 415
|
57
|
-
end
|
63
|
+
sinatra.get '/stats/images' do
|
64
|
+
$thumbnailer.images.to_s
|
65
|
+
end
|
58
66
|
|
67
|
+
sinatra.put %r{/thumbnail/(.*)} do |specs|
|
59
68
|
thumbnail_specs = ThumbnailSpecs.from_uri(specs)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
$thumbnailer.load(request.body) do |original_image_handler|
|
70
|
+
status 200
|
71
|
+
headers "Content-Type" => "multipart/mixed; boundary=\"#{settings.boundary}\""
|
72
|
+
|
73
|
+
stream do |out| # this is non blocking
|
74
|
+
original_image_handler.use do |original_image|
|
75
|
+
thumbnail_specs.each do |spec|
|
76
|
+
logger.info "Thumbnailing: #{spec}"
|
77
|
+
out << "--#{settings.boundary}\r\n"
|
78
|
+
|
79
|
+
begin
|
80
|
+
thumbnail_data = original_image.thumbnail(spec)
|
81
|
+
|
82
|
+
out << "Content-Type: #{spec.mime}\r\n\r\n"
|
83
|
+
out << thumbnail_data
|
84
|
+
rescue => e
|
85
|
+
logger.error "Thumbnailing error: #{e.class.name}: #{e}: \n#{e.backtrace.join("\n")}"
|
86
|
+
out << "Content-Type: text/plain\r\n\r\n"
|
87
|
+
out << "Error: #{e.class.name}: #{e}\r\n"
|
88
|
+
ensure
|
89
|
+
out << "\r\n"
|
90
|
+
end
|
72
91
|
end
|
73
|
-
|
74
|
-
out << "Content-Type: #{spec.mime}\r\n\r\n"
|
75
|
-
out << thumbnail_data
|
76
|
-
|
77
|
-
thumbnail_data = nil
|
78
|
-
thumbnail.destroy!
|
79
|
-
rescue => e
|
80
|
-
out << "Content-Type: text/plain\r\n\r\n"
|
81
|
-
out << "Error: #{e.class.name}: #{e}\r\n"
|
82
|
-
ensure
|
83
|
-
out << "\r\n"
|
92
|
+
out << "--#{settings.boundary}--"
|
84
93
|
end
|
85
94
|
end
|
86
|
-
out << "--#{settings.boundary}--"
|
87
95
|
end
|
88
96
|
end
|
89
97
|
|
98
|
+
sinatra.error Thumbnailer::UnsupportedMediaTypeError do
|
99
|
+
plain_exception(env['sinatra.error'])
|
100
|
+
halt 415
|
101
|
+
end
|
102
|
+
|
103
|
+
sinatra.error 404 do
|
104
|
+
plain_response("Resource '#{request.path_info}' not found")
|
105
|
+
end
|
106
|
+
|
90
107
|
sinatra.error do
|
91
108
|
plain_exception(env['sinatra.error'])
|
92
109
|
end
|
@@ -4,53 +4,131 @@ Feature: Generating set of thumbnails with single PUT request
|
|
4
4
|
/thumbnail[/<thumbnail type>,<width>,<height>,<format>[,<option key>:<option value>]+]+
|
5
5
|
|
6
6
|
Background:
|
7
|
+
Given httpthumbnailer log is empty
|
7
8
|
Given httpthumbnailer server is running at http://localhost:3100/
|
8
9
|
|
9
10
|
Scenario: Single thumbnail
|
10
11
|
Given test.jpg file content as request body
|
11
12
|
When I do PUT request http://localhost:3100/thumbnail/crop,16,16,PNG
|
12
|
-
Then
|
13
|
-
|
14
|
-
|
13
|
+
Then response status will be 200
|
14
|
+
And I will get multipart response
|
15
|
+
Then first part will contain PNG image of size 16x16
|
16
|
+
And first part mime type will be image/png
|
17
|
+
And there will be no leaked images
|
15
18
|
|
16
19
|
Scenario: Multiple thumbnails
|
17
20
|
Given test.jpg file content as request body
|
18
21
|
When I do PUT request http://localhost:3100/thumbnail/crop,16,16,PNG/crop,4,8,JPG/crop,16,32,JPEG
|
19
|
-
Then
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
Then response status will be 200
|
23
|
+
And I will get multipart response
|
24
|
+
Then first part will contain PNG image of size 16x16
|
25
|
+
And first part mime type will be image/png
|
26
|
+
Then second part will contain JPEG image of size 4x8
|
27
|
+
And second part mime type will be image/jpeg
|
28
|
+
Then third part will contain JPEG image of size 16x32
|
29
|
+
And third part mime type will be image/jpeg
|
30
|
+
And there will be no leaked images
|
26
31
|
|
27
32
|
Scenario: Transparent image to JPEG handling - default background color white
|
28
33
|
Given test-transparent.png file content as request body
|
29
34
|
When I do PUT request http://localhost:3100/thumbnail/fit,128,128,JPEG
|
30
|
-
Then
|
35
|
+
Then response status will be 200
|
36
|
+
And I will get multipart response
|
31
37
|
And first part body will be saved as test-transparent-default.png for human inspection
|
32
38
|
And first part will contain JPEG image of size 128x128
|
33
39
|
And that image pixel at 32x32 will be of color white
|
40
|
+
And there will be no leaked images
|
34
41
|
|
35
42
|
Scenario: Fit thumbnailing method
|
36
43
|
Given test.jpg file content as request body
|
37
44
|
When I do PUT request http://localhost:3100/thumbnail/fit,128,128,PNG
|
38
|
-
Then
|
45
|
+
Then response status will be 200
|
46
|
+
And I will get multipart response
|
39
47
|
And first part will contain PNG image of size 91x128
|
48
|
+
And there will be no leaked images
|
40
49
|
|
41
50
|
Scenario: Pad thumbnailing method - default background color white
|
42
51
|
Given test.jpg file content as request body
|
43
52
|
When I do PUT request http://localhost:3100/thumbnail/pad,128,128,PNG
|
44
|
-
Then
|
53
|
+
Then response status will be 200
|
54
|
+
And I will get multipart response
|
45
55
|
And first part body will be saved as test-pad.png for human inspection
|
46
56
|
And first part will contain PNG image of size 128x128
|
47
57
|
And that image pixel at 2x2 will be of color white
|
58
|
+
And there will be no leaked images
|
48
59
|
|
49
60
|
Scenario: Pad thumbnailing method with specified background color
|
50
61
|
Given test.jpg file content as request body
|
51
62
|
When I do PUT request http://localhost:3100/thumbnail/pad,128,128,PNG,background-color:green
|
52
|
-
Then
|
63
|
+
Then response status will be 200
|
64
|
+
And I will get multipart response
|
53
65
|
And first part body will be saved as test-pad-background-color.png for human inspection
|
54
66
|
And first part will contain PNG image of size 128x128
|
55
67
|
And that image pixel at 2x2 will be of color green
|
68
|
+
And there will be no leaked images
|
69
|
+
|
70
|
+
Scenario: Image leaking on error
|
71
|
+
Given test.jpg file content as request body
|
72
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,0,0,PNG/fit,0,0,JPG/pad,0,0,JPEG
|
73
|
+
Then response status will be 200
|
74
|
+
And I will get multipart response
|
75
|
+
And first part content type will be text/plain
|
76
|
+
And second part content type will be text/plain
|
77
|
+
And third part content type will be text/plain
|
78
|
+
And there will be no leaked images
|
79
|
+
|
80
|
+
Scenario: Reporitng of missing resource
|
81
|
+
When I do GET request http://localhost:3100/blah
|
82
|
+
Then response status will be 404
|
83
|
+
And response content type will be text/plain
|
84
|
+
And response body will be CRLF endend lines
|
85
|
+
"""
|
86
|
+
Resource '/blah' not found
|
87
|
+
"""
|
88
|
+
|
89
|
+
Scenario: Reporitng of unsupported media type
|
90
|
+
Given test.txt file content as request body
|
91
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,128,128,PNG
|
92
|
+
Then response status will be 415
|
93
|
+
And response content type will be text/plain
|
94
|
+
And response body will be CRLF endend lines like
|
95
|
+
"""
|
96
|
+
Error: Thumbnailer::UnsupportedMediaTypeError: Magick::ImageMagickError:
|
97
|
+
"""
|
98
|
+
|
99
|
+
Scenario: Reporitng of bad thumbanil spec format - missing param
|
100
|
+
Given test.txt file content as request body
|
101
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,128,PNG
|
102
|
+
Then response status will be 500
|
103
|
+
And response content type will be text/plain
|
104
|
+
And response body will be CRLF endend lines
|
105
|
+
"""
|
106
|
+
Error: ThumbnailSpecs::BadThubnailSpecFormat: missing argument in: crop,128,PNG
|
107
|
+
"""
|
108
|
+
|
109
|
+
Scenario: Reporitng of bad thumbanil spec format - bad options format
|
110
|
+
Given test.txt file content as request body
|
111
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,128,128,PNG,fas-fda
|
112
|
+
Then response status will be 500
|
113
|
+
And response content type will be text/plain
|
114
|
+
And response body will be CRLF endend lines
|
115
|
+
"""
|
116
|
+
Error: ThumbnailSpecs::BadThubnailSpecFormat: missing option key or value in: fas-fda
|
117
|
+
"""
|
118
|
+
|
119
|
+
Scenario: Reporitng of image thumbnailing errors
|
120
|
+
Given test.jpg file content as request body
|
121
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,16,16,PNG/crop,0,0,JPG/crop,16,32,JPEG
|
122
|
+
Then response status will be 200
|
123
|
+
And I will get multipart response
|
124
|
+
Then first part will contain PNG image of size 16x16
|
125
|
+
And first part mime type will be image/png
|
126
|
+
And second part content type will be text/plain
|
127
|
+
And second part body will be CRLF endend lines
|
128
|
+
"""
|
129
|
+
Error: ArgumentError: invalid result dimension (0, 0 given)
|
130
|
+
"""
|
131
|
+
Then third part will contain JPEG image of size 16x32
|
132
|
+
And third part mime type will be image/jpeg
|
133
|
+
And there will be no leaked images
|
56
134
|
|
@@ -1,3 +1,7 @@
|
|
1
|
+
Given /httpthumbnailer log is empty/ do
|
2
|
+
(support_dir + 'server.log').truncate(0)
|
3
|
+
end
|
4
|
+
|
1
5
|
Given /httpthumbnailer server is running at (.*)/ do |url|
|
2
6
|
start_server(
|
3
7
|
"bundle exec #{script('httpthumbnailer')}",
|
@@ -20,10 +24,37 @@ Then /I will get multipart response/ do
|
|
20
24
|
@response_multipart = MultipartResponse.new(@response.header['Content-Type'].last, @response.body)
|
21
25
|
end
|
22
26
|
|
27
|
+
Then /response body will be CRLF endend lines like/ do |body|
|
28
|
+
@response.body.should match(body)
|
29
|
+
@response.body.each do |line|
|
30
|
+
line[-2,2].should == "\r\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Then /response body will be CRLF endend lines$/ do |body|
|
35
|
+
@response.body.should == body.gsub("\n", "\r\n") + "\r\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
Then /response status will be (.*)/ do |status|
|
39
|
+
@response.status.should == status.to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
Then /response content type will be (.*)/ do |content_type|
|
43
|
+
@response.header['Content-Type'].first.should == content_type
|
44
|
+
end
|
45
|
+
|
23
46
|
Then /(.*) part mime type will be (.*)/ do |part, mime|
|
24
47
|
@response_multipart.part[part_no(part)].header['Content-Type'].should == mime
|
25
48
|
end
|
26
49
|
|
50
|
+
Then /(.*) part content type will be (.*)/ do |part, content_type|
|
51
|
+
@response_multipart.part[part_no(part)].header['Content-Type'].should == content_type
|
52
|
+
end
|
53
|
+
|
54
|
+
Then /(.*) part body will be CRLF endend lines$/ do |part, body|
|
55
|
+
@response_multipart.part[part_no(part)].body.should == body.gsub("\n", "\r\n") + "\r\n"
|
56
|
+
end
|
57
|
+
|
27
58
|
Then /(.*) part will contain (.*) image of size (.*)x(.*)/ do |part, format, width, height|
|
28
59
|
mime = @response_multipart.part[part_no(part)].header['Content-Type']
|
29
60
|
data = @response_multipart.part[part_no(part)].body
|
@@ -46,3 +77,8 @@ And /that image pixel at (.*)x(.*) will be of color (.*)/ do |x, y, color|
|
|
46
77
|
@image.pixel_color(x.to_i, y.to_i).to_color.sub(/^#/, '0x').should == color
|
47
78
|
end
|
48
79
|
|
80
|
+
|
81
|
+
And /there will be no leaked images/ do
|
82
|
+
HTTPClient.new.get_content("http://localhost:3100/stats/images").to_i.should == 0
|
83
|
+
end
|
84
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
hello world
|
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.0.
|
8
|
+
s.version = "0.0.4"
|
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 = "2011-11-
|
12
|
+
s.date = "2011-11-29"
|
13
13
|
s.description = "Provides HTTP API for thumbnailing images"
|
14
14
|
s.email = "jpastuszek@gmail.com"
|
15
15
|
s.executables = ["httpthumbnailer"]
|
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
"features/support/env.rb",
|
33
33
|
"features/support/test-transparent.png",
|
34
34
|
"features/support/test.jpg",
|
35
|
+
"features/support/test.txt",
|
35
36
|
"httpthumbnailer.gemspec",
|
36
37
|
"lib/httpthumbnailer/multipart_response.rb",
|
37
38
|
"lib/httpthumbnailer/thumbnail_specs.rb",
|
@@ -1,16 +1,22 @@
|
|
1
1
|
require 'httpthumbnailer/thumbnailer'
|
2
2
|
|
3
3
|
class ThumbnailSpecs < Array
|
4
|
+
class BadThubnailSpecFormat < ArgumentError
|
5
|
+
end
|
6
|
+
|
4
7
|
def self.from_uri(specs)
|
5
8
|
ts = ThumbnailSpecs.new
|
6
9
|
specs.split('/').each do |spec|
|
7
10
|
method, width, height, format, *options = *spec.split(',')
|
11
|
+
raise BadThubnailSpecFormat, "missing argument in: #{spec}" unless method and width and height and format
|
12
|
+
|
8
13
|
width = width.to_i
|
9
14
|
height = height.to_i
|
10
15
|
|
11
16
|
opts = {}
|
12
17
|
options.each do |option|
|
13
18
|
key, value = option.split(':')
|
19
|
+
raise BadThubnailSpecFormat, "missing option key or value in: #{option}" unless key and value
|
14
20
|
opts[key] = value
|
15
21
|
end
|
16
22
|
|
@@ -1,5 +1,18 @@
|
|
1
1
|
require 'logger'
|
2
2
|
|
3
|
+
class Magick::Image
|
4
|
+
def render_on_background!(background_color)
|
5
|
+
Thumbnailer::ImageHandler.new do
|
6
|
+
self
|
7
|
+
end.use do |image|
|
8
|
+
Magick::Image.new(image.columns, image.rows) {
|
9
|
+
self.background_color = background_color
|
10
|
+
}.composite!(image, Magick::CenterGravity, Magick::OverCompositeOp)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
3
16
|
class ThumbnailSpec
|
4
17
|
def initialize(method, width, height, format, options = {})
|
5
18
|
@method = method
|
@@ -31,55 +44,120 @@ class Thumbnailer
|
|
31
44
|
end
|
32
45
|
end
|
33
46
|
|
34
|
-
class
|
35
|
-
def initialize(
|
36
|
-
super("
|
47
|
+
class UnsupportedMediaTypeError < ArgumentError
|
48
|
+
def initialize(e)
|
49
|
+
super("#{e.class.name}: #{e}")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class ImageHandler
|
54
|
+
class ImageDestroyedError < RuntimeError
|
55
|
+
def initialize
|
56
|
+
super("image was already used")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize
|
61
|
+
@image = yield
|
62
|
+
end
|
63
|
+
|
64
|
+
def use
|
65
|
+
raise ImageDestroyedError unless @image
|
66
|
+
begin
|
67
|
+
yield @image
|
68
|
+
ensure
|
69
|
+
@image.destroy!
|
70
|
+
@image = nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def destroy!
|
75
|
+
return unless @image
|
76
|
+
@image.destroy!
|
77
|
+
@image = nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class OriginalImage
|
82
|
+
def initialize(io, methods, options = {})
|
83
|
+
@options = options
|
84
|
+
@logger = (options[:logger] or Logger.new('/dev/null'))
|
85
|
+
|
86
|
+
begin
|
87
|
+
@image = Magick::Image.from_blob(io.read).first.strip!
|
88
|
+
rescue Magick::ImageMagickError => e
|
89
|
+
raise UnsupportedMediaTypeError, e
|
90
|
+
end
|
91
|
+
@methods = methods
|
92
|
+
end
|
93
|
+
|
94
|
+
def thumbnail(spec)
|
95
|
+
ImageHandler.new do
|
96
|
+
process_image(@image, spec).render_on_background!((spec.options['background-color'] or 'white').sub(/^0x/, '#'))
|
97
|
+
end.use do |thumb|
|
98
|
+
thumb.to_blob do |inf|
|
99
|
+
inf.format = spec.format
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def destroy!
|
105
|
+
@image.destroy!
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def process_image(image, spec)
|
111
|
+
impl = @methods[spec.method] or raise UnsupportedMethodError.new(spec.method)
|
112
|
+
copy = image.copy
|
113
|
+
begin
|
114
|
+
impl.call(copy, spec)
|
115
|
+
rescue
|
116
|
+
copy.destroy!
|
117
|
+
raise
|
118
|
+
end
|
37
119
|
end
|
38
120
|
end
|
39
121
|
|
40
122
|
def initialize(options = {})
|
41
|
-
@images = {}
|
42
123
|
@methods = {}
|
43
124
|
@options = options
|
44
|
-
@options = options
|
45
125
|
@logger = (options[:logger] or Logger.new('/dev/null'))
|
46
|
-
end
|
47
126
|
|
48
|
-
|
49
|
-
@logger.info "Loading image #{id}"
|
50
|
-
@images[id] = Magick::Image.from_blob(io.read).first
|
51
|
-
@images[id].strip!
|
127
|
+
@logger.info "Initializing thumbniler"
|
52
128
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
129
|
+
@images = 0
|
130
|
+
Magick.trace_proc = lambda do |which, description, id, method|
|
131
|
+
case which
|
132
|
+
when :c
|
133
|
+
@images += 1
|
134
|
+
when :d
|
135
|
+
@images -= 1
|
136
|
+
end
|
137
|
+
@logger.debug "Image event: #{which}, #{description}, #{id}, #{method}: loaded images: #{images}"
|
61
138
|
end
|
62
139
|
end
|
63
140
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
141
|
+
def load(io)
|
142
|
+
h = ImageHandler.new do
|
143
|
+
OriginalImage.new(io, @methods, @options)
|
144
|
+
end
|
67
145
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
146
|
+
begin
|
147
|
+
yield h
|
148
|
+
rescue
|
149
|
+
# make sure that we destroy original image if there was an error before it could be used
|
150
|
+
h.destroy!
|
151
|
+
raise
|
152
|
+
end
|
72
153
|
end
|
73
154
|
|
74
|
-
def
|
75
|
-
|
76
|
-
self.background_color = (spec.options['background-color'] or 'white').sub(/^0x/, '#')
|
77
|
-
}.composite!(image, Magick::CenterGravity, Magick::OverCompositeOp)
|
155
|
+
def images
|
156
|
+
@images
|
78
157
|
end
|
79
158
|
|
80
|
-
def
|
81
|
-
|
82
|
-
impl.call(image, spec)
|
159
|
+
def method(method, &impl)
|
160
|
+
@methods[method] = impl
|
83
161
|
end
|
84
162
|
end
|
85
163
|
|
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: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
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: 2011-11-
|
18
|
+
date: 2011-11-29 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
type: :runtime
|
@@ -221,6 +221,7 @@ files:
|
|
221
221
|
- features/support/env.rb
|
222
222
|
- features/support/test-transparent.png
|
223
223
|
- features/support/test.jpg
|
224
|
+
- features/support/test.txt
|
224
225
|
- httpthumbnailer.gemspec
|
225
226
|
- lib/httpthumbnailer/multipart_response.rb
|
226
227
|
- lib/httpthumbnailer/thumbnail_specs.rb
|