vitals_image 0.2.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -1
- data/README.md +17 -5
- data/app/helpers/vitals_image/tag_helper.rb +6 -21
- data/app/models/vitals_image/source.rb +2 -2
- data/db/migrate/20210809171706_add_fingerprint_to_vitals_image_sources.rb +6 -0
- data/lib/vitals_image.rb +1 -2
- data/lib/vitals_image/cache.rb +11 -1
- data/lib/vitals_image/engine.rb +10 -9
- data/lib/vitals_image/gem_version.rb +1 -1
- data/lib/vitals_image/optimizer.rb +2 -7
- data/lib/vitals_image/optimizer/invariable.rb +40 -0
- data/lib/vitals_image/optimizer/url.rb +5 -1
- data/lib/vitals_image/optimizer/{active_storage.rb → variable.rb} +11 -15
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 070dabcbfcfe58cf4ad78ed7509cf16963484fa160db4358ed2f400a1a7d7925
|
4
|
+
data.tar.gz: cecf4c19afeed8df374686752e3ee7300ecbe6ced03c15781a9f0caa6134418b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 424b3c5908a10ee87df1e8174b786f30166af7b8fc28c4473ca77775dafb77fb1cce5780568a1098efac6898eb4b97584857ea122555d68f81ead1f6b1cfbb5c
|
7
|
+
data.tar.gz: 9510a8c14a5363997d6729933b3356f0bf7145410498e850ccd27d346fbde54e6bdf013e4b6b97afd557279f26dae4e082c07ad188ecdbcdb3e1e3b984c1655e
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,34 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.5]
|
4
|
+
|
5
|
+
- Add `domains` config to allow limiting from which domains images will be analyzed
|
6
|
+
- User `after_commit` to enqueued analyze job
|
7
|
+
|
8
|
+
## [0.4.1] - 2021-07-22
|
9
|
+
|
10
|
+
- Do not discard the specified `style` attribute
|
11
|
+
|
12
|
+
## [0.4.0] - 2021-07-06
|
13
|
+
|
14
|
+
- Fixed resize and pad in vips
|
15
|
+
- Fixed image quality in vips
|
16
|
+
- Reduced JPEG quality from 85 to 80
|
17
|
+
- Removed optimal quality
|
18
|
+
- Updated Vitals Image to 0.5
|
19
|
+
|
20
|
+
## [0.3.0] - 2021-05-22
|
21
|
+
|
22
|
+
- Redo the image helper
|
23
|
+
- Redo the active storage optimizer
|
24
|
+
|
25
|
+
## [0.2.1] - 2021-05-22
|
26
|
+
|
27
|
+
- Do not attempt to transform invariable images
|
28
|
+
|
3
29
|
## [0.2.0] - 2021-05-18
|
4
30
|
|
5
|
-
- Use the `
|
31
|
+
- Use the `optimal_quality` value of blob metadata instead of fixed `85` if its available;
|
6
32
|
- Remove some unecessary configs;
|
7
33
|
- Drop analyzers and use `active_analysis` gem instead;
|
8
34
|
- Use "retry once" strategy instead of `create_or_find_by`;
|
data/README.md
CHANGED
@@ -134,16 +134,30 @@ The following configuration options are available. The defaults were chosen for
|
|
134
134
|
| jpeg_optimization | see below | see below | Hash of options to pass to active storage when optimizing a JPEG. |
|
135
135
|
| png_optimization | see below | see below | Hash of options to pass to active storage when optimizing a PNG. |
|
136
136
|
| active_storage_route | `:inherited` | `:inherited` | Defines how urls of active storage images will be generated. If `inherited` it will use the same as active storage. Other valid options are `redirect`, `proxy` and `public`. Whatever is set here can be overriden in the helper. |
|
137
|
+
| domains | empty | - | Limits the domains that vitals image source can be created from |
|
137
138
|
|
139
|
+
Minimagick
|
138
140
|
```ruby
|
139
141
|
# jpeg_conversion
|
140
|
-
{
|
142
|
+
{ saver: { strip: true, quality: 85, interlace: "JPEG", sampling_factor: "4:2:0", colorspace: "sRGB", background: :white, flatten: true, alpha: :off }, format: "jpg" }
|
141
143
|
|
142
144
|
# jpeg_optimization:
|
143
|
-
{
|
145
|
+
{ saver: { strip: true, quality: 85, interlace: "JPEG", sampling_factor: "4:2:0", colorspace: "sRGB" } }
|
144
146
|
|
145
147
|
# png_optimization:
|
146
|
-
{ strip: true, quality: 00 }
|
148
|
+
{ saver: { strip: true, quality: 00 } }
|
149
|
+
```
|
150
|
+
|
151
|
+
Vips
|
152
|
+
```ruby
|
153
|
+
# jpeg_conversion
|
154
|
+
{ saver: { strip: true, quality: 85, interlace: true, optimize_coding: true, trellis_quant: true, quant_table: 3, background: 255 }, format: "jpg" }
|
155
|
+
|
156
|
+
# jpeg_optimization:
|
157
|
+
{ saver: { strip: true, quality: 85, interlace: true, optimize_coding: true, trellis_quant: true, quant_table: 3 } }
|
158
|
+
|
159
|
+
# png_optimization:
|
160
|
+
{ saver: { strip: true, compression: 9 } }
|
147
161
|
```
|
148
162
|
|
149
163
|
These can be configured in your environment files, just like any other rails settings:
|
@@ -151,8 +165,6 @@ These can be configured in your environment files, just like any other rails set
|
|
151
165
|
```
|
152
166
|
Rails.application.configure do |config|
|
153
167
|
config.vitals_image.image_library = :vips
|
154
|
-
config.vitals_image.mobile_width = 410
|
155
|
-
config.vitals_image.desktop_width = 1264
|
156
168
|
config.vitals_image.lazy_loading = :lozad
|
157
169
|
config.vitals_image.require_alt_attribute = true
|
158
170
|
config.vitals_image.check_for_white_background = true
|
@@ -6,32 +6,17 @@ module VitalsImage
|
|
6
6
|
source = image_url(source) if source.is_a?(String)
|
7
7
|
optimizer = VitalsImage::Base.optimizer(source, options)
|
8
8
|
|
9
|
-
if
|
10
|
-
vitals_image_invariable_tag(optimizer)
|
11
|
-
elsif optimizer.native_lazy_load?
|
12
|
-
vitals_image_variable_tag(optimizer)
|
13
|
-
else
|
14
|
-
vitals_image_lazy_tag(optimizer)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
def vitals_image_invariable_tag(optimizer)
|
20
|
-
image_tag optimizer.src, optimizer.html_options
|
21
|
-
end
|
22
|
-
|
23
|
-
def vitals_image_variable_tag(optimizer)
|
24
|
-
url = vitals_image_url(optimizer.src, optimizer.html_options)
|
25
|
-
image_tag url, optimizer.html_options
|
26
|
-
end
|
27
|
-
|
28
|
-
def vitals_image_lazy_tag(optimizer)
|
9
|
+
if optimizer.non_native_lazy_load?
|
29
10
|
url = vitals_image_url(optimizer.html_options["data"]["src"], optimizer.html_options)
|
30
11
|
optimizer.html_options["data"]["src"] = url
|
31
|
-
|
32
12
|
image_tag optimizer.src, optimizer.html_options
|
13
|
+
else
|
14
|
+
url = vitals_image_url(optimizer.src, optimizer.html_options)
|
15
|
+
image_tag url, optimizer.html_options
|
33
16
|
end
|
17
|
+
end
|
34
18
|
|
19
|
+
private
|
35
20
|
def vitals_image_url(source, options)
|
36
21
|
active_storage_route = options.delete("active_storage_route") || VitalsImage.active_storage_route
|
37
22
|
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module VitalsImage
|
4
4
|
class Source < ActiveRecord::Base
|
5
|
-
store :metadata, accessors: [ :analyzed, :width, :height ], coder: ActiveRecord::Coders::JSON
|
5
|
+
store :metadata, accessors: [ :identified, :analyzed, :width, :height ], coder: ActiveRecord::Coders::JSON
|
6
6
|
|
7
|
-
|
7
|
+
after_create_commit -> { AnalyzeJob.perform_later(self) }
|
8
8
|
end
|
9
9
|
end
|
data/lib/vitals_image.rb
CHANGED
@@ -14,8 +14,6 @@ module VitalsImage
|
|
14
14
|
mattr_accessor :analyzers
|
15
15
|
mattr_accessor :image_library
|
16
16
|
|
17
|
-
mattr_accessor :mobile_width
|
18
|
-
mattr_accessor :desktop_width
|
19
17
|
mattr_accessor :resolution
|
20
18
|
mattr_accessor :lazy_loading
|
21
19
|
mattr_accessor :lazy_loading_placeholder
|
@@ -28,6 +26,7 @@ module VitalsImage
|
|
28
26
|
mattr_accessor :jpeg_optimization
|
29
27
|
mattr_accessor :png_optimization
|
30
28
|
mattr_accessor :active_storage_route
|
29
|
+
mattr_accessor :domains
|
31
30
|
|
32
31
|
mattr_accessor :skip_ssl_verification
|
33
32
|
end
|
data/lib/vitals_image/cache.rb
CHANGED
@@ -15,7 +15,7 @@ module VitalsImage
|
|
15
15
|
source = @store.read(key)
|
16
16
|
|
17
17
|
if source.blank?
|
18
|
-
source =
|
18
|
+
source = find_or_create_by(key)
|
19
19
|
expires_in = source.analyzed ? nil : 1.minute
|
20
20
|
@store.write(key, source, expires_in: expires_in)
|
21
21
|
end
|
@@ -25,6 +25,16 @@ module VitalsImage
|
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
28
|
+
def find_or_create_by(key)
|
29
|
+
uri = URI.parse(key)
|
30
|
+
|
31
|
+
if VitalsImage.domains.present? && !VitalsImage.domains.include?(uri.host)
|
32
|
+
Source.new(key: key, metadata: { identified: false })
|
33
|
+
else
|
34
|
+
Source.find_or_create_by(key: key) { |source| source.identified = true }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
28
38
|
def with_retry
|
29
39
|
yield
|
30
40
|
rescue ActiveRecord::RecordNotUnique
|
data/lib/vitals_image/engine.rb
CHANGED
@@ -19,15 +19,17 @@ require "vitals_image/errors"
|
|
19
19
|
require "vitals_image/optimizer"
|
20
20
|
require "vitals_image/optimizer/blank"
|
21
21
|
require "vitals_image/optimizer/url"
|
22
|
-
require "vitals_image/optimizer/
|
22
|
+
require "vitals_image/optimizer/variable"
|
23
|
+
require "vitals_image/optimizer/invariable"
|
23
24
|
|
24
25
|
module VitalsImage
|
25
26
|
class Engine < ::Rails::Engine
|
26
27
|
isolate_namespace VitalsImage
|
27
28
|
|
28
29
|
config.vitals_image = ActiveSupport::OrderedOptions.new
|
29
|
-
config.vitals_image.optimizers = [VitalsImage::Optimizer::Blank, VitalsImage::Optimizer::
|
30
|
+
config.vitals_image.optimizers = [VitalsImage::Optimizer::Blank, VitalsImage::Optimizer::Variable, VitalsImage::Optimizer::Invariable, VitalsImage::Optimizer::Url]
|
30
31
|
config.vitals_image.analyzers = [VitalsImage::Analyzer::UrlAnalyzer]
|
32
|
+
config.vitals_image.domains = []
|
31
33
|
|
32
34
|
config.eager_load_namespaces << VitalsImage
|
33
35
|
|
@@ -39,8 +41,6 @@ module VitalsImage
|
|
39
41
|
VitalsImage.optimizers = app.config.vitals_image.optimizers || []
|
40
42
|
VitalsImage.analyzers = app.config.vitals_image.analyzers || []
|
41
43
|
|
42
|
-
VitalsImage.mobile_width = app.config.vitals_image.mobile_width || :original
|
43
|
-
VitalsImage.desktop_width = app.config.vitals_image.desktop_width || :original
|
44
44
|
VitalsImage.resolution = app.config.vitals_image.resolution || 2
|
45
45
|
VitalsImage.lazy_loading = app.config.vitals_image.lazy_loading || :native
|
46
46
|
VitalsImage.lazy_loading_placeholder = app.config.vitals_image.lazy_loading_placeholder || VitalsImage::Base::TINY_GIF
|
@@ -53,6 +53,7 @@ module VitalsImage
|
|
53
53
|
VitalsImage.jpeg_conversion = app.config.vitals_image.jpeg_conversion
|
54
54
|
VitalsImage.jpeg_optimization = app.config.vitals_image.jpeg_optimization
|
55
55
|
VitalsImage.png_optimization = app.config.vitals_image.png_optimization
|
56
|
+
VitalsImage.domains = app.config.vitals_image.domains || []
|
56
57
|
|
57
58
|
VitalsImage.skip_ssl_verification = app.config.vitals_image.skip_ssl_verification || false
|
58
59
|
end
|
@@ -69,13 +70,13 @@ module VitalsImage
|
|
69
70
|
initializer "vitals_image.optimizations" do
|
70
71
|
config.after_initialize do |app|
|
71
72
|
if VitalsImage.image_library == :vips
|
72
|
-
VitalsImage.jpeg_conversion ||= { saver: { strip: true, quality:
|
73
|
-
VitalsImage.jpeg_optimization ||= { saver: { strip: true, quality:
|
73
|
+
VitalsImage.jpeg_conversion ||= { saver: { strip: true, quality: 80, interlace: true, optimize_coding: true, trellis_quant: true, quant_table: 3, background: 255 }, format: "jpg" }
|
74
|
+
VitalsImage.jpeg_optimization ||= { saver: { strip: true, quality: 80, interlace: true, optimize_coding: true, trellis_quant: true, quant_table: 3 } }
|
74
75
|
VitalsImage.png_optimization ||= { saver: { strip: true, compression: 9 } }
|
75
76
|
else
|
76
|
-
VitalsImage.jpeg_conversion ||= { saver: { strip: true, quality:
|
77
|
-
VitalsImage.jpeg_optimization ||= { saver: { strip: true, quality:
|
78
|
-
VitalsImage.png_optimization ||= { saver: { strip: true, quality:
|
77
|
+
VitalsImage.jpeg_conversion ||= { saver: { strip: true, quality: 80, interlace: "JPEG", sampling_factor: "4:2:0", colorspace: "sRGB", background: :white, flatten: true, alpha: :off }, format: "jpg" }
|
78
|
+
VitalsImage.jpeg_optimization ||= { saver: { strip: true, quality: 80, interlace: "JPEG", sampling_factor: "4:2:0", colorspace: "sRGB" } }
|
79
|
+
VitalsImage.png_optimization ||= { saver: { strip: true, quality: 75 } }
|
79
80
|
end
|
80
81
|
end
|
81
82
|
end
|
@@ -26,10 +26,10 @@ module VitalsImage
|
|
26
26
|
|
27
27
|
def html_options
|
28
28
|
@html_options ||= begin
|
29
|
-
html_options = @options.dup
|
29
|
+
html_options = @options.dup.except("lazy_load")
|
30
30
|
html_options["width"] = width
|
31
31
|
html_options["height"] = height
|
32
|
-
html_options["style"] = style
|
32
|
+
html_options["style"] = "#{style} #{html_options["style"]}".squish.presence
|
33
33
|
html_options["class"] = "vitals-image #{html_options["class"]}".squish
|
34
34
|
|
35
35
|
if non_native_lazy_load?
|
@@ -57,11 +57,6 @@ module VitalsImage
|
|
57
57
|
lazy_load? && VitalsImage.lazy_loading == :native
|
58
58
|
end
|
59
59
|
|
60
|
-
# Override this method in a concrete subclass. Have it return true the source is an active storage blob
|
61
|
-
def variable?
|
62
|
-
false
|
63
|
-
end
|
64
|
-
|
65
60
|
private
|
66
61
|
def style
|
67
62
|
if analyzed? && !requested_height
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VitalsImage
|
4
|
+
class Optimizer::Invariable < Optimizer
|
5
|
+
def self.accept?(source)
|
6
|
+
source.respond_to?(:variable?) && !source.variable?
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
def source_url
|
11
|
+
@source
|
12
|
+
end
|
13
|
+
|
14
|
+
def style
|
15
|
+
if !analyzed?
|
16
|
+
# Do nothing
|
17
|
+
elsif !requested_height
|
18
|
+
"height:auto;"
|
19
|
+
elsif fixed_dimensions?
|
20
|
+
"object-fit: contain;"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def original_width
|
25
|
+
metadata[:width]
|
26
|
+
end
|
27
|
+
|
28
|
+
def original_height
|
29
|
+
metadata[:height]
|
30
|
+
end
|
31
|
+
|
32
|
+
def metadata
|
33
|
+
@source.metadata
|
34
|
+
end
|
35
|
+
|
36
|
+
def analyzed?
|
37
|
+
metadata[:analyzed]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -17,7 +17,7 @@ module VitalsImage
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def style
|
20
|
-
if !analyzed?
|
20
|
+
if !identified? || !analyzed?
|
21
21
|
# Do nothing
|
22
22
|
elsif !requested_height
|
23
23
|
"height:auto;"
|
@@ -26,6 +26,10 @@ module VitalsImage
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def identified?
|
30
|
+
metadata.identified
|
31
|
+
end
|
32
|
+
|
29
33
|
def analyzed?
|
30
34
|
metadata.analyzed
|
31
35
|
end
|
@@ -1,13 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module VitalsImage
|
4
|
-
class Optimizer::
|
4
|
+
class Optimizer::Variable < Optimizer
|
5
5
|
def self.accept?(source)
|
6
|
-
source.
|
7
|
-
end
|
8
|
-
|
9
|
-
def variable?
|
10
|
-
true
|
6
|
+
source.respond_to?(:variable?) && source.variable?
|
11
7
|
end
|
12
8
|
|
13
9
|
private
|
@@ -65,31 +61,31 @@ module VitalsImage
|
|
65
61
|
end
|
66
62
|
|
67
63
|
def optimize_jpeg
|
68
|
-
@source.variant
|
64
|
+
@source.variant resize_and_flatten(VitalsImage.jpeg_optimization)
|
69
65
|
end
|
70
66
|
|
71
67
|
def optimize_png
|
72
68
|
if alpha? || !VitalsImage.convert_to_jpeg
|
73
|
-
@source.variant
|
69
|
+
@source.variant resize(VitalsImage.png_optimization)
|
74
70
|
else
|
75
|
-
@source.variant
|
71
|
+
@source.variant resize_and_flatten(VitalsImage.jpeg_conversion)
|
76
72
|
end
|
77
73
|
end
|
78
74
|
|
79
75
|
def optimize_generic
|
80
76
|
if alpha? || !VitalsImage.convert_to_jpeg
|
81
|
-
@source.variant
|
77
|
+
@source.variant resize
|
82
78
|
else
|
83
|
-
@source.variant
|
79
|
+
@source.variant resize_and_flatten(VitalsImage.jpeg_conversion)
|
84
80
|
end
|
85
81
|
end
|
86
82
|
|
87
|
-
def
|
88
|
-
|
89
|
-
defaults.merge
|
83
|
+
def resize_and_flatten(defaults = {})
|
84
|
+
resize = resize_mode != :resize_and_pad ? dimensions : dimensions.push(background: [255])
|
85
|
+
defaults.merge "#{resize_mode}": resize
|
90
86
|
end
|
91
87
|
|
92
|
-
def
|
88
|
+
def resize(defaults = {})
|
93
89
|
defaults.merge "#{resize_mode}": dimensions
|
94
90
|
end
|
95
91
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vitals_image
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Breno Gazzola
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '0.
|
131
|
+
version: '0.5'
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0.
|
138
|
+
version: '0.5'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: sqlite3
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -243,6 +243,7 @@ files:
|
|
243
243
|
- app/views/layouts/vitals_image/application.html.erb
|
244
244
|
- config/routes.rb
|
245
245
|
- db/migrate/20210502132155_create_vitals_image_sources.rb
|
246
|
+
- db/migrate/20210809171706_add_fingerprint_to_vitals_image_sources.rb
|
246
247
|
- lib/tasks/vitals_image_tasks.rake
|
247
248
|
- lib/vitals_image.rb
|
248
249
|
- lib/vitals_image/analyzer.rb
|
@@ -253,9 +254,10 @@ files:
|
|
253
254
|
- lib/vitals_image/errors.rb
|
254
255
|
- lib/vitals_image/gem_version.rb
|
255
256
|
- lib/vitals_image/optimizer.rb
|
256
|
-
- lib/vitals_image/optimizer/active_storage.rb
|
257
257
|
- lib/vitals_image/optimizer/blank.rb
|
258
|
+
- lib/vitals_image/optimizer/invariable.rb
|
258
259
|
- lib/vitals_image/optimizer/url.rb
|
260
|
+
- lib/vitals_image/optimizer/variable.rb
|
259
261
|
- lib/vitals_image/test_case.rb
|
260
262
|
- lib/vitals_image/version.rb
|
261
263
|
homepage: https://github.com/FestaLab/vitals_image
|