dynamic_image 2.0.22 → 2.1.1

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
  SHA256:
3
- metadata.gz: bfb9c218b8902487079281c04685088ba37cee03ba5944425c8e391869ed1f54
4
- data.tar.gz: 6be8904c347f0721fe0d52f4693c65c7a7c96d77d81b169c00b83859df46c741
3
+ metadata.gz: 814628e7438a06292a2a283be0c88b724a1449327276c2f7ca89656947c690d7
4
+ data.tar.gz: 8ff9d551e13362514d102cae1c04e61d3374689282715911448019c425c12487
5
5
  SHA512:
6
- metadata.gz: 712f4d5d9077baec9e3f67d01ae686a38ef380686a37a5c6c91b2e0d27db50e2623cd30c3b25e107a3b03fc6e0712fe20bc0643fc47ae73473ee735e94d031b5
7
- data.tar.gz: 8ef5cd0021f2d32bc0876923c19f9e059edd5fdb52e06893cbab4dc4d739f72551f5bf53da8ee0007854f78d2cb5cc1de157542e40be9d27b17c6eeee735ccdb
6
+ metadata.gz: c52354d7f7100b367b402ea9be16a522872d423e8f1a21f49482bc86eb6223ac9d0c1194979e1d6b49fcfac2352922460aa44395e37adef1ca8cac0c6009e2b6
7
+ data.tar.gz: 94c370ea4a7ab9fe575ae324f8d50844c6600c5a677efcfe03471703130b4eea7613c5e3ac48d894481a1520484efdae2843ef90e36486f114009aa168681d1e
data/README.md CHANGED
@@ -31,6 +31,7 @@ and enumeration attacks.
31
31
  * Rails 5
32
32
  * Ruby 2.4+
33
33
  * ImageMagick command line tools
34
+ * ExifTool
34
35
 
35
36
  ## Documentation
36
37
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "mini_exiftool"
3
4
  require "mini_magick"
4
5
  require "dis"
5
6
  require "vector2d"
@@ -12,11 +13,12 @@ require "dynamic_image/errors"
12
13
  require "dynamic_image/helper"
13
14
  require "dynamic_image/image_reader"
14
15
  require "dynamic_image/image_sizing"
16
+ require "dynamic_image/jobs"
15
17
  require "dynamic_image/metadata"
16
18
  require "dynamic_image/model"
17
19
  require "dynamic_image/processed_image"
18
20
  require "dynamic_image/routing"
19
21
 
20
22
  module DynamicImage
21
- cattr_accessor :digest_verifier
23
+ cattr_accessor :digest_verifier, :process_later_limit
22
24
  end
@@ -44,13 +44,39 @@ module DynamicImage
44
44
  private
45
45
 
46
46
  def cache_expiration_header
47
- expires_in 30.days, public: true
47
+ expires_in 30.days, public: true if response.status == 200
48
48
  end
49
49
 
50
50
  def find_record
51
51
  @record = model.find(params[:id])
52
52
  end
53
53
 
54
+ def process_and_send(image, options)
55
+ processed_image = DynamicImage::ProcessedImage.new(image, options)
56
+ if process_later?(processed_image, requested_size)
57
+ process_later(image, options, requested_size)
58
+ head 503, retry_after: 10
59
+ else
60
+ send_image(processed_image, requested_size)
61
+ end
62
+ rescue MiniMagick::Error
63
+ process_later(image, options, requested_size)
64
+ raise
65
+ end
66
+
67
+ def process_later(image, options, requested_size)
68
+ DynamicImage::Jobs::CreateVariant
69
+ .perform_later(image, options, requested_size.to_s)
70
+ end
71
+
72
+ def process_later?(processed_image, size)
73
+ return false unless DynamicImage.process_later_limit
74
+
75
+ image_size = processed_image.record.size.x * processed_image.record.size.y
76
+ image_size > DynamicImage.process_later_limit &&
77
+ !processed_image.find_variant(size)
78
+ end
79
+
54
80
  def render_image(options)
55
81
  return unless stale?(@record)
56
82
 
@@ -60,7 +86,7 @@ module DynamicImage
60
86
  layout: false, locals: { options: options })
61
87
  end
62
88
  format.any(:gif, :jpeg, :jpg, :png, :tiff, :webp) do
63
- send_image(DynamicImage::ProcessedImage.new(@record, options))
89
+ process_and_send(@record, options)
64
90
  end
65
91
  end
66
92
  end
@@ -82,12 +108,10 @@ module DynamicImage
82
108
  params[:format]
83
109
  end
84
110
 
85
- def send_image(processed_image)
86
- send_data(
87
- processed_image.cropped_and_resized(requested_size),
88
- content_type: processed_image.content_type,
89
- disposition: "inline"
90
- )
111
+ def send_image(processed_image, requested_size)
112
+ send_data(processed_image.cropped_and_resized(requested_size),
113
+ content_type: processed_image.content_type,
114
+ disposition: "inline")
91
115
  end
92
116
 
93
117
  def verify_signed_params
@@ -3,11 +3,17 @@
3
3
  module DynamicImage
4
4
  module Errors
5
5
  class Error < StandardError; end
6
+
6
7
  class InvalidImage < DynamicImage::Errors::Error; end
8
+
7
9
  class InvalidHeader < DynamicImage::Errors::Error; end
10
+
8
11
  class InvalidSignature < DynamicImage::Errors::Error; end
12
+
9
13
  class InvalidSizeOptions < DynamicImage::Errors::Error; end
14
+
10
15
  class InvalidTransformation < DynamicImage::Errors::Error; end
16
+
11
17
  class ParameterMissing < DynamicImage::Errors::Error; end
12
18
  end
13
19
  end
@@ -21,6 +21,12 @@ module DynamicImage
21
21
  @data = data
22
22
  end
23
23
 
24
+ def exif
25
+ raise DynamicImage::Errors::InvalidHeader unless valid_header?
26
+
27
+ MiniExiftool.new(string_io)
28
+ end
29
+
24
30
  def read
25
31
  raise DynamicImage::Errors::InvalidHeader unless valid_header?
26
32
 
@@ -39,7 +45,11 @@ module DynamicImage
39
45
  private
40
46
 
41
47
  def file_header
42
- @file_header ||= StringIO.new(@data, "rb").read(8)
48
+ @file_header ||= string_io.read(8)
49
+ end
50
+
51
+ def string_io
52
+ StringIO.new(@data, "rb")
43
53
  end
44
54
  end
45
55
  end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dynamic_image/jobs/create_variant"
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicImage
4
+ module Jobs
5
+ # = Create variant
6
+ #
7
+ # Creates an image variant.
8
+ class CreateVariant < ActiveJob::Base
9
+ queue_as :dis
10
+
11
+ def perform(record, options, size)
12
+ size_v = Vector2d.parse(size)
13
+ DynamicImage::ProcessedImage.new(record, options)
14
+ .find_or_create_variant(size_v)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -6,6 +6,8 @@ module DynamicImage
6
6
  # Handles all processing of images. Takes an instance of
7
7
  # +DynamicImage::Model+ as argument.
8
8
  class ProcessedImage
9
+ attr_reader :record
10
+
9
11
  def initialize(record, options = {})
10
12
  @record = record
11
13
  @uncropped = options[:uncropped] ? true : false
@@ -40,10 +42,24 @@ module DynamicImage
40
42
  find_or_create_variant(size).data
41
43
  end
42
44
 
45
+ # Find or create a variant with the given size.
46
+ def find_or_create_variant(size)
47
+ find_variant(size) || create_variant(size)
48
+ rescue ActiveRecord::RecordNotUnique
49
+ find_variant(size)
50
+ end
51
+
52
+ # Find a variant with the given size.
53
+ def find_variant(size)
54
+ return nil unless record.persisted?
55
+
56
+ record.variants.find_by(variant_params(size))
57
+ end
58
+
43
59
  # Normalizes the image.
44
60
  #
45
61
  # * Applies EXIF rotation
46
- # * CMYK images are converted to sRGB
62
+ # * Converts to sRGB
47
63
  # * Strips metadata
48
64
  # * Optimizes GIFs
49
65
  # * Performs format conversion if the requested format is different
@@ -59,7 +75,7 @@ module DynamicImage
59
75
  process_data do |image|
60
76
  image.combine_options do |combined|
61
77
  combined.auto_orient
62
- combined.colorspace("sRGB") if needs_colorspace_conversion?
78
+ convert_to_srgb(image, combined)
63
79
  yield(combined) if block_given?
64
80
  optimize(combined)
65
81
  end
@@ -73,6 +89,14 @@ module DynamicImage
73
89
  gif? ? DynamicImage::ImageReader.new(image.coalesce.to_blob).read : image
74
90
  end
75
91
 
92
+ def convert_to_srgb(image, combined)
93
+ if image.data["profiles"].present? &&
94
+ exif.colorspacedata&.strip&.downcase == record.colorspace
95
+ combined.profile(srgb_profile)
96
+ end
97
+ combined.colorspace("sRGB") if record.cmyk?
98
+ end
99
+
76
100
  def create_variant(size)
77
101
  record.variants.create(
78
102
  variant_params(size).merge(filename: record.filename,
@@ -90,10 +114,8 @@ module DynamicImage
90
114
  end
91
115
  end
92
116
 
93
- def find_or_create_variant(size)
94
- record.variants.find_by(variant_params(size)) || create_variant(size)
95
- rescue ActiveRecord::RecordNotUnique
96
- record.variants.find_by(variant_params(size))
117
+ def exif
118
+ @exif ||= DynamicImage::ImageReader.new(record.data).exif
97
119
  end
98
120
 
99
121
  def format
@@ -105,7 +127,7 @@ module DynamicImage
105
127
  end
106
128
 
107
129
  def jpeg?
108
- content_type == "image/jpeg" || content_type == "image/jpeg"
130
+ content_type == "image/jpeg"
109
131
  end
110
132
 
111
133
  def image_sizing
@@ -113,10 +135,6 @@ module DynamicImage
113
135
  DynamicImage::ImageSizing.new(record, uncropped: @uncropped)
114
136
  end
115
137
 
116
- def needs_colorspace_conversion?
117
- record.cmyk?
118
- end
119
-
120
138
  def needs_format_conversion?
121
139
  format != record_format
122
140
  end
@@ -136,15 +154,9 @@ module DynamicImage
136
154
  result
137
155
  end
138
156
 
139
- attr_reader :record
140
-
141
157
  def record_format
142
- { "image/bmp" => "BMP",
143
- "image/png" => "PNG",
144
- "image/gif" => "GIF",
145
- "image/jpeg" => "JPEG",
146
- "image/pjpeg" => "JPEG",
147
- "image/tiff" => "TIFF",
158
+ { "image/bmp" => "BMP", "image/png" => "PNG", "image/gif" => "GIF",
159
+ "image/jpeg" => "JPEG", "image/pjpeg" => "JPEG", "image/tiff" => "TIFF",
148
160
  "image/webp" => "WEBP" }[record.content_type]
149
161
  end
150
162
 
@@ -152,6 +164,10 @@ module DynamicImage
152
164
  raise DynamicImage::Errors::InvalidImage unless record.valid?
153
165
  end
154
166
 
167
+ def srgb_profile
168
+ File.join(File.dirname(__FILE__), "profiles/sRGB_ICC_v4_Appearance.icc")
169
+ end
170
+
155
171
  def variant_params(size)
156
172
  crop_size, crop_start = image_sizing.crop_geometry(size)
157
173
 
@@ -13,8 +13,9 @@ module DynamicImage
13
13
  options = {
14
14
  path: "#{resource_name}/:digest(/:size)",
15
15
  constraints: { size: /\d+x\d+/ },
16
- only: [:show]
16
+ only: %i[show]
17
17
  }.merge(options)
18
+
18
19
  resources resource_name, options do
19
20
  get :uncropped, on: :member
20
21
  get :original, on: :member
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DynamicImage
4
- VERSION = "2.0.22"
4
+ VERSION = "2.1.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamic_image
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.22
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Inge Jørgensen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-12 00:00:00.000000000 Z
11
+ date: 2021-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dis
@@ -30,6 +30,20 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 1.0.6
33
+ - !ruby/object:Gem::Dependency
34
+ name: mini_exiftool
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.10'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.10'
33
47
  - !ruby/object:Gem::Dependency
34
48
  name: mini_magick
35
49
  requirement: !ruby/object:Gem::Requirement
@@ -155,6 +169,8 @@ files:
155
169
  - lib/dynamic_image/helper.rb
156
170
  - lib/dynamic_image/image_reader.rb
157
171
  - lib/dynamic_image/image_sizing.rb
172
+ - lib/dynamic_image/jobs.rb
173
+ - lib/dynamic_image/jobs/create_variant.rb
158
174
  - lib/dynamic_image/metadata.rb
159
175
  - lib/dynamic_image/model.rb
160
176
  - lib/dynamic_image/model/dimensions.rb
@@ -162,6 +178,7 @@ files:
162
178
  - lib/dynamic_image/model/validations.rb
163
179
  - lib/dynamic_image/model/variants.rb
164
180
  - lib/dynamic_image/processed_image.rb
181
+ - lib/dynamic_image/profiles/sRGB_ICC_v4_Appearance.icc
165
182
  - lib/dynamic_image/routing.rb
166
183
  - lib/dynamic_image/templates/show.html.erb
167
184
  - lib/dynamic_image/version.rb
@@ -170,7 +187,7 @@ homepage: https://github.com/elektronaut/dynamic_image
170
187
  licenses:
171
188
  - MIT
172
189
  metadata: {}
173
- post_install_message:
190
+ post_install_message:
174
191
  rdoc_options: []
175
192
  require_paths:
176
193
  - lib
@@ -185,8 +202,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
202
  - !ruby/object:Gem::Version
186
203
  version: '0'
187
204
  requirements: []
188
- rubygems_version: 3.1.2
189
- signing_key:
205
+ rubygems_version: 3.1.4
206
+ signing_key:
190
207
  specification_version: 4
191
208
  summary: Rails plugin that simplifies image uploading and processing
192
209
  test_files: []