carrierwave 0.11.2 → 3.0.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of carrierwave might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/README.md +452 -178
- data/lib/carrierwave/compatibility/paperclip.rb +4 -4
- data/lib/carrierwave/downloader/base.rb +101 -0
- data/lib/carrierwave/downloader/remote_file.rb +68 -0
- data/lib/carrierwave/error.rb +1 -0
- data/lib/carrierwave/locale/en.yml +11 -5
- data/lib/carrierwave/mount.rb +212 -182
- data/lib/carrierwave/mounter.rb +255 -0
- data/lib/carrierwave/orm/activerecord.rb +22 -33
- data/lib/carrierwave/processing/mini_magick.rb +140 -84
- data/lib/carrierwave/processing/rmagick.rb +72 -21
- data/lib/carrierwave/processing/vips.rb +284 -0
- data/lib/carrierwave/processing.rb +1 -1
- data/lib/carrierwave/sanitized_file.rb +83 -84
- data/lib/carrierwave/storage/abstract.rb +16 -3
- data/lib/carrierwave/storage/file.rb +71 -3
- data/lib/carrierwave/storage/fog.rb +215 -57
- data/lib/carrierwave/storage.rb +1 -9
- data/lib/carrierwave/test/matchers.rb +88 -19
- data/lib/carrierwave/uploader/cache.rb +75 -45
- data/lib/carrierwave/uploader/callbacks.rb +1 -3
- data/lib/carrierwave/uploader/configuration.rb +80 -16
- data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
- data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
- data/lib/carrierwave/uploader/default_url.rb +3 -5
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/download.rb +4 -74
- data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
- data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
- data/lib/carrierwave/uploader/file_size.rb +43 -0
- data/lib/carrierwave/uploader/mountable.rb +13 -8
- data/lib/carrierwave/uploader/processing.rb +48 -13
- data/lib/carrierwave/uploader/proxy.rb +20 -9
- data/lib/carrierwave/uploader/remove.rb +0 -2
- data/lib/carrierwave/uploader/serialization.rb +2 -4
- data/lib/carrierwave/uploader/store.rb +59 -28
- data/lib/carrierwave/uploader/url.rb +8 -7
- data/lib/carrierwave/uploader/versions.rb +170 -122
- data/lib/carrierwave/uploader.rb +12 -10
- data/lib/carrierwave/utilities/file_name.rb +47 -0
- data/lib/carrierwave/utilities/uri.rb +14 -12
- data/lib/carrierwave/utilities.rb +1 -3
- data/lib/carrierwave/validations/active_model.rb +7 -11
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +39 -21
- data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +5 -9
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +132 -80
- data/lib/carrierwave/locale/cs.yml +0 -11
- data/lib/carrierwave/locale/de.yml +0 -11
- data/lib/carrierwave/locale/el.yml +0 -11
- data/lib/carrierwave/locale/es.yml +0 -11
- data/lib/carrierwave/locale/fr.yml +0 -11
- data/lib/carrierwave/locale/ja.yml +0 -11
- data/lib/carrierwave/locale/nb.yml +0 -11
- data/lib/carrierwave/locale/nl.yml +0 -11
- data/lib/carrierwave/locale/pl.yml +0 -11
- data/lib/carrierwave/locale/pt-BR.yml +0 -11
- data/lib/carrierwave/locale/pt-PT.yml +0 -11
- data/lib/carrierwave/locale/ru.yml +0 -11
- data/lib/carrierwave/locale/sk.yml +0 -11
- data/lib/carrierwave/locale/tr.yml +0 -11
- data/lib/carrierwave/processing/mime_types.rb +0 -74
- data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
- data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
- data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
- data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
- data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -0,0 +1,255 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
|
3
|
+
# this is an internal class, used by CarrierWave::Mount so that
|
4
|
+
# we don't pollute the model with a lot of methods.
|
5
|
+
class Mounter # :nodoc:
|
6
|
+
class Single < Mounter # :nodoc
|
7
|
+
def identifier
|
8
|
+
uploaders.first&.identifier
|
9
|
+
end
|
10
|
+
|
11
|
+
def temporary_identifier
|
12
|
+
temporary_identifiers.first
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Multiple < Mounter # :nodoc
|
17
|
+
def identifier
|
18
|
+
uploaders.map(&:identifier).presence
|
19
|
+
end
|
20
|
+
|
21
|
+
def temporary_identifier
|
22
|
+
temporary_identifiers.presence
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.build(record, column)
|
27
|
+
if record.class.uploader_options[column][:multiple]
|
28
|
+
Multiple.new(record, column)
|
29
|
+
else
|
30
|
+
Single.new(record, column)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :column, :record, :remote_urls, :remove,
|
35
|
+
:integrity_errors, :processing_errors, :download_errors
|
36
|
+
attr_accessor :remote_request_headers, :uploader_options
|
37
|
+
|
38
|
+
def initialize(record, column)
|
39
|
+
@record = record
|
40
|
+
@column = column
|
41
|
+
@options = record.class.uploader_options[column]
|
42
|
+
@download_errors = []
|
43
|
+
@processing_errors = []
|
44
|
+
@integrity_errors = []
|
45
|
+
|
46
|
+
@removed_uploaders = []
|
47
|
+
@added_uploaders = []
|
48
|
+
end
|
49
|
+
|
50
|
+
def uploader_class
|
51
|
+
record.class.uploaders[column]
|
52
|
+
end
|
53
|
+
|
54
|
+
def blank_uploader
|
55
|
+
uploader_class.new(record, column)
|
56
|
+
end
|
57
|
+
|
58
|
+
def identifiers
|
59
|
+
uploaders.map(&:identifier)
|
60
|
+
end
|
61
|
+
|
62
|
+
def read_identifiers
|
63
|
+
[record.read_uploader(serialization_column)].flatten.reject(&:blank?)
|
64
|
+
end
|
65
|
+
|
66
|
+
def uploaders
|
67
|
+
@uploaders ||= read_identifiers.map do |identifier|
|
68
|
+
uploader = blank_uploader
|
69
|
+
uploader.retrieve_from_store!(identifier)
|
70
|
+
uploader
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def cache(new_files)
|
75
|
+
return if !new_files.is_a?(Array) && new_files.blank?
|
76
|
+
old_uploaders = uploaders
|
77
|
+
@uploaders = new_files.map do |new_file|
|
78
|
+
handle_error do
|
79
|
+
if new_file.is_a?(String)
|
80
|
+
if (uploader = old_uploaders.detect { |old_uploader| old_uploader.identifier == new_file })
|
81
|
+
uploader.staged = true
|
82
|
+
uploader
|
83
|
+
else
|
84
|
+
begin
|
85
|
+
uploader = blank_uploader
|
86
|
+
uploader.retrieve_from_cache!(new_file)
|
87
|
+
uploader
|
88
|
+
rescue CarrierWave::InvalidParameter
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
uploader = blank_uploader
|
94
|
+
uploader.cache!(new_file)
|
95
|
+
uploader
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end.reject(&:blank?)
|
99
|
+
@removed_uploaders += (old_uploaders - @uploaders)
|
100
|
+
write_temporary_identifier
|
101
|
+
end
|
102
|
+
|
103
|
+
def cache_names
|
104
|
+
uploaders.map(&:cache_name).compact
|
105
|
+
end
|
106
|
+
|
107
|
+
def cache_names=(cache_names)
|
108
|
+
cache_names = cache_names.reject(&:blank?)
|
109
|
+
return if cache_names.blank?
|
110
|
+
clear_unstaged
|
111
|
+
cache_names.each do |cache_name|
|
112
|
+
uploader = blank_uploader
|
113
|
+
uploader.retrieve_from_cache!(cache_name)
|
114
|
+
@uploaders << uploader
|
115
|
+
rescue CarrierWave::InvalidParameter
|
116
|
+
# ignore
|
117
|
+
end
|
118
|
+
write_temporary_identifier
|
119
|
+
end
|
120
|
+
|
121
|
+
def remote_urls=(urls)
|
122
|
+
if urls.nil?
|
123
|
+
urls = []
|
124
|
+
else
|
125
|
+
urls = Array.wrap(urls).reject(&:blank?)
|
126
|
+
return if urls.blank?
|
127
|
+
end
|
128
|
+
@remote_urls = urls
|
129
|
+
|
130
|
+
clear_unstaged
|
131
|
+
@remote_urls.zip(remote_request_headers || []) do |url, header|
|
132
|
+
handle_error do
|
133
|
+
uploader = blank_uploader
|
134
|
+
uploader.download!(url, header || {})
|
135
|
+
@uploaders << uploader
|
136
|
+
end
|
137
|
+
end
|
138
|
+
write_temporary_identifier
|
139
|
+
end
|
140
|
+
|
141
|
+
def store!
|
142
|
+
uploaders.each(&:store!)
|
143
|
+
end
|
144
|
+
|
145
|
+
def write_identifier
|
146
|
+
return if record.frozen?
|
147
|
+
|
148
|
+
clear! if remove?
|
149
|
+
|
150
|
+
additions, remains = uploaders.partition(&:cached?)
|
151
|
+
existing_identifiers = (@removed_uploaders + remains).map(&:identifier)
|
152
|
+
additions.each do |uploader|
|
153
|
+
uploader.deduplicate(existing_identifiers)
|
154
|
+
existing_identifiers << uploader.identifier
|
155
|
+
end
|
156
|
+
@added_uploaders += additions
|
157
|
+
|
158
|
+
record.write_uploader(serialization_column, identifier)
|
159
|
+
end
|
160
|
+
|
161
|
+
def urls(*args)
|
162
|
+
uploaders.map { |u| u.url(*args) }
|
163
|
+
end
|
164
|
+
|
165
|
+
def blank?
|
166
|
+
uploaders.none?(&:present?)
|
167
|
+
end
|
168
|
+
|
169
|
+
def remove=(value)
|
170
|
+
@remove = value
|
171
|
+
write_temporary_identifier
|
172
|
+
end
|
173
|
+
|
174
|
+
def remove?
|
175
|
+
remove.present? && (remove.to_s !~ /\A0|false$\z/)
|
176
|
+
end
|
177
|
+
|
178
|
+
def remove!
|
179
|
+
uploaders.each(&:remove!)
|
180
|
+
clear!
|
181
|
+
end
|
182
|
+
|
183
|
+
def clear!
|
184
|
+
@removed_uploaders += uploaders
|
185
|
+
@remove = nil
|
186
|
+
@uploaders = []
|
187
|
+
end
|
188
|
+
|
189
|
+
def reset_changes!
|
190
|
+
@removed_uploaders = []
|
191
|
+
@added_uploaders = []
|
192
|
+
end
|
193
|
+
|
194
|
+
def serialization_column
|
195
|
+
option(:mount_on) || column
|
196
|
+
end
|
197
|
+
|
198
|
+
def remove_previous
|
199
|
+
current_paths = uploaders.map(&:path)
|
200
|
+
@removed_uploaders
|
201
|
+
.reject {|uploader| current_paths.include?(uploader.path) }
|
202
|
+
.each { |uploader| uploader.remove! if uploader.remove_previously_stored_files_after_update }
|
203
|
+
reset_changes!
|
204
|
+
end
|
205
|
+
|
206
|
+
def remove_added
|
207
|
+
current_paths = (@removed_uploaders + uploaders.select(&:staged)).map(&:path)
|
208
|
+
@added_uploaders
|
209
|
+
.reject {|uploader| current_paths.include?(uploader.path) }
|
210
|
+
.each { |uploader| uploader.remove! }
|
211
|
+
reset_changes!
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
def option(name)
|
217
|
+
self.uploader_options ||= {}
|
218
|
+
self.uploader_options[name] ||= record.class.uploader_option(column, name)
|
219
|
+
end
|
220
|
+
|
221
|
+
def clear_unstaged
|
222
|
+
@uploaders ||= []
|
223
|
+
staged, unstaged = @uploaders.partition(&:staged)
|
224
|
+
@uploaders = staged
|
225
|
+
@removed_uploaders += unstaged
|
226
|
+
end
|
227
|
+
|
228
|
+
def handle_error
|
229
|
+
yield
|
230
|
+
rescue CarrierWave::DownloadError => e
|
231
|
+
@download_errors << e
|
232
|
+
raise e unless option(:ignore_download_errors)
|
233
|
+
rescue CarrierWave::ProcessingError => e
|
234
|
+
@processing_errors << e
|
235
|
+
raise e unless option(:ignore_processing_errors)
|
236
|
+
rescue CarrierWave::IntegrityError => e
|
237
|
+
@integrity_errors << e
|
238
|
+
raise e unless option(:ignore_integrity_errors)
|
239
|
+
end
|
240
|
+
|
241
|
+
def write_temporary_identifier
|
242
|
+
return if record.frozen?
|
243
|
+
|
244
|
+
record.write_uploader(serialization_column, temporary_identifier)
|
245
|
+
end
|
246
|
+
|
247
|
+
def temporary_identifiers
|
248
|
+
if remove?
|
249
|
+
[]
|
250
|
+
else
|
251
|
+
uploaders.map { |uploader| uploader.temporary_identifier }
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end # Mounter
|
255
|
+
end # CarrierWave
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require 'active_record'
|
4
2
|
require 'carrierwave/validations/active_model'
|
5
3
|
|
@@ -8,10 +6,9 @@ module CarrierWave
|
|
8
6
|
|
9
7
|
include CarrierWave::Mount
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def mount_uploader(column, uploader=nil, options={}, &block)
|
9
|
+
private
|
10
|
+
|
11
|
+
def mount_base(column, uploader=nil, options={}, &block)
|
15
12
|
super
|
16
13
|
|
17
14
|
alias_method :read_uploader, :read_attribute
|
@@ -29,43 +26,35 @@ module CarrierWave
|
|
29
26
|
before_save :"write_#{column}_identifier"
|
30
27
|
after_commit :"remove_#{column}!", :on => :destroy
|
31
28
|
after_commit :"mark_remove_#{column}_false", :on => :update
|
32
|
-
before_update :"store_previous_model_for_#{column}"
|
33
|
-
after_save :"remove_previously_stored_#{column}"
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
send(:"\#{column}_will_change!")
|
39
|
-
super
|
40
|
-
end
|
30
|
+
after_commit :"reset_previous_changes_for_#{column}"
|
31
|
+
after_commit :"remove_previously_stored_#{column}", :on => :update
|
32
|
+
after_rollback :"remove_rolled_back_#{column}"
|
41
33
|
|
42
|
-
|
43
|
-
|
44
|
-
|
34
|
+
mod = Module.new
|
35
|
+
prepend mod
|
36
|
+
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
|
37
|
+
# Reset cached mounter on record reload
|
38
|
+
def reload(*)
|
39
|
+
@_mounters = nil
|
45
40
|
super
|
46
41
|
end
|
47
42
|
|
48
|
-
|
43
|
+
# Reset cached mounter on record dup
|
44
|
+
def initialize_dup(other)
|
45
|
+
old_uploaders = _mounter(:"#{column}").uploaders
|
46
|
+
@_mounters[:"#{column}"] = nil
|
49
47
|
super
|
50
|
-
|
51
|
-
|
48
|
+
# The attribute needs to be cleared to prevent it from picked up as identifier
|
49
|
+
write_attribute(:"#{column}", nil)
|
50
|
+
_mounter(:"#{column}").cache(old_uploaders)
|
52
51
|
end
|
53
52
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
except = options && options[:except] && Array.wrap(options[:except]).map(&:to_s)
|
58
|
-
only = options && options[:only] && Array.wrap(options[:only]).map(&:to_s)
|
59
|
-
|
60
|
-
self.class.uploaders.each do |column, uploader|
|
61
|
-
if (!only && !except) || (only && only.include?(column.to_s)) || (!only && except && !except.include?(column.to_s))
|
62
|
-
hash[column.to_s] = _mounter(column).uploader.serializable_hash
|
63
|
-
end
|
64
|
-
end
|
65
|
-
super(options).merge(hash)
|
53
|
+
def write_#{column}_identifier
|
54
|
+
return unless has_attribute?(_mounter(:#{column}).serialization_column)
|
55
|
+
super
|
66
56
|
end
|
67
57
|
RUBY
|
68
|
-
|
69
58
|
end
|
70
59
|
|
71
60
|
end # ActiveRecord
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module CarrierWave
|
4
2
|
|
5
3
|
##
|
@@ -23,9 +21,11 @@ module CarrierWave
|
|
23
21
|
# process :resize_to_fit => [200, 200]
|
24
22
|
# end
|
25
23
|
#
|
26
|
-
# Or create your own helpers with the powerful
|
27
|
-
#
|
28
|
-
#
|
24
|
+
# Or create your own helpers with the powerful minimagick! method, which
|
25
|
+
# yields an ImageProcessing::Builder object. Check out the ImageProcessing
|
26
|
+
# docs at http://github.com/janko-m/image_processing and the list of all
|
27
|
+
# available ImageMagick options at
|
28
|
+
# http://www.imagemagick.org/script/command-line-options.php for more info.
|
29
29
|
#
|
30
30
|
# class MyUploader < CarrierWave::Uploader::Base
|
31
31
|
# include CarrierWave::MiniMagick
|
@@ -33,35 +33,30 @@ module CarrierWave
|
|
33
33
|
# process :radial_blur => 10
|
34
34
|
#
|
35
35
|
# def radial_blur(amount)
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
36
|
+
# minimagick! do |builder|
|
37
|
+
# builder.radial_blur(amount)
|
38
|
+
# builder = yield(builder) if block_given?
|
39
|
+
# builder
|
40
40
|
# end
|
41
41
|
# end
|
42
|
+
# end
|
42
43
|
#
|
43
44
|
# === Note
|
44
45
|
#
|
45
|
-
# MiniMagick
|
46
|
-
#
|
46
|
+
# The ImageProcessing gem uses MiniMagick, a mini replacement for RMagick
|
47
|
+
# that uses ImageMagick command-line tools, to build a "convert" command that
|
48
|
+
# performs the processing.
|
47
49
|
#
|
48
50
|
# You can find more information here:
|
49
51
|
#
|
50
|
-
#
|
51
|
-
# and
|
52
|
-
# https://github.com/minimagic/minimagick/
|
52
|
+
# https://github.com/minimagick/minimagick/
|
53
53
|
#
|
54
54
|
#
|
55
55
|
module MiniMagick
|
56
56
|
extend ActiveSupport::Concern
|
57
57
|
|
58
58
|
included do
|
59
|
-
|
60
|
-
require "mini_magick"
|
61
|
-
rescue LoadError => e
|
62
|
-
e.message << " (You may need to install the mini_magick gem)"
|
63
|
-
raise e
|
64
|
-
end
|
59
|
+
require "image_processing/mini_magick"
|
65
60
|
end
|
66
61
|
|
67
62
|
module ClassMethods
|
@@ -81,7 +76,7 @@ module CarrierWave
|
|
81
76
|
process :resize_to_fill => [width, height, gravity]
|
82
77
|
end
|
83
78
|
|
84
|
-
def resize_and_pad(width, height, background=:transparent, gravity
|
79
|
+
def resize_and_pad(width, height, background=:transparent, gravity='Center')
|
85
80
|
process :resize_and_pad => [width, height, background, gravity]
|
86
81
|
end
|
87
82
|
end
|
@@ -93,7 +88,7 @@ module CarrierWave
|
|
93
88
|
#
|
94
89
|
# === Parameters
|
95
90
|
#
|
96
|
-
# [format (#to_s)] an
|
91
|
+
# [format (#to_s)] an abbreviation of the format
|
97
92
|
#
|
98
93
|
# === Yields
|
99
94
|
#
|
@@ -103,12 +98,11 @@ module CarrierWave
|
|
103
98
|
#
|
104
99
|
# image.convert(:png)
|
105
100
|
#
|
106
|
-
def convert(format)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
img
|
101
|
+
def convert(format, page=nil, &block)
|
102
|
+
minimagick!(block) do |builder|
|
103
|
+
builder = builder.convert(format)
|
104
|
+
builder = builder.loader(page: page) if page
|
105
|
+
builder
|
112
106
|
end
|
113
107
|
end
|
114
108
|
|
@@ -122,16 +116,18 @@ module CarrierWave
|
|
122
116
|
#
|
123
117
|
# [width (Integer)] the width to scale the image to
|
124
118
|
# [height (Integer)] the height to scale the image to
|
119
|
+
# [combine_options (Hash)] additional ImageMagick options to apply before resizing
|
125
120
|
#
|
126
121
|
# === Yields
|
127
122
|
#
|
128
123
|
# [MiniMagick::Image] additional manipulations to perform
|
129
124
|
#
|
130
|
-
def resize_to_limit(width, height)
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
125
|
+
def resize_to_limit(width, height, combine_options: {}, &block)
|
126
|
+
width, height = resolve_dimensions(width, height)
|
127
|
+
|
128
|
+
minimagick!(block) do |builder|
|
129
|
+
builder.resize_to_limit(width, height)
|
130
|
+
.apply(combine_options)
|
135
131
|
end
|
136
132
|
end
|
137
133
|
|
@@ -144,16 +140,18 @@ module CarrierWave
|
|
144
140
|
#
|
145
141
|
# [width (Integer)] the width to scale the image to
|
146
142
|
# [height (Integer)] the height to scale the image to
|
143
|
+
# [combine_options (Hash)] additional ImageMagick options to apply before resizing
|
147
144
|
#
|
148
145
|
# === Yields
|
149
146
|
#
|
150
147
|
# [MiniMagick::Image] additional manipulations to perform
|
151
148
|
#
|
152
|
-
def resize_to_fit(width, height)
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
149
|
+
def resize_to_fit(width, height, combine_options: {}, &block)
|
150
|
+
width, height = resolve_dimensions(width, height)
|
151
|
+
|
152
|
+
minimagick!(block) do |builder|
|
153
|
+
builder.resize_to_fit(width, height)
|
154
|
+
.apply(combine_options)
|
157
155
|
end
|
158
156
|
end
|
159
157
|
|
@@ -167,34 +165,18 @@ module CarrierWave
|
|
167
165
|
# [width (Integer)] the width to scale the image to
|
168
166
|
# [height (Integer)] the height to scale the image to
|
169
167
|
# [gravity (String)] the current gravity suggestion (default: 'Center'; options: 'NorthWest', 'North', 'NorthEast', 'West', 'Center', 'East', 'SouthWest', 'South', 'SouthEast')
|
168
|
+
# [combine_options (Hash)] additional ImageMagick options to apply before resizing
|
170
169
|
#
|
171
170
|
# === Yields
|
172
171
|
#
|
173
172
|
# [MiniMagick::Image] additional manipulations to perform
|
174
173
|
#
|
175
|
-
def resize_to_fill(width, height, gravity = 'Center')
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
scale_y = height/rows.to_f
|
182
|
-
if scale_x >= scale_y
|
183
|
-
cols = (scale_x * (cols + 0.5)).round
|
184
|
-
rows = (scale_x * (rows + 0.5)).round
|
185
|
-
cmd.resize "#{cols}"
|
186
|
-
else
|
187
|
-
cols = (scale_y * (cols + 0.5)).round
|
188
|
-
rows = (scale_y * (rows + 0.5)).round
|
189
|
-
cmd.resize "x#{rows}"
|
190
|
-
end
|
191
|
-
end
|
192
|
-
cmd.gravity gravity
|
193
|
-
cmd.background "rgba(255,255,255,0.0)"
|
194
|
-
cmd.extent "#{width}x#{height}" if cols != width || rows != height
|
195
|
-
end
|
196
|
-
img = yield(img) if block_given?
|
197
|
-
img
|
174
|
+
def resize_to_fill(width, height, gravity = 'Center', combine_options: {}, &block)
|
175
|
+
width, height = resolve_dimensions(width, height)
|
176
|
+
|
177
|
+
minimagick!(block) do |builder|
|
178
|
+
builder.resize_to_fill(width, height, gravity: gravity)
|
179
|
+
.apply(combine_options)
|
198
180
|
end
|
199
181
|
end
|
200
182
|
|
@@ -213,33 +195,51 @@ module CarrierWave
|
|
213
195
|
# [height (Integer)] the height to scale the image to
|
214
196
|
# [background (String, :transparent)] the color of the background as a hexcode, like "#ff45de"
|
215
197
|
# [gravity (String)] how to position the image
|
198
|
+
# [combine_options (Hash)] additional ImageMagick options to apply before resizing
|
216
199
|
#
|
217
200
|
# === Yields
|
218
201
|
#
|
219
202
|
# [MiniMagick::Image] additional manipulations to perform
|
220
203
|
#
|
221
|
-
def resize_and_pad(width, height, background=:transparent, gravity='Center')
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
else
|
228
|
-
cmd.background background
|
229
|
-
end
|
230
|
-
cmd.gravity gravity
|
231
|
-
cmd.extent "#{width}x#{height}"
|
232
|
-
end
|
233
|
-
img = yield(img) if block_given?
|
234
|
-
img
|
204
|
+
def resize_and_pad(width, height, background=:transparent, gravity='Center', combine_options: {}, &block)
|
205
|
+
width, height = resolve_dimensions(width, height)
|
206
|
+
|
207
|
+
minimagick!(block) do |builder|
|
208
|
+
builder.resize_and_pad(width, height, background: background, gravity: gravity)
|
209
|
+
.apply(combine_options)
|
235
210
|
end
|
236
211
|
end
|
237
212
|
|
213
|
+
##
|
214
|
+
# Returns the width of the image in pixels.
|
215
|
+
#
|
216
|
+
# === Returns
|
217
|
+
#
|
218
|
+
# [Integer] the image's width in pixels
|
219
|
+
#
|
220
|
+
def width
|
221
|
+
mini_magick_image[:width]
|
222
|
+
end
|
223
|
+
|
224
|
+
##
|
225
|
+
# Returns the height of the image in pixels.
|
226
|
+
#
|
227
|
+
# === Returns
|
228
|
+
#
|
229
|
+
# [Integer] the image's height in pixels
|
230
|
+
#
|
231
|
+
def height
|
232
|
+
mini_magick_image[:height]
|
233
|
+
end
|
234
|
+
|
238
235
|
##
|
239
236
|
# Manipulate the image with MiniMagick. This method will load up an image
|
240
237
|
# and then pass each of its frames to the supplied block. It will then
|
241
238
|
# save the image to disk.
|
242
239
|
#
|
240
|
+
# NOTE: This method exists mostly for backwards compatibility, you should
|
241
|
+
# probably use #minimagick!.
|
242
|
+
#
|
243
243
|
# === Gotcha
|
244
244
|
#
|
245
245
|
# This method assumes that the object responds to +current_path+.
|
@@ -259,19 +259,75 @@ module CarrierWave
|
|
259
259
|
cache_stored_file! if !cached?
|
260
260
|
image = ::MiniMagick::Image.open(current_path)
|
261
261
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
262
|
+
image = yield(image)
|
263
|
+
FileUtils.mv image.path, current_path
|
264
|
+
|
265
|
+
image.run_command("identify", current_path)
|
266
|
+
rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
|
267
|
+
raise e if e.message =~ /(You must have .+ installed|is not installed|executable not found)/
|
268
|
+
message = I18n.translate(:"errors.messages.processing_error")
|
269
|
+
raise CarrierWave::ProcessingError, message
|
270
|
+
ensure
|
271
|
+
image.destroy! if image
|
272
|
+
end
|
273
|
+
|
274
|
+
# Process the image with MiniMagick, using the ImageProcessing gem. This
|
275
|
+
# method will build a "convert" ImageMagick command and execute it on the
|
276
|
+
# current image.
|
277
|
+
#
|
278
|
+
# === Gotcha
|
279
|
+
#
|
280
|
+
# This method assumes that the object responds to +current_path+.
|
281
|
+
# Any class that this module is mixed into must have a +current_path+ method.
|
282
|
+
# CarrierWave::Uploader does, so you won't need to worry about this in
|
283
|
+
# most cases.
|
284
|
+
#
|
285
|
+
# === Yields
|
286
|
+
#
|
287
|
+
# [ImageProcessing::Builder] use it to define processing to be performed
|
288
|
+
#
|
289
|
+
# === Raises
|
290
|
+
#
|
291
|
+
# [CarrierWave::ProcessingError] if processing failed.
|
292
|
+
def minimagick!(block = nil)
|
293
|
+
builder = ImageProcessing::MiniMagick.source(current_path)
|
294
|
+
builder = yield(builder)
|
295
|
+
|
296
|
+
result = builder.call
|
297
|
+
result.close
|
298
|
+
|
299
|
+
# backwards compatibility (we want to eventually move away from MiniMagick::Image)
|
300
|
+
if block
|
301
|
+
image = ::MiniMagick::Image.new(result.path, result)
|
302
|
+
image = block.call(image)
|
303
|
+
result = image.instance_variable_get(:@tempfile)
|
304
|
+
end
|
305
|
+
|
306
|
+
FileUtils.mv result.path, current_path
|
307
|
+
|
308
|
+
if File.extname(result.path) != File.extname(current_path)
|
309
|
+
move_to = current_path.chomp(File.extname(current_path)) + File.extname(result.path)
|
310
|
+
file.content_type = Marcel::Magic.by_path(move_to).try(:type)
|
311
|
+
file.move_to(move_to, permissions, directory_permissions)
|
269
312
|
end
|
270
313
|
rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
|
271
|
-
|
272
|
-
message = I18n.translate(:"errors.messages.
|
314
|
+
raise e if e.message =~ /(You must have .+ installed|is not installed|executable not found)/
|
315
|
+
message = I18n.translate(:"errors.messages.processing_error")
|
273
316
|
raise CarrierWave::ProcessingError, message
|
274
317
|
end
|
275
318
|
|
319
|
+
private
|
320
|
+
|
321
|
+
def resolve_dimensions(*dimensions)
|
322
|
+
dimensions.map do |value|
|
323
|
+
next value unless value.instance_of?(Proc)
|
324
|
+
value.arity >= 1 ? value.call(self) : value.call
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def mini_magick_image
|
329
|
+
::MiniMagick::Image.read(read)
|
330
|
+
end
|
331
|
+
|
276
332
|
end # MiniMagick
|
277
333
|
end # CarrierWave
|