httpthumbnailer 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +4 -3
  3. data/Gemfile.lock +12 -12
  4. data/README.md +242 -68
  5. data/Rakefile +8 -2
  6. data/VERSION +1 -1
  7. data/bin/httpthumbnailer +35 -7
  8. data/lib/httpthumbnailer/error_reporter.rb +4 -2
  9. data/lib/httpthumbnailer/ownership.rb +54 -0
  10. data/lib/httpthumbnailer/plugin.rb +87 -0
  11. data/lib/httpthumbnailer/plugin/thumbnailer.rb +22 -427
  12. data/lib/httpthumbnailer/plugin/thumbnailer/service.rb +163 -0
  13. data/lib/httpthumbnailer/plugin/thumbnailer/service/built_in_plugins.rb +134 -0
  14. data/lib/httpthumbnailer/plugin/thumbnailer/service/images.rb +295 -0
  15. data/lib/httpthumbnailer/plugin/thumbnailer/service/magick.rb +208 -0
  16. data/lib/httpthumbnailer/thumbnail_specs.rb +130 -37
  17. data/lib/httpthumbnailer/thumbnailer.rb +29 -11
  18. metadata +30 -81
  19. data/.rspec +0 -1
  20. data/features/httpthumbnailer.feature +0 -24
  21. data/features/identify.feature +0 -31
  22. data/features/step_definitions/httpthumbnailer_steps.rb +0 -159
  23. data/features/support/env.rb +0 -106
  24. data/features/support/test-large.jpg +0 -0
  25. data/features/support/test-transparent.png +0 -0
  26. data/features/support/test.jpg +0 -0
  27. data/features/support/test.png +0 -0
  28. data/features/support/test.txt +0 -1
  29. data/features/thumbnail.feature +0 -269
  30. data/features/thumbnails.feature +0 -158
  31. data/httpthumbnailer.gemspec +0 -121
  32. data/load_test/extralarge.jpg +0 -0
  33. data/load_test/large.jpg +0 -0
  34. data/load_test/large.png +0 -0
  35. data/load_test/load_test-374846090-1.1.0-rc1-identify-only.csv +0 -3
  36. data/load_test/load_test-374846090-1.1.0-rc1.csv +0 -11
  37. data/load_test/load_test-cd9679c.csv +0 -10
  38. data/load_test/load_test-v0.3.1.csv +0 -10
  39. data/load_test/load_test.jmx +0 -733
  40. data/load_test/medium.jpg +0 -0
  41. data/load_test/small.jpg +0 -0
  42. data/load_test/soak_test-ac0c6bcbe5e-broken-libjpeg-tatoos.csv +0 -11
  43. data/load_test/soak_test-cd9679c.csv +0 -10
  44. data/load_test/soak_test-f98334a-tatoos.csv +0 -11
  45. data/load_test/soak_test.jmx +0 -754
  46. data/load_test/tiny.jpg +0 -0
  47. data/load_test/v0.0.13-loading.csv +0 -7
  48. data/load_test/v0.0.13.csv +0 -7
  49. data/load_test/v0.0.14-no-optimization.csv +0 -10
  50. data/load_test/v0.0.14.csv +0 -10
  51. data/spec/image_processing_spec.rb +0 -148
  52. data/spec/plugin_thumbnailer_spec.rb +0 -318
  53. data/spec/spec_helper.rb +0 -14
  54. data/spec/support/square_even.png +0 -0
  55. data/spec/support/square_odd.png +0 -0
  56. data/spec/support/test_image.rb +0 -16
  57. data/spec/thumbnail_specs_spec.rb +0 -43
@@ -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.2.0"
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 "cucumber", ">= 0"
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
 
@@ -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.1.1)
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.1.0)
23
+ daemon (1.2.0)
24
24
  diff-lcs (1.2.4)
25
- facter (1.6.18)
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.2)
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.1)
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.8.2)
92
+ unicorn (4.9.0)
93
93
  kgio (~> 2.6)
94
94
  rack
95
95
  raindrops (~> 0.7)
96
- unicorn-cuba-base (1.2.0)
96
+ unicorn-cuba-base (1.6.0)
97
97
  cli (~> 1.3)
98
98
  cuba (~> 3.0)
99
- facter (~> 1.6.11)
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.2.0)
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
- * identification of image foramt and size
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="http-access"` that can be used to filter access log entries out from application log entries.
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
- ### Supported operations
121
+ Using `--perf-stats` switch will enable logging of performance statistics. This log entries will be logged with `"type":"perf-stats"`.
107
122
 
108
- As operation type you can select one of the following options:
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 scale image and pad image with background colour to given dimensions keeping aspect ratio
112
- * `limit` - fit scale image to given dimensions if it is larger than that dimensions
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 operation.
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` operations 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
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
- ### API
133
-
134
- #### Single thumbnail API
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/<operation type>,<width>,<height>,<format>[,<option key>:<option value>]*
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
- #### Multipart API
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/<operation type>,<width>,<height>,<format>[,<option key>:<option value>]*[/<operation type>,<width>,<height>,<format>[,<option key>:<option value>]*]*
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
- /thumbnails/crop,16,16,png/crop,4,8,jpg/pad,16,32,jpeg
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
- #### Identification API
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
- ### Ruby API client
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
- ### 400
243
+ #### 400
195
244
 
196
245
  * requested thumbnail method is not supported
197
- * at least one image dimension is zero in thumbnail spec
198
- * missing option key or value in thumbnail spec
199
- * missing argument in in thumbnail spec
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
- ### 413
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
- ### 415
257
+ #### 415
209
258
 
210
259
  * unsupported media type - see **Supported formats** section
211
260
 
212
- ### 500
261
+ #### 500
213
262
 
214
263
  * unexpected error has occurred - see the log file
215
264
 
216
- ### Multipart API
265
+ ### Error handling with multipart API
217
266
 
218
- In multipart API when error relates to single thumbnail `Content-Type: plain/text` header will be used for that part.
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
- ## Statistics API
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
- total_requests: 119
232
- total_errors: 1
280
+ workers: 5
281
+ total_requests: 18239789
282
+ total_errors: 903
233
283
  calling: 1
234
284
  writing: 0
235
- total_images_loaded: 115
236
- total_images_reloaded: 30
237
- total_images_downscaled: 30
238
- total_thumbnails_created: 147
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: 3
241
- max_images_loaded_worker: 3
242
- total_images_created: 312
243
- total_images_destroyed: 312
244
- total_images_created_from_blob: 115
245
- total_images_created_initialize: 53
246
- total_images_created_resize: 101
247
- total_images_created_crop: 13
248
- total_images_created_sample: 30
249
- total_write_multipart: 16
250
- total_write: 101
251
- total_write_part: 48
252
- total_write_error: 1
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/total_write_multipart
256
- 16
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