dynamic_image 2.0.20 → 2.0.25

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: f0a95aa4e97d054b1bd7d757c14f0a98790061806a930b6a2c8bc9294d85d00a
4
- data.tar.gz: dbe583ffcfe362d0406c0b272bc1f7a53d625be553d0e804baa5bf6753100cae
3
+ metadata.gz: 20b1cfa9c326762d6b3d1bca63b4d8d65516cc266abd03f55328b4cca8086dc3
4
+ data.tar.gz: 4a0496d6507534664dc8e39bc59358a2607df6aaaa966ee0eda3990f72cae8bf
5
5
  SHA512:
6
- metadata.gz: 681e4621406b2e6c4eae033dcba0ca1ea085c3429307a29e897eed62cbf22f2810183107142aae0432c351e2a8a47f5a25aa7ca901afe4e908109cf6126d54d3
7
- data.tar.gz: a7e5975010f4eb0f3dfaa3bf9185ea5a8e4d134f6f963d353da7d7dca0c4894094aee2a8557083bf1870ef9770fc26e3a5e58346fe55742f0af07f73e691f612
6
+ metadata.gz: c04933c776c41870142473869f983fd0d8d1a0b98602abf41b3fb5392f6d6ef8c4cb2f77c875044f32cbc7903d1dd9de06c644fcfc73c913bd414583ee27dfae
7
+ data.tar.gz: 79ad9d9b59398d56765878253170eae968d2d8320c31b992fd9758ff2dd00b8131db1fae2746f6af359eeb8b9934dfe4020b30cd91602f1b6872302c95b2d1d6
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [![Version](https://img.shields.io/gem/v/dynamic_image.svg?style=flat)](https://rubygems.org/gems/dynamic_image)
2
- [![Build Status](https://travis-ci.org/elektronaut/dynamic_image.svg?branch=master)](https://travis-ci.org/elektronaut/dynamic_image)
2
+ ![Build](https://github.com/elektronaut/dynamic_image/workflows/Build/badge.svg)
3
3
  [![Code Climate](https://codeclimate.com/github/elektronaut/dynamic_image/badges/gpa.svg)](https://codeclimate.com/github/elektronaut/dynamic_image)
4
4
  [![Code Climate](https://codeclimate.com/github/elektronaut/dynamic_image/badges/coverage.svg)](https://codeclimate.com/github/elektronaut/dynamic_image)
5
5
  [![Inline docs](http://inch-ci.org/github/elektronaut/dynamic_image.svg)](http://inch-ci.org/github/elektronaut/dynamic_image)
@@ -12,11 +12,12 @@ require "dynamic_image/errors"
12
12
  require "dynamic_image/helper"
13
13
  require "dynamic_image/image_reader"
14
14
  require "dynamic_image/image_sizing"
15
+ require "dynamic_image/jobs"
15
16
  require "dynamic_image/metadata"
16
17
  require "dynamic_image/model"
17
18
  require "dynamic_image/processed_image"
18
19
  require "dynamic_image/routing"
19
20
 
20
21
  module DynamicImage
21
- cattr_accessor :digest_verifier
22
+ cattr_accessor :digest_verifier, :process_later_limit
22
23
  end
@@ -8,7 +8,7 @@ module DynamicImage
8
8
 
9
9
  module ClassMethods
10
10
  def belongs_to_image(name, scope = nil, **options)
11
- belongs_to(name, scope, options)
11
+ belongs_to(name, scope, **options)
12
12
 
13
13
  define_method "#{name}=" do |new_image|
14
14
  if new_image.present? && !new_image.is_a?(DynamicImage::Model)
@@ -44,13 +44,21 @@ 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_later?(processed_image, size)
55
+ return false unless DynamicImage.process_later_limit
56
+
57
+ image_size = processed_image.record.size.x * processed_image.record.size.y
58
+ image_size > DynamicImage.process_later_limit &&
59
+ !processed_image.find_variant(size)
60
+ end
61
+
54
62
  def render_image(options)
55
63
  return unless stale?(@record)
56
64
 
@@ -59,8 +67,8 @@ module DynamicImage
59
67
  render(file: File.join(File.dirname(__FILE__), "templates/show"),
60
68
  layout: false, locals: { options: options })
61
69
  end
62
- format.any(:gif, :jpeg, :png, :tiff, :webp) do
63
- send_image(DynamicImage::ProcessedImage.new(@record, options))
70
+ format.any(:gif, :jpeg, :jpg, :png, :tiff, :webp) do
71
+ send_image(@record, options)
64
72
  end
65
73
  end
66
74
  end
@@ -69,7 +77,7 @@ module DynamicImage
69
77
  return unless stale?(@record)
70
78
 
71
79
  respond_to do |format|
72
- format.any(:gif, :jpeg, :png, :tiff, :webp) do
80
+ format.any(:gif, :jpeg, :jpg, :png, :tiff, :webp) do
73
81
  send_data(@record.data,
74
82
  filename: filename,
75
83
  content_type: @record.content_type,
@@ -82,12 +90,17 @@ module DynamicImage
82
90
  params[:format]
83
91
  end
84
92
 
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
- )
93
+ def send_image(image, options)
94
+ processed_image = DynamicImage::ProcessedImage.new(image, options)
95
+ if process_later?(processed_image, requested_size)
96
+ DynamicImage::Jobs::CreateVariant
97
+ .perform_later(image, options, requested_size.to_s)
98
+ head 503, retry_after: 10
99
+ else
100
+ send_data(processed_image.cropped_and_resized(requested_size),
101
+ content_type: processed_image.content_type,
102
+ disposition: "inline")
103
+ end
91
104
  end
92
105
 
93
106
  def verify_signed_params
@@ -17,11 +17,21 @@ module DynamicImage
17
17
  end
18
18
  end
19
19
 
20
+ initializer "dynamic_image.mime_types" do
21
+ Mime::Type.register "image/bmp", :bmp
22
+ Mime::Type.register "image/gif", :gif
23
+ Mime::Type.register "image/jpeg", :jpg
24
+ Mime::Type.register "image/jpeg", :jpeg
25
+ Mime::Type.register "image/png", :png
26
+ Mime::Type.register "image/tiff", :tiff
27
+ Mime::Type.register "image/webp", :webp
28
+ end
29
+
20
30
  initializer "dynamic_image.extensions", before: :load_active_support do
21
31
  ActiveSupport.on_load(:active_record) do
22
32
  send :include, DynamicImage::BelongsTo
23
33
  end
24
- ActionDispatch::Routing::Mapper.send :include, DynamicImage::Routing
34
+ ActionDispatch::Routing::Mapper.include DynamicImage::Routing
25
35
 
26
36
  ActionDispatch::ExceptionWrapper.rescue_responses.merge!(
27
37
  "DynamicImage::Errors::InvalidSignature" => :unauthorized
@@ -149,8 +149,8 @@ module DynamicImage
149
149
  @uncropped
150
150
  end
151
151
 
152
- def vector(x, y)
153
- Vector2d.new(x, y)
152
+ def vector(width, height)
153
+ Vector2d.new(width, height)
154
154
  end
155
155
  end
156
156
  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
@@ -82,8 +82,8 @@ module DynamicImage
82
82
 
83
83
  private
84
84
 
85
- def vector(x, y)
86
- Vector2d.new(x, y)
85
+ def vector(width, height)
86
+ Vector2d.new(width, height)
87
87
  end
88
88
  end
89
89
  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
@@ -70,27 +86,29 @@ module DynamicImage
70
86
  private
71
87
 
72
88
  def coalesced(image)
73
- return image unless gif?
89
+ gif? ? DynamicImage::ImageReader.new(image.coalesce.to_blob).read : image
90
+ end
91
+
92
+ def convert_to_srgb(image, combined)
93
+ combined.profile(srgb_profile) if image.data["profiles"].present?
94
+ combined.colorspace("sRGB") if record.cmyk?
95
+ end
74
96
 
75
- DynamicImage::ImageReader.new(image.coalesce.to_blob).read
97
+ def create_variant(size)
98
+ record.variants.create(
99
+ variant_params(size).merge(filename: record.filename,
100
+ content_type: content_type,
101
+ data: crop_and_resize(size))
102
+ )
76
103
  end
77
104
 
78
105
  def crop_and_resize(size)
79
106
  normalized do |image|
80
- if record.cropped? || size != record.size
81
- image.crop(image_sizing.crop_geometry_string(size))
82
- image.resize(size)
83
- end
84
- end
85
- end
107
+ next unless record.cropped? || size != record.size
86
108
 
87
- def find_or_create_variant(size)
88
- record.variants.find_by(variant_params(size)) ||
89
- record.variants.create(
90
- variant_params(size).merge(filename: record.filename,
91
- content_type: content_type,
92
- data: crop_and_resize(size))
93
- )
109
+ image.crop(image_sizing.crop_geometry_string(size))
110
+ image.resize(size)
111
+ end
94
112
  end
95
113
 
96
114
  def format
@@ -102,7 +120,7 @@ module DynamicImage
102
120
  end
103
121
 
104
122
  def jpeg?
105
- content_type == "image/jpeg" || content_type == "image/jpeg"
123
+ content_type == "image/jpeg"
106
124
  end
107
125
 
108
126
  def image_sizing
@@ -110,10 +128,6 @@ module DynamicImage
110
128
  DynamicImage::ImageSizing.new(record, uncropped: @uncropped)
111
129
  end
112
130
 
113
- def needs_colorspace_conversion?
114
- record.cmyk?
115
- end
116
-
117
131
  def needs_format_conversion?
118
132
  format != record_format
119
133
  end
@@ -133,15 +147,9 @@ module DynamicImage
133
147
  result
134
148
  end
135
149
 
136
- attr_reader :record
137
-
138
150
  def record_format
139
- { "image/bmp" => "BMP",
140
- "image/png" => "PNG",
141
- "image/gif" => "GIF",
142
- "image/jpeg" => "JPEG",
143
- "image/pjpeg" => "JPEG",
144
- "image/tiff" => "TIFF",
151
+ { "image/bmp" => "BMP", "image/png" => "PNG", "image/gif" => "GIF",
152
+ "image/jpeg" => "JPEG", "image/pjpeg" => "JPEG", "image/tiff" => "TIFF",
145
153
  "image/webp" => "WEBP" }[record.content_type]
146
154
  end
147
155
 
@@ -149,15 +157,16 @@ module DynamicImage
149
157
  raise DynamicImage::Errors::InvalidImage unless record.valid?
150
158
  end
151
159
 
160
+ def srgb_profile
161
+ File.join(File.dirname(__FILE__), "profiles/sRGB_ICC_v4_Appearance.icc")
162
+ end
163
+
152
164
  def variant_params(size)
153
165
  crop_size, crop_start = image_sizing.crop_geometry(size)
154
166
 
155
- { width: size.x.round,
156
- height: size.y.round,
157
- crop_width: crop_size.x,
158
- crop_height: crop_size.y,
159
- crop_start_x: crop_start.x,
160
- crop_start_y: crop_start.y,
167
+ { width: size.x.round, height: size.y.round,
168
+ crop_width: crop_size.x, crop_height: crop_size.y,
169
+ crop_start_x: crop_start.x, crop_start_y: crop_start.y,
161
170
  format: format }
162
171
  end
163
172
  end
@@ -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.20"
4
+ VERSION = "2.0.25"
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.20
4
+ version: 2.0.25
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-03-13 00:00:00.000000000 Z
11
+ date: 2020-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dis
@@ -78,6 +78,20 @@ dependencies:
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
80
  version: 2.2.1
81
+ - !ruby/object:Gem::Dependency
82
+ name: rails-controller-testing
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
81
95
  - !ruby/object:Gem::Dependency
82
96
  name: rspec-rails
83
97
  requirement: !ruby/object:Gem::Requirement
@@ -92,6 +106,20 @@ dependencies:
92
106
  - - "~>"
93
107
  - !ruby/object:Gem::Version
94
108
  version: 3.7.0
109
+ - !ruby/object:Gem::Dependency
110
+ name: simplecov
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: 0.17.1
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: 0.17.1
95
123
  - !ruby/object:Gem::Dependency
96
124
  name: sqlite3
97
125
  requirement: !ruby/object:Gem::Requirement
@@ -127,6 +155,8 @@ files:
127
155
  - lib/dynamic_image/helper.rb
128
156
  - lib/dynamic_image/image_reader.rb
129
157
  - lib/dynamic_image/image_sizing.rb
158
+ - lib/dynamic_image/jobs.rb
159
+ - lib/dynamic_image/jobs/create_variant.rb
130
160
  - lib/dynamic_image/metadata.rb
131
161
  - lib/dynamic_image/model.rb
132
162
  - lib/dynamic_image/model/dimensions.rb
@@ -134,6 +164,7 @@ files:
134
164
  - lib/dynamic_image/model/validations.rb
135
165
  - lib/dynamic_image/model/variants.rb
136
166
  - lib/dynamic_image/processed_image.rb
167
+ - lib/dynamic_image/profiles/sRGB_ICC_v4_Appearance.icc
137
168
  - lib/dynamic_image/routing.rb
138
169
  - lib/dynamic_image/templates/show.html.erb
139
170
  - lib/dynamic_image/version.rb
@@ -142,7 +173,7 @@ homepage: https://github.com/elektronaut/dynamic_image
142
173
  licenses:
143
174
  - MIT
144
175
  metadata: {}
145
- post_install_message:
176
+ post_install_message:
146
177
  rdoc_options: []
147
178
  require_paths:
148
179
  - lib
@@ -158,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
189
  version: '0'
159
190
  requirements: []
160
191
  rubygems_version: 3.1.2
161
- signing_key:
192
+ signing_key:
162
193
  specification_version: 4
163
194
  summary: Rails plugin that simplifies image uploading and processing
164
195
  test_files: []