image_vise 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3bb222a8353542a7b5224ab75dc03df4b453e2b7
4
- data.tar.gz: 94c346a22cd2a34b80eaefe97f05e50a8fe944f7
3
+ metadata.gz: 6a71e26e83e715290293b8e512fe6f72aaa39098
4
+ data.tar.gz: 4dd57c319fe8728e0bc8cf0e2fdd67ab41bc028b
5
5
  SHA512:
6
- metadata.gz: cdad17d7b3d12eb171158a50566b0abccab8a48aa48c28716e25e20741cdc15e369f5035793f53a0d0ce5ec405ad0b86013721b8f251bcfad3952a5ea1698e66
7
- data.tar.gz: 3d8cc40c202b112de3ed0b4a1462fbfbba0ba08051ba3ab51a6db894c5e146985a3785ada873b96182de63f1f46f90f3be2e44eee7472b79a8250aaefbf3fb5c
6
+ metadata.gz: 8c53127c2ef018e94200a23281d6923497d5466d19ae63b8d18ad0a292f3eb6e6615baccee577d01cee774e50b32fa04e6c5e910d2e9a9cd445fc47f5bfb814f
7
+ data.tar.gz: f0fbe07c4fb401161714862fff8833300821d51f710140a0f16f6336251243ae48679a4ff5ac9df48970baaed97c4ba4080e0562fcb4c5cf7dbe3b6be437cbc9
data/README.md CHANGED
@@ -208,6 +208,7 @@ The gem version is specified in `image_vise.rb`. When contributing, please follo
208
208
 
209
209
  Copyright (c) 2016 WeTransfer. See LICENSE.txt for further details.
210
210
  The licensing terms also apply to the `waterside_magic_hour.jpg` test image.
211
+ The `worker_in_tube.jpg` is used with permission from Arcadis Nederland B.V.
211
212
 
212
213
  The sRGB color profiles are [downloaded from the ICC](http://www.color.org/srgbprofiles.xalter) and it's
213
214
  use is governed by the terms present in the LICENSE.txt
data/image_vise.gemspec CHANGED
@@ -40,4 +40,5 @@ Gem::Specification.new do |spec|
40
40
  spec.add_development_dependency "addressable"
41
41
  spec.add_development_dependency "strenv"
42
42
  spec.add_development_dependency "simplecov"
43
+ spec.add_development_dependency "pry"
43
44
  end
data/lib/image_vise.rb CHANGED
@@ -11,12 +11,15 @@ class ImageVise
11
11
  require_relative 'image_vise/version'
12
12
  S_MUTEX = Mutex.new
13
13
  private_constant :S_MUTEX
14
+ # The default cache liftime is 30 days, and will be used if no custom lifetime is set.
15
+ DEFAULT_CACHE_LIFETIME = 2_592_000
14
16
 
15
17
  @allowed_hosts = Set.new
16
18
  @keys = Set.new
17
19
  @operators = {}
18
20
  @allowed_glob_patterns = Set.new
19
21
  @fetchers = {}
22
+ @cache_lifetime = DEFAULT_CACHE_LIFETIME
20
23
 
21
24
  class << self
22
25
  # Resets all allowed hosts
@@ -51,6 +54,21 @@ class ImageVise
51
54
  S_MUTEX.synchronize { @allowed_glob_patterns.clear }
52
55
  end
53
56
 
57
+ def cache_lifetime_seconds=(length)
58
+ Integer(length)
59
+ S_MUTEX.synchronize { @cache_lifetime = length.to_i }
60
+ rescue => e
61
+ raise ArgumentError, "The custom cache lifetime value must be an integer"
62
+ end
63
+
64
+ def cache_lifetime_seconds
65
+ S_MUTEX.synchronize { @cache_lifetime }
66
+ end
67
+
68
+ def reset_cache_lifetime_seconds!
69
+ S_MUTEX.synchronize { @cache_lifetime = DEFAULT_CACHE_LIFETIME }
70
+ end
71
+
54
72
  # Adds a key against which the parameters are going to be verified.
55
73
  # Multiple applications may have their own different keys,
56
74
  # so we need to have multiple keys.
@@ -25,6 +25,9 @@ class ImageVise::SRGB
25
25
  PROFILE_PATH = File.expand_path(__dir__ + '/sRGB_v4_ICC_preference_displayclass.icc')
26
26
  def apply!(magick_image)
27
27
  magick_image.add_profile(PROFILE_PATH)
28
+ rescue Magick::ImageMagickError
29
+ magick_image.strip!
30
+ magick_image.add_profile(PROFILE_PATH)
28
31
  end
29
32
  ImageVise.add_operator 'srgb', self
30
33
  end
@@ -20,13 +20,13 @@
20
20
  'Cache-Control' => 'public, max-age=5'
21
21
  }).freeze
22
22
 
23
- # "public" of course. Add max-age so that there is _some_
23
+ # Cache details: "public" of course. Add max-age so that there is _some_
24
24
  # revalidation after a time (otherwise some proxies treat it
25
25
  # as "must-revalidate" always), and "no-transform" so that
26
26
  # various deflate schemes are not applied to it (does happen
27
27
  # with Rack::Cache and leads Chrome to throw up on content
28
28
  # decoding for example).
29
- IMAGE_CACHE_CONTROL = 'public, no-transform, max-age=2592000'
29
+ IMAGE_CACHE_CONTROL = "public, no-transform, max-age=%d"
30
30
 
31
31
  # How long is a render (the ImageMagick/write part) is allowed to
32
32
  # take before we kill it
@@ -166,7 +166,8 @@
166
166
  # `process_image_request` unsplatted, and returns a triplet that
167
167
  # can be returned as a Rack response. The Rack response will contain
168
168
  # an iterable body object that is designed to automatically delete
169
- # the Tempfile it wraps on close.
169
+ # the Tempfile it wraps on close. Sets the cache lifetime to either the default
170
+ # value of 2592000 or the value the user selected using add_custom_cache_max_length.
170
171
  #
171
172
  # @param render_destination_file[File] the File handle to the rendered image
172
173
  # @param render_file_type[MagicBytes::FileType] the rendered file type
@@ -175,7 +176,7 @@
175
176
  response_headers = DEFAULT_HEADERS.merge({
176
177
  'Content-Type' => render_file_type.mime,
177
178
  'Content-Length' => '%d' % render_destination_file.size,
178
- 'Cache-Control' => IMAGE_CACHE_CONTROL,
179
+ 'Cache-Control' => IMAGE_CACHE_CONTROL % ImageVise.cache_lifetime_seconds,
179
180
  'ETag' => etag
180
181
  })
181
182
 
@@ -1,3 +1,3 @@
1
1
  class ImageVise
2
- VERSION = '0.2.3'
2
+ VERSION = '0.2.4'
3
3
  end
@@ -37,6 +37,7 @@ describe ImageVise::RenderEngine do
37
37
  after :each do
38
38
  ImageVise.reset_allowed_hosts!
39
39
  ImageVise.reset_secret_keys!
40
+ ImageVise.reset_cache_lifetime_seconds!
40
41
  end
41
42
 
42
43
  it 'halts with 400 when the requested image cannot be opened by ImageMagick' do
@@ -137,6 +138,37 @@ describe ImageVise::RenderEngine do
137
138
  expect(last_response.status).to eq(304)
138
139
  end
139
140
 
141
+ it 'allows for setting a custom cache lifetime' do
142
+ uri = Addressable::URI.parse(public_url)
143
+ ImageVise.add_allowed_host!(uri.host)
144
+ ImageVise.add_secret_key!('l33tness')
145
+
146
+ ImageVise.cache_lifetime_seconds = '900'
147
+ p = ImageVise::Pipeline.new.fit_crop(width: 10, height: 35, gravity: 'c')
148
+ image_request = ImageVise::ImageRequest.new(src_url: uri.to_s, pipeline: p)
149
+
150
+ req_path = image_request.to_path_params('l33tness')
151
+
152
+ get req_path, {}
153
+ expect(last_response).to be_ok
154
+ expect(last_response['Cache-Control']).to match(/max-age=900/)
155
+ end
156
+
157
+ it 'uses the correct default cache lifetime if one is not specified' do
158
+ uri = Addressable::URI.parse(public_url)
159
+ ImageVise.add_allowed_host!(uri.host)
160
+ ImageVise.add_secret_key!('l33tness')
161
+
162
+ p = ImageVise::Pipeline.new.fit_crop(width: 10, height: 35, gravity: 'c')
163
+ image_request = ImageVise::ImageRequest.new(src_url: uri.to_s, pipeline: p)
164
+
165
+ req_path = image_request.to_path_params('l33tness')
166
+
167
+ get req_path, {}
168
+ expect(last_response).to be_ok
169
+ expect(last_response['Cache-Control']).to match(/max-age=2592000/)
170
+ end
171
+
140
172
  it 'responds with an image that passes through all the processing steps' do
141
173
  uri = Addressable::URI.parse(public_url)
142
174
  ImageVise.add_allowed_host!(uri.host)
@@ -20,4 +20,17 @@ describe ImageVise::SRGB do
20
20
  image.strip!
21
21
  examine_image(image, "from-srgb-SHOULD-LOOK-IDENTICAL")
22
22
  end
23
+
24
+ it 'applies the profile for an image with non-matching colorspace and profile' do
25
+ image = Magick::Image.read(test_image_mismatched_colorspace_profile_path).first
26
+ examine_image(image, 'pre-mismatched-colors')
27
+ described_class.new.apply!(image)
28
+ examine_image(image, 'post-mismatched-colors')
29
+ end
30
+
31
+ it "strips the image's profile if the profile and colorspace are non-matching" do
32
+ non_matching_image = Magick::Image.read(test_image_mismatched_colorspace_profile_path).first
33
+ expect(non_matching_image).to receive(:strip!).and_call_original
34
+ described_class.new.apply!(non_matching_image)
35
+ end
23
36
  end
@@ -3,16 +3,16 @@ require 'rack/test'
3
3
 
4
4
  describe ImageVise do
5
5
  include Rack::Test::Methods
6
-
6
+
7
7
  def app
8
8
  described_class.new
9
9
  end
10
-
10
+
11
11
  context 'ImageVise.allowed_hosts' do
12
12
  it 'returns the allowed hosts and is empty by default' do
13
13
  expect(described_class.allowed_hosts).to be_empty
14
14
  end
15
-
15
+
16
16
  it 'allows add_allowed_host! and reset_allowed_hosts!' do
17
17
  described_class.add_allowed_host!('www.imageboard.im')
18
18
  expect(described_class.allowed_hosts).to include('www.imageboard.im')
@@ -20,14 +20,14 @@ describe ImageVise do
20
20
  expect(described_class.allowed_hosts).not_to include('www.imageboard.im')
21
21
  end
22
22
  end
23
-
23
+
24
24
  context 'ImageVise.secret_keys' do
25
25
  it 'raises when asked for a key and no keys has been set' do
26
26
  expect {
27
27
  described_class.secret_keys
28
28
  }.to raise_error("No keys set, add a key using `ImageVise.add_secret_key!(key)'")
29
29
  end
30
-
30
+
31
31
  it 'allows add_secret_key!(key) and reset_secret_keys!' do
32
32
  described_class.add_secret_key!('l33t')
33
33
  expect(described_class.secret_keys).to include('l33t')
@@ -38,6 +38,34 @@ describe ImageVise do
38
38
  end
39
39
  end
40
40
 
41
+ context 'ImageVise.cache_lifetime_seconds=' do
42
+ it 'raises when given something other than an integer' do
43
+ expect {
44
+ described_class.cache_lifetime_seconds = "Wh0ops!"
45
+ }.to raise_error("The custom cache lifetime value must be an integer")
46
+ end
47
+
48
+ it 'succeeds when given an integer' do
49
+ expect {
50
+ described_class.cache_lifetime_seconds=(900)
51
+ }.not_to raise_error
52
+ end
53
+ end
54
+
55
+ context 'ImageVise.cache_lifetime_seconds' do
56
+ it 'allows cache_lifetime_seconds to be set' do
57
+ described_class.cache_lifetime_seconds = 100
58
+ expect(described_class.cache_lifetime_seconds).to eq(100)
59
+ end
60
+
61
+ it 'allows reset_cache_lifetime_seconds!' do
62
+ described_class.cache_lifetime_seconds = 100
63
+ expect(described_class.cache_lifetime_seconds).to eq(100)
64
+ described_class.reset_cache_lifetime_seconds!
65
+ expect(described_class.cache_lifetime_seconds).to eq(2592000)
66
+ end
67
+ end
68
+
41
69
  describe 'ImageVise.new.call' do
42
70
  it 'instantiates a new app and performs call() on it' do
43
71
  expect_any_instance_of(ImageVise::RenderEngine).to receive(:call).with(:mock_env) { :yes }
@@ -51,7 +79,7 @@ describe ImageVise do
51
79
  ImageVise.call(:mock_env)
52
80
  end
53
81
  end
54
-
82
+
55
83
  describe '.image_params' do
56
84
  it 'generates a Hash with paremeters for processing the resized image' do
57
85
  params = ImageVise.image_params(src_url: 'http://host.com/image.jpg', secret: 'l33t') do |pipe|
@@ -69,7 +97,7 @@ describe ImageVise do
69
97
  expect(http).to respond_to(:fetch_uri_to_tempfile)
70
98
  file = ImageVise.fetcher_for('file')
71
99
  expect(http).to respond_to(:fetch_uri_to_tempfile)
72
-
100
+
73
101
  expect {
74
102
  ImageVise.fetcher_for('undernet')
75
103
  }.to raise_error(/No fetcher registered/)
@@ -84,14 +112,14 @@ describe ImageVise do
84
112
  expect(path).to start_with('/')
85
113
  end
86
114
  end
87
-
115
+
88
116
  describe 'methods dealing with the operator list' do
89
117
  it 'have the basic operators already set up' do
90
118
  oplist = ImageVise.defined_operator_names
91
119
  expect(oplist).to include('sharpen')
92
120
  expect(oplist).to include('crop')
93
121
  end
94
-
122
+
95
123
  it 'allows an operator to be added and retrieved' do
96
124
  class CustomOp; end
97
125
  ImageVise.add_operator 'custom_op', CustomOp
@@ -99,7 +127,7 @@ describe ImageVise do
99
127
  expect(ImageVise.operator_name_for(CustomOp.new)).to eq('custom_op')
100
128
  expect(ImageVise.defined_operator_names).to include('custom_op')
101
129
  end
102
-
130
+
103
131
  it 'raises an exception when an operator key is requested that does not exist' do
104
132
  class UnknownOp; end
105
133
  expect {
data/spec/spec_helper.rb CHANGED
@@ -8,9 +8,9 @@ Bundler.require
8
8
 
9
9
  require 'tmpdir'
10
10
  require 'securerandom'
11
-
12
11
  require 'addressable/uri'
13
12
  require 'strenv'
13
+ require 'pry'
14
14
  require_relative 'test_server'
15
15
 
16
16
  TEST_RENDERS_DIR = Dir.mktmpdir
@@ -82,6 +82,10 @@ RSpec.configure do | config |
82
82
  File.expand_path(__dir__ + '/waterside_magic_hour_adobergb.jpg')
83
83
  end
84
84
 
85
+ def test_image_mismatched_colorspace_profile_path
86
+ File.expand_path(__dir__ + '/worker_in_tube.jpg')
87
+ end
88
+
85
89
  def test_image_png_transparency
86
90
  File.expand_path(__dir__ + '/waterside_magic_hour_transp.png')
87
91
  end
Binary file
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.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-06-17 00:00:00.000000000 Z
11
+ date: 2017-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: patron
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - ">="
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: pry
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
181
195
  description: Image processing via URLs
182
196
  email:
183
197
  - me@julik.nl
@@ -246,6 +260,7 @@ files:
246
260
  - spec/waterside_magic_hour_adobergb.jpg
247
261
  - spec/waterside_magic_hour_gray.tif
248
262
  - spec/waterside_magic_hour_transp.png
263
+ - spec/worker_in_tube.jpg
249
264
  homepage: https://github.com/WeTransfer/image_vise
250
265
  licenses:
251
266
  - MIT
@@ -267,7 +282,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
267
282
  version: '0'
268
283
  requirements: []
269
284
  rubyforge_project:
270
- rubygems_version: 2.4.5.2
285
+ rubygems_version: 2.5.2
271
286
  signing_key:
272
287
  specification_version: 4
273
288
  summary: Runtime thumbnailing proxy