imgix 3.0.0 → 3.1.0

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: a7ecfad08f5fb987982e65a9e4c22a7427f08be4
4
- data.tar.gz: 23579307f97e575b2f30c065360b1244795e1081
3
+ metadata.gz: c260521282fd6b24c05cf774caaf4b140fef9b5a
4
+ data.tar.gz: d7b53e8cce58a50020eeba7d9c4ad6aa556dfbb5
5
5
  SHA512:
6
- metadata.gz: '098a9a3ace9b4c06d8466ceb3ec4a3dc73ef64ee004d6d9d62082d200a0c19e34ad4b066eb418b36f7731213c30f1b172834e4b7a4deddc3326839ab1f12e1ae'
7
- data.tar.gz: e1cd1ae2bb0eaeb1a6ddf330e53fe844d60cbc84133c102ba8f57774e3d6fe823f0eb820426af8adabacaa20b1cb9e1a77fb64cefdeb07c01e35ad649110b088
6
+ metadata.gz: 33ff8d7ea4e778dcea4ade90283896b034c40b9d6cbd613920ec2712390b925d39041f996b3d44698a76dd279b829ab1d0a55e86e05dd57fbb2a417a03cf3b7b
7
+ data.tar.gz: 87ab1ed154e7ea3bfa69538a8904d3f8e9145f3cfa9175b3db60dc9855a20ca0f9845663be9a12eadcf340e8bf3cd1e29de630fa6561c092a0e7e9700a493b22
@@ -3,9 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project adheres to [Semantic Versioning](http://semver.org/).
5
5
 
6
+ ## [3.1.0](https://github.com/imgix/imgix-rb/compare/2.1.0...3.1.0) - July 28, 2019
7
+
8
+ * feat: add srcset generation ([#47](https://github.com/imgix/imgix-rb/pull/47))
9
+
6
10
  ## [3.0.0](https://github.com/imgix/imgix-rb/compare/2.1.0...3.0.0) - June 7, 2019
7
11
 
8
- * fix: remove deprecated domain sharding functionality ([#46](https://github.com/imgix/imgix-rb/pull/46))
12
+ * fix: remove deprecated domain sharding functionality ([#46](https://github.com/imgix/imgix-rb/pull/46))
9
13
 
10
14
  ## [2.1.0](https://github.com/imgix/imgix-rb/compare/2.0.0...2.1.0) - May 7, 2019
11
15
 
data/README.md CHANGED
@@ -46,6 +46,48 @@ path.defaults.width(300).to_url # Resets parameters
46
46
  path.rect(x: 0, y: 50, width: 200, height: 300).to_url # Rect helper
47
47
  ```
48
48
 
49
+ ## Srcset Generation
50
+
51
+ The imgix gem allows for generation of custom `srcset` attributes, which can be invoked through `Imgix::Path#to_srcset`. By default, the `srcset` generated will allow for responsive size switching by building a list of image-width mappings.
52
+
53
+ ```rb
54
+ client = Imgix::Client.new(host: 'your-subdomain.imgix.net', secure_url_token: 'your-token', include_library_param: false)
55
+ path = client.path('/images/demo.png')
56
+
57
+ srcset = path.to_srcset
58
+ ```
59
+
60
+ Will produce the following attribute value, which can then be served to the client:
61
+
62
+ ```html
63
+ https://your-subdomain.imgix.net/images/demo.png?w=100&s=efb3e4ae8eaa1884357f40510b11787c 100w,
64
+ https://your-subdomain.imgix.net/images/demo.png?w=116&s=1417ebeaaaecff39533408cb44893eda 116w,
65
+ https://your-subdomain.imgix.net/images/demo.png?w=134&s=4e45e67c087df930b9ddc8cf5be869d0 134w,
66
+ ...
67
+ https://your-subdomain.imgix.net/images/demo.png?w=7400&s=a5dd7dda1dbac613f0475f1ffd90ef79 7400w,
68
+ https://your-subdomain.imgix.net/images/demo.png?w=8192&s=9fbd257c53e770e345ce3412b64a3452 8192w
69
+ ```
70
+
71
+ In cases where enough information is provided about an image's dimensions, `to_srcset` will instead build a `srcset` that will allow for an image to be served at different resolutions. The parameters taken into consideration when determining if an image is fixed-width are `w`, `h`, and `ar`. By invoking `to_srcset` with either a width **or** the height and aspect ratio provided, a different `srcset` will be generated for a fixed-size image instead.
72
+
73
+ ```rb
74
+ client = Imgix::Client.new(host: 'your-subdomain.imgix.net', secure_url_token: 'your-token')
75
+ path = client.path('/images/demo.png')
76
+
77
+ srcset = path.to_srcset(h:800, ar:'3:2')
78
+ ```
79
+
80
+ Will produce the following attribute value:
81
+
82
+ ```html
83
+ https://your-subdomain.imgix.net/images/demo.png?h=800&ar=3%3A2&s=be8c153bb9ed0dd152e846414a8fdc86 1x,
84
+ https://your-subdomain.imgix.net/images/demo.png?h=800&ar=3%3A2&s=be8c153bb9ed0dd152e846414a8fdc86 2x,
85
+ https://your-subdomain.imgix.net/images/demo.png?h=800&ar=3%3A2&s=be8c153bb9ed0dd152e846414a8fdc86 3x,
86
+ https://your-subdomain.imgix.net/images/demo.png?h=800&ar=3%3A2&s=be8c153bb9ed0dd152e846414a8fdc86 4x,
87
+ https://your-subdomain.imgix.net/images/demo.png?h=800&ar=3%3A2&s=be8c153bb9ed0dd152e846414a8fdc86 5x
88
+ ```
89
+
90
+ For more information to better understand `srcset`, we highly recommend [Eric Portis' "Srcset and sizes" article](https://ericportis.com/posts/2014/srcset-sizes/) which goes into depth about the subject.
49
91
 
50
92
  ## Multiple Parameters
51
93
 
@@ -5,5 +5,23 @@ require 'imgix/client'
5
5
  require 'imgix/path'
6
6
 
7
7
  module Imgix
8
+ # regex pattern used to determine if a domain is valid
8
9
  DOMAIN_REGEX = /^(?:[a-z\d\-_]{1,62}\.){0,125}(?:[a-z\d](?:\-(?=\-*[a-z\d])|[a-z]|\d){0,62}\.)[a-z\d]{1,63}$/i
10
+
11
+ # returns an array of width values used during scrset generation
12
+ TARGET_WIDTHS = lambda {
13
+ increment_percentage = 8
14
+ max_size = 8192
15
+ resolutions = []
16
+ prev = 100
17
+
18
+ while(prev <= max_size)
19
+ # ensures that each width is even
20
+ resolutions.push((2 * (prev / 2).round))
21
+ prev *= 1 + ((increment_percentage.to_f) / 100) * 2
22
+ end
23
+
24
+ resolutions.push(max_size)
25
+ return resolutions
26
+ }
9
27
  end
@@ -39,6 +39,7 @@ module Imgix
39
39
 
40
40
  @path = CGI.escape(@path) if /^https?/ =~ @path
41
41
  @path = "/#{@path}" if @path[0] != '/'
42
+ @target_widths = TARGET_WIDTHS.call
42
43
  end
43
44
 
44
45
  def to_url(opts = {})
@@ -83,6 +84,19 @@ module Imgix
83
84
  end
84
85
  end
85
86
 
87
+ def to_srcset(params = {})
88
+ @options.merge!(params)
89
+ width = @options['w'.to_sym]
90
+ height = @options['h'.to_sym]
91
+ aspect_ratio = @options['ar'.to_sym]
92
+
93
+ if ((width) || (height && aspect_ratio))
94
+ build_dpr_srcset(@options)
95
+ else
96
+ build_srcset_pairs(@options)
97
+ end
98
+ end
99
+
86
100
  private
87
101
 
88
102
  def signature
@@ -108,5 +122,28 @@ module Imgix
108
122
  def has_query?
109
123
  query.length > 0
110
124
  end
125
+
126
+ def build_srcset_pairs(params = {})
127
+ srcset = ''
128
+ for width in @target_widths do
129
+ currentParams = params || {}
130
+ currentParams['w'] = width
131
+ srcset += "#{to_url(currentParams)} #{width}w,\n"
132
+ end
133
+
134
+ return srcset[0..-3]
135
+ end
136
+
137
+ def build_dpr_srcset(params = {})
138
+ srcset = ''
139
+ target_ratios = [1,2,3,4,5]
140
+ url = to_url(params)
141
+
142
+ for ratio in target_ratios do
143
+ srcset += "#{url} #{ratio}x,\n"
144
+ end
145
+
146
+ return srcset[0..-3]
147
+ end
111
148
  end
112
149
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Imgix
4
- VERSION = '3.0.0'
4
+ VERSION = '3.1.0'
5
5
  end
@@ -0,0 +1,226 @@
1
+ require 'test_helper'
2
+
3
+ module SrcsetTest
4
+
5
+ class SrcsetDefault < Imgix::Test
6
+ def test_no_parameters
7
+ srcset = path.to_srcset()
8
+ expected_number_of_pairs = 31
9
+ assert_equal expected_number_of_pairs, srcset.split(',').length
10
+ end
11
+
12
+ private
13
+ def path
14
+ @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg')
15
+ end
16
+ end
17
+
18
+ class SrcsetGivenWidth < Imgix::Test
19
+ def test_srcset_in_dpr_form
20
+ device_pixel_ratio = 1
21
+
22
+ srcset.split(',').map { |src|
23
+ ratio = src.split(' ')[1]
24
+ assert_equal ("#{device_pixel_ratio}x"), ratio
25
+ device_pixel_ratio += 1
26
+ }
27
+ end
28
+
29
+ def test_srcset_signs_urls
30
+ expected_signature = 'b95cfd915f4a198442bff4ce5befe5b8'
31
+
32
+ srcset.split(',').map { |src|
33
+ url = src.split(' ')[0]
34
+ assert_includes url, "s="
35
+
36
+ generated_signature = url.slice(url.index("s=")+2, url.length)
37
+ assert_equal expected_signature, generated_signature
38
+ }
39
+ end
40
+
41
+ private
42
+ def srcset
43
+ @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100)
44
+ end
45
+ end
46
+
47
+ class SrcsetGivenHeight < Imgix::Test
48
+ def test_srcset_generates_width_pairs
49
+ expected_number_of_pairs = 31
50
+ assert_equal expected_number_of_pairs, srcset.split(',').length
51
+ end
52
+
53
+ def test_srcset_respects_height_parameter
54
+ srcset.split(',').map { |src|
55
+ assert_includes src, 'h='
56
+ }
57
+ end
58
+
59
+ def test_srcset_within_bounds
60
+ min, *max = srcset.split(',')
61
+
62
+ # parse out the width descriptor as an integer
63
+ min = min.split(' ')[1].to_i
64
+ max = max[max.length-1].split(' ')[1].to_i
65
+
66
+ assert_operator min, :>=, 100
67
+ assert_operator max, :<=, 8192
68
+ end
69
+
70
+ def test_srcset_iterates_18_percent
71
+ increment_allowed = 0.18
72
+
73
+ # create an array of widths
74
+ widths = srcset.split(',').map { |src|
75
+ src.split(' ')[1].to_i
76
+ }
77
+
78
+ prev = widths[0]
79
+
80
+ for i in 1..widths.length-1 do
81
+ element = widths[i]
82
+ assert_operator (element / prev), :<, (1 + increment_allowed)
83
+ prev = element
84
+ end
85
+ end
86
+
87
+ def test_srcset_signs_urls
88
+ srcset.split(',').map { |srcset_split|
89
+ src = srcset_split.split(' ')[0]
90
+ assert_includes src, 's='
91
+
92
+ # parses out all parameters except for 's=...'
93
+ params = src.slice(src.index('?'), src.length)
94
+ params = params.slice(0, params.index('s=')-1)
95
+ # parses out the 's=...' parameter
96
+ generated_signature = src.slice(src.index('s=')+2, src.length)
97
+
98
+ signature_base = 'MYT0KEN' + '/image.jpg' + params;
99
+ expected_signature = Digest::MD5.hexdigest(signature_base)
100
+
101
+ assert_equal expected_signature, generated_signature
102
+ }
103
+ end
104
+
105
+ private
106
+ def srcset
107
+ @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(h:100)
108
+ end
109
+ end
110
+
111
+ class SrcsetGivenWidthAndHeight < Imgix::Test
112
+ def test_srcset_in_dpr_form
113
+ device_pixel_ratio = 1
114
+
115
+ srcset.split(',').map { |src|
116
+ ratio = src.split(' ')[1]
117
+ assert_equal ("#{device_pixel_ratio}x"), ratio
118
+ device_pixel_ratio += 1
119
+ }
120
+ end
121
+
122
+ def test_srcset_signs_urls
123
+ expected_signature = 'fb081a45c449b28f69e012d474943df3'
124
+
125
+ srcset.split(',').map { |src|
126
+ url = src.split(' ')[0]
127
+ assert_includes url, "s="
128
+
129
+ generated_signature = url.slice(url.index("s=")+2, url.length)
130
+ assert_equal expected_signature, generated_signature
131
+ }
132
+ end
133
+
134
+ private
135
+ def srcset
136
+ @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100,h:100)
137
+ end
138
+ end
139
+
140
+ class SrcsetGivenAspectRatio < Imgix::Test
141
+ def test_srcset_generates_width_pairs
142
+ expected_number_of_pairs = 31
143
+ assert_equal expected_number_of_pairs, srcset.split(',').length
144
+ end
145
+
146
+ def test_srcset_within_bounds
147
+ min, *max = srcset.split(',')
148
+
149
+ # parse out the width descriptor as an integer
150
+ min = min.split(' ')[1].to_i
151
+ max = max[max.length-1].split(' ')[1].to_i
152
+
153
+ assert_operator min, :>=, 100
154
+ assert_operator max, :<=, 8192
155
+ end
156
+
157
+ def test_srcset_iterates_18_percent
158
+ increment_allowed = 0.18
159
+
160
+ # create an array of widths
161
+ widths = srcset.split(',').map { |src|
162
+ src.split(' ')[1].to_i
163
+ }
164
+
165
+ prev = widths[0]
166
+
167
+ for i in 1..widths.length-1 do
168
+ element = widths[i]
169
+ assert_operator (element / prev), :<, (1 + increment_allowed)
170
+ prev = element
171
+ end
172
+ end
173
+
174
+ def test_srcset_signs_urls
175
+ srcset.split(',').map { |srcset_split|
176
+ src = srcset_split.split(' ')[0]
177
+ assert_includes src, 's='
178
+
179
+ # parses out all parameters except for 's=...'
180
+ params = src.slice(src.index('?'), src.length)
181
+ params = params.slice(0, params.index('s=')-1)
182
+ # parses out the 's=...' parameter
183
+ generated_signature = src.slice(src.index('s=')+2, src.length)
184
+
185
+ signature_base = 'MYT0KEN' + '/image.jpg' + params;
186
+ expected_signature = Digest::MD5.hexdigest(signature_base)
187
+
188
+ assert_equal expected_signature, generated_signature
189
+ }
190
+ end
191
+
192
+ private
193
+ def srcset
194
+ @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(ar:'3:2')
195
+ end
196
+ end
197
+
198
+ class SrcsetGivenAspectRatioAndHeight < Imgix::Test
199
+ def test_srcset_in_dpr_form
200
+ device_pixel_ratio = 1
201
+
202
+ srcset.split(',').map { |src|
203
+ ratio = src.split(' ')[1]
204
+ assert_equal ("#{device_pixel_ratio}x"), ratio
205
+ device_pixel_ratio += 1
206
+ }
207
+ end
208
+
209
+ def test_srcset_signs_urls
210
+ expected_signature = '84db8cb226483fc0130b4fb58e1e6ff2'
211
+
212
+ srcset.split(',').map { |src|
213
+ url = src.split(' ')[0]
214
+ assert_includes url, "s="
215
+
216
+ generated_signature = url.slice(url.index("s=")+2, url.length)
217
+ assert_equal expected_signature, generated_signature
218
+ }
219
+ end
220
+
221
+ private
222
+ def srcset
223
+ @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset({h:100,ar:'3:2'})
224
+ end
225
+ end
226
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imgix
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kelly Sutton
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2019-06-07 00:00:00.000000000 Z
16
+ date: 2019-07-29 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: addressable
@@ -73,6 +73,7 @@ files:
73
73
  - test/units/domains_test.rb
74
74
  - test/units/path_test.rb
75
75
  - test/units/purge_test.rb
76
+ - test/units/srcset_test.rb
76
77
  - test/units/url_test.rb
77
78
  homepage: https://github.com/imgix/imgix-rb
78
79
  licenses:
@@ -103,4 +104,5 @@ test_files:
103
104
  - test/units/domains_test.rb
104
105
  - test/units/path_test.rb
105
106
  - test/units/purge_test.rb
107
+ - test/units/srcset_test.rb
106
108
  - test/units/url_test.rb