dynamic_image 2.0.0 → 2.0.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 +4 -4
- data/Rakefile +5 -5
- data/lib/dynamic_image/belongs_to.rb +4 -4
- data/lib/dynamic_image/controller.rb +26 -25
- data/lib/dynamic_image/digest_verifier.rb +9 -3
- data/lib/dynamic_image/errors.rb +2 -1
- data/lib/dynamic_image/helper.rb +29 -32
- data/lib/dynamic_image/image_reader.rb +48 -0
- data/lib/dynamic_image/image_sizing.rb +6 -8
- data/lib/dynamic_image/metadata.rb +26 -22
- data/lib/dynamic_image/model/dimensions.rb +3 -8
- data/lib/dynamic_image/model/validations.rb +21 -23
- data/lib/dynamic_image/model.rb +8 -9
- data/lib/dynamic_image/processed_image.rb +11 -16
- data/lib/dynamic_image/railtie.rb +1 -1
- data/lib/dynamic_image/routing.rb +1 -1
- data/lib/dynamic_image/version.rb +1 -1
- data/lib/dynamic_image.rb +1 -0
- data/lib/rails/generators/dynamic_image/resource/resource_generator.rb +16 -21
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3daa2b118705fafabe134cb7f5707d4d714d67a
|
4
|
+
data.tar.gz: 46ea0855ee40eb1ab22787daab087369eaae5c11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1b7ce51abac870c79574a04cc4d57dc016118590433588757748c508693d2fd7bae9e33c7d1db70d8d6be64b745ec2d364b6c8f0c42373634278bedc6e2b612
|
7
|
+
data.tar.gz: 16b8a043dec55f1f430860217612e6a1ba15dad53ad91e89d41611764c1265a5067f512a5d5969b8fd725a9a20b716e369950ce1f0a6e371b19ade29996d698c
|
data/Rakefile
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
|
4
|
-
APP_RAKEFILE =
|
4
|
+
APP_RAKEFILE = 'spec/internal/Rakefile'.freeze
|
5
5
|
load 'rails/tasks/engine.rake'
|
6
6
|
|
7
7
|
RSpec::Core::RakeTask.new
|
8
8
|
|
9
|
-
task :
|
10
|
-
task :
|
9
|
+
task default: :spec
|
10
|
+
task test: :spec
|
@@ -7,16 +7,16 @@ module DynamicImage
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
module ClassMethods
|
10
|
-
def belongs_to_image(name, scope=nil, options={})
|
10
|
+
def belongs_to_image(name, scope = nil, options = {})
|
11
11
|
belongs_to(name, scope, options)
|
12
12
|
|
13
13
|
define_method "#{name}=" do |new_image|
|
14
|
-
if new_image.present? && !new_image.
|
15
|
-
new_image =
|
14
|
+
if new_image.present? && !new_image.is_a?(DynamicImage::Model)
|
15
|
+
new_image = send("build_#{name}", file: new_image)
|
16
16
|
end
|
17
17
|
super(new_image)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
end
|
22
|
+
end
|
@@ -29,15 +29,14 @@ module DynamicImage
|
|
29
29
|
|
30
30
|
# Renders the original image data, without any processing.
|
31
31
|
def original
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
32
|
+
return unless stale?(@record)
|
33
|
+
respond_to do |format|
|
34
|
+
format.any(:gif, :jpeg, :png, :tiff) do
|
35
|
+
send_data(
|
36
|
+
@record.data,
|
37
|
+
content_type: @record.content_type,
|
38
|
+
disposition: 'inline'
|
39
|
+
)
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
@@ -58,20 +57,14 @@ module DynamicImage
|
|
58
57
|
end
|
59
58
|
|
60
59
|
def render_image(options)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
send_data(
|
70
|
-
processed_image.cropped_and_resized(requested_size),
|
71
|
-
content_type: processed_image.content_type,
|
72
|
-
disposition: 'inline'
|
73
|
-
)
|
74
|
-
end
|
60
|
+
return unless stale?(@record)
|
61
|
+
respond_to do |format|
|
62
|
+
format.html do
|
63
|
+
render(file: File.join(File.dirname(__FILE__), 'templates/show'),
|
64
|
+
layout: false, locals: { options: options })
|
65
|
+
end
|
66
|
+
format.any(:gif, :jpeg, :png, :tiff) do
|
67
|
+
send_image(DynamicImage::ProcessedImage.new(@record, options))
|
75
68
|
end
|
76
69
|
end
|
77
70
|
end
|
@@ -80,10 +73,18 @@ module DynamicImage
|
|
80
73
|
params[:format]
|
81
74
|
end
|
82
75
|
|
76
|
+
def send_image(image)
|
77
|
+
send_data(
|
78
|
+
image.cropped_and_resized(requested_size),
|
79
|
+
content_type: image.content_type,
|
80
|
+
disposition: 'inline'
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
83
84
|
def verify_signed_params
|
84
|
-
key = [:action, :id, :size].map
|
85
|
+
key = [:action, :id, :size].map do |k|
|
85
86
|
k == :id ? params.require(k).to_i : params.require(k)
|
86
|
-
|
87
|
+
end.join('-')
|
87
88
|
DynamicImage.digest_verifier.verify(key, params[:digest])
|
88
89
|
end
|
89
90
|
end
|
@@ -52,11 +52,17 @@ module DynamicImage
|
|
52
52
|
|
53
53
|
def generate_digest(data)
|
54
54
|
require 'openssl' unless defined?(OpenSSL)
|
55
|
-
OpenSSL::HMAC.hexdigest(
|
55
|
+
OpenSSL::HMAC.hexdigest(
|
56
|
+
OpenSSL::Digest.const_get(@digest).new,
|
57
|
+
@secret,
|
58
|
+
data
|
59
|
+
)
|
56
60
|
end
|
57
61
|
|
58
62
|
def valid_digest?(data, digest)
|
59
|
-
data.present? &&
|
63
|
+
data.present? &&
|
64
|
+
digest.present? &&
|
65
|
+
secure_compare(digest, generate_digest(data))
|
60
66
|
end
|
61
67
|
end
|
62
|
-
end
|
68
|
+
end
|
data/lib/dynamic_image/errors.rb
CHANGED
@@ -4,7 +4,8 @@ module DynamicImage
|
|
4
4
|
module Errors
|
5
5
|
class Error < StandardError; end
|
6
6
|
class InvalidImage < DynamicImage::Errors::Error; end
|
7
|
+
class InvalidHeader < DynamicImage::Errors::Error; end
|
7
8
|
class InvalidSignature < DynamicImage::Errors::Error; end
|
8
9
|
class InvalidSizeOptions < DynamicImage::Errors::Error; end
|
9
10
|
end
|
10
|
-
end
|
11
|
+
end
|
data/lib/dynamic_image/helper.rb
CHANGED
@@ -7,7 +7,7 @@ module DynamicImage
|
|
7
7
|
module Helper
|
8
8
|
# Returns the path for a DynamicImage::Model record.
|
9
9
|
# Takes the same options as +dynamic_image_url+
|
10
|
-
def dynamic_image_path(record_or_array, options={})
|
10
|
+
def dynamic_image_path(record_or_array, options = {})
|
11
11
|
dynamic_image_url(record_or_array, { routing_type: :path }.merge(options))
|
12
12
|
end
|
13
13
|
|
@@ -29,24 +29,18 @@ module DynamicImage
|
|
29
29
|
# # => <img alt="My file" height="200" src="..." width="320" />
|
30
30
|
# dynamic_image_tag(image, size: "100x100", alt="Avatar")
|
31
31
|
# # => <img alt="Avatar" height="62" src="..." width="100" />
|
32
|
-
def dynamic_image_tag(record_or_array, options={})
|
32
|
+
def dynamic_image_tag(record_or_array, options = {})
|
33
33
|
record = extract_dynamic_image_record(record_or_array)
|
34
|
-
options = {
|
35
|
-
alt: image_alt(record.filename)
|
36
|
-
}.merge(options)
|
34
|
+
options = { alt: image_alt(record.filename) }.merge(options)
|
37
35
|
|
38
36
|
size = fit_size!(record_or_array, options)
|
39
37
|
url_options = options.extract!(*allowed_dynamic_image_url_options)
|
40
38
|
html_options = { size: size }.merge(options)
|
41
39
|
|
42
|
-
image_tag(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
url_options
|
47
|
-
),
|
48
|
-
html_options
|
49
|
-
)
|
40
|
+
image_tag(dynamic_image_path_with_size(record_or_array,
|
41
|
+
size,
|
42
|
+
url_options),
|
43
|
+
html_options)
|
50
44
|
end
|
51
45
|
|
52
46
|
# Returns the URL for a DynamicImage::Model record.
|
@@ -71,38 +65,38 @@ module DynamicImage
|
|
71
65
|
# # => "http://example.com/images/72...c2/100x62/1-2014062020...00.jpg"
|
72
66
|
# dynamic_image_url(image, size: '100x100', crop: true)
|
73
67
|
# # => "http://example.com/images/a4...6b/100x100/1-2014062020...00.jpg"
|
74
|
-
def dynamic_image_url(record_or_array, options={})
|
68
|
+
def dynamic_image_url(record_or_array, options = {})
|
75
69
|
size = fit_size!(record_or_array, options)
|
76
70
|
dynamic_image_url_with_size(record_or_array, size, options)
|
77
71
|
end
|
78
72
|
|
79
73
|
# Returns a path to the original uploaded file, without any processing
|
80
74
|
# applied. Sizing options are not supported.
|
81
|
-
def original_dynamic_image_path(record_or_array, options={})
|
75
|
+
def original_dynamic_image_path(record_or_array, options = {})
|
82
76
|
dynamic_image_path(record_or_array, { action: :original }.merge(options))
|
83
77
|
end
|
84
78
|
|
85
79
|
# Returns a URL to the original uploaded file, without any processing
|
86
80
|
# applied. Sizing options are not supported.
|
87
|
-
def original_dynamic_image_url(record_or_array, options={})
|
81
|
+
def original_dynamic_image_url(record_or_array, options = {})
|
88
82
|
dynamic_image_url(record_or_array, { action: :original }.merge(options))
|
89
83
|
end
|
90
84
|
|
91
85
|
# Same as +dynamic_image_path+, but points to an image with any
|
92
86
|
# pre-cropping disabled.
|
93
|
-
def uncropped_dynamic_image_path(record_or_array, options={})
|
87
|
+
def uncropped_dynamic_image_path(record_or_array, options = {})
|
94
88
|
dynamic_image_path(record_or_array, { action: :uncropped }.merge(options))
|
95
89
|
end
|
96
90
|
|
97
91
|
# Same as +dynamic_image_tag+, but renders an image with any
|
98
92
|
# pre-cropping disabled.
|
99
|
-
def uncropped_dynamic_image_tag(record_or_array, options={})
|
93
|
+
def uncropped_dynamic_image_tag(record_or_array, options = {})
|
100
94
|
dynamic_image_tag(record_or_array, { action: :uncropped }.merge(options))
|
101
95
|
end
|
102
96
|
|
103
97
|
# Same as +dynamic_image_url+, but points to an image with any
|
104
98
|
# pre-cropping disabled.
|
105
|
-
def uncropped_dynamic_image_url(record_or_array, options={})
|
99
|
+
def uncropped_dynamic_image_url(record_or_array, options = {})
|
106
100
|
dynamic_image_url(record_or_array, { action: :uncropped }.merge(options))
|
107
101
|
end
|
108
102
|
|
@@ -120,16 +114,18 @@ module DynamicImage
|
|
120
114
|
Mime::Type.lookup(record.safe_content_type).to_sym
|
121
115
|
end
|
122
116
|
|
123
|
-
def dynamic_image_digest(record, action, size=nil)
|
117
|
+
def dynamic_image_digest(record, action, size = nil)
|
124
118
|
key = [action || 'show', record.id, size].compact.join('-')
|
125
119
|
DynamicImage.digest_verifier.generate(key)
|
126
120
|
end
|
127
121
|
|
128
|
-
def dynamic_image_path_with_size(record_or_array, size=nil, options={})
|
129
|
-
dynamic_image_url_with_size(record_or_array,
|
122
|
+
def dynamic_image_path_with_size(record_or_array, size = nil, options = {})
|
123
|
+
dynamic_image_url_with_size(record_or_array,
|
124
|
+
size,
|
125
|
+
{ routing_type: :path }.merge(options))
|
130
126
|
end
|
131
127
|
|
132
|
-
def dynamic_image_url_with_size(record_or_array, size=nil, options={})
|
128
|
+
def dynamic_image_url_with_size(record_or_array, size = nil, options = {})
|
133
129
|
record = extract_dynamic_image_record(record_or_array)
|
134
130
|
options = {
|
135
131
|
routing_type: :url,
|
@@ -137,7 +133,8 @@ module DynamicImage
|
|
137
133
|
format: default_format_for_image(record),
|
138
134
|
size: size
|
139
135
|
}.merge(options)
|
140
|
-
options[:digest] =
|
136
|
+
options[:digest] =
|
137
|
+
dynamic_image_digest(record, options[:action], options[:size])
|
141
138
|
polymorphic_url(record_or_array, options)
|
142
139
|
end
|
143
140
|
|
@@ -154,17 +151,17 @@ module DynamicImage
|
|
154
151
|
record = extract_dynamic_image_record(record_or_array)
|
155
152
|
action = options[:action].try(:to_s)
|
156
153
|
size_opts = options.extract!(:size, :crop, :upscale)
|
157
|
-
|
158
154
|
if size_opts[:size]
|
159
|
-
|
160
|
-
record,
|
161
|
-
uncropped: (action == "uncropped")
|
162
|
-
).fit(size_opts[:size], size_opts).floor.to_s
|
163
|
-
elsif action == "original"
|
164
|
-
record.real_size.floor.to_s
|
155
|
+
image_sizing(record, size_opts, (action == 'uncropped'))
|
165
156
|
else
|
166
|
-
record.size.floor.to_s
|
157
|
+
(action == 'original' ? record.real_size : record.size).floor.to_s
|
167
158
|
end
|
168
159
|
end
|
160
|
+
|
161
|
+
def image_sizing(record, size_opts, uncropped)
|
162
|
+
ImageSizing
|
163
|
+
.new(record, uncropped: uncropped)
|
164
|
+
.fit(size_opts[:size], size_opts).floor.to_s
|
165
|
+
end
|
169
166
|
end
|
170
167
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module DynamicImage
|
4
|
+
class ImageReader
|
5
|
+
def initialize(data)
|
6
|
+
@data = data
|
7
|
+
end
|
8
|
+
|
9
|
+
def read
|
10
|
+
raise DynamicImage::Errors::InvalidHeader unless valid_header?
|
11
|
+
MiniMagick::Image.read(@data)
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid_header?
|
15
|
+
magic_bytes.each do |expr|
|
16
|
+
if (expr.is_a?(Regexp) && file_header =~ /^#{expr}/) ||
|
17
|
+
(expr.is_a?(String) && file_header.start_with?(expr))
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def file_header
|
27
|
+
@file_header ||= StringIO.new(@data, "rb").read(10)
|
28
|
+
end
|
29
|
+
|
30
|
+
def magic_bytes
|
31
|
+
[
|
32
|
+
# GIF
|
33
|
+
"\x47\x49\x46\x38\x37\x61".force_encoding("binary"),
|
34
|
+
"\x47\x49\x46\x38\x39\x61".force_encoding("binary"),
|
35
|
+
# PNG
|
36
|
+
"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a".force_encoding("binary"),
|
37
|
+
# JPEG
|
38
|
+
"\xff\xd8\xff\xdb".force_encoding("binary"),
|
39
|
+
Regexp.new("\xff\xd8\xff\xe0(.*){2}JFIF".force_encoding("binary")),
|
40
|
+
Regexp.new("\xff\xd8\xff\xe1(.*){2}Exif".force_encoding("binary")),
|
41
|
+
"\xff\xd8\xff\xee\x00\x0e".force_encoding("binary"), # Adobe JPEG
|
42
|
+
# TIFF
|
43
|
+
"\x49\x49\x2a\x00".force_encoding("binary"),
|
44
|
+
"\x4d\x4d\x00\x2a".force_encoding("binary"),
|
45
|
+
]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -5,7 +5,7 @@ module DynamicImage
|
|
5
5
|
#
|
6
6
|
# Calculates cropping and fitting for image sizes.
|
7
7
|
class ImageSizing
|
8
|
-
def initialize(record, options={})
|
8
|
+
def initialize(record, options = {})
|
9
9
|
@record = record
|
10
10
|
@uncropped = options[:uncropped] ? true : false
|
11
11
|
end
|
@@ -76,7 +76,7 @@ module DynamicImage
|
|
76
76
|
# sizing.fit(Vector2d(500, 500), upscale: true)
|
77
77
|
# # => Vector2d(500.0, 312.5)
|
78
78
|
#
|
79
|
-
def fit(fit_size, options={})
|
79
|
+
def fit(fit_size, options = {})
|
80
80
|
fit_size = parse_vector(fit_size)
|
81
81
|
require_dimensions!(fit_size) if options[:crop]
|
82
82
|
fit_size = size.fit(fit_size) unless options[:crop]
|
@@ -122,12 +122,10 @@ module DynamicImage
|
|
122
122
|
end
|
123
123
|
|
124
124
|
def parse_vector(v)
|
125
|
-
v.
|
125
|
+
v.is_a?(String) ? str_to_vector(v) : v
|
126
126
|
end
|
127
127
|
|
128
|
-
|
129
|
-
@record
|
130
|
-
end
|
128
|
+
attr_reader :record
|
131
129
|
|
132
130
|
def require_dimensions!(v)
|
133
131
|
raise DynamicImage::Errors::InvalidSizeOptions unless v.x > 0 && v.y > 0
|
@@ -141,7 +139,7 @@ module DynamicImage
|
|
141
139
|
end
|
142
140
|
|
143
141
|
def str_to_vector(str)
|
144
|
-
x, y = str.match(/(\d*)x(\d*)/)[1,2].map(&:to_i)
|
142
|
+
x, y = str.match(/(\d*)x(\d*)/)[1, 2].map(&:to_i)
|
145
143
|
Vector2d.new(x, y)
|
146
144
|
end
|
147
145
|
|
@@ -153,4 +151,4 @@ module DynamicImage
|
|
153
151
|
Vector2d.new(x, y)
|
154
152
|
end
|
155
153
|
end
|
156
|
-
end
|
154
|
+
end
|
@@ -16,27 +16,23 @@ module DynamicImage
|
|
16
16
|
if valid?
|
17
17
|
case metadata[:colorspace]
|
18
18
|
when /rgb/i
|
19
|
-
|
19
|
+
'rgb'
|
20
20
|
when /cmyk/i
|
21
|
-
|
21
|
+
'cmyk'
|
22
22
|
when /gray/i
|
23
|
-
|
23
|
+
'gray'
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
# Returns the content type of the image.
|
29
29
|
def content_type
|
30
|
-
if valid?
|
31
|
-
"image/#{format.downcase}"
|
32
|
-
end
|
30
|
+
"image/#{format.downcase}" if valid?
|
33
31
|
end
|
34
32
|
|
35
33
|
# Returns the dimensions of the image as a vector.
|
36
34
|
def dimensions
|
37
|
-
if valid?
|
38
|
-
Vector2d.new(*metadata[:dimensions])
|
39
|
-
end
|
35
|
+
Vector2d.new(*metadata[:dimensions]) if valid?
|
40
36
|
end
|
41
37
|
|
42
38
|
# Returns the width of the image.
|
@@ -51,14 +47,12 @@ module DynamicImage
|
|
51
47
|
|
52
48
|
# Returns the format of the image.
|
53
49
|
def format
|
54
|
-
if valid?
|
55
|
-
metadata[:format]
|
56
|
-
end
|
50
|
+
metadata[:format] if valid?
|
57
51
|
end
|
58
52
|
|
59
53
|
# Returns true if the image is valid.
|
60
54
|
def valid?
|
61
|
-
@data && metadata != :invalid
|
55
|
+
@data && reader.valid_header? && metadata != :invalid
|
62
56
|
end
|
63
57
|
|
64
58
|
private
|
@@ -67,18 +61,28 @@ module DynamicImage
|
|
67
61
|
@metadata ||= read_metadata
|
68
62
|
end
|
69
63
|
|
70
|
-
def
|
71
|
-
image =
|
64
|
+
def read_image
|
65
|
+
image = reader.read
|
72
66
|
image.auto_orient
|
73
|
-
|
74
|
-
colorspace: image[:colorspace],
|
75
|
-
dimensions: image[:dimensions],
|
76
|
-
format: image[:format]
|
77
|
-
}
|
67
|
+
result = yield image
|
78
68
|
image.destroy!
|
79
|
-
|
69
|
+
result
|
80
70
|
rescue MiniMagick::Invalid
|
81
71
|
:invalid
|
82
72
|
end
|
73
|
+
|
74
|
+
def reader
|
75
|
+
@reader ||= DynamicImage::ImageReader.new(@data)
|
76
|
+
end
|
77
|
+
|
78
|
+
def read_metadata
|
79
|
+
read_image do |image|
|
80
|
+
{
|
81
|
+
colorspace: image[:colorspace],
|
82
|
+
dimensions: image[:dimensions],
|
83
|
+
format: image[:format]
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
83
87
|
end
|
84
|
-
end
|
88
|
+
end
|
@@ -5,7 +5,6 @@ module DynamicImage
|
|
5
5
|
# = DynamicImage Model Dimensions
|
6
6
|
#
|
7
7
|
module Dimensions
|
8
|
-
|
9
8
|
# Returns the crop gravity.
|
10
9
|
#
|
11
10
|
# DynamicImage will try to keep the pixel represented by
|
@@ -33,9 +32,7 @@ module DynamicImage
|
|
33
32
|
|
34
33
|
# Returns the crop size, or nil if no cropping is applied.
|
35
34
|
def crop_size
|
36
|
-
if crop_size?
|
37
|
-
vector(crop_width, crop_height)
|
38
|
-
end
|
35
|
+
vector(crop_width, crop_height) if crop_size?
|
39
36
|
end
|
40
37
|
|
41
38
|
# Returns true if crop size has been set.
|
@@ -64,9 +61,7 @@ module DynamicImage
|
|
64
61
|
|
65
62
|
# Returns the real size of the image, without any cropping applied.
|
66
63
|
def real_size
|
67
|
-
if real_size?
|
68
|
-
vector(real_width, real_height)
|
69
|
-
end
|
64
|
+
vector(real_width, real_height) if real_size?
|
70
65
|
end
|
71
66
|
|
72
67
|
# Returns true if the size has been set.
|
@@ -92,4 +87,4 @@ module DynamicImage
|
|
92
87
|
end
|
93
88
|
end
|
94
89
|
end
|
95
|
-
end
|
90
|
+
end
|
@@ -13,34 +13,34 @@ module DynamicImage
|
|
13
13
|
validates_data_presence
|
14
14
|
|
15
15
|
validates :colorspace,
|
16
|
-
|
17
|
-
|
16
|
+
presence: true,
|
17
|
+
inclusion: { in: allowed_colorspaces }
|
18
18
|
|
19
19
|
validates :content_type,
|
20
|
-
|
21
|
-
|
20
|
+
presence: true,
|
21
|
+
inclusion: { in: allowed_content_types }
|
22
22
|
|
23
23
|
validates :content_length,
|
24
|
-
|
25
|
-
|
24
|
+
presence: true,
|
25
|
+
numericality: { greater_than: 0, only_integer: true }
|
26
26
|
|
27
27
|
validates :filename,
|
28
|
-
|
29
|
-
|
28
|
+
presence: true,
|
29
|
+
length: { maximum: 255 }
|
30
30
|
|
31
31
|
validates :real_width, :real_height,
|
32
|
-
|
32
|
+
numericality: { greater_than: 0, only_integer: true }
|
33
33
|
|
34
34
|
validates :real_width, :real_height,
|
35
|
-
|
35
|
+
numericality: { greater_than: 0, only_integer: true }
|
36
36
|
|
37
37
|
validates :crop_width, :crop_height,
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
:crop_gravity_x, :crop_gravity_y,
|
39
|
+
numericality: { greater_than: 0, only_integer: true },
|
40
|
+
allow_nil: true
|
41
41
|
|
42
42
|
validates :real_width, :real_height,
|
43
|
-
|
43
|
+
presence: true
|
44
44
|
|
45
45
|
validates :crop_width, presence: true, if: :crop_height?
|
46
46
|
validates :crop_height, presence: true, if: :crop_width?
|
@@ -57,21 +57,21 @@ module DynamicImage
|
|
57
57
|
|
58
58
|
module ClassMethods
|
59
59
|
def allowed_colorspaces
|
60
|
-
%w
|
60
|
+
%w(
|
61
61
|
rgb
|
62
62
|
cmyk
|
63
63
|
gray
|
64
|
-
|
64
|
+
)
|
65
65
|
end
|
66
66
|
|
67
67
|
def allowed_content_types
|
68
|
-
%w
|
68
|
+
%w(
|
69
69
|
image/gif
|
70
70
|
image/jpeg
|
71
71
|
image/pjpeg
|
72
72
|
image/png
|
73
73
|
image/tiff
|
74
|
-
|
74
|
+
)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
@@ -80,15 +80,13 @@ module DynamicImage
|
|
80
80
|
def validate_crop_bounds
|
81
81
|
required_size = crop_start + crop_size
|
82
82
|
if required_size.x > real_size.x || required_size.y > real_size.y
|
83
|
-
|
83
|
+
errors.add(:crop_size, 'is out of bounds')
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
87
|
def validate_image
|
88
|
-
unless valid_image?
|
89
|
-
self.errors.add(:data, :invalid)
|
90
|
-
end
|
88
|
+
errors.add(:data, :invalid) unless valid_image?
|
91
89
|
end
|
92
90
|
end
|
93
91
|
end
|
94
|
-
end
|
92
|
+
end
|
data/lib/dynamic_image/model.rb
CHANGED
@@ -70,17 +70,17 @@ module DynamicImage
|
|
70
70
|
|
71
71
|
# Returns true if the image is in the CMYK colorspace
|
72
72
|
def cmyk?
|
73
|
-
colorspace ==
|
73
|
+
colorspace == 'cmyk'
|
74
74
|
end
|
75
75
|
|
76
76
|
# Returns true if the image is in the grayscale colorspace
|
77
77
|
def gray?
|
78
|
-
colorspace ==
|
78
|
+
colorspace == 'gray'
|
79
79
|
end
|
80
80
|
|
81
81
|
# Returns true if the image is in the RGB colorspace
|
82
82
|
def rgb?
|
83
|
-
colorspace ==
|
83
|
+
colorspace == 'rgb'
|
84
84
|
end
|
85
85
|
|
86
86
|
# Finds a web safe content type. GIF, JPEG and PNG images are allowed,
|
@@ -102,15 +102,14 @@ module DynamicImage
|
|
102
102
|
private
|
103
103
|
|
104
104
|
def read_image_metadata
|
105
|
-
metadata = DynamicImage::Metadata.new(
|
105
|
+
metadata = DynamicImage::Metadata.new(data)
|
106
|
+
@valid_image = false
|
106
107
|
if metadata.valid?
|
107
108
|
self.colorspace = metadata.colorspace
|
108
109
|
self.real_width = metadata.width
|
109
110
|
self.real_height = metadata.height
|
110
111
|
self.content_type = metadata.content_type
|
111
112
|
@valid_image = true
|
112
|
-
else
|
113
|
-
@valid_image = false
|
114
113
|
end
|
115
114
|
true
|
116
115
|
end
|
@@ -120,11 +119,11 @@ module DynamicImage
|
|
120
119
|
end
|
121
120
|
|
122
121
|
def safe_content_types
|
123
|
-
%w
|
122
|
+
%w(
|
124
123
|
image/png
|
125
124
|
image/gif
|
126
125
|
image/jpeg
|
127
|
-
|
126
|
+
)
|
128
127
|
end
|
129
128
|
end
|
130
|
-
end
|
129
|
+
end
|
@@ -6,11 +6,11 @@ module DynamicImage
|
|
6
6
|
# Handles all processing of images. Takes an instance of
|
7
7
|
# +DynamicImage::Model+ as argument.
|
8
8
|
class ProcessedImage
|
9
|
-
def initialize(record, options={})
|
9
|
+
def initialize(record, options = {})
|
10
10
|
@record = record
|
11
11
|
@uncropped = options[:uncropped] ? true : false
|
12
12
|
@format = options[:format].to_s.upcase if options[:format]
|
13
|
-
@format =
|
13
|
+
@format = 'JPEG' if defined?(@format) && @format == 'JPG'
|
14
14
|
end
|
15
15
|
|
16
16
|
# Returns the content type of the processed image.
|
@@ -57,7 +57,7 @@ module DynamicImage
|
|
57
57
|
# jpg_data = processed.normalized
|
58
58
|
#
|
59
59
|
# Returns a binary string.
|
60
|
-
def normalized
|
60
|
+
def normalized
|
61
61
|
require_valid_image!
|
62
62
|
process_data do |image|
|
63
63
|
image.combine_options do |combined|
|
@@ -75,7 +75,7 @@ module DynamicImage
|
|
75
75
|
def coalesced(image)
|
76
76
|
if gif?
|
77
77
|
image.coalesce
|
78
|
-
image =
|
78
|
+
image = DynamicImage::ImageReader.new(image.to_blob).read
|
79
79
|
end
|
80
80
|
image
|
81
81
|
end
|
@@ -89,7 +89,8 @@ module DynamicImage
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def image_sizing
|
92
|
-
@image_sizing ||= DynamicImage::ImageSizing.new(record,
|
92
|
+
@image_sizing ||= DynamicImage::ImageSizing.new(record,
|
93
|
+
uncropped: @uncropped)
|
93
94
|
end
|
94
95
|
|
95
96
|
def needs_colorspace_conversion?
|
@@ -101,23 +102,19 @@ module DynamicImage
|
|
101
102
|
end
|
102
103
|
|
103
104
|
def optimize(image)
|
104
|
-
if gif?
|
105
|
-
image.layers 'optimize'
|
106
|
-
end
|
105
|
+
image.layers 'optimize' if gif?
|
107
106
|
image.strip
|
108
107
|
end
|
109
108
|
|
110
|
-
def process_data
|
111
|
-
image = coalesced(
|
109
|
+
def process_data
|
110
|
+
image = coalesced(DynamicImage::ImageReader.new(record.data).read)
|
112
111
|
yield(image)
|
113
112
|
result = image.to_blob
|
114
113
|
image.destroy!
|
115
114
|
result
|
116
115
|
end
|
117
116
|
|
118
|
-
|
119
|
-
@record
|
120
|
-
end
|
117
|
+
attr_reader :record
|
121
118
|
|
122
119
|
def record_format
|
123
120
|
case record.content_type
|
@@ -133,9 +130,7 @@ module DynamicImage
|
|
133
130
|
end
|
134
131
|
|
135
132
|
def require_valid_image!
|
136
|
-
unless record.valid?
|
137
|
-
raise DynamicImage::Errors::InvalidImage
|
138
|
-
end
|
133
|
+
raise DynamicImage::Errors::InvalidImage unless record.valid?
|
139
134
|
end
|
140
135
|
end
|
141
136
|
end
|
@@ -9,7 +9,7 @@ module DynamicImage
|
|
9
9
|
# Declares an image resource.
|
10
10
|
#
|
11
11
|
# image_resources :avatars
|
12
|
-
def image_resources(resource_name, options={})
|
12
|
+
def image_resources(resource_name, options = {})
|
13
13
|
options = {
|
14
14
|
path: "#{resource_name}/:digest(/:size)",
|
15
15
|
constraints: { size: /\d+x\d+/ },
|
data/lib/dynamic_image.rb
CHANGED
@@ -9,6 +9,7 @@ require 'dynamic_image/controller'
|
|
9
9
|
require 'dynamic_image/digest_verifier'
|
10
10
|
require 'dynamic_image/errors'
|
11
11
|
require 'dynamic_image/helper'
|
12
|
+
require 'dynamic_image/image_reader'
|
12
13
|
require 'dynamic_image/image_sizing'
|
13
14
|
require 'dynamic_image/metadata'
|
14
15
|
require 'dynamic_image/model'
|
@@ -6,7 +6,7 @@ require 'rails/generators/rails/resource/resource_generator'
|
|
6
6
|
module DynamicImage
|
7
7
|
module Generators
|
8
8
|
class ResourceGenerator < Rails::Generators::ResourceGenerator
|
9
|
-
desc
|
9
|
+
desc 'Creates a DynamicImage resource'
|
10
10
|
|
11
11
|
def initialize(args, *options)
|
12
12
|
super(inject_dynamic_image_attributes(args), *options)
|
@@ -14,14 +14,14 @@ module DynamicImage
|
|
14
14
|
|
15
15
|
def add_controller_extension
|
16
16
|
inject_into_file(
|
17
|
-
File.join(
|
17
|
+
File.join(
|
18
|
+
'app/controllers',
|
19
|
+
class_path,
|
20
|
+
"#{file_name.pluralize}_controller.rb"),
|
18
21
|
after: "ApplicationController\n"
|
19
22
|
) do
|
20
|
-
" include DynamicImage::Controller\n\n"
|
21
|
-
|
22
|
-
" def model\n" +
|
23
|
-
" #{class_name}\n" +
|
24
|
-
" end\n"
|
23
|
+
" include DynamicImage::Controller\n\n private\n\n" \
|
24
|
+
" def model\n #{class_name}\n end\n"
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -46,29 +46,24 @@ module DynamicImage
|
|
46
46
|
|
47
47
|
def inject_dynamic_image_attributes(args)
|
48
48
|
if args.any?
|
49
|
-
|
49
|
+
[args[0]] + dynamic_image_attributes + args[1..args.length]
|
50
50
|
else
|
51
51
|
args
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
55
|
def dynamic_image_attributes
|
56
|
-
%w
|
57
|
-
content_hash:string
|
58
|
-
content_type:string
|
56
|
+
%w(
|
57
|
+
content_hash:string content_type:string
|
59
58
|
content_length:integer
|
60
59
|
filename:string
|
61
60
|
colorspace:string
|
62
|
-
real_width:integer
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
crop_start_y:integer
|
68
|
-
crop_gravity_x:integer
|
69
|
-
crop_gravity_y:integer
|
70
|
-
}
|
61
|
+
real_width:integer real_height:integer
|
62
|
+
crop_width:integer crop_height:integer
|
63
|
+
crop_start_x:integer crop_start_y:integer
|
64
|
+
crop_gravity_x:integer crop_gravity_y:integer
|
65
|
+
)
|
71
66
|
end
|
72
67
|
end
|
73
68
|
end
|
74
|
-
end
|
69
|
+
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.
|
4
|
+
version: 2.0.1
|
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: 2016-
|
11
|
+
date: 2016-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -116,6 +116,7 @@ files:
|
|
116
116
|
- lib/dynamic_image/digest_verifier.rb
|
117
117
|
- lib/dynamic_image/errors.rb
|
118
118
|
- lib/dynamic_image/helper.rb
|
119
|
+
- lib/dynamic_image/image_reader.rb
|
119
120
|
- lib/dynamic_image/image_sizing.rb
|
120
121
|
- lib/dynamic_image/metadata.rb
|
121
122
|
- lib/dynamic_image/model.rb
|