dynamic_image 2.0.16 → 2.0.17
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 +4 -4
- data/README.md +2 -2
- data/Rakefile +3 -1
- data/app/models/dynamic_image/variant.rb +22 -0
- data/db/migrate/20190620160500_create_dynamic_image_variants.rb +32 -0
- data/lib/dynamic_image.rb +2 -2
- data/lib/dynamic_image/belongs_to.rb +1 -1
- data/lib/dynamic_image/controller.rb +12 -12
- data/lib/dynamic_image/digest_verifier.rb +8 -10
- data/lib/dynamic_image/{railtie.rb → engine.rb} +23 -12
- data/lib/dynamic_image/errors.rb +1 -1
- data/lib/dynamic_image/helper.rb +7 -9
- data/lib/dynamic_image/image_reader.rb +18 -14
- data/lib/dynamic_image/image_sizing.rb +9 -7
- data/lib/dynamic_image/metadata.rb +11 -11
- data/lib/dynamic_image/model.rb +6 -6
- data/lib/dynamic_image/model/dimensions.rb +1 -1
- data/lib/dynamic_image/model/transformations.rb +3 -1
- data/lib/dynamic_image/model/validations.rb +15 -17
- data/lib/dynamic_image/model/variants.rb +29 -0
- data/lib/dynamic_image/processed_image.rb +46 -30
- data/lib/dynamic_image/routing.rb +3 -3
- data/lib/dynamic_image/version.rb +2 -2
- data/lib/rails/generators/dynamic_image/resource/resource_generator.rb +9 -11
- metadata +38 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a62dce84fcc98c58fd62f1a59ef08bb918cfe77c3441542959609b0eb8e6b5da
|
4
|
+
data.tar.gz: 8dc11abb55c9cf425fd651f9017cd9477235bd712b185c268c36f36191833422
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da083259103d212b5bc8909659b5e3110a18ac8ca34cc232c2a1d120e6927d8165ae04f9367661e96687cf43f1be9079002b54cd3947d9c5aa61d15eea5c44f7
|
7
|
+
data.tar.gz: fe2692f3948999720c135ce33e94e979d945bf985617d852bb10bd972e917519ea03f3e3e321bce2677da9f88c7fd70aea4f86f4d4fda1373adf547658542fa0
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DynamicImage
|
4
|
+
class Variant < ApplicationRecord
|
5
|
+
include Dis::Model
|
6
|
+
|
7
|
+
self.table_name = "dynamic_image_variants"
|
8
|
+
self.dis_type = "image-variants"
|
9
|
+
|
10
|
+
belongs_to :image, polymorphic: true, inverse_of: :variants
|
11
|
+
|
12
|
+
validates_data_presence
|
13
|
+
|
14
|
+
validates :format, presence: true
|
15
|
+
|
16
|
+
validates :width, :height, :crop_width, :crop_height,
|
17
|
+
numericality: { greater_than: 0, only_integer: true }
|
18
|
+
|
19
|
+
validates :crop_start_x, :crop_start_y,
|
20
|
+
numericality: { only_integer: true }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateDynamicImageVariants < ActiveRecord::Migration[5.2]
|
4
|
+
def change
|
5
|
+
create_table :dynamic_image_variants do |t|
|
6
|
+
t.references :image, polymorphic: true, null: false
|
7
|
+
|
8
|
+
# Dis attributes
|
9
|
+
t.string :content_hash, null: false
|
10
|
+
t.string :content_type, null: false
|
11
|
+
t.integer :content_length, null: false
|
12
|
+
t.string :filename, null: false
|
13
|
+
|
14
|
+
t.string :format, null: false
|
15
|
+
t.integer :width, :height, null: false
|
16
|
+
t.integer :crop_width, :crop_height, null: false
|
17
|
+
t.integer :crop_start_x, :crop_start_y, null: false
|
18
|
+
|
19
|
+
t.timestamps null: false
|
20
|
+
end
|
21
|
+
|
22
|
+
add_index(:dynamic_image_variants,
|
23
|
+
%i[image_id image_type],
|
24
|
+
name: "dynamic_image_variants_by_image")
|
25
|
+
|
26
|
+
add_index(:dynamic_image_variants,
|
27
|
+
%i[image_id image_type format width height crop_width
|
28
|
+
crop_height crop_start_x crop_start_y],
|
29
|
+
name: "dynamic_image_variants_by_format_and_size",
|
30
|
+
unique: true)
|
31
|
+
end
|
32
|
+
end
|
data/lib/dynamic_image.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "mini_magick"
|
4
4
|
require "dis"
|
@@ -7,6 +7,7 @@ require "vector2d"
|
|
7
7
|
require "dynamic_image/belongs_to"
|
8
8
|
require "dynamic_image/controller"
|
9
9
|
require "dynamic_image/digest_verifier"
|
10
|
+
require "dynamic_image/engine"
|
10
11
|
require "dynamic_image/errors"
|
11
12
|
require "dynamic_image/helper"
|
12
13
|
require "dynamic_image/image_reader"
|
@@ -14,7 +15,6 @@ require "dynamic_image/image_sizing"
|
|
14
15
|
require "dynamic_image/metadata"
|
15
16
|
require "dynamic_image/model"
|
16
17
|
require "dynamic_image/processed_image"
|
17
|
-
require "dynamic_image/railtie"
|
18
18
|
require "dynamic_image/routing"
|
19
19
|
|
20
20
|
module DynamicImage
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
# = DynamicImage Controller
|
@@ -53,6 +53,7 @@ module DynamicImage
|
|
53
53
|
|
54
54
|
def render_image(options)
|
55
55
|
return unless stale?(@record)
|
56
|
+
|
56
57
|
respond_to do |format|
|
57
58
|
format.html do
|
58
59
|
render(file: File.join(File.dirname(__FILE__), "templates/show"),
|
@@ -66,14 +67,13 @@ module DynamicImage
|
|
66
67
|
|
67
68
|
def render_raw_image(disposition: "inline", filename: nil)
|
68
69
|
return unless stale?(@record)
|
70
|
+
|
69
71
|
respond_to do |format|
|
70
72
|
format.any(:gif, :jpeg, :png, :tiff) do
|
71
|
-
send_data(
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
disposition: disposition
|
76
|
-
)
|
73
|
+
send_data(@record.data,
|
74
|
+
filename: filename,
|
75
|
+
content_type: @record.content_type,
|
76
|
+
disposition: disposition)
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -82,16 +82,16 @@ module DynamicImage
|
|
82
82
|
params[:format]
|
83
83
|
end
|
84
84
|
|
85
|
-
def send_image(
|
85
|
+
def send_image(processed_image)
|
86
86
|
send_data(
|
87
|
-
|
88
|
-
content_type:
|
89
|
-
disposition:
|
87
|
+
processed_image.cropped_and_resized(requested_size),
|
88
|
+
content_type: processed_image.content_type,
|
89
|
+
disposition: "inline"
|
90
90
|
)
|
91
91
|
end
|
92
92
|
|
93
93
|
def verify_signed_params
|
94
|
-
key = [
|
94
|
+
key = %i[action id size].map do |k|
|
95
95
|
k == :id ? params.require(k).to_i : params.require(k)
|
96
96
|
end.join("-")
|
97
97
|
DynamicImage.digest_verifier.verify(key, params[:digest])
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
# = DynamicImage Digest Verifier
|
@@ -31,22 +31,20 @@ module DynamicImage
|
|
31
31
|
# Verifies that <tt>digest</tt> is valid for <tt>data</tt>.
|
32
32
|
# Raises a +DynamicImage::Errors::InvalidSignature+ error if not.
|
33
33
|
def verify(data, digest)
|
34
|
-
if valid_digest?(data, digest)
|
35
|
-
|
36
|
-
|
37
|
-
raise DynamicImage::Errors::InvalidSignature
|
38
|
-
end
|
34
|
+
return true if valid_digest?(data, digest)
|
35
|
+
|
36
|
+
raise DynamicImage::Errors::InvalidSignature
|
39
37
|
end
|
40
38
|
|
41
39
|
private
|
42
40
|
|
43
|
-
def secure_compare(
|
44
|
-
return false unless
|
41
|
+
def secure_compare(str, other)
|
42
|
+
return false unless str.bytesize == other.bytesize
|
45
43
|
|
46
|
-
l =
|
44
|
+
l = str.unpack "C#{str.bytesize}"
|
47
45
|
|
48
46
|
res = 0
|
49
|
-
|
47
|
+
other.each_byte { |byte| res |= byte ^ l.shift }
|
50
48
|
res.zero?
|
51
49
|
end
|
52
50
|
|
@@ -1,29 +1,40 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
|
-
class
|
5
|
-
initializer "dynamic_image" do
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
initializer "dynamic_image.digest_verifier" do
|
6
|
+
config.after_initialize do |app|
|
7
|
+
secret = app.key_generator.generate_key("dynamic_image")
|
8
|
+
DynamicImage.digest_verifier = DynamicImage::DigestVerifier.new(secret)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
initializer "dynamic_image.migrations" do |app|
|
13
|
+
unless app.root.to_s.match?(root.to_s)
|
14
|
+
config.paths["db/migrate"].expanded.each do |expanded_path|
|
15
|
+
app.config.paths["db/migrate"] << expanded_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
initializer "dynamic_image.extensions", before: :load_active_support do
|
21
|
+
ActiveSupport.on_load(:active_record) do
|
22
|
+
send :include, DynamicImage::BelongsTo
|
23
|
+
end
|
6
24
|
ActionDispatch::Routing::Mapper.send :include, DynamicImage::Routing
|
7
25
|
|
8
26
|
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(
|
9
27
|
"DynamicImage::Errors::InvalidSignature" => :unauthorized
|
10
28
|
)
|
29
|
+
end
|
11
30
|
|
31
|
+
initializer "dynamic_image.sentry" do
|
12
32
|
# If Sentry is configured, exclude reporting of tampered signatures
|
13
33
|
if Object.const_defined?("Raven")
|
14
34
|
Raven.configure do |c|
|
15
35
|
c.excluded_exceptions += ["DynamicImage::Errors::InvalidSignature"]
|
16
36
|
end
|
17
37
|
end
|
18
|
-
|
19
|
-
config.after_initialize do |app|
|
20
|
-
secret = app.key_generator.generate_key("dynamic_image")
|
21
|
-
DynamicImage.digest_verifier = DynamicImage::DigestVerifier.new(secret)
|
22
|
-
end
|
23
|
-
|
24
|
-
ActiveSupport.on_load(:active_record) do
|
25
|
-
send :include, DynamicImage::BelongsTo
|
26
|
-
end
|
27
38
|
end
|
28
39
|
end
|
29
40
|
end
|
data/lib/dynamic_image/errors.rb
CHANGED
data/lib/dynamic_image/helper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
# = DynamicImage Helper
|
@@ -117,11 +117,9 @@ module DynamicImage
|
|
117
117
|
private
|
118
118
|
|
119
119
|
def allowed_dynamic_image_url_options
|
120
|
-
[
|
121
|
-
|
122
|
-
|
123
|
-
:action, :routing_type
|
124
|
-
]
|
120
|
+
%i[format only_path protocol host subdomain domain
|
121
|
+
tld_length port anchor trailing_slash script_name
|
122
|
+
action routing_type ]
|
125
123
|
end
|
126
124
|
|
127
125
|
def default_format_for_image(record)
|
@@ -162,9 +160,9 @@ module DynamicImage
|
|
162
160
|
end
|
163
161
|
|
164
162
|
def filename_to_alt(str)
|
165
|
-
File.basename(str, ".*"
|
166
|
-
.sub(/-[[:xdigit:]]{32,64}\z/, ""
|
167
|
-
.tr("-_"
|
163
|
+
File.basename(str, ".*")
|
164
|
+
.sub(/-[[:xdigit:]]{32,64}\z/, "")
|
165
|
+
.tr("-_", " ")
|
168
166
|
.capitalize
|
169
167
|
end
|
170
168
|
|
@@ -1,19 +1,35 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
class ImageReader
|
5
|
+
class << self
|
6
|
+
def magic_bytes
|
7
|
+
@magic_bytes ||= [
|
8
|
+
"\x47\x49\x46\x38\x37\x61", # GIF
|
9
|
+
"\x47\x49\x46\x38\x39\x61",
|
10
|
+
"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", # PNG
|
11
|
+
"\xff\xd8", # JPEG
|
12
|
+
"\x49\x49\x2a\x00", # TIFF
|
13
|
+
"\x4d\x4d\x00\x2a",
|
14
|
+
"\x42\x4d" # BMP
|
15
|
+
].map { |s| s.dup.force_encoding("binary") }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
5
19
|
def initialize(data)
|
6
20
|
@data = data
|
7
21
|
end
|
8
22
|
|
9
23
|
def read
|
10
24
|
raise DynamicImage::Errors::InvalidHeader unless valid_header?
|
25
|
+
|
11
26
|
MiniMagick::Image.read(@data)
|
12
27
|
end
|
13
28
|
|
14
29
|
def valid_header?
|
15
30
|
return false if file_header.blank?
|
16
|
-
|
31
|
+
|
32
|
+
self.class.magic_bytes.each do |str|
|
17
33
|
return true if file_header.start_with?(str)
|
18
34
|
end
|
19
35
|
false
|
@@ -24,17 +40,5 @@ module DynamicImage
|
|
24
40
|
def file_header
|
25
41
|
@file_header ||= StringIO.new(@data, "rb").read(8)
|
26
42
|
end
|
27
|
-
|
28
|
-
def magic_bytes
|
29
|
-
[
|
30
|
-
"\x47\x49\x46\x38\x37\x61".force_encoding("binary"), # GIF
|
31
|
-
"\x47\x49\x46\x38\x39\x61".force_encoding("binary"),
|
32
|
-
"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a".force_encoding("binary"), # PNG
|
33
|
-
"\xff\xd8".force_encoding("binary"), # JPEG
|
34
|
-
"\x49\x49\x2a\x00".force_encoding("binary"), # TIFF
|
35
|
-
"\x4d\x4d\x00\x2a".force_encoding("binary"),
|
36
|
-
"\x42\x4d".force_encoding("binary") # BMP
|
37
|
-
]
|
38
|
-
end
|
39
43
|
end
|
40
44
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
# = DynamicImage Image Sizing
|
@@ -121,20 +121,22 @@ module DynamicImage
|
|
121
121
|
start
|
122
122
|
end
|
123
123
|
|
124
|
-
def parse_vector(
|
125
|
-
|
124
|
+
def parse_vector(vector)
|
125
|
+
vector.is_a?(String) ? str_to_vector(vector) : vector
|
126
126
|
end
|
127
127
|
|
128
128
|
attr_reader :record
|
129
129
|
|
130
|
-
def require_dimensions!(
|
131
|
-
|
130
|
+
def require_dimensions!(vector)
|
131
|
+
return if vector.x.positive? && vector.y.positive?
|
132
|
+
|
133
|
+
raise DynamicImage::Errors::InvalidSizeOptions
|
132
134
|
end
|
133
135
|
|
134
136
|
def shift_vector(vect)
|
135
137
|
vector(
|
136
|
-
vect.x
|
137
|
-
vect.y
|
138
|
+
vect.x.negative? ? vect.x.abs : 0,
|
139
|
+
vect.y.negative? ? vect.y.abs : 0
|
138
140
|
)
|
139
141
|
end
|
140
142
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
# = DynamicImage Metadata
|
@@ -13,15 +13,15 @@ module DynamicImage
|
|
13
13
|
# Returns the color space of the image as a string. The result will be one
|
14
14
|
# of the following: "rgb", "cmyk", "gray".
|
15
15
|
def colorspace
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
return unless valid?
|
17
|
+
|
18
|
+
case metadata[:colorspace]
|
19
|
+
when /rgb/i
|
20
|
+
"rgb"
|
21
|
+
when /cmyk/i
|
22
|
+
"cmyk"
|
23
|
+
when /gray/i
|
24
|
+
"gray"
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -80,7 +80,7 @@ module DynamicImage
|
|
80
80
|
{
|
81
81
|
colorspace: image[:colorspace],
|
82
82
|
dimensions: image[:dimensions],
|
83
|
-
format:
|
83
|
+
format: image[:format]
|
84
84
|
}
|
85
85
|
end
|
86
86
|
end
|
data/lib/dynamic_image/model.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "dynamic_image/model/dimensions"
|
4
4
|
require "dynamic_image/model/transformations"
|
5
5
|
require "dynamic_image/model/validations"
|
6
|
+
require "dynamic_image/model/variants"
|
6
7
|
|
7
8
|
module DynamicImage
|
8
9
|
# = DynamicImage Model
|
@@ -65,6 +66,7 @@ module DynamicImage
|
|
65
66
|
include DynamicImage::Model::Dimensions
|
66
67
|
include DynamicImage::Model::Transformations
|
67
68
|
include DynamicImage::Model::Validations
|
69
|
+
include DynamicImage::Model::Variants
|
68
70
|
|
69
71
|
included do
|
70
72
|
before_validation :read_image_metadata, if: :data_changed?
|
@@ -121,11 +123,9 @@ module DynamicImage
|
|
121
123
|
end
|
122
124
|
|
123
125
|
def safe_content_types
|
124
|
-
%w
|
125
|
-
|
126
|
-
|
127
|
-
image/jpeg
|
128
|
-
)
|
126
|
+
%w[image/png
|
127
|
+
image/gif
|
128
|
+
image/jpeg]
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
module Model
|
@@ -59,6 +59,7 @@ module DynamicImage
|
|
59
59
|
|
60
60
|
def rotated_crop(new_width)
|
61
61
|
return nil unless cropped?
|
62
|
+
|
62
63
|
[
|
63
64
|
new_width - (crop_start_y + crop_height),
|
64
65
|
crop_start_x,
|
@@ -69,6 +70,7 @@ module DynamicImage
|
|
69
70
|
|
70
71
|
def rotated_crop_gravity(new_width)
|
71
72
|
return nil unless crop_gravity?
|
73
|
+
|
72
74
|
[new_width - crop_gravity_y, crop_gravity_x]
|
73
75
|
end
|
74
76
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
module Model
|
@@ -9,6 +9,7 @@ module DynamicImage
|
|
9
9
|
# integrity.
|
10
10
|
module Validations
|
11
11
|
extend ActiveSupport::Concern
|
12
|
+
|
12
13
|
included do
|
13
14
|
validates_data_presence
|
14
15
|
|
@@ -57,22 +58,18 @@ module DynamicImage
|
|
57
58
|
|
58
59
|
module ClassMethods
|
59
60
|
def allowed_colorspaces
|
60
|
-
%w
|
61
|
-
|
62
|
-
|
63
|
-
gray
|
64
|
-
)
|
61
|
+
%w[rgb
|
62
|
+
cmyk
|
63
|
+
gray]
|
65
64
|
end
|
66
65
|
|
67
66
|
def allowed_content_types
|
68
|
-
%w
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
image/tiff
|
75
|
-
)
|
67
|
+
%w[image/bmp
|
68
|
+
image/gif
|
69
|
+
image/jpeg
|
70
|
+
image/pjpeg
|
71
|
+
image/png
|
72
|
+
image/tiff]
|
76
73
|
end
|
77
74
|
end
|
78
75
|
|
@@ -80,9 +77,10 @@ module DynamicImage
|
|
80
77
|
|
81
78
|
def validate_crop_bounds
|
82
79
|
required_size = crop_start + crop_size
|
83
|
-
|
84
|
-
|
85
|
-
|
80
|
+
return unless required_size.x > real_size.x ||
|
81
|
+
required_size.y > real_size.y
|
82
|
+
|
83
|
+
errors.add(:crop_size, "is out of bounds")
|
86
84
|
end
|
87
85
|
|
88
86
|
def validate_image
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DynamicImage
|
4
|
+
module Model
|
5
|
+
# = DynamicImage Model Variants
|
6
|
+
#
|
7
|
+
# Validates that all necessary attributes are valid. All of these are
|
8
|
+
# managed by +DynamicImage::Model+, so this is mostly for enforcing
|
9
|
+
# integrity.
|
10
|
+
module Variants
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
has_many :variants,
|
15
|
+
as: :image,
|
16
|
+
class_name: "DynamicImage::Variant",
|
17
|
+
dependent: :destroy
|
18
|
+
|
19
|
+
before_update :clear_variants, if: :data_changed?
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def clear_variants
|
25
|
+
variants.destroy_all
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
# = DynamicImage Processed Image
|
@@ -35,12 +35,9 @@ module DynamicImage
|
|
35
35
|
#
|
36
36
|
# Returns a binary string.
|
37
37
|
def cropped_and_resized(size)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
image.resize(size)
|
42
|
-
end
|
43
|
-
end
|
38
|
+
return crop_and_resize(size) unless record.persisted?
|
39
|
+
|
40
|
+
find_or_create_variant(size).data
|
44
41
|
end
|
45
42
|
|
46
43
|
# Normalizes the image.
|
@@ -73,11 +70,27 @@ module DynamicImage
|
|
73
70
|
private
|
74
71
|
|
75
72
|
def coalesced(image)
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
return image unless gif?
|
74
|
+
|
75
|
+
DynamicImage::ImageReader.new(image.coalesce.to_blob).read
|
76
|
+
end
|
77
|
+
|
78
|
+
def crop_and_resize(size)
|
79
|
+
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
|
79
84
|
end
|
80
|
-
|
85
|
+
end
|
86
|
+
|
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
|
+
)
|
81
94
|
end
|
82
95
|
|
83
96
|
def format
|
@@ -93,8 +106,8 @@ module DynamicImage
|
|
93
106
|
end
|
94
107
|
|
95
108
|
def image_sizing
|
96
|
-
@image_sizing ||=
|
97
|
-
|
109
|
+
@image_sizing ||=
|
110
|
+
DynamicImage::ImageSizing.new(record, uncropped: @uncropped)
|
98
111
|
end
|
99
112
|
|
100
113
|
def needs_colorspace_conversion?
|
@@ -108,11 +121,8 @@ module DynamicImage
|
|
108
121
|
def optimize(image)
|
109
122
|
image.layers "optimize" if gif?
|
110
123
|
image.strip
|
111
|
-
if jpeg?
|
112
|
-
|
113
|
-
image.sampling_factor "4:2:0"
|
114
|
-
image.interlace "JPEG"
|
115
|
-
end
|
124
|
+
image.quality(85).sampling_factor("4:2:0").interlace("JPEG") if jpeg?
|
125
|
+
image
|
116
126
|
end
|
117
127
|
|
118
128
|
def process_data
|
@@ -126,22 +136,28 @@ module DynamicImage
|
|
126
136
|
attr_reader :record
|
127
137
|
|
128
138
|
def record_format
|
129
|
-
|
130
|
-
|
131
|
-
"
|
132
|
-
|
133
|
-
"
|
134
|
-
|
135
|
-
"GIF"
|
136
|
-
when "image/jpeg", "image/pjpeg"
|
137
|
-
"JPEG"
|
138
|
-
when "image/tiff"
|
139
|
-
"TIFF"
|
140
|
-
end
|
139
|
+
{ "image/bmp" => "BMP",
|
140
|
+
"image/png" => "PNG",
|
141
|
+
"image/gif" => "GIF",
|
142
|
+
"image/jpeg" => "JPEG",
|
143
|
+
"image/pjpeg" => "JPEG",
|
144
|
+
"image/tiff" => "TIFF" }[record.content_type]
|
141
145
|
end
|
142
146
|
|
143
147
|
def require_valid_image!
|
144
148
|
raise DynamicImage::Errors::InvalidImage unless record.valid?
|
145
149
|
end
|
150
|
+
|
151
|
+
def variant_params(size)
|
152
|
+
crop_size, crop_start = image_sizing.crop_geometry(size)
|
153
|
+
|
154
|
+
{ width: size.x,
|
155
|
+
height: size.y,
|
156
|
+
crop_width: crop_size.x,
|
157
|
+
crop_height: crop_size.y,
|
158
|
+
crop_start_x: crop_start.x,
|
159
|
+
crop_start_y: crop_start.y,
|
160
|
+
format: format }
|
161
|
+
end
|
146
162
|
end
|
147
163
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DynamicImage
|
4
4
|
# = DynamicImage Routing
|
@@ -11,9 +11,9 @@ module DynamicImage
|
|
11
11
|
# image_resources :avatars
|
12
12
|
def image_resources(resource_name, options = {})
|
13
13
|
options = {
|
14
|
-
path:
|
14
|
+
path: "#{resource_name}/:digest(/:size)",
|
15
15
|
constraints: { size: /\d+x\d+/ },
|
16
|
-
only:
|
16
|
+
only: [:show]
|
17
17
|
}.merge(options)
|
18
18
|
resources resource_name, options do
|
19
19
|
get :uncropped, on: :member
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails/generators"
|
4
4
|
require "rails/generators/rails/resource/resource_generator"
|
@@ -52,16 +52,14 @@ module DynamicImage
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def dynamic_image_attributes
|
55
|
-
%w
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
crop_gravity_x:integer crop_gravity_y:integer
|
64
|
-
)
|
55
|
+
%w[content_hash:string content_type:string
|
56
|
+
content_length:integer
|
57
|
+
filename:string
|
58
|
+
colorspace:string
|
59
|
+
real_width:integer real_height:integer
|
60
|
+
crop_width:integer crop_height:integer
|
61
|
+
crop_start_x:integer crop_start_y:integer
|
62
|
+
crop_gravity_x:integer crop_gravity_y:integer]
|
65
63
|
end
|
66
64
|
end
|
67
65
|
end
|
metadata
CHANGED
@@ -1,111 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamic_image
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Inge Jørgensen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: dis
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.6
|
17
20
|
- - "~>"
|
18
21
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
22
|
+
version: '1.1'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.0.6
|
24
30
|
- - "~>"
|
25
31
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
32
|
+
version: '1.1'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
34
|
+
name: mini_magick
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
37
|
- - "~>"
|
32
38
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
-
- - ">="
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: 2.2.1
|
39
|
+
version: '4.9'
|
37
40
|
type: :runtime
|
38
41
|
prerelease: false
|
39
42
|
version_requirements: !ruby/object:Gem::Requirement
|
40
43
|
requirements:
|
41
44
|
- - "~>"
|
42
45
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
44
|
-
- - ">="
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: 2.2.1
|
46
|
+
version: '4.9'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: rails
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: '5.0'
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
60
|
+
version: '5.0'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
62
|
+
name: vector2d
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: '
|
67
|
+
version: '2.2'
|
68
68
|
- - ">="
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version:
|
70
|
+
version: 2.2.1
|
71
71
|
type: :runtime
|
72
72
|
prerelease: false
|
73
73
|
version_requirements: !ruby/object:Gem::Requirement
|
74
74
|
requirements:
|
75
75
|
- - "~>"
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
77
|
+
version: '2.2'
|
78
78
|
- - ">="
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version:
|
80
|
+
version: 2.2.1
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
|
-
name:
|
82
|
+
name: rspec-rails
|
83
83
|
requirement: !ruby/object:Gem::Requirement
|
84
84
|
requirements:
|
85
|
-
- - "
|
85
|
+
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version:
|
87
|
+
version: 3.7.0
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
|
-
- - "
|
92
|
+
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version:
|
94
|
+
version: 3.7.0
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
|
-
name:
|
96
|
+
name: sqlite3
|
97
97
|
requirement: !ruby/object:Gem::Requirement
|
98
98
|
requirements:
|
99
|
-
- - "
|
99
|
+
- - ">="
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
101
|
+
version: '0'
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
|
-
- - "
|
106
|
+
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version:
|
108
|
+
version: '0'
|
109
109
|
description: DynamicImage is a Rails plugin that simplifies image uploading and processing
|
110
110
|
email:
|
111
111
|
- inge@elektronaut.no
|
@@ -116,10 +116,13 @@ files:
|
|
116
116
|
- MIT-LICENSE
|
117
117
|
- README.md
|
118
118
|
- Rakefile
|
119
|
+
- app/models/dynamic_image/variant.rb
|
120
|
+
- db/migrate/20190620160500_create_dynamic_image_variants.rb
|
119
121
|
- lib/dynamic_image.rb
|
120
122
|
- lib/dynamic_image/belongs_to.rb
|
121
123
|
- lib/dynamic_image/controller.rb
|
122
124
|
- lib/dynamic_image/digest_verifier.rb
|
125
|
+
- lib/dynamic_image/engine.rb
|
123
126
|
- lib/dynamic_image/errors.rb
|
124
127
|
- lib/dynamic_image/helper.rb
|
125
128
|
- lib/dynamic_image/image_reader.rb
|
@@ -129,8 +132,8 @@ files:
|
|
129
132
|
- lib/dynamic_image/model/dimensions.rb
|
130
133
|
- lib/dynamic_image/model/transformations.rb
|
131
134
|
- lib/dynamic_image/model/validations.rb
|
135
|
+
- lib/dynamic_image/model/variants.rb
|
132
136
|
- lib/dynamic_image/processed_image.rb
|
133
|
-
- lib/dynamic_image/railtie.rb
|
134
137
|
- lib/dynamic_image/routing.rb
|
135
138
|
- lib/dynamic_image/templates/show.html.erb
|
136
139
|
- lib/dynamic_image/version.rb
|
@@ -147,15 +150,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
147
150
|
requirements:
|
148
151
|
- - ">="
|
149
152
|
- !ruby/object:Gem::Version
|
150
|
-
version:
|
153
|
+
version: 2.4.0
|
151
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
152
155
|
requirements:
|
153
156
|
- - ">="
|
154
157
|
- !ruby/object:Gem::Version
|
155
158
|
version: '0'
|
156
159
|
requirements: []
|
157
|
-
|
158
|
-
rubygems_version: 2.7.6
|
160
|
+
rubygems_version: 3.0.1
|
159
161
|
signing_key:
|
160
162
|
specification_version: 4
|
161
163
|
summary: Rails plugin that simplifies image uploading and processing
|