dynamic_image 2.0.16 → 2.0.17
Sign up to get free protection for your applications and to get access to all the features.
- 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
|