httpthumbnailer 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Gemfile +4 -3
- data/Gemfile.lock +12 -12
- data/README.md +242 -68
- data/Rakefile +8 -2
- data/VERSION +1 -1
- data/bin/httpthumbnailer +35 -7
- data/lib/httpthumbnailer/error_reporter.rb +4 -2
- data/lib/httpthumbnailer/ownership.rb +54 -0
- data/lib/httpthumbnailer/plugin.rb +87 -0
- data/lib/httpthumbnailer/plugin/thumbnailer.rb +22 -427
- data/lib/httpthumbnailer/plugin/thumbnailer/service.rb +163 -0
- data/lib/httpthumbnailer/plugin/thumbnailer/service/built_in_plugins.rb +134 -0
- data/lib/httpthumbnailer/plugin/thumbnailer/service/images.rb +295 -0
- data/lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb +208 -0
- data/lib/httpthumbnailer/thumbnail_specs.rb +130 -37
- data/lib/httpthumbnailer/thumbnailer.rb +29 -11
- metadata +30 -81
- data/.rspec +0 -1
- data/features/httpthumbnailer.feature +0 -24
- data/features/identify.feature +0 -31
- data/features/step_definitions/httpthumbnailer_steps.rb +0 -159
- data/features/support/env.rb +0 -106
- data/features/support/test-large.jpg +0 -0
- data/features/support/test-transparent.png +0 -0
- data/features/support/test.jpg +0 -0
- data/features/support/test.png +0 -0
- data/features/support/test.txt +0 -1
- data/features/thumbnail.feature +0 -269
- data/features/thumbnails.feature +0 -158
- data/httpthumbnailer.gemspec +0 -121
- data/load_test/extralarge.jpg +0 -0
- data/load_test/large.jpg +0 -0
- data/load_test/large.png +0 -0
- data/load_test/load_test-374846090-1.1.0-rc1-identify-only.csv +0 -3
- data/load_test/load_test-374846090-1.1.0-rc1.csv +0 -11
- data/load_test/load_test-cd9679c.csv +0 -10
- data/load_test/load_test-v0.3.1.csv +0 -10
- data/load_test/load_test.jmx +0 -733
- data/load_test/medium.jpg +0 -0
- data/load_test/small.jpg +0 -0
- data/load_test/soak_test-ac0c6bcbe5e-broken-libjpeg-tatoos.csv +0 -11
- data/load_test/soak_test-cd9679c.csv +0 -10
- data/load_test/soak_test-f98334a-tatoos.csv +0 -11
- data/load_test/soak_test.jmx +0 -754
- data/load_test/tiny.jpg +0 -0
- data/load_test/v0.0.13-loading.csv +0 -7
- data/load_test/v0.0.13.csv +0 -7
- data/load_test/v0.0.14-no-optimization.csv +0 -10
- data/load_test/v0.0.14.csv +0 -10
- data/spec/image_processing_spec.rb +0 -148
- data/spec/plugin_thumbnailer_spec.rb +0 -318
- data/spec/spec_helper.rb +0 -14
- data/spec/support/square_even.png +0 -0
- data/spec/support/square_odd.png +0 -0
- data/spec/support/test_image.rb +0 -16
- data/spec/thumbnail_specs_spec.rb +0 -43
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MzQwNTc5MDc2YmNhZTY3Njg3N2U3ODJiNGQ2YWZmNmJjM2Q2ZjMwNQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ODM1ZmJmZTNjNmY2MGUzYmY5ZjkzZTMwMzk0YzRiNzU3NTc3YzIwNw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NzdmN2JhYTg4OTA2YjczZDI3OWYyMTgzYmJiZGQyYWQ4ZmU0ZTFhM2M4OGVm
|
10
|
+
YjRjMDg5M2RiZTFlNjBhNmNhNDgzNjY4OWNiNWEwNDYxODA5ZmQ5ZTI3Njll
|
11
|
+
MTc0ZTliMWRkMTNkMDNmMmFhNzFjNjU2NWY0ZjQzMzY5NjNkYjA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NzU0NTQ1OTFkMWFkYjU3M2U3MTY0OTNlYWYyYmUwYWFkYWFkODM4YjU5MmE4
|
14
|
+
NTM1ODZhOGQxNGU0NTcxMTVkMTQyNjM1NjdhZjU2MjYwYjgxZDE1MTFmOWE3
|
15
|
+
NTBjNzk1NWZiZjJiZmE3N2NjYjBiODQ4ODEyNDM0MTEzNjJkMzc=
|
data/Gemfile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
ruby "1.9.3"
|
3
3
|
|
4
|
-
gem "unicorn-cuba-base", "~> 1.
|
4
|
+
gem "unicorn-cuba-base", "~> 1.6"
|
5
5
|
#gem "unicorn-cuba-base", path: "../unicorn-cuba-base"
|
6
6
|
gem "rmagick", "~> 2"
|
7
7
|
|
@@ -10,12 +10,13 @@ gem "rmagick", "~> 2"
|
|
10
10
|
group :development do
|
11
11
|
gem "rspec", "~> 2.13"
|
12
12
|
gem "rspec-mocks", "~> 2.13"
|
13
|
-
gem
|
13
|
+
gem 'cucumber', '~> 1.3'
|
14
14
|
gem "capybara", "~> 1.1"
|
15
|
-
gem "jeweler", "~> 1.8.8"
|
15
|
+
gem "jeweler", "~> 1.8", ">= 1.8.8"
|
16
16
|
gem "httpclient", "~> 2.3"
|
17
17
|
gem "rdoc", "~> 3.9"
|
18
18
|
gem "multipart-parser", "~> 0.1.1"
|
19
19
|
gem "daemon", "~> 1.1"
|
20
|
+
#gem "daemon", path: '../daemon'
|
20
21
|
end
|
21
22
|
|
data/Gemfile.lock
CHANGED
@@ -13,16 +13,16 @@ GEM
|
|
13
13
|
childprocess (0.3.9)
|
14
14
|
ffi (~> 1.0, >= 1.0.11)
|
15
15
|
cli (1.3.1)
|
16
|
-
cuba (3.
|
16
|
+
cuba (3.4.0)
|
17
17
|
rack
|
18
18
|
cucumber (1.3.1)
|
19
19
|
builder (>= 2.1.2)
|
20
20
|
diff-lcs (>= 1.1.3)
|
21
21
|
gherkin (~> 2.12.0)
|
22
22
|
multi_json (~> 1.3)
|
23
|
-
daemon (1.
|
23
|
+
daemon (1.2.0)
|
24
24
|
diff-lcs (1.2.4)
|
25
|
-
facter (1.6
|
25
|
+
facter (1.7.6)
|
26
26
|
faraday (0.8.8)
|
27
27
|
multipart-post (~> 1.2.0)
|
28
28
|
ffi (1.8.1)
|
@@ -52,7 +52,7 @@ GEM
|
|
52
52
|
json (1.7.7)
|
53
53
|
jwt (0.1.8)
|
54
54
|
multi_json (>= 1.5)
|
55
|
-
kgio (2.9.
|
55
|
+
kgio (2.9.3)
|
56
56
|
mime-types (1.23)
|
57
57
|
multi_json (1.7.3)
|
58
58
|
multi_xml (0.5.5)
|
@@ -82,24 +82,24 @@ GEM
|
|
82
82
|
rspec-expectations (2.13.0)
|
83
83
|
diff-lcs (>= 1.1.3, < 2.0)
|
84
84
|
rspec-mocks (2.13.1)
|
85
|
-
ruby-ip (0.9.
|
85
|
+
ruby-ip (0.9.3)
|
86
86
|
rubyzip (0.9.9)
|
87
87
|
selenium-webdriver (2.32.1)
|
88
88
|
childprocess (>= 0.2.5)
|
89
89
|
multi_json (~> 1.0)
|
90
90
|
rubyzip
|
91
91
|
websocket (~> 1.0.4)
|
92
|
-
unicorn (4.
|
92
|
+
unicorn (4.9.0)
|
93
93
|
kgio (~> 2.6)
|
94
94
|
rack
|
95
95
|
raindrops (~> 0.7)
|
96
|
-
unicorn-cuba-base (1.
|
96
|
+
unicorn-cuba-base (1.6.0)
|
97
97
|
cli (~> 1.3)
|
98
98
|
cuba (~> 3.0)
|
99
|
-
facter (~> 1.6.
|
99
|
+
facter (~> 1.6, >= 1.6.18)
|
100
100
|
raindrops (~> 0.11)
|
101
101
|
ruby-ip (~> 0.9)
|
102
|
-
unicorn (>= 4.6.2)
|
102
|
+
unicorn (~> 4.6, >= 4.6.2)
|
103
103
|
websocket (1.0.7)
|
104
104
|
xpath (0.1.4)
|
105
105
|
nokogiri (~> 1.3)
|
@@ -109,13 +109,13 @@ PLATFORMS
|
|
109
109
|
|
110
110
|
DEPENDENCIES
|
111
111
|
capybara (~> 1.1)
|
112
|
-
cucumber
|
112
|
+
cucumber (~> 1.3)
|
113
113
|
daemon (~> 1.1)
|
114
114
|
httpclient (~> 2.3)
|
115
|
-
jeweler (~> 1.8.8)
|
115
|
+
jeweler (~> 1.8, >= 1.8.8)
|
116
116
|
multipart-parser (~> 0.1.1)
|
117
117
|
rdoc (~> 3.9)
|
118
118
|
rmagick (~> 2)
|
119
119
|
rspec (~> 2.13)
|
120
120
|
rspec-mocks (~> 2.13)
|
121
|
-
unicorn-cuba-base (~> 1.
|
121
|
+
unicorn-cuba-base (~> 1.6)
|
data/README.md
CHANGED
@@ -1,22 +1,32 @@
|
|
1
1
|
# HTTP Thumbnailer
|
2
2
|
|
3
|
-
HTTP API server for image thumbnailing and format conversion.
|
3
|
+
Stateless HTTP API server for image thumbnailing, editing and format conversion.
|
4
4
|
|
5
5
|
It is using [ImageMagick](http://www.imagemagick.org) or [GraphicsMagick](http://www.graphicsmagick.org) via [RMagick](http://rmagick.rubyforge.org) gem as the image processing library.
|
6
6
|
|
7
7
|
## Features
|
8
8
|
|
9
9
|
* thumbnailing images with different aspect ratio keeping methods
|
10
|
-
*
|
10
|
+
* applying image edits like rotate, crop, blur, pixelate, etc.
|
11
|
+
* identification of image format and size
|
11
12
|
* support of many input and output formats
|
12
13
|
* efficient API for generating multiple thumbnails from single input image with just one request
|
14
|
+
* completely stateless
|
13
15
|
* many image scaling and loading performance optimizations
|
14
16
|
* efficient memory usage
|
15
17
|
* memory limits and disk memory offloading support
|
18
|
+
* custom plugin support
|
16
19
|
* based on [Unicorn HTTP server](http://unicorn.bogomips.org) with UNIX socket communication support
|
17
20
|
|
18
21
|
## Changelog
|
19
22
|
|
23
|
+
### 1.3.0
|
24
|
+
* added edits support
|
25
|
+
* added performance statistics
|
26
|
+
* added plugin support
|
27
|
+
* switches to control optimizations
|
28
|
+
* using downsampling by default when image gets upscaled on load
|
29
|
+
|
20
30
|
### 1.2.0
|
21
31
|
* added `float-x` and `float-y` option support
|
22
32
|
* added `interlace` option support
|
@@ -74,8 +84,13 @@ cat ~/Pictures/compute.jpg | httpthumbnailer-client -t crop,100,200,png > thumbn
|
|
74
84
|
|
75
85
|
# generate multiple thumbnails
|
76
86
|
cat ~/Pictures/compute.jpg | httpthumbnailer-client -t crop,100,200,jpeg,quality:100 -t pad,200,200,png thumbnail1.jpg thumbnail2.png
|
87
|
+
|
88
|
+
# applay edits to the image and thumbnail - pixelate middle of the image and draw blue rectangle at the bottom of it
|
89
|
+
cat ~/Pictures/compute.jpg | httpthumbnailer-client -t 'fit,280,280,png!pixelate,0.3,0.2,0.4,0.4!rectangle,0.04,0.8,0.92,0.17,color:blue' > thumbnail.png
|
77
90
|
```
|
78
91
|
|
92
|
+
### Ruby API client
|
93
|
+
|
79
94
|
In this example we use [httpthumbnailer-client](http://github.com/jpastuszek/httpthumbnailer-client) gem CLI tool that will use HTTP API of the server to generate thumbnails.
|
80
95
|
|
81
96
|
### Running the server
|
@@ -98,18 +113,20 @@ If running as root you can use `--user` option to specify user with whose privil
|
|
98
113
|
|
99
114
|
Additionally `httpthumbnailer` will log requests in [common NCSA format](http://en.wikipedia.org/wiki/Common_Log_Format) to `httpthumbnailer_access.log` file. Use `--access-log-file` option to change location of access log.
|
100
115
|
|
101
|
-
Syslog logging can be enabled with `--syslog-facility` option followed by name of syslog facility to use. When enabled log files are not created and both application logs and access logs are sent to syslog.
|
102
|
-
Access logs will gain meta information that will include `type
|
116
|
+
Syslog logging can be enabled with `--syslog-facility` option followed by name of syslog facility to use. When enabled log files are not created and both application logs and access logs are sent to syslog.
|
117
|
+
Access logs will gain meta information that will include `"type":"http-access"` that can be used to filter access log entries out from application log entries.
|
103
118
|
|
104
119
|
With `--xid-header` option name of HTTP request header can be specified. Value of this header will be logged in meta information tag `xid` along side all request related log entries.
|
105
120
|
|
106
|
-
|
121
|
+
Using `--perf-stats` switch will enable logging of performance statistics. This log entries will be logged with `"type":"perf-stats"`.
|
107
122
|
|
108
|
-
|
123
|
+
### Thumbnailing methods
|
124
|
+
|
125
|
+
For method you can use one of the following value:
|
109
126
|
* `fit` - fit image within given dimensions keeping aspect ratio
|
110
127
|
* `crop` - cut image to fit within given dimensions keeping aspect ratio
|
111
|
-
* `pad` - fit
|
112
|
-
* `limit` - fit
|
128
|
+
* `pad` - fit resize image and pad image with background colour to given dimensions keeping aspect ratio
|
129
|
+
* `limit` - fit resize image to given dimensions if it is larger than that dimensions
|
113
130
|
|
114
131
|
### Supported formats
|
115
132
|
|
@@ -118,7 +135,7 @@ Optionally format `input` can be used to use the same thumbnail format as input
|
|
118
135
|
|
119
136
|
### Thumbnail width and height
|
120
137
|
|
121
|
-
Width and height values are interpreted depending on
|
138
|
+
Width and height values are in pixels and are interpreted depending on method used.
|
122
139
|
`input` string can be used for width and/or height to use input image width or height.
|
123
140
|
|
124
141
|
### Thumbnail options
|
@@ -126,45 +143,87 @@ Width and height values are interpreted depending on operation.
|
|
126
143
|
Following options can be used with thumbnail specification:
|
127
144
|
* `quality` - set output image quality; this is format specific: for JPEG 0 is maximum compression and 100 is maximum quality, for PNG first digit is zlib compression level and second one is filter level
|
128
145
|
* `background-color` - color in HTML notation or textual description ('red', 'green' etc.) used for background when processing transparent images or padding; by default white background is used
|
129
|
-
* `float-x` and `float-y` - value between 0.0 and 1.0; can be used with `crop` and `pad`
|
146
|
+
* `float-x` and `float-y` - value between 0.0 and 1.0; can be used with `crop` and `pad` methods to move cropping view or image over background left to right or top to bottom (0.0 to 1.0); both default to 0.5 centering the view or image
|
130
147
|
* `interlace` - one of `UndefinedInterlace`, `NoInterlace`, `LineInterlace`, `PlaneInterlace`, `PartitionInterlace`, `GIFInterlace`, `JPEGInterlace`, `PNGInterlace`; some formats support interlaced output format; use `JPEGInterlace` or `LineInterlace` or `PlaneInterlace` with `jpeg` format to produce progressive JPEG; defaults to `NoInterlace`
|
131
148
|
|
132
|
-
###
|
133
|
-
|
134
|
-
|
149
|
+
### Edits
|
150
|
+
|
151
|
+
Edits are applied on input image (after possibly being downsampled) and before the final thumbnail is generated.
|
152
|
+
Relative vector values are relative to input image dimensions (width and hight), scalar values are relative to input image diagonal. This way edits will look more or less the same no matter what the input or output image resolution is. Also client does not need to know the resolution of input image.
|
153
|
+
|
154
|
+
One or more edits can be used with thumbnail specification:
|
155
|
+
* `resize_crop` - cut image to fit within given dimensions keeping aspect ratio
|
156
|
+
* arguments: width, height - dimensions to resize and crop image to in pixels
|
157
|
+
* options:
|
158
|
+
* `float-x`, `float-y` - value between 0.0 and 1.0; move cropping view left to right or top to bottom (0.0 to 1.0); default: 0.5 (center)
|
159
|
+
* `resize_fit` - fit image within given dimensions keeping aspect ratio
|
160
|
+
* arguments: width, height in pixels
|
161
|
+
* `resize_limit` - same as `resize_fit` but applied only if image is larger than given dimensions
|
162
|
+
* arguments: width, height - dimension to limit image to in pixels
|
163
|
+
* `crop`
|
164
|
+
* arguments: x, y, width, height - values between 0.0 and 1.0; region of image starting from relative position to image width from left (x) and height from top (y) with relative width and height
|
165
|
+
* `pixelate` - pixelate (sample) given region of image
|
166
|
+
* arguments: box_x, box_y, box_widthd, box_height - values between 0.0 and 1.0; region of image starting from relative position to image width from left (x) and height from top (y) with relative width and height
|
167
|
+
* options:
|
168
|
+
* `size` - size of the pixel (relative to imgae diagonal); default: 0.01
|
169
|
+
* `blur` - blur region of image
|
170
|
+
* arguments: x, y, width, height - values between 0.0 and 1.0; region of image starting from relative position to image width from left (x) and height from top (y) with relative width and height
|
171
|
+
* options:
|
172
|
+
* `sigma` - amount of blur (relative to imgae diagonal); resulting value is capped to 50 pixels
|
173
|
+
* `radius` - radius of the blur (0.0 - calculated for given sigma) (relative to image diagonal); resulting value is capped to 50 pixels; default: 0.0
|
174
|
+
* `rectangle` - draw rectangle over image
|
175
|
+
* arguments: box_x, box_y, box_width, box_height - values between 0.0 and 1.0; rectangle over image starting from relative position to image width from left (x) and height from top (y) with relative width and height
|
176
|
+
* options:
|
177
|
+
* `color` - color of the rectangle; default: black
|
178
|
+
* `rotate` - rotate image clockwise by given angle filling any new image surface with color
|
179
|
+
* arguments: angle - rotation angle in degree
|
180
|
+
* options:
|
181
|
+
* `background-color` - color of the background (when not 90x rotation is used); default: thumbnail `background-color` option or transparent
|
182
|
+
|
183
|
+
## API
|
184
|
+
|
185
|
+
### Single thumbnail API
|
135
186
|
|
136
187
|
To generate single thumbnail send input image with **PUT** request to URI in format:
|
137
188
|
|
138
|
-
/thumbnail/<
|
189
|
+
/thumbnail/<method>,<width>,<height>,<format>[,<option key>:<option value>]*[!<edit name>[,<edit arg>]*[,<edit option>:<edit option value>]*]*
|
139
190
|
|
140
191
|
Server will respond with thumbnail data with correct **Content-Type** header value.
|
141
192
|
|
142
|
-
For example the URI may look like this:
|
193
|
+
For example the URI may look like this:
|
143
194
|
|
144
195
|
/thumbnail/pad,100,100,png,background-color:green
|
145
196
|
|
197
|
+
With additional edits:
|
198
|
+
|
199
|
+
/thumbnail/pad,100,100,png,background-color:green!blur,0.2,0.1,0.6,0.6,size:0.03!rectangle,0.1,0.8,0.8,0.1,color:blue
|
200
|
+
|
146
201
|
For detailed information about the API see [cucumber features](http://github.com/jpastuszek/httpthumbnailer/blob/master/features/thumbnail.feature).
|
147
202
|
|
148
|
-
|
203
|
+
### Multipart API
|
149
204
|
|
150
205
|
To generate multiple thumbnails of single image send that image with **PUT** request to URI in format:
|
151
206
|
|
152
|
-
/thumbnails/<
|
207
|
+
/thumbnails/<method>,<width>,<height>,<format>[,<option key>:<option value>]*[!<edit name>[,<edit arg>]*[,<edit option>:<edit option value>]*]*[/<method>,<width>,<height>,<format>[,<option key>:<option value>]*]*[!<edit name>[,<edit arg>]*[,<edit option>:<edit option value>]*]*
|
153
208
|
|
154
209
|
Server will respond with **multi-part content** with each part containing **Content-Type** header and thumbnail data corresponding to format defined in the URI.
|
155
210
|
|
156
|
-
For example the URI may look like this:
|
211
|
+
For example the URI may look like this:
|
212
|
+
|
213
|
+
/thumbnails/crop,16,16,png/crop,4,8,jpg/pad,16,32,jpeg
|
214
|
+
|
215
|
+
With additional edits:
|
157
216
|
|
158
|
-
|
217
|
+
/thumbnails/crop,16,16,png!blur,0.2,0.1,0.6,0.6,size:0.03!rectangle,0.1,0.8,0.8,0.1,color:blue/crop,4,8,jpg/pad,16,32,jpeg!rotate,90!pixelate,0.3,0.2,0.4,0.4
|
159
218
|
|
160
|
-
HTTP Thumbnailer will generate 3 thumbnails:
|
219
|
+
HTTP Thumbnailer will generate 3 thumbnails:
|
161
220
|
1. 16x16 cropped PNG
|
162
221
|
2. 4x8 cropped JPEG
|
163
222
|
3. 16x32 colour padded JPEG
|
164
223
|
|
165
224
|
For detailed information about the API see [cucumber features](http://github.com/jpastuszek/httpthumbnailer/blob/master/features/thumbnails.feature).
|
166
225
|
|
167
|
-
|
226
|
+
### Identification API
|
168
227
|
|
169
228
|
You can identify image mime type, width and height with **PUT** request to URI in format:
|
170
229
|
|
@@ -176,50 +235,40 @@ Server will respond with **JSON** containing **contentType**, **width** and **he
|
|
176
235
|
|
177
236
|
For detailed information about the API see [cucumber features](http://github.com/jpastuszek/httpthumbnailer/blob/master/features/identify.feature).
|
178
237
|
|
179
|
-
###
|
180
|
-
|
181
|
-
To make it easier to use this server [httpthumbnailer-client](http://github.com/jpastuszek/httpthumbnailer-client) gem provides useful class.
|
182
|
-
|
183
|
-
### Memory limits
|
184
|
-
|
185
|
-
Each worker uses [ImageMagick](http://www.imagemagick.org) memory usage limit feature.
|
186
|
-
By default it will use up to 128MiB of RAM and up to 1GiB of disk backed virtual memory.
|
187
|
-
To change this defaults use `--limit-memory` option for RAM limit and `--limit-disk` to control file backed memory mapping limit in MiB.
|
188
|
-
|
189
|
-
## Status codes
|
238
|
+
### Error status codes
|
190
239
|
|
191
240
|
HTTP Thumbnailer will respond with different status codes on different situations.
|
192
241
|
If all goes well 200 OK will be returned otherwise:
|
193
242
|
|
194
|
-
|
243
|
+
#### 400
|
195
244
|
|
196
245
|
* requested thumbnail method is not supported
|
197
|
-
* at least one image dimension is zero in thumbnail
|
198
|
-
* missing option key or value in thumbnail
|
199
|
-
* missing argument in in thumbnail
|
246
|
+
* at least one image dimension is zero in thumbnail specification
|
247
|
+
* missing option key or value in thumbnail specification
|
248
|
+
* missing argument in in thumbnail specification
|
200
249
|
* bad argument value
|
201
250
|
|
202
|
-
|
251
|
+
#### 413
|
203
252
|
|
204
253
|
* request body is too long
|
205
254
|
* input image is too big to fit in memory
|
206
255
|
* memory or pixel cache limit has been exceeded
|
207
256
|
|
208
|
-
|
257
|
+
#### 415
|
209
258
|
|
210
259
|
* unsupported media type - see **Supported formats** section
|
211
260
|
|
212
|
-
|
261
|
+
#### 500
|
213
262
|
|
214
263
|
* unexpected error has occurred - see the log file
|
215
264
|
|
216
|
-
###
|
265
|
+
### Error handling with multipart API
|
217
266
|
|
218
|
-
|
267
|
+
With multipart API when error relates to single thumbnail `Content-Type: plain/text` header will be used for that part.
|
219
268
|
In addition `Status` header will be set for failing part with number corresponding to above status codes.
|
220
269
|
The body will contain description of the error.
|
221
270
|
|
222
|
-
|
271
|
+
### Statistics API
|
223
272
|
|
224
273
|
HTTP Thumbnailer comes with statistics API that shows various runtime collected statistics.
|
225
274
|
It is set up under `/stats` URI. You can also request single stat with `/stats/<stat name>` request.
|
@@ -228,42 +277,168 @@ Example:
|
|
228
277
|
|
229
278
|
```bash
|
230
279
|
$ curl 127.0.0.1:3100/stats
|
231
|
-
|
232
|
-
|
280
|
+
workers: 5
|
281
|
+
total_requests: 18239789
|
282
|
+
total_errors: 903
|
233
283
|
calling: 1
|
234
284
|
writing: 0
|
235
|
-
total_images_loaded:
|
236
|
-
total_images_reloaded:
|
237
|
-
total_images_downscaled:
|
238
|
-
total_thumbnails_created:
|
285
|
+
total_images_loaded: 17633702
|
286
|
+
total_images_reloaded: 0
|
287
|
+
total_images_downscaled: 21805
|
288
|
+
total_thumbnails_created: 17633090
|
239
289
|
images_loaded: 0
|
240
|
-
max_images_loaded:
|
241
|
-
max_images_loaded_worker:
|
242
|
-
total_images_created:
|
243
|
-
total_images_destroyed:
|
244
|
-
total_images_created_from_blob:
|
245
|
-
total_images_created_initialize:
|
246
|
-
total_images_created_resize:
|
247
|
-
total_images_created_crop:
|
248
|
-
total_images_created_sample:
|
249
|
-
total_write_multipart:
|
250
|
-
total_write:
|
251
|
-
total_write_part:
|
252
|
-
total_write_error:
|
290
|
+
max_images_loaded: 101
|
291
|
+
max_images_loaded_worker: 101
|
292
|
+
total_images_created: 50178054
|
293
|
+
total_images_destroyed: 50178054
|
294
|
+
total_images_created_from_blob: 17634825
|
295
|
+
total_images_created_initialize: 9763067
|
296
|
+
total_images_created_resize: 16261541
|
297
|
+
total_images_created_crop: 6496816
|
298
|
+
total_images_created_sample: 21805
|
299
|
+
total_write_multipart: 0
|
300
|
+
total_write: 18238885
|
301
|
+
total_write_part: 0
|
302
|
+
total_write_error: 903
|
253
303
|
total_write_error_part: 0
|
254
304
|
|
255
|
-
$ curl 127.0.0.1:3100/stats/
|
256
|
-
|
305
|
+
$ curl 127.0.0.1:3100/stats/total_thumbnails_created
|
306
|
+
17633106
|
307
|
+
```
|
308
|
+
|
309
|
+
## Memory limits
|
310
|
+
|
311
|
+
Each worker uses [ImageMagick](http://www.imagemagick.org) memory usage limit feature.
|
312
|
+
By default it will use up to 128MiB of RAM and up to 1GiB of disk backed virtual memory.
|
313
|
+
To change this defaults use `--limit-memory` option for RAM limit and `--limit-disk` to control file backed memory mapping limit in MiB.
|
314
|
+
|
315
|
+
## Plugins
|
316
|
+
|
317
|
+
Custom thumbnailing methods and edits can be programed using plugin API.
|
318
|
+
By default HTTP Thumbnailer will look for plugins in `/usr/share/httpthumbnailer/plugins`. Options `--plugins` can be used to point to different directory; it can also be specified multiple times to point to more than one directory.
|
319
|
+
Plugin file needs to end with `.rb` extension to be found anywhere within directory structure pointed by `--plugins` option (or in default directory).
|
320
|
+
|
321
|
+
### Defining new thumbnailing methods
|
322
|
+
|
323
|
+
To define new thumbnailing method provide block like this:
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
thumbnailing_method('method_name') do |image, width, height, options|
|
327
|
+
# do something with image
|
328
|
+
end
|
329
|
+
```
|
330
|
+
|
331
|
+
Name of the method is defined by value of `thumbnailing_method` method argument (string).
|
332
|
+
|
333
|
+
Server will pass following objects:
|
334
|
+
* `image` - [RMagick::Image](https://rmagick.github.io/index.html) object
|
335
|
+
* `width` and `height` - integers representing required width and height of the thumbnail
|
336
|
+
* `options` - key-value map, where keys and values are strings, passed to request specification
|
337
|
+
|
338
|
+
Block should return (last value or with `next` keyword) new image or the image passed with `image` argument or `nil` if no change was done.
|
339
|
+
|
340
|
+
### Defining new edits
|
341
|
+
|
342
|
+
To define new edit provide block like this:
|
343
|
+
|
344
|
+
```ruby
|
345
|
+
edit('edit_name') do |image, arg1, arg2, argN, options, thumbnail_spec|
|
346
|
+
# do something with image
|
347
|
+
end
|
348
|
+
```
|
349
|
+
|
350
|
+
Name of the edit is defined by value of `edit` method argument (string).
|
351
|
+
|
352
|
+
Server will pass following objects:
|
353
|
+
* `image` - [RMagick::Image](https://rmagick.github.io/index.html) object; input image or output of previous edit
|
354
|
+
* all arguments as passed to the API; you can capture as many as you need
|
355
|
+
* `options` - key-value map, where keys and values are strings, passed to request with edit specification
|
356
|
+
* `thumbnail_spec` - object representing thumbnailing specification; you can call following methods:
|
357
|
+
* `method` - name of the thumbnailing method
|
358
|
+
* `width` and `height` - integers representing required width and height of the thumbnail
|
359
|
+
* `format` - requested output format (e.g. `png` or `jpeg`)
|
360
|
+
* `options` - key-value map of thumbnailing options
|
361
|
+
* `edits` - array representing all edits; each edit has following methods:
|
362
|
+
* `name` - name of the edit
|
363
|
+
* `args` - array of edit arguments
|
364
|
+
* `options` - key-value map of edit options
|
365
|
+
|
366
|
+
Block should return (last value or with `next` keyword) new image or the image passed with `image` argument or `nil` if no change was done.
|
367
|
+
|
368
|
+
### Processing images
|
369
|
+
|
370
|
+
If more than one image is created during processing it is important to call `get` on every newly created image (unless it is the one being returned). This method will pass the image to first block argument and will ensure that image is destroyed after use or on exception. Returning `nil` or same image as input will make `get` to return the input image without destroying it.
|
371
|
+
|
372
|
+
Example of `get` usage:
|
373
|
+
|
374
|
+
```ruby
|
375
|
+
image.crop(cut_x * image.columns, cut_y * image.rows, cut_w * image.columns, cut_h * image.rows, true).get do |image|
|
376
|
+
image.resize_to_fit(width, height) if image.columns != width or image.rows != height
|
377
|
+
end
|
378
|
+
```
|
379
|
+
|
380
|
+
For examples see built-in thumbnailing methods and edits defined in [built_in_plugins.rb](lib/httpthumbnailer/plugin/thumbnailer/service/built_in_plugins.rb).
|
381
|
+
|
382
|
+
### Helper functions
|
383
|
+
|
384
|
+
Following helper functions are available in plugin context:
|
385
|
+
* `int!(name, arg, default = nil)` - returns integer from given `arg` string; `name` is used for reporting errors; if `arg` is an empty string returns `default` if not `nil` or fail with **400 Bad Request**
|
386
|
+
* `uint!(name, arg, default = nil)` - returns positive integer from given `arg` string; `name` is used for reporting errors; if `arg` is an empty string returns `default` if not `nil` or fail with **400 Bad Request**
|
387
|
+
* `float!(name, arg, default = nil)` - returns float from given `arg` string; `name` is used for reporting errors; if `arg` is an empty string returns `default` if not `nil` or fail with **400 Bad Request**
|
388
|
+
* `ufloat!(name, arg, default = nil)` - returns positive float from given `arg` string; `name` is used for reporting errors; if `arg` is an empty string returns `default` if not `nil` or fail with **400 Bad Request**
|
389
|
+
* `offset_to_center(x, y, w, h)` - returns center (`[x, y]`) of the given region
|
390
|
+
* `center_to_offset(center_x, center_y, w, h)` - returns offset (`[x, y]`) of given region center (`center_x`, `center_y`) and `width` and `height`
|
391
|
+
* `normalize_region(x, y, width, height)` - returns normalized relative (values between 0.0 and 1.0) region offset and dimensions (`[x, y, width, height]`) that fits within normal values so that width and height will never be 0.0 (`Float::EPSILON` instead), `x + width` and `y + height` will never be grater than 1.0 and all values will not be negative
|
392
|
+
|
393
|
+
Additional [RMagick::Image](https://rmagick.github.io/index.html) object methods are provided:
|
394
|
+
* `RMagick::Image.new_8bit(width, height, background_color = 'none')` - create new image of given dimensions and background color (which can be described by pallet color name like **black** of by hex value)
|
395
|
+
* `render_on_background(background_color, width = nil, height = nil, float_x = 0.5, float_y = 0.5)` - overlay current image on top of new image (with optionally different dimensions and floating) of given color
|
396
|
+
* `float_to_offset(float_width, float_height, float_x = 0.5, float_y = 0.5)` - calculated offset (`[x, y]`) of image with given dimensions (`float_width`, `float_height`) on top of this image given `float_x` and `float_y` values
|
397
|
+
* `pixelate_region(x, y, w, h, size)` - pixelate region given with offset (`x`, `y`) and dimensions (`w`, `h`) in pixels of pixel diagonal size (`size`) also in pixels
|
398
|
+
* `blur_region(x, y, w, h, radius, sigma)` - blur region given with offset (`x`, `y`) and dimensions (`w`, `h`) in pixels using effect `radius` and `sigma` in pixels
|
399
|
+
* `render_rectangle(x, y, w, h, color)` - draw rectangle given with offset (`x`, `y`) and dimensions (`w`, `h`) in pixels
|
400
|
+
* `with_background_color(color, &block)` - do **RMagick** image operation that uses background color in given block and restore previous background color when finished
|
401
|
+
* `rel_to_px_pos(x, y)` - convert relative offset to offset represented in pixels (using `Float#floor` value)
|
402
|
+
* `rel_to_px_dim(width, height)` - convert relative width and height to width and height in pixels (using `Float#ceil` value)
|
403
|
+
* `rel_to_diagonal(v)` - convert relative diagonal to diagonal in pixels (using `Float#ceil` value)
|
404
|
+
* `width` - alias for `#columns`
|
405
|
+
* `height` - alias for `#height`
|
406
|
+
* `diagonal` - calculate diagonal in pixels (using `Float#ceil` value)
|
407
|
+
|
408
|
+
### Memory usage and leaks
|
409
|
+
|
410
|
+
To avoid memory leaks (leaked images) make use of `get` method on intermediate images.
|
411
|
+
Observe value of `total_images_reloaded` - if it is increasing and not dropping to 0 after you used the thumbnailing API you have a leak!
|
412
|
+
|
413
|
+
```bash
|
414
|
+
$ curl 127.0.0.1:3100/stats/images_loaded
|
415
|
+
0
|
416
|
+
```
|
417
|
+
|
418
|
+
Also avoid keeping too many images loaded at the same time. Chain `get` calls rather than nest them:
|
419
|
+
|
420
|
+
```ruby
|
421
|
+
image.get do |image|
|
422
|
+
# image is the input image
|
423
|
+
# image processing step 1
|
424
|
+
end.get do |image|
|
425
|
+
# image is now result of step 1
|
426
|
+
# image processing step 2
|
427
|
+
end.get do |image|
|
428
|
+
# image is now result of step 2
|
429
|
+
# image processing final step
|
430
|
+
end
|
257
431
|
```
|
258
432
|
|
259
433
|
## See also
|
260
434
|
|
261
|
-
[HTTP Image Store](https://github.com/jpastuszek/httpimagestore) service is configurable image storage and processing HTTP API server that uses this service as thumbnailing backend.
|
435
|
+
[HTTP Image Store](https://github.com/jpastuszek/httpimagestore) service is configurable image storage and processing HTTP API server that uses this service as thumbnailing backend.
|
262
436
|
|
263
437
|
## Known Issues
|
264
438
|
|
265
|
-
* When 413 error is reported due to memory limit exhaustion the disk offloading won't work any more and only requests that can fit in the memory can be processed without getting 413 - this is due to a bug in ImageMagick v6.8.6-8 (2013-08-06 6.8.6-8) or less
|
439
|
+
* When 413 error is reported due to memory limit exhaustion the disk offloading won't work any more and only requests that can fit in the memory can be processed without getting 413 - this is due to a bug in ImageMagick v6.8.6-8 (2013-08-06 6.8.6-8) or less; recommended version is 6.8.7-8
|
266
440
|
* Mime type generated for images may not be the official mime type assigned for given format; please let me know of any inconsistencies or send a patch to get better output in efficient way
|
441
|
+
* CMYK profile JPEGs may render negative
|
267
442
|
|
268
443
|
## TODO
|
269
444
|
|
@@ -271,7 +446,7 @@ $ curl 127.0.0.1:3100/stats/total_write_multipart
|
|
271
446
|
* Allow for specifying different quality values for different image types, e.g.: quality[jpeg]:97,quality[png]:85
|
272
447
|
|
273
448
|
## Contributing to HTTP Thumbnailer
|
274
|
-
|
449
|
+
|
275
450
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
276
451
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
277
452
|
* Fork the project
|
@@ -282,6 +457,5 @@ $ curl 127.0.0.1:3100/stats/total_write_multipart
|
|
282
457
|
|
283
458
|
## Copyright
|
284
459
|
|
285
|
-
Copyright (c) 2013 Jakub Pastuszek. See LICENSE.txt for
|
286
|
-
further details.
|
460
|
+
Copyright (c) 2013 - 2015 Jakub Pastuszek. See LICENSE.txt for further details.
|
287
461
|
|