image_vise 0.2.3 → 0.2.4

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 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