dynamic_image 2.0.22 → 2.1.1

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
  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: []