image_vise 0.0.19 → 0.0.20
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.
- checksums.yaml +4 -4
- data/README.md +113 -43
- data/image_vise.gemspec +5 -3
- data/lib/image_vise.rb +3 -1
- data/lib/image_vise/image_request.rb +0 -3
- data/lib/image_vise/render_engine.rb +0 -2
- data/lib/image_vise/strip_metadata.rb +10 -0
- data/spec/image_vise/geom_spec.rb +16 -0
- data/spec/image_vise/pipeline_spec.rb +3 -1
- data/spec/image_vise/strip_metadata_spec.rb +14 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec4d4b81f950cbc31ce3ac5c43d311c0049a5497
|
4
|
+
data.tar.gz: d3558ea48e705fe17e18fff1036d48f8c1ecdd3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b21bc99a45b1b6830d7f38b6b507103d50603e5fd370167a9f1d2ba9eb941d332580fa5d713f20a80e58eeb21cb2e0e9a79a2ea8054e12a816d7260a33299d50
|
7
|
+
data.tar.gz: e14e15cf5306b14cb53e7f89e306753bc1e4c3db601f689716d7c146636b8d701e02d2f1144fa152c26a4aa1ff07925945a2eae55db608f697d534a8d39b0a0a
|
data/README.md
CHANGED
@@ -23,30 +23,38 @@ take care of encoding the source URL and the commands in the right way, as well
|
|
23
23
|
|
24
24
|
Mount ImageVise in your `routes.rb`:
|
25
25
|
|
26
|
-
|
26
|
+
```ruby
|
27
|
+
mount '/images' => ImageVise
|
28
|
+
```
|
27
29
|
|
28
30
|
and add an initializer (like `config/initializers/image_vise_config.rb`) to set up the permitted hosts
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
+
```ruby
|
33
|
+
ImageVise.add_allowed_host! your_application_hostname
|
34
|
+
ImageVise.add_secret_key! ENV.fetch('IMAGE_VISE_SECRET')
|
35
|
+
```
|
32
36
|
|
33
37
|
You might want to define a helper method for generating signed URLs as well, which will look something like this:
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
```ruby
|
40
|
+
def thumb_url(source_image_url)
|
41
|
+
qs_params = ImageVise.image_params(src_url: source_image_url, secret: ENV.fetch('IMAGE_VISE_SECRET')) do |pipeline|
|
42
|
+
# For example, you can also yield `pipeline` to the caller
|
43
|
+
pipeline.fit_crop width: 128, height: 128, gravity: 'c'
|
44
|
+
end
|
45
|
+
'/images?' + Rack::Utils.build_query(qs_params) # or use url_for...
|
46
|
+
end
|
47
|
+
```
|
42
48
|
|
43
49
|
## Using ImageVise within a Rack application
|
44
50
|
|
45
51
|
Mount ImageVise under a script name in your `config.ru`:
|
46
52
|
|
47
|
-
|
48
|
-
|
49
|
-
|
53
|
+
```ruby
|
54
|
+
map '/images' do
|
55
|
+
run ImageVise
|
56
|
+
end
|
57
|
+
```
|
50
58
|
|
51
59
|
and add the initialization code either to `config.ru` proper or to some file in your application:
|
52
60
|
|
@@ -55,16 +63,17 @@ and add the initialization code either to `config.ru` proper or to some file in
|
|
55
63
|
|
56
64
|
You might want to define a helper method for generating signed URLs as well, which will look something like this:
|
57
65
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
```ruby
|
67
|
+
def thumb_url(source_image_url)
|
68
|
+
qs_params = ImageVise.image_params(src_url: source_image_url, secret: ENV.fetch('IMAGE_VISE_SECRET')) do |pipe|
|
69
|
+
pipe.fit_crop width: 256, height: 256, gravity: 'c'
|
70
|
+
pipe.sharpen sigma: 0.5, radius: 2
|
71
|
+
pipe.ellipse_stencil
|
72
|
+
end
|
73
|
+
# Output a URL to the app
|
74
|
+
'/images?' + Rack::Utils.build_query(image_request)
|
75
|
+
end
|
76
|
+
```
|
68
77
|
|
69
78
|
## Processing files on the local filesystem instead of remote ones
|
70
79
|
|
@@ -93,27 +102,32 @@ of decent image filtering choices in ImageMagick proper).
|
|
93
102
|
|
94
103
|
Here is an example pipeline, JSON-encoded (this is what is passed in the URL):
|
95
104
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
105
|
+
```json
|
106
|
+
[
|
107
|
+
["auto_orient", {}],
|
108
|
+
["geom", {"geometry_string": "512x512"}],
|
109
|
+
["fit_crop", {"width": 32, "height": 32, "gravity": "se"}],
|
110
|
+
["sharpen", {"radius": 0.75, "sigma": 0.5}],
|
111
|
+
["ellipse_stencil", {}]
|
112
|
+
]
|
113
|
+
```
|
103
114
|
|
104
115
|
The same pipeline can be created using the `Pipeline` DSL:
|
105
116
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
117
|
+
```ruby
|
118
|
+
pipe = Pipeline.new.
|
119
|
+
auto_orient.
|
120
|
+
geom(geometry_string: '512x512').
|
121
|
+
fit_crop(width: 32, height: 32, gravity: 'se').
|
122
|
+
sharpen(radius: 0.75, sigma: 0.5).
|
123
|
+
ellipse_stencil
|
124
|
+
```
|
113
125
|
and can then be applied to a `Magick::Image` object:
|
114
126
|
|
115
|
-
|
116
|
-
|
127
|
+
```ruby
|
128
|
+
image = Magick::Image.read(my_image_path)[0]
|
129
|
+
pipe.apply!(image)
|
130
|
+
```
|
117
131
|
|
118
132
|
## Performance and memory
|
119
133
|
|
@@ -161,7 +175,9 @@ CDN.
|
|
161
175
|
To allow `ImageVise` to recognize the signature when the signature is going to be received, add it to the list
|
162
176
|
of the shared keys on the `ImageVise` server:
|
163
177
|
|
164
|
-
|
178
|
+
```ruby
|
179
|
+
ImageVise.add_secret_key!('ahoy! this is a secret!')
|
180
|
+
```
|
165
181
|
|
166
182
|
A single `ImageVise` server can maintain multiple signature keys, so that you will be able to generate thumbnails from
|
167
183
|
multiple applications all using different keys for their signatures. Every request will be validated against
|
@@ -173,18 +189,72 @@ accepted and the request will be allowed to go through.
|
|
173
189
|
By default, `ImageVise` will refuse to process images from URLs on "unknown" hosts. To mark a host as "known"
|
174
190
|
tell `ImageVise` to
|
175
191
|
|
176
|
-
|
192
|
+
```ruby
|
193
|
+
ImageVise.add_allowed_host!('my-image-store.ourcompany.co.uk')
|
194
|
+
```
|
177
195
|
|
178
196
|
If you want to permit images from the local server filesystem to be accessed, add the glob pattern
|
179
197
|
to the set of allowed filesystem patterns:
|
180
198
|
|
181
|
-
|
199
|
+
```ruby
|
200
|
+
ImageVise.allow_filesystem_source!(Rails.root + '/public/*.jpg')
|
201
|
+
```
|
182
202
|
|
183
203
|
Note that these are _glob_ patterns. The image path will be checked against them using `File.fnmatch`.
|
184
204
|
|
205
|
+
## Handling errors within the rendering Rack app
|
206
|
+
|
207
|
+
By default, the Rack app within ImageVise swallows all exceptions and returns the error message
|
208
|
+
within a machine-readable JSON payload. If that doesn't work for you, or you want to add error
|
209
|
+
handling using some error tracking provider, either subclass `ImageVise::RenderEngine` or prepend
|
210
|
+
a module into it that will intercept the errors. For example, [Sentry](https://sentry.io) has a neat
|
211
|
+
property of picking up `rack.exception` from the Rack request env. Using the hooks in the render engine,
|
212
|
+
you can add Sentry support by using the following module:
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
module ImageViseSentrySupport
|
216
|
+
ImageVise::RenderEngine.prepend self
|
217
|
+
|
218
|
+
def setup_error_handling(rack_env)
|
219
|
+
@env = rack_env
|
220
|
+
end
|
221
|
+
|
222
|
+
def handle_request_error(err)
|
223
|
+
@env['rack.exception'] = err
|
224
|
+
end
|
225
|
+
|
226
|
+
def handle_generic_error(err)
|
227
|
+
@env['rack.exception'] = err
|
228
|
+
end
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
For [Appsignal](https://appsignal.com) you can use the following module instead:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
module ImageViseAppsignal
|
236
|
+
ImageVise::RenderEngine.prepend self
|
237
|
+
|
238
|
+
def setup_error_handling(rack_env)
|
239
|
+
txn = Appsignal::Transaction.current
|
240
|
+
txn.set_action('%s#%s' % [self.class, 'call'])
|
241
|
+
end
|
242
|
+
|
243
|
+
def handle_request_error(err)
|
244
|
+
Appsignal.add_exception(err)
|
245
|
+
end
|
246
|
+
|
247
|
+
def handle_generic_error(err)
|
248
|
+
Appsignal.add_exception(err)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
In both cases you need the overall Rack error handling middleware to be wrapping ImageVise, of course.
|
254
|
+
|
185
255
|
## State
|
186
256
|
|
187
|
-
Except for the HTTP cache
|
257
|
+
Except for the HTTP cache no state is stored (`ImageVise` does not care whether you store
|
188
258
|
your images using Dragonfly, CarrierWave or some custom handling code). All the app needs is the full URL.
|
189
259
|
|
190
260
|
## Running the tests, versioning, contributing
|
data/image_vise.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: image_vise 0.0.
|
5
|
+
# stub: image_vise 0.0.20 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "image_vise"
|
9
|
-
s.version = "0.0.
|
9
|
+
s.version = "0.0.20"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Julik Tarkhanov"]
|
14
|
-
s.date = "2016-10-
|
14
|
+
s.date = "2016-10-17"
|
15
15
|
s.description = "Image processing via URLs"
|
16
16
|
s.email = "me@julik.nl"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
"lib/image_vise/sRGB_v4_ICC_preference_displayclass.icc",
|
39
39
|
"lib/image_vise/sharpen.rb",
|
40
40
|
"lib/image_vise/srgb.rb",
|
41
|
+
"lib/image_vise/strip_metadata.rb",
|
41
42
|
"spec/image_vise/auto_orient_spec.rb",
|
42
43
|
"spec/image_vise/crop_spec.rb",
|
43
44
|
"spec/image_vise/ellipse_stencil_spec.rb",
|
@@ -49,6 +50,7 @@ Gem::Specification.new do |s|
|
|
49
50
|
"spec/image_vise/render_engine_spec.rb",
|
50
51
|
"spec/image_vise/sharpen_spec.rb",
|
51
52
|
"spec/image_vise/srgb_spec.rb",
|
53
|
+
"spec/image_vise/strip_metadata_spec.rb",
|
52
54
|
"spec/image_vise_spec.rb",
|
53
55
|
"spec/spec_helper.rb",
|
54
56
|
"spec/test_server.rb",
|
data/lib/image_vise.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Strips metadata from the image (EXIF, IPTC etc.) using the
|
2
|
+
# RMagick `strip!` method
|
3
|
+
#
|
4
|
+
# The corresponding Pipeline method is `strip_metadata`.
|
5
|
+
class ImageVise::StripMetadata
|
6
|
+
def apply!(magick_image)
|
7
|
+
magick_image.strip!
|
8
|
+
end
|
9
|
+
ImageVise.add_operator 'strip_metadata', self
|
10
|
+
end
|
@@ -5,6 +5,22 @@ describe ImageVise::Geom do
|
|
5
5
|
expect { described_class.new(geometry_string: nil) }.to raise_error(ArgumentError)
|
6
6
|
end
|
7
7
|
|
8
|
+
it 'fits to height' do
|
9
|
+
image = Magick::Image.read(test_image_path)[0]
|
10
|
+
crop = described_class.new(geometry_string: 'x200')
|
11
|
+
crop.apply!(image)
|
12
|
+
expect(image.rows).to eq(200)
|
13
|
+
examine_image(image, 'fit-height-200')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'fits to width' do
|
17
|
+
image = Magick::Image.read(test_image_path)[0]
|
18
|
+
crop = described_class.new(geometry_string: '100x')
|
19
|
+
crop.apply!(image)
|
20
|
+
expect(image.columns).to eq(100)
|
21
|
+
examine_image(image, 'fit-width-100')
|
22
|
+
end
|
23
|
+
|
8
24
|
it 'applies various geometry strings' do
|
9
25
|
%w( ^220x110 !20x20 !10x100 ).each do |geom_string|
|
10
26
|
image = Magick::Image.read(test_image_path)[0]
|
@@ -37,8 +37,10 @@ describe ImageVise::Pipeline do
|
|
37
37
|
pipeline = subject.
|
38
38
|
auto_orient.
|
39
39
|
fit_crop(width: 48, height: 48, gravity: 'c').
|
40
|
+
srgb.
|
40
41
|
sharpen(radius: 2, sigma: 0.5).
|
41
|
-
ellipse_stencil
|
42
|
+
ellipse_stencil.
|
43
|
+
strip_metadata
|
42
44
|
|
43
45
|
image = Magick::Image.read(test_image_path)[0]
|
44
46
|
pipeline.apply! image
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ImageVise::StripMetadata do
|
4
|
+
it 'applies the strip! method to the image' do
|
5
|
+
image = Magick::Image.read(test_image_path).first
|
6
|
+
expect(image).to receive(:strip!).and_call_original
|
7
|
+
described_class.new.apply!(image)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'is registered with the operator registry' do
|
11
|
+
op = ImageVise.operator_from('strip_metadata')
|
12
|
+
expect(op).to eq(described_class)
|
13
|
+
end
|
14
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: image_vise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -267,6 +267,7 @@ files:
|
|
267
267
|
- lib/image_vise/sRGB_v4_ICC_preference_displayclass.icc
|
268
268
|
- lib/image_vise/sharpen.rb
|
269
269
|
- lib/image_vise/srgb.rb
|
270
|
+
- lib/image_vise/strip_metadata.rb
|
270
271
|
- spec/image_vise/auto_orient_spec.rb
|
271
272
|
- spec/image_vise/crop_spec.rb
|
272
273
|
- spec/image_vise/ellipse_stencil_spec.rb
|
@@ -278,6 +279,7 @@ files:
|
|
278
279
|
- spec/image_vise/render_engine_spec.rb
|
279
280
|
- spec/image_vise/sharpen_spec.rb
|
280
281
|
- spec/image_vise/srgb_spec.rb
|
282
|
+
- spec/image_vise/strip_metadata_spec.rb
|
281
283
|
- spec/image_vise_spec.rb
|
282
284
|
- spec/spec_helper.rb
|
283
285
|
- spec/test_server.rb
|