httpthumbnailer 0.0.2 → 0.0.3
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 +15 -5
- data/features/httpthumbnailer.feature +35 -2
- data/features/step_definitions/httpthumbnailer_steps.rb +26 -19
- data/features/support/env.rb +36 -29
- data/features/support/test-transparent.png +0 -0
- data/httpthumbnailer.gemspec +3 -2
- data/lib/httpthumbnailer/thumbnailer.rb +8 -1
- metadata +5 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/bin/httpthumbnailer
CHANGED
@@ -24,6 +24,16 @@ sinatra.before do
|
|
24
24
|
@thumbnailer.method('crop') do |image, spec|
|
25
25
|
image.resize_to_fill(spec.width, spec.height)
|
26
26
|
end
|
27
|
+
|
28
|
+
@thumbnailer.method('fit') do |image, spec|
|
29
|
+
image.resize_to_fit(spec.width, spec.height)
|
30
|
+
end
|
31
|
+
|
32
|
+
@thumbnailer.method('pad') do |image, spec|
|
33
|
+
Magick::Image.new(spec.width, spec.height) {
|
34
|
+
self.background_color = Magick::Pixel.new(Magick::MaxRGB, Magick::MaxRGB, Magick::MaxRGB, Magick::MaxRGB) # transparent
|
35
|
+
}.composite!(image.resize_to_fit(spec.width, spec.height), Magick::CenterGravity, Magick::OverCompositeOp)
|
36
|
+
end
|
27
37
|
end
|
28
38
|
end
|
29
39
|
|
@@ -51,17 +61,17 @@ sinatra.put %r{/thumbnail/(.*)} do |specs|
|
|
51
61
|
status 200
|
52
62
|
headers "Content-Type" => "multipart/mixed; boundary=\"#{settings.boundary}\""
|
53
63
|
stream do |out|
|
54
|
-
thumbnail_specs.each do |
|
55
|
-
logger.info "Thumbnailing: #{
|
64
|
+
thumbnail_specs.each do |spec|
|
65
|
+
logger.info "Thumbnailing: #{spec}"
|
56
66
|
out << "--#{settings.boundary}\r\n"
|
57
67
|
|
58
68
|
begin
|
59
|
-
thumbnail = @thumbnailer.thumbnail('current',
|
69
|
+
thumbnail = @thumbnailer.thumbnail('current', spec)
|
60
70
|
thumbnail_data = thumbnail.to_blob do |inf|
|
61
|
-
inf.format =
|
71
|
+
inf.format = spec.format
|
62
72
|
end
|
63
73
|
|
64
|
-
out << "Content-Type: #{
|
74
|
+
out << "Content-Type: #{spec.mime}\r\n\r\n"
|
65
75
|
out << thumbnail_data
|
66
76
|
|
67
77
|
thumbnail_data = nil
|
@@ -3,16 +3,19 @@ Feature: Generating set of thumbnails with single PUT request
|
|
3
3
|
A user must PUT original image to URL in format
|
4
4
|
/thumbnail[/<thumbnail type>,<width>,<height>,<format>[,<option key>:<option value>]+]+
|
5
5
|
|
6
|
+
Background:
|
7
|
+
Given httpthumbnailer server is running at http://localhost:3100/
|
8
|
+
|
6
9
|
Scenario: Single thumbnail
|
7
10
|
Given test.jpg file content as request body
|
8
|
-
When I do PUT request /thumbnail/crop,16,16,PNG
|
11
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,16,16,PNG
|
9
12
|
Then I will get multipart response
|
10
13
|
Then first part mime type will be image/png
|
11
14
|
And first part will contain PNG image of size 16x16
|
12
15
|
|
13
16
|
Scenario: Multiple thumbnails
|
14
17
|
Given test.jpg file content as request body
|
15
|
-
When I do PUT request /thumbnail/crop,16,16,PNG/crop,4,8,JPG/crop,16,32,JPEG
|
18
|
+
When I do PUT request http://localhost:3100/thumbnail/crop,16,16,PNG/crop,4,8,JPG/crop,16,32,JPEG
|
16
19
|
Then I will get multipart response
|
17
20
|
Then first part mime type will be image/png
|
18
21
|
And first part will contain PNG image of size 16x16
|
@@ -21,3 +24,33 @@ Feature: Generating set of thumbnails with single PUT request
|
|
21
24
|
Then third part mime type will be image/jpeg
|
22
25
|
And third part will contain JPEG image of size 16x32
|
23
26
|
|
27
|
+
Scenario: Transparent image to JPEG handling - default background color white
|
28
|
+
Given test-transparent.png file content as request body
|
29
|
+
When I do PUT request http://localhost:3100/thumbnail/fit,128,128,JPEG
|
30
|
+
Then I will get multipart response
|
31
|
+
And first part body will be saved as test-transparent-default.png for human inspection
|
32
|
+
And first part will contain JPEG image of size 128x128
|
33
|
+
And that image pixel at 32x32 will be of color white
|
34
|
+
|
35
|
+
Scenario: Fit thumbnailing method
|
36
|
+
Given test.jpg file content as request body
|
37
|
+
When I do PUT request http://localhost:3100/thumbnail/fit,128,128,PNG
|
38
|
+
Then I will get multipart response
|
39
|
+
And first part will contain PNG image of size 91x128
|
40
|
+
|
41
|
+
Scenario: Pad thumbnailing method - default background color white
|
42
|
+
Given test.jpg file content as request body
|
43
|
+
When I do PUT request http://localhost:3100/thumbnail/pad,128,128,PNG
|
44
|
+
Then I will get multipart response
|
45
|
+
And first part body will be saved as test-pad.png for human inspection
|
46
|
+
And first part will contain PNG image of size 128x128
|
47
|
+
And that image pixel at 2x2 will be of color white
|
48
|
+
|
49
|
+
Scenario: Pad thumbnailing method with specified background color
|
50
|
+
Given test.jpg file content as request body
|
51
|
+
When I do PUT request http://localhost:3100/thumbnail/pad,128,128,PNG,background-color:green
|
52
|
+
Then I will get multipart response
|
53
|
+
And first part body will be saved as test-pad-background-color.png for human inspection
|
54
|
+
And first part will contain PNG image of size 128x128
|
55
|
+
And that image pixel at 2x2 will be of color green
|
56
|
+
|
@@ -1,20 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
After do
|
9
|
-
server_stop
|
1
|
+
Given /httpthumbnailer server is running at (.*)/ do |url|
|
2
|
+
start_server(
|
3
|
+
"bundle exec #{script('httpthumbnailer')}",
|
4
|
+
'/tmp/httpthumbnailer.pid',
|
5
|
+
support_dir + 'server.log',
|
6
|
+
url
|
7
|
+
)
|
10
8
|
end
|
11
9
|
|
12
10
|
Given /(.*) file content as request body/ do |file|
|
13
11
|
@request_body = File.open(support_dir + file){|f| f.read }
|
14
12
|
end
|
15
13
|
|
16
|
-
When /I do (.*) request (.*)/ do |method,
|
17
|
-
@response =
|
14
|
+
When /I do (.*) request (.*)/ do |method, url|
|
15
|
+
@response = HTTPClient.new.request(method, url, nil, @request_body)
|
18
16
|
end
|
19
17
|
|
20
18
|
Then /I will get multipart response/ do
|
@@ -26,16 +24,25 @@ Then /(.*) part mime type will be (.*)/ do |part, mime|
|
|
26
24
|
@response_multipart.part[part_no(part)].header['Content-Type'].should == mime
|
27
25
|
end
|
28
26
|
|
29
|
-
Then /(.*) part will contain (.*) image of size (.*)/ do |part,
|
27
|
+
Then /(.*) part will contain (.*) image of size (.*)x(.*)/ do |part, format, width, height|
|
28
|
+
mime = @response_multipart.part[part_no(part)].header['Content-Type']
|
30
29
|
data = @response_multipart.part[part_no(part)].body
|
30
|
+
fail("expecte image got #{mime}: #{data}") unless mime =~ /^image\//
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
32
|
+
@image.destroy! if @image
|
33
|
+
@image = Magick::Image.from_blob(data).first
|
34
|
+
|
35
|
+
@image.format.should == format
|
36
|
+
@image.columns.should == width.to_i
|
37
|
+
@image.rows.should == height.to_i
|
39
38
|
end
|
40
39
|
|
40
|
+
And /(.*) part body will be saved as (.*) for human inspection/ do |part, file|
|
41
|
+
data = @response_multipart.part[part_no(part)].body
|
42
|
+
(support_dir + file).open('w'){|f| f.write(data)}
|
43
|
+
end
|
44
|
+
|
45
|
+
And /that image pixel at (.*)x(.*) will be of color (.*)/ do |x, y, color|
|
46
|
+
@image.pixel_color(x.to_i, y.to_i).to_color.sub(/^#/, '0x').should == color
|
47
|
+
end
|
41
48
|
|
data/features/support/env.rb
CHANGED
@@ -16,6 +16,7 @@ require 'httpclient'
|
|
16
16
|
require 'httpthumbnailer/multipart_response'
|
17
17
|
require "open3"
|
18
18
|
require "thread"
|
19
|
+
require 'RMagick'
|
19
20
|
|
20
21
|
def gem_dir
|
21
22
|
Pathname.new(__FILE__).dirname + '..' + '..'
|
@@ -33,24 +34,37 @@ def script(file)
|
|
33
34
|
gem_dir + 'bin' + file
|
34
35
|
end
|
35
36
|
|
36
|
-
def
|
37
|
-
|
37
|
+
def part_no(part)
|
38
|
+
case part
|
39
|
+
when 'first' then 0
|
40
|
+
when 'second' then 1
|
41
|
+
when 'third' then 2
|
42
|
+
else fail "add more parts?"
|
43
|
+
end
|
38
44
|
end
|
39
45
|
|
40
|
-
|
41
|
-
|
46
|
+
|
47
|
+
def get(url)
|
48
|
+
HTTPClient.new.get_content(url)
|
42
49
|
end
|
43
50
|
|
44
|
-
def
|
45
|
-
|
51
|
+
def start_server(cmd, pid_file, log_file, test_url)
|
52
|
+
stop_server(pid_file)
|
53
|
+
|
46
54
|
fork do
|
47
|
-
Daemon.daemonize(
|
48
|
-
exec(
|
55
|
+
Daemon.daemonize(pid_file, log_file)
|
56
|
+
exec(cmd)
|
57
|
+
end
|
58
|
+
Process.wait
|
59
|
+
|
60
|
+
ppid = Process.pid
|
61
|
+
at_exit do
|
62
|
+
stop_server(pid_file) if Process.pid == ppid
|
49
63
|
end
|
50
64
|
|
51
65
|
Timeout.timeout(10) do
|
52
66
|
begin
|
53
|
-
|
67
|
+
get test_url
|
54
68
|
rescue Errno::ECONNREFUSED
|
55
69
|
sleep 0.1
|
56
70
|
retry
|
@@ -58,28 +72,21 @@ def server_start
|
|
58
72
|
end
|
59
73
|
end
|
60
74
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
75
|
+
def stop_server(pid_file)
|
76
|
+
pid_file = Pathname.new(pid_file)
|
77
|
+
return unless pid_file.exist?
|
78
|
+
|
79
|
+
pid = pid_file.read.strip.to_i
|
80
|
+
|
81
|
+
Timeout.timeout(20) do
|
82
|
+
begin
|
83
|
+
loop do
|
84
|
+
Process.kill("TERM", pid)
|
85
|
+
sleep 0.1
|
72
86
|
end
|
87
|
+
rescue Errno::ESRCH
|
88
|
+
pid_file.unlink
|
73
89
|
end
|
74
90
|
end
|
75
91
|
end
|
76
92
|
|
77
|
-
def part_no(part)
|
78
|
-
case part
|
79
|
-
when 'first' then 0
|
80
|
-
when 'second' then 1
|
81
|
-
when 'third' then 2
|
82
|
-
else fail "add more parts?"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
Binary file
|
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.3"
|
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-28"
|
13
13
|
s.description = "Provides HTTP API for thumbnailing images"
|
14
14
|
s.email = "jpastuszek@gmail.com"
|
15
15
|
s.executables = ["httpthumbnailer"]
|
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
|
|
30
30
|
"features/httpthumbnailer.feature",
|
31
31
|
"features/step_definitions/httpthumbnailer_steps.rb",
|
32
32
|
"features/support/env.rb",
|
33
|
+
"features/support/test-transparent.png",
|
33
34
|
"features/support/test.jpg",
|
34
35
|
"httpthumbnailer.gemspec",
|
35
36
|
"lib/httpthumbnailer/multipart_response.rb",
|
@@ -67,7 +67,14 @@ class Thumbnailer
|
|
67
67
|
|
68
68
|
def thumbnail(id, spec)
|
69
69
|
image = @images[id] or raise ImageNotFound.new(id)
|
70
|
-
process_image(image, spec)
|
70
|
+
thumb = process_image(image, spec)
|
71
|
+
replace_transparency(thumb, spec)
|
72
|
+
end
|
73
|
+
|
74
|
+
def replace_transparency(image, spec)
|
75
|
+
Magick::Image.new(image.columns, image.rows) {
|
76
|
+
self.background_color = (spec.options['background-color'] or 'white').sub(/^0x/, '#')
|
77
|
+
}.composite!(image, Magick::CenterGravity, Magick::OverCompositeOp)
|
71
78
|
end
|
72
79
|
|
73
80
|
def process_image(image, spec)
|
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: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
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-28 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
type: :runtime
|
@@ -219,6 +219,7 @@ files:
|
|
219
219
|
- features/httpthumbnailer.feature
|
220
220
|
- features/step_definitions/httpthumbnailer_steps.rb
|
221
221
|
- features/support/env.rb
|
222
|
+
- features/support/test-transparent.png
|
222
223
|
- features/support/test.jpg
|
223
224
|
- httpthumbnailer.gemspec
|
224
225
|
- lib/httpthumbnailer/multipart_response.rb
|