image_vise 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.travis.yml +13 -0
  4. data/DEVELOPMENT.md +0 -11
  5. data/Gemfile +2 -20
  6. data/Rakefile +3 -26
  7. data/image_vise.gemspec +37 -132
  8. data/lib/image_vise/file_response.rb +2 -2
  9. data/lib/image_vise/image_request.rb +2 -0
  10. data/lib/image_vise/operators/background_fill.rb +18 -0
  11. data/lib/image_vise/operators/ellipse_stencil.rb +7 -5
  12. data/lib/image_vise/operators/force_jpg_out.rb +17 -0
  13. data/lib/image_vise/pipeline.rb +13 -3
  14. data/lib/image_vise/render_engine.rb +36 -64
  15. data/lib/image_vise/version.rb +3 -0
  16. data/lib/image_vise/writers/auto_writer.rb +23 -0
  17. data/lib/image_vise/writers/jpeg_writer.rb +9 -0
  18. data/lib/image_vise.rb +19 -19
  19. metadata +43 -135
  20. data/spec/image_vise/auto_orient_spec.rb +0 -10
  21. data/spec/image_vise/crop_spec.rb +0 -20
  22. data/spec/image_vise/ellipse_stencil_spec.rb +0 -19
  23. data/spec/image_vise/fetcher_file_spec.rb +0 -48
  24. data/spec/image_vise/fetcher_http_spec.rb +0 -44
  25. data/spec/image_vise/file_response_spec.rb +0 -45
  26. data/spec/image_vise/fit_crop_spec.rb +0 -20
  27. data/spec/image_vise/geom_spec.rb +0 -33
  28. data/spec/image_vise/image_request_spec.rb +0 -62
  29. data/spec/image_vise/pipeline_spec.rb +0 -72
  30. data/spec/image_vise/render_engine_spec.rb +0 -325
  31. data/spec/image_vise/sharpen_spec.rb +0 -17
  32. data/spec/image_vise/srgb_spec.rb +0 -28
  33. data/spec/image_vise/strip_metadata_spec.rb +0 -14
  34. data/spec/image_vise_spec.rb +0 -110
  35. data/spec/layers-with-blending.psd +0 -0
  36. data/spec/spec_helper.rb +0 -103
  37. data/spec/test_server.rb +0 -61
  38. data/spec/waterside_magic_hour.jpg +0 -0
  39. data/spec/waterside_magic_hour.psd +0 -0
  40. data/spec/waterside_magic_hour_adobergb.jpg +0 -0
  41. data/spec/waterside_magic_hour_gray.tif +0 -0
  42. data/spec/waterside_magic_hour_transp.png +0 -0
@@ -0,0 +1,23 @@
1
+ # Picks the most reasonable "default" output format for web resources. In practice, if the
2
+ # image contains transparency (an alpha channel) PNG will be chosen, and if not - JPEG will
3
+ # be chosen. Since ImageVise URLs do not contain a file extension we are free to pick
4
+ # the suitable format at render time
5
+ class ImageVise::AutoWriter
6
+ # The default file type for images with alpha
7
+ PNG_FILE_TYPE = MagicBytes::FileType.new('png','image/png').freeze
8
+
9
+ # Renders the file as a jpg if the custom output filetype operator is used
10
+ JPG_FILE_TYPE = MagicBytes::FileType.new('jpg','image/jpeg').freeze
11
+
12
+ def write_image!(magick_image, _, render_to_path)
13
+ # If processing the image has created an alpha channel, use PNG always.
14
+ # Otherwise, keep the original format for as far as the supported formats list goes.
15
+ render_file_type = if magick_image.alpha?
16
+ PNG_FILE_TYPE
17
+ else
18
+ JPG_FILE_TYPE
19
+ end
20
+ magick_image.format = render_file_type.ext
21
+ magick_image.write(render_to_path)
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ class ImageVise::JPGWriter < Ks.strict(:quality)
2
+ JPG_FILE_TYPE = MagicBytes::FileType.new('jpg','image/jpeg').freeze
3
+
4
+ def write_image!(magick_image, _, render_to_path)
5
+ q = self.quality # to avoid the changing "self" context
6
+ magick_image.format = JPG_FILE_TYPE.ext
7
+ magick_image.write(render_to_path) { self.quality = q }
8
+ end
9
+ end
data/lib/image_vise.rb CHANGED
@@ -8,37 +8,37 @@ require 'base64'
8
8
  require 'rack'
9
9
 
10
10
  class ImageVise
11
- VERSION = '0.1.6'
11
+ require_relative 'image_vise/version'
12
12
  S_MUTEX = Mutex.new
13
13
  private_constant :S_MUTEX
14
-
14
+
15
15
  @allowed_hosts = Set.new
16
16
  @keys = Set.new
17
17
  @operators = {}
18
18
  @allowed_glob_patterns = Set.new
19
19
  @fetchers = {}
20
-
20
+
21
21
  class << self
22
22
  # Resets all allowed hosts
23
23
  def reset_allowed_hosts!
24
24
  S_MUTEX.synchronize { @allowed_hosts.clear }
25
25
  end
26
-
26
+
27
27
  # Add an allowed host
28
28
  def add_allowed_host!(hostname)
29
29
  S_MUTEX.synchronize { @allowed_hosts << hostname }
30
30
  end
31
-
31
+
32
32
  # Returns both the allowed hosts added at runtime and the ones set in the constant
33
33
  def allowed_hosts
34
34
  S_MUTEX.synchronize { @allowed_hosts.to_a }
35
35
  end
36
-
36
+
37
37
  # Removes all set keys
38
38
  def reset_secret_keys!
39
39
  S_MUTEX.synchronize { @keys.clear }
40
40
  end
41
-
41
+
42
42
  def allow_filesystem_source!(glob_pattern)
43
43
  S_MUTEX.synchronize { @allowed_glob_patterns << glob_pattern }
44
44
  end
@@ -52,24 +52,24 @@ class ImageVise
52
52
  end
53
53
 
54
54
  # Adds a key against which the parameters are going to be verified.
55
- # Multiple applications may have their own different keys,
55
+ # Multiple applications may have their own different keys,
56
56
  # so we need to have multiple keys.
57
57
  def add_secret_key!(key)
58
58
  S_MUTEX.synchronize { @keys << key }
59
59
  self
60
60
  end
61
-
61
+
62
62
  # Returns the array of defined keys or raises an exception if no keys have been set yet
63
63
  def secret_keys
64
64
  keys = S_MUTEX.synchronize { @keys.any? && @keys.to_a }
65
65
  keys or raise "No keys set, add a key using `ImageVise.add_secret_key!(key)'"
66
66
  end
67
-
67
+
68
68
  # Generate a set of querystring params for a resized image. Yields a Pipeline object that
69
69
  # will receive method calls for adding image operations to a stack.
70
70
  #
71
71
  # ImageVise.image_params(src_url: image_url_on_s3, secret: '...') do |p|
72
- # p.center_fit width: 128, height: 128
72
+ # p.center_fit width: 128, height: 128
73
73
  # p.elliptic_stencil
74
74
  # end #=> {q: '...', sig: '...'}
75
75
  #
@@ -88,7 +88,7 @@ class ImageVise
88
88
  # will receive method calls for adding image operations to a stack.
89
89
  #
90
90
  # ImageVise.image_path(src_url: image_url_on_s3, secret: '...') do |p|
91
- # p.center_fit width: 128, height: 128
91
+ # p.center_fit width: 128, height: 128
92
92
  # p.elliptic_stencil
93
93
  # end #=> "/abcdef/xyz123"
94
94
  #
@@ -112,26 +112,26 @@ class ImageVise
112
112
  def operator_from(operator_name)
113
113
  @operators.fetch(operator_name.to_s)
114
114
  end
115
-
115
+
116
116
  def defined_operator_names
117
117
  @operators.keys
118
118
  end
119
-
119
+
120
120
  def register_fetcher(scheme, fetcher)
121
121
  S_MUTEX.synchronize { @fetchers[scheme.to_s] = fetcher }
122
122
  end
123
-
123
+
124
124
  def fetcher_for(scheme)
125
125
  S_MUTEX.synchronize { @fetchers[scheme.to_s] or raise "No fetcher registered for #{scheme}" }
126
126
  end
127
-
127
+
128
128
  def operator_name_for(operator)
129
129
  S_MUTEX.synchronize do
130
130
  @operators.key(operator.class) or raise "Operator #{operator.inspect} not registered using ImageVise.add_operator"
131
131
  end
132
132
  end
133
133
  end
134
-
134
+
135
135
  # Made available since the object that is used with `mount()` in Rails
136
136
  # has to, by itself, to respond to `call`.
137
137
  #
@@ -146,11 +146,11 @@ class ImageVise
146
146
  def self.call(rack_env)
147
147
  ImageVise::RenderEngine.new.call(rack_env)
148
148
  end
149
-
149
+
150
150
  def call(rack_env)
151
151
  ImageVise::RenderEngine.new.call(rack_env)
152
152
  end
153
-
153
+
154
154
  # Used as a shorthand to force-destroy Magick images in ensure() blocks. Since
155
155
  # ensure blocks sometimes deal with variables in inconsistent states (variable
156
156
  # in scope but not yet set to an image) we take the possibility of nils into account.
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.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-07 00:00:00.000000000 Z
11
+ date: 2017-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: patron
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.15'
41
- - !ruby/object:Gem::Dependency
42
- name: exceptional_fork
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.2'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.2'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: ks
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -70,88 +56,60 @@ dependencies:
70
56
  name: magic_bytes
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
- - - ">="
59
+ - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '0'
61
+ version: '1'
76
62
  type: :runtime
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: bundler
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: yard
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
66
+ - - "~>"
109
67
  - !ruby/object:Gem::Version
110
- version: '0'
68
+ version: '1'
111
69
  - !ruby/object:Gem::Dependency
112
- name: simplecov
70
+ name: rack
113
71
  requirement: !ruby/object:Gem::Requirement
114
72
  requirements:
115
- - - ">="
73
+ - - "~>"
116
74
  - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
75
+ version: '1'
76
+ type: :runtime
119
77
  prerelease: false
120
78
  version_requirements: !ruby/object:Gem::Requirement
121
79
  requirements:
122
- - - ">="
80
+ - - "~>"
123
81
  - !ruby/object:Gem::Version
124
- version: '0'
82
+ version: '1'
125
83
  - !ruby/object:Gem::Dependency
126
- name: rack-cache
84
+ name: bundler
127
85
  requirement: !ruby/object:Gem::Requirement
128
86
  requirements:
129
- - - ">="
87
+ - - "~>"
130
88
  - !ruby/object:Gem::Version
131
- version: '0'
89
+ version: '1.7'
132
90
  type: :development
133
91
  prerelease: false
134
92
  version_requirements: !ruby/object:Gem::Requirement
135
93
  requirements:
136
- - - ">="
94
+ - - "~>"
137
95
  - !ruby/object:Gem::Version
138
- version: '0'
96
+ version: '1.7'
139
97
  - !ruby/object:Gem::Dependency
140
- name: strenv
98
+ name: rake
141
99
  requirement: !ruby/object:Gem::Requirement
142
100
  requirements:
143
- - - ">="
101
+ - - "~>"
144
102
  - !ruby/object:Gem::Version
145
- version: '0'
103
+ version: '10.0'
146
104
  type: :development
147
105
  prerelease: false
148
106
  version_requirements: !ruby/object:Gem::Requirement
149
107
  requirements:
150
- - - ">="
108
+ - - "~>"
151
109
  - !ruby/object:Gem::Version
152
- version: '0'
110
+ version: '10.0'
153
111
  - !ruby/object:Gem::Dependency
154
- name: addressable
112
+ name: rack-test
155
113
  requirement: !ruby/object:Gem::Requirement
156
114
  requirements:
157
115
  - - ">="
@@ -165,21 +123,21 @@ dependencies:
165
123
  - !ruby/object:Gem::Version
166
124
  version: '0'
167
125
  - !ruby/object:Gem::Dependency
168
- name: rack
126
+ name: rspec
169
127
  requirement: !ruby/object:Gem::Requirement
170
128
  requirements:
171
129
  - - "~>"
172
130
  - !ruby/object:Gem::Version
173
- version: '1'
131
+ version: '3.0'
174
132
  type: :development
175
133
  prerelease: false
176
134
  version_requirements: !ruby/object:Gem::Requirement
177
135
  requirements:
178
136
  - - "~>"
179
137
  - !ruby/object:Gem::Version
180
- version: '1'
138
+ version: '3.0'
181
139
  - !ruby/object:Gem::Dependency
182
- name: rack-test
140
+ name: addressable
183
141
  requirement: !ruby/object:Gem::Requirement
184
142
  requirements:
185
143
  - - ">="
@@ -193,7 +151,7 @@ dependencies:
193
151
  - !ruby/object:Gem::Version
194
152
  version: '0'
195
153
  - !ruby/object:Gem::Dependency
196
- name: foreman
154
+ name: strenv
197
155
  requirement: !ruby/object:Gem::Requirement
198
156
  requirements:
199
157
  - - ">="
@@ -207,41 +165,7 @@ dependencies:
207
165
  - !ruby/object:Gem::Version
208
166
  version: '0'
209
167
  - !ruby/object:Gem::Dependency
210
- name: rspec
211
- requirement: !ruby/object:Gem::Requirement
212
- requirements:
213
- - - "<"
214
- - !ruby/object:Gem::Version
215
- version: '3.3'
216
- - - "~>"
217
- - !ruby/object:Gem::Version
218
- version: '3.2'
219
- type: :development
220
- prerelease: false
221
- version_requirements: !ruby/object:Gem::Requirement
222
- requirements:
223
- - - "<"
224
- - !ruby/object:Gem::Version
225
- version: '3.3'
226
- - - "~>"
227
- - !ruby/object:Gem::Version
228
- version: '3.2'
229
- - !ruby/object:Gem::Dependency
230
- name: rake
231
- requirement: !ruby/object:Gem::Requirement
232
- requirements:
233
- - - "~>"
234
- - !ruby/object:Gem::Version
235
- version: '10'
236
- type: :development
237
- prerelease: false
238
- version_requirements: !ruby/object:Gem::Requirement
239
- requirements:
240
- - - "~>"
241
- - !ruby/object:Gem::Version
242
- version: '10'
243
- - !ruby/object:Gem::Dependency
244
- name: jeweler
168
+ name: simplecov
245
169
  requirement: !ruby/object:Gem::Requirement
246
170
  requirements:
247
171
  - - ">="
@@ -255,13 +179,14 @@ dependencies:
255
179
  - !ruby/object:Gem::Version
256
180
  version: '0'
257
181
  description: Image processing via URLs
258
- email: me@julik.nl
182
+ email:
183
+ - me@julik.nl
259
184
  executables: []
260
185
  extensions: []
261
- extra_rdoc_files:
262
- - LICENSE.txt
263
- - README.md
186
+ extra_rdoc_files: []
264
187
  files:
188
+ - ".gitignore"
189
+ - ".travis.yml"
265
190
  - DEVELOPMENT.md
266
191
  - Gemfile
267
192
  - LICENSE.txt
@@ -279,9 +204,11 @@ files:
279
204
  - lib/image_vise/file_response.rb
280
205
  - lib/image_vise/image_request.rb
281
206
  - lib/image_vise/operators/auto_orient.rb
207
+ - lib/image_vise/operators/background_fill.rb
282
208
  - lib/image_vise/operators/crop.rb
283
209
  - lib/image_vise/operators/ellipse_stencil.rb
284
210
  - lib/image_vise/operators/fit_crop.rb
211
+ - lib/image_vise/operators/force_jpg_out.rb
285
212
  - lib/image_vise/operators/geom.rb
286
213
  - lib/image_vise/operators/sRGB_v4_ICC_preference_displayclass.icc
287
214
  - lib/image_vise/operators/sharpen.rb
@@ -289,33 +216,14 @@ files:
289
216
  - lib/image_vise/operators/strip_metadata.rb
290
217
  - lib/image_vise/pipeline.rb
291
218
  - lib/image_vise/render_engine.rb
292
- - spec/image_vise/auto_orient_spec.rb
293
- - spec/image_vise/crop_spec.rb
294
- - spec/image_vise/ellipse_stencil_spec.rb
295
- - spec/image_vise/fetcher_file_spec.rb
296
- - spec/image_vise/fetcher_http_spec.rb
297
- - spec/image_vise/file_response_spec.rb
298
- - spec/image_vise/fit_crop_spec.rb
299
- - spec/image_vise/geom_spec.rb
300
- - spec/image_vise/image_request_spec.rb
301
- - spec/image_vise/pipeline_spec.rb
302
- - spec/image_vise/render_engine_spec.rb
303
- - spec/image_vise/sharpen_spec.rb
304
- - spec/image_vise/srgb_spec.rb
305
- - spec/image_vise/strip_metadata_spec.rb
306
- - spec/image_vise_spec.rb
307
- - spec/layers-with-blending.psd
308
- - spec/spec_helper.rb
309
- - spec/test_server.rb
310
- - spec/waterside_magic_hour.jpg
311
- - spec/waterside_magic_hour.psd
312
- - spec/waterside_magic_hour_adobergb.jpg
313
- - spec/waterside_magic_hour_gray.tif
314
- - spec/waterside_magic_hour_transp.png
219
+ - lib/image_vise/version.rb
220
+ - lib/image_vise/writers/auto_writer.rb
221
+ - lib/image_vise/writers/jpeg_writer.rb
315
222
  homepage: https://github.com/WeTransfer/image_vise
316
223
  licenses:
317
224
  - MIT
318
- metadata: {}
225
+ metadata:
226
+ allowed_push_host: https://rubygems.org
319
227
  post_install_message:
320
228
  rdoc_options: []
321
229
  require_paths:
@@ -332,7 +240,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
332
240
  version: '0'
333
241
  requirements: []
334
242
  rubyforge_project:
335
- rubygems_version: 2.4.5.1
243
+ rubygems_version: 2.5.2
336
244
  signing_key:
337
245
  specification_version: 4
338
246
  summary: Runtime thumbnailing proxy
@@ -1,10 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ImageVise::AutoOrient do
4
- it 'applies auto orient to the image' do
5
- image = Magick::Image.read(test_image_path)[0]
6
- orient = described_class.new
7
- expect(image).to receive(:auto_orient!).and_call_original
8
- orient.apply!(image)
9
- end
10
- end
@@ -1,20 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ImageVise::Crop do
4
- it 'refuses invalid parameters' do
5
- expect { described_class.new(width: 0, height: -1, gravity: '') }.to raise_error(ArgumentError)
6
- end
7
-
8
- it 'applies the crop with different gravities' do
9
- %w( s sw se n ne nw c).each do |gravity|
10
- image = Magick::Image.read(test_image_path)[0]
11
- crop = described_class.new(width: 120, height: 220, gravity: gravity)
12
-
13
- crop.apply!(image)
14
-
15
- expect(image.columns).to eq(120)
16
- expect(image.rows).to eq(220)
17
- examine_image(image, "gravity-%s-" % gravity)
18
- end
19
- end
20
- end
@@ -1,19 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ImageVise::EllipseStencil do
4
- it 'applies the circle stencil' do
5
- image = Magick::Image.read(test_image_path)[0]
6
- stencil = described_class.new
7
- stencil.apply!(image)
8
- examine_image(image, "circle-stencil")
9
- end
10
-
11
- it 'applies the circle stencil to a png with transparency' do
12
- png_transparent_path = File.expand_path(__dir__ + '/../waterside_magic_hour_transp.png')
13
- image = Magick::Image.read(png_transparent_path)[0]
14
- stencil = described_class.new
15
- stencil.apply!(image)
16
- examine_image(image, "circle-stencil-transparent-bg")
17
- end
18
-
19
- end
@@ -1,48 +0,0 @@
1
- require_relative '../spec_helper'
2
-
3
- describe ImageVise::FetcherFile do
4
- it 'is a class (can be inherited from)' do
5
- expect(ImageVise::FetcherFile).to be_kind_of(Class)
6
- end
7
-
8
- it 'is registered as a fetcher for file://' do
9
- expect(ImageVise.fetcher_for('file')).to eq(ImageVise::FetcherFile)
10
- end
11
-
12
- it 'returns a Tempfile containing this test suite' do
13
- path = File.expand_path(__FILE__)
14
- ruby_files_in_this_directory = __dir__ + '/*.rb'
15
- ImageVise.allow_filesystem_source! ruby_files_in_this_directory
16
-
17
- uri = URI('file://' + URI.encode(path))
18
- fetched = ImageVise::FetcherFile.fetch_uri_to_tempfile(uri)
19
-
20
- expect(fetched).to be_kind_of(Tempfile)
21
- expect(fetched.size).to eq(File.size(__FILE__))
22
- expect(fetched.pos).to be_zero
23
- end
24
-
25
- it 'raises a meaningful exception if no file sources are permitted' do
26
- path = File.expand_path(__FILE__)
27
-
28
- ImageVise.deny_filesystem_sources!
29
-
30
- uri = URI('file://' + URI.encode(path))
31
- expect {
32
- ImageVise::FetcherFile.fetch_uri_to_tempfile(uri)
33
- }.to raise_error(ImageVise::FetcherFile::AccessError)
34
- end
35
-
36
- it 'raises a meaningful exception if this file is not permitted as source' do
37
- path = File.expand_path(__FILE__)
38
-
39
- text_files_in_this_directory = __dir__ + '/*.txt'
40
- ImageVise.deny_filesystem_sources!
41
- ImageVise.allow_filesystem_source! text_files_in_this_directory
42
-
43
- uri = URI('file://' + URI.encode(path))
44
- expect {
45
- ImageVise::FetcherFile.fetch_uri_to_tempfile(uri)
46
- }.to raise_error(ImageVise::FetcherFile::AccessError)
47
- end
48
- end
@@ -1,44 +0,0 @@
1
- require_relative '../spec_helper'
2
-
3
- describe ImageVise::FetcherHTTP do
4
- it 'is a class (can be inherited from)' do
5
- expect(ImageVise::FetcherHTTP).to be_kind_of(Class)
6
- end
7
-
8
- it 'is registered as a fetcher for http:// and https://' do
9
- expect(ImageVise.fetcher_for('http')).to eq(ImageVise::FetcherHTTP)
10
- expect(ImageVise.fetcher_for('https')).to eq(ImageVise::FetcherHTTP)
11
- end
12
-
13
- it 'raises an AccessError if the host of the URL is not on the whitelist' do
14
- uri = URI('https://wrong-origin.com/image.psd')
15
- expect {
16
- ImageVise::FetcherHTTP.fetch_uri_to_tempfile(uri)
17
- }.to raise_error(ImageVise::FetcherHTTP::AccessError, /is not permitted as source/)
18
- end
19
-
20
- it 'raises an UpstreamError if the upstream fetch returns an error-ish status code' do
21
- uri = URI('http://localhost:9001/forbidden')
22
- ImageVise.add_allowed_host! 'localhost'
23
-
24
- expect {
25
- ImageVise::FetcherHTTP.fetch_uri_to_tempfile(uri)
26
- }.to raise_error {|e|
27
- expect(e).to be_kind_of(ImageVise::FetcherHTTP::UpstreamError)
28
- expect(e.message).to include(uri.to_s)
29
- expect(e.message).to include('403')
30
- expect(e.http_status).to eq(403)
31
- }
32
- end
33
-
34
- it 'fetches the image into a Tempfile' do
35
- uri = URI(public_url_psd)
36
- ImageVise.add_allowed_host! 'localhost'
37
-
38
- result = ImageVise::FetcherHTTP.fetch_uri_to_tempfile(uri)
39
-
40
- expect(result).to be_kind_of(Tempfile)
41
- expect(result.size).to be_nonzero
42
- expect(result.pos).to be_zero
43
- end
44
- end
@@ -1,45 +0,0 @@
1
- require_relative '../spec_helper'
2
-
3
- describe ImageVise::FileResponse do
4
- it 'reads the file in binary mode, closes and unlinks the tempfile when close() is called' do
5
- random_data = SecureRandom.random_bytes(1024 * 2048)
6
- f = Tempfile.new("experiment")
7
- f.binmode
8
- f << random_data
9
-
10
- response = described_class.new(f)
11
- readback = ''.encode(Encoding::BINARY)
12
- response.each do | chunk |
13
- expect(chunk.encoding).to eq(Encoding::BINARY)
14
- readback << chunk
15
- end
16
-
17
- response.close
18
-
19
- expect(readback).to eq(random_data)
20
- expect(f).to be_closed
21
- expect(f.path).to be_nil
22
- end
23
-
24
- it 'only asks for the path of the tempfile and uses a separate file descriptor' do
25
- f = Tempfile.new("experiment")
26
- f.binmode
27
- f << SecureRandom.random_bytes(2048)
28
- f.flush
29
-
30
- # Use a double so that all the methods except the ones we mock raise an assertion
31
- double = double(path: f.path)
32
- expect(double).to receive(:flush)
33
-
34
- read_from_response = ''.encode(Encoding::BINARY)
35
- response = described_class.new(double)
36
- response.each{|b| read_from_response << b }
37
-
38
- f.rewind
39
-
40
- expect(f.read).to eq(read_from_response)
41
-
42
- f.close
43
- f.unlink
44
- end
45
- end
@@ -1,20 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ImageVise::FitCrop do
4
- it 'refuses invalid arguments' do
5
- expect { described_class.new(width: 0, height: -1, gravity: '') }.to raise_error(ArgumentError)
6
- end
7
-
8
- it 'applies the crop with different gravities' do
9
- %w( s sw se n ne nw c).each do |gravity|
10
- image = Magick::Image.read(test_image_path)[0]
11
- crop = described_class.new(width: 120, height: 220, gravity: gravity)
12
-
13
- crop.apply!(image)
14
-
15
- expect(image.columns).to eq(120)
16
- expect(image.rows).to eq(220)
17
- examine_image(image, "gravity-%s-" % gravity)
18
- end
19
- end
20
- end