carrierwave 1.3.2 → 3.0.0
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 +4 -4
- data/README.md +235 -91
- data/lib/carrierwave/compatibility/paperclip.rb +4 -2
- data/lib/carrierwave/downloader/base.rb +101 -0
- data/lib/carrierwave/downloader/remote_file.rb +68 -0
- data/lib/carrierwave/locale/en.yml +9 -6
- data/lib/carrierwave/mount.rb +48 -61
- data/lib/carrierwave/mounter.rb +165 -77
- data/lib/carrierwave/orm/activerecord.rb +13 -55
- data/lib/carrierwave/processing/mini_magick.rb +108 -123
- data/lib/carrierwave/processing/rmagick.rb +11 -15
- data/lib/carrierwave/processing/vips.rb +284 -0
- data/lib/carrierwave/processing.rb +1 -0
- data/lib/carrierwave/sanitized_file.rb +60 -66
- data/lib/carrierwave/storage/abstract.rb +5 -5
- data/lib/carrierwave/storage/file.rb +6 -5
- data/lib/carrierwave/storage/fog.rb +101 -62
- data/lib/carrierwave/storage.rb +1 -0
- data/lib/carrierwave/test/matchers.rb +11 -7
- data/lib/carrierwave/uploader/cache.rb +40 -24
- data/lib/carrierwave/uploader/callbacks.rb +1 -1
- data/lib/carrierwave/uploader/configuration.rb +38 -19
- data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
- data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/download.rb +2 -123
- 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 +2 -2
- data/lib/carrierwave/uploader/mountable.rb +6 -0
- data/lib/carrierwave/uploader/processing.rb +42 -7
- data/lib/carrierwave/uploader/proxy.rb +17 -4
- data/lib/carrierwave/uploader/serialization.rb +1 -1
- data/lib/carrierwave/uploader/store.rb +46 -7
- data/lib/carrierwave/uploader/url.rb +7 -4
- data/lib/carrierwave/uploader/versions.rb +140 -105
- data/lib/carrierwave/uploader.rb +10 -17
- data/lib/carrierwave/utilities/file_name.rb +47 -0
- data/lib/carrierwave/utilities/uri.rb +14 -11
- data/lib/carrierwave/utilities.rb +1 -0
- data/lib/carrierwave/validations/active_model.rb +7 -9
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +13 -17
- data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +2 -2
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +100 -33
- 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 -51
- data/lib/carrierwave/uploader/extension_whitelist.rb +0 -52
@@ -21,9 +21,11 @@ module CarrierWave
|
|
21
21
|
# process :resize_to_fit => [200, 200]
|
22
22
|
# end
|
23
23
|
#
|
24
|
-
# Or create your own helpers with the powerful
|
25
|
-
#
|
26
|
-
#
|
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.
|
27
29
|
#
|
28
30
|
# class MyUploader < CarrierWave::Uploader::Base
|
29
31
|
# include CarrierWave::MiniMagick
|
@@ -31,23 +33,22 @@ module CarrierWave
|
|
31
33
|
# process :radial_blur => 10
|
32
34
|
#
|
33
35
|
# def radial_blur(amount)
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
36
|
+
# minimagick! do |builder|
|
37
|
+
# builder.radial_blur(amount)
|
38
|
+
# builder = yield(builder) if block_given?
|
39
|
+
# builder
|
38
40
|
# end
|
39
41
|
# end
|
40
42
|
# end
|
41
43
|
#
|
42
44
|
# === Note
|
43
45
|
#
|
44
|
-
# MiniMagick
|
45
|
-
#
|
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.
|
46
49
|
#
|
47
50
|
# You can find more information here:
|
48
51
|
#
|
49
|
-
# http://mini_magick.rubyforge.org/
|
50
|
-
# and
|
51
52
|
# https://github.com/minimagick/minimagick/
|
52
53
|
#
|
53
54
|
#
|
@@ -55,19 +56,7 @@ module CarrierWave
|
|
55
56
|
extend ActiveSupport::Concern
|
56
57
|
|
57
58
|
included do
|
58
|
-
|
59
|
-
require "mini_magick"
|
60
|
-
rescue LoadError => e
|
61
|
-
e.message << " (You may need to install the mini_magick gem)"
|
62
|
-
raise e
|
63
|
-
end
|
64
|
-
|
65
|
-
prepend Module.new {
|
66
|
-
def initialize(*)
|
67
|
-
super
|
68
|
-
@format = nil
|
69
|
-
end
|
70
|
-
}
|
59
|
+
require "image_processing/mini_magick"
|
71
60
|
end
|
72
61
|
|
73
62
|
module ClassMethods
|
@@ -99,7 +88,7 @@ module CarrierWave
|
|
99
88
|
#
|
100
89
|
# === Parameters
|
101
90
|
#
|
102
|
-
# [format (#to_s)] an
|
91
|
+
# [format (#to_s)] an abbreviation of the format
|
103
92
|
#
|
104
93
|
# === Yields
|
105
94
|
#
|
@@ -109,12 +98,11 @@ module CarrierWave
|
|
109
98
|
#
|
110
99
|
# image.convert(:png)
|
111
100
|
#
|
112
|
-
def convert(format, page=nil)
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
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
|
118
106
|
end
|
119
107
|
end
|
120
108
|
|
@@ -128,21 +116,18 @@ module CarrierWave
|
|
128
116
|
#
|
129
117
|
# [width (Integer)] the width to scale the image to
|
130
118
|
# [height (Integer)] the height to scale the image to
|
119
|
+
# [combine_options (Hash)] additional ImageMagick options to apply before resizing
|
131
120
|
#
|
132
121
|
# === Yields
|
133
122
|
#
|
134
123
|
# [MiniMagick::Image] additional manipulations to perform
|
135
124
|
#
|
136
|
-
def resize_to_limit(width, height, combine_options: {})
|
137
|
-
width =
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
append_combine_options cmd, combine_options
|
143
|
-
end
|
144
|
-
img = yield(img) if block_given?
|
145
|
-
img
|
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)
|
146
131
|
end
|
147
132
|
end
|
148
133
|
|
@@ -155,21 +140,18 @@ module CarrierWave
|
|
155
140
|
#
|
156
141
|
# [width (Integer)] the width to scale the image to
|
157
142
|
# [height (Integer)] the height to scale the image to
|
143
|
+
# [combine_options (Hash)] additional ImageMagick options to apply before resizing
|
158
144
|
#
|
159
145
|
# === Yields
|
160
146
|
#
|
161
147
|
# [MiniMagick::Image] additional manipulations to perform
|
162
148
|
#
|
163
|
-
def resize_to_fit(width, height, combine_options: {})
|
164
|
-
width =
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
append_combine_options cmd, combine_options
|
170
|
-
end
|
171
|
-
img = yield(img) if block_given?
|
172
|
-
img
|
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)
|
173
155
|
end
|
174
156
|
end
|
175
157
|
|
@@ -183,37 +165,18 @@ module CarrierWave
|
|
183
165
|
# [width (Integer)] the width to scale the image to
|
184
166
|
# [height (Integer)] the height to scale the image to
|
185
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
|
186
169
|
#
|
187
170
|
# === Yields
|
188
171
|
#
|
189
172
|
# [MiniMagick::Image] additional manipulations to perform
|
190
173
|
#
|
191
|
-
def resize_to_fill(width, height, gravity = 'Center', combine_options: {})
|
192
|
-
width =
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
if width != cols || height != rows
|
198
|
-
scale_x = width/cols.to_f
|
199
|
-
scale_y = height/rows.to_f
|
200
|
-
if scale_x >= scale_y
|
201
|
-
cols = (scale_x * (cols + 0.5)).round
|
202
|
-
rows = (scale_x * (rows + 0.5)).round
|
203
|
-
cmd.resize "#{cols}"
|
204
|
-
else
|
205
|
-
cols = (scale_y * (cols + 0.5)).round
|
206
|
-
rows = (scale_y * (rows + 0.5)).round
|
207
|
-
cmd.resize "x#{rows}"
|
208
|
-
end
|
209
|
-
end
|
210
|
-
cmd.gravity gravity
|
211
|
-
cmd.background "rgba(255,255,255,0.0)"
|
212
|
-
cmd.extent "#{width}x#{height}" if cols != width || rows != height
|
213
|
-
append_combine_options cmd, combine_options
|
214
|
-
end
|
215
|
-
img = yield(img) if block_given?
|
216
|
-
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)
|
217
180
|
end
|
218
181
|
end
|
219
182
|
|
@@ -232,28 +195,18 @@ module CarrierWave
|
|
232
195
|
# [height (Integer)] the height to scale the image to
|
233
196
|
# [background (String, :transparent)] the color of the background as a hexcode, like "#ff45de"
|
234
197
|
# [gravity (String)] how to position the image
|
198
|
+
# [combine_options (Hash)] additional ImageMagick options to apply before resizing
|
235
199
|
#
|
236
200
|
# === Yields
|
237
201
|
#
|
238
202
|
# [MiniMagick::Image] additional manipulations to perform
|
239
203
|
#
|
240
|
-
def resize_and_pad(width, height, background=:transparent, gravity='Center', combine_options: {})
|
241
|
-
width =
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
if background == :transparent
|
247
|
-
cmd.background "rgba(255, 255, 255, 0.0)"
|
248
|
-
else
|
249
|
-
cmd.background background
|
250
|
-
end
|
251
|
-
cmd.gravity gravity
|
252
|
-
cmd.extent "#{width}x#{height}"
|
253
|
-
append_combine_options cmd, combine_options
|
254
|
-
end
|
255
|
-
img = yield(img) if block_given?
|
256
|
-
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)
|
257
210
|
end
|
258
211
|
end
|
259
212
|
|
@@ -284,6 +237,9 @@ module CarrierWave
|
|
284
237
|
# and then pass each of its frames to the supplied block. It will then
|
285
238
|
# save the image to disk.
|
286
239
|
#
|
240
|
+
# NOTE: This method exists mostly for backwards compatibility, you should
|
241
|
+
# probably use #minimagick!.
|
242
|
+
#
|
287
243
|
# === Gotcha
|
288
244
|
#
|
289
245
|
# This method assumes that the object responds to +current_path+.
|
@@ -303,46 +259,75 @@ module CarrierWave
|
|
303
259
|
cache_stored_file! if !cached?
|
304
260
|
image = ::MiniMagick::Image.open(current_path)
|
305
261
|
|
306
|
-
|
307
|
-
|
308
|
-
image = yield(image)
|
309
|
-
image.write(current_path)
|
262
|
+
image = yield(image)
|
263
|
+
FileUtils.mv image.path, current_path
|
310
264
|
|
311
|
-
|
312
|
-
move_to = current_path.chomp(File.extname(current_path)) + ".#{@format}"
|
313
|
-
file.content_type = ::MIME::Types.type_for(move_to).first.to_s
|
314
|
-
file.move_to(move_to, permissions, directory_permissions)
|
315
|
-
end
|
316
|
-
|
317
|
-
image.run_command("identify", current_path)
|
318
|
-
ensure
|
319
|
-
image.destroy!
|
320
|
-
end
|
265
|
+
image.run_command("identify", current_path)
|
321
266
|
rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
|
322
|
-
message
|
267
|
+
raise e if e.message =~ /(You must have .+ installed|is not installed|executable not found)/
|
268
|
+
message = I18n.translate(:"errors.messages.processing_error")
|
323
269
|
raise CarrierWave::ProcessingError, message
|
270
|
+
ensure
|
271
|
+
image.destroy! if image
|
324
272
|
end
|
325
273
|
|
326
|
-
|
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
|
327
298
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
cmd.send(method, options)
|
334
|
-
end
|
335
|
-
end
|
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)
|
336
304
|
end
|
337
305
|
|
338
|
-
|
339
|
-
|
340
|
-
|
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)
|
341
312
|
end
|
313
|
+
rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
|
314
|
+
raise e if e.message =~ /(You must have .+ installed|is not installed|executable not found)/
|
315
|
+
message = I18n.translate(:"errors.messages.processing_error")
|
316
|
+
raise CarrierWave::ProcessingError, message
|
317
|
+
end
|
318
|
+
|
319
|
+
private
|
342
320
|
|
343
|
-
|
344
|
-
|
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
|
345
325
|
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def mini_magick_image
|
329
|
+
::MiniMagick::Image.read(read)
|
330
|
+
end
|
346
331
|
|
347
332
|
end # MiniMagick
|
348
333
|
end # CarrierWave
|
@@ -62,10 +62,12 @@ module CarrierWave
|
|
62
62
|
begin
|
63
63
|
require "rmagick"
|
64
64
|
rescue LoadError
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
65
|
+
begin
|
66
|
+
require "RMagick"
|
67
|
+
rescue LoadError => e
|
68
|
+
e.message << " (You may need to install the rmagick gem)"
|
69
|
+
raise e
|
70
|
+
end
|
69
71
|
end
|
70
72
|
|
71
73
|
prepend Module.new {
|
@@ -109,7 +111,7 @@ module CarrierWave
|
|
109
111
|
#
|
110
112
|
# === Parameters
|
111
113
|
#
|
112
|
-
# [format (#to_s)] an
|
114
|
+
# [format (#to_s)] an abbreviation of the format
|
113
115
|
#
|
114
116
|
# === Yields
|
115
117
|
#
|
@@ -228,13 +230,7 @@ module CarrierWave
|
|
228
230
|
height = dimension_from height
|
229
231
|
manipulate! do |img|
|
230
232
|
img.resize_to_fit!(width, height)
|
231
|
-
|
232
|
-
if background == :transparent
|
233
|
-
filled = new_img.matte_floodfill(1, 1)
|
234
|
-
else
|
235
|
-
filled = new_img.color_floodfill(1, 1, ::Magick::Pixel.from_color(background))
|
236
|
-
end
|
237
|
-
destroy_image(new_img)
|
233
|
+
filled = ::Magick::Image.new(width, height) { |image| image.background_color = background == :transparent ? 'rgba(255,255,255,0)' : background.to_s }
|
238
234
|
filled.composite!(img, gravity, ::Magick::OverCompositeOp)
|
239
235
|
destroy_image(img)
|
240
236
|
filled = yield(filled) if block_given?
|
@@ -363,15 +359,15 @@ module CarrierWave
|
|
363
359
|
if options[:format] || @format
|
364
360
|
frames.write("#{options[:format] || @format}:#{current_path}", &write_block)
|
365
361
|
move_to = current_path.chomp(File.extname(current_path)) + ".#{options[:format] || @format}"
|
366
|
-
file.content_type = ::
|
362
|
+
file.content_type = Marcel::Magic.by_path(move_to).try(:type)
|
367
363
|
file.move_to(move_to, permissions, directory_permissions)
|
368
364
|
else
|
369
365
|
frames.write(current_path, &write_block)
|
370
366
|
end
|
371
367
|
|
372
368
|
destroy_image(frames)
|
373
|
-
rescue ::Magick::ImageMagickError
|
374
|
-
raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.
|
369
|
+
rescue ::Magick::ImageMagickError
|
370
|
+
raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.processing_error")
|
375
371
|
end
|
376
372
|
|
377
373
|
private
|
@@ -0,0 +1,284 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
|
3
|
+
##
|
4
|
+
# This module simplifies manipulation with vips by providing a set
|
5
|
+
# of convenient helper methods. If you want to use them, you'll need to
|
6
|
+
# require this file:
|
7
|
+
#
|
8
|
+
# require 'carrierwave/processing/vips'
|
9
|
+
#
|
10
|
+
# And then include it in your uploader:
|
11
|
+
#
|
12
|
+
# class MyUploader < CarrierWave::Uploader::Base
|
13
|
+
# include CarrierWave::Vips
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# You can now use the provided helpers:
|
17
|
+
#
|
18
|
+
# class MyUploader < CarrierWave::Uploader::Base
|
19
|
+
# include CarrierWave::Vips
|
20
|
+
#
|
21
|
+
# process :resize_to_fit => [200, 200]
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Or create your own helpers with the powerful vips! 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 Vips options at
|
28
|
+
# https://libvips.github.io/libvips/API/current/using-cli.html for more info.
|
29
|
+
#
|
30
|
+
# class MyUploader < CarrierWave::Uploader::Base
|
31
|
+
# include CarrierWave::Vips
|
32
|
+
#
|
33
|
+
# process :radial_blur => 10
|
34
|
+
#
|
35
|
+
# def radial_blur(amount)
|
36
|
+
# vips! do |builder|
|
37
|
+
# builder.radial_blur(amount)
|
38
|
+
# builder = yield(builder) if block_given?
|
39
|
+
# builder
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# === Note
|
45
|
+
#
|
46
|
+
# The ImageProcessing gem uses ruby-vips, a binding for the vips image
|
47
|
+
# library. You can find more information here:
|
48
|
+
#
|
49
|
+
# https://github.com/libvips/ruby-vips
|
50
|
+
#
|
51
|
+
#
|
52
|
+
module Vips
|
53
|
+
extend ActiveSupport::Concern
|
54
|
+
|
55
|
+
included do
|
56
|
+
require "image_processing/vips"
|
57
|
+
# We need to disable caching since we're editing images in place.
|
58
|
+
::Vips.cache_set_max(0)
|
59
|
+
end
|
60
|
+
|
61
|
+
module ClassMethods
|
62
|
+
def convert(format)
|
63
|
+
process :convert => format
|
64
|
+
end
|
65
|
+
|
66
|
+
def resize_to_limit(width, height)
|
67
|
+
process :resize_to_limit => [width, height]
|
68
|
+
end
|
69
|
+
|
70
|
+
def resize_to_fit(width, height)
|
71
|
+
process :resize_to_fit => [width, height]
|
72
|
+
end
|
73
|
+
|
74
|
+
def resize_to_fill(width, height, gravity='centre')
|
75
|
+
process :resize_to_fill => [width, height, gravity]
|
76
|
+
end
|
77
|
+
|
78
|
+
def resize_and_pad(width, height, background=nil, gravity='centre', alpha=nil)
|
79
|
+
process :resize_and_pad => [width, height, background, gravity, alpha]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Changes the image encoding format to the given format
|
85
|
+
#
|
86
|
+
# See https://libvips.github.io/libvips/API/current/using-cli.html#using-command-line-conversion
|
87
|
+
#
|
88
|
+
# === Parameters
|
89
|
+
#
|
90
|
+
# [format (#to_s)] an abbreviation of the format
|
91
|
+
#
|
92
|
+
# === Yields
|
93
|
+
#
|
94
|
+
# [Vips::Image] additional manipulations to perform
|
95
|
+
#
|
96
|
+
# === Examples
|
97
|
+
#
|
98
|
+
# image.convert(:png)
|
99
|
+
#
|
100
|
+
def convert(format, page=nil)
|
101
|
+
vips! do |builder|
|
102
|
+
builder = builder.convert(format)
|
103
|
+
builder = builder.loader(page: page) if page
|
104
|
+
builder
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Resize the image to fit within the specified dimensions while retaining
|
110
|
+
# the original aspect ratio. Will only resize the image if it is larger than the
|
111
|
+
# specified dimensions. The resulting image may be shorter or narrower than specified
|
112
|
+
# in the smaller dimension but will not be larger than the specified values.
|
113
|
+
#
|
114
|
+
# === Parameters
|
115
|
+
#
|
116
|
+
# [width (Integer)] the width to scale the image to
|
117
|
+
# [height (Integer)] the height to scale the image to
|
118
|
+
# [combine_options (Hash)] additional Vips options to apply before resizing
|
119
|
+
#
|
120
|
+
# === Yields
|
121
|
+
#
|
122
|
+
# [Vips::Image] additional manipulations to perform
|
123
|
+
#
|
124
|
+
def resize_to_limit(width, height, combine_options: {})
|
125
|
+
width, height = resolve_dimensions(width, height)
|
126
|
+
|
127
|
+
vips! do |builder|
|
128
|
+
builder.resize_to_limit(width, height)
|
129
|
+
.apply(combine_options)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Resize the image to fit within the specified dimensions while retaining
|
135
|
+
# the original aspect ratio. The image may be shorter or narrower than
|
136
|
+
# specified in the smaller dimension but will not be larger than the specified values.
|
137
|
+
#
|
138
|
+
# === Parameters
|
139
|
+
#
|
140
|
+
# [width (Integer)] the width to scale the image to
|
141
|
+
# [height (Integer)] the height to scale the image to
|
142
|
+
# [combine_options (Hash)] additional Vips options to apply before resizing
|
143
|
+
#
|
144
|
+
# === Yields
|
145
|
+
#
|
146
|
+
# [Vips::Image] additional manipulations to perform
|
147
|
+
#
|
148
|
+
def resize_to_fit(width, height, combine_options: {})
|
149
|
+
width, height = resolve_dimensions(width, height)
|
150
|
+
|
151
|
+
vips! do |builder|
|
152
|
+
builder.resize_to_fit(width, height)
|
153
|
+
.apply(combine_options)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# Resize the image to fit within the specified dimensions while retaining
|
159
|
+
# the aspect ratio of the original image. If necessary, crop the image in the
|
160
|
+
# larger dimension.
|
161
|
+
#
|
162
|
+
# === Parameters
|
163
|
+
#
|
164
|
+
# [width (Integer)] the width to scale the image to
|
165
|
+
# [height (Integer)] the height to scale the image to
|
166
|
+
# [combine_options (Hash)] additional vips options to apply before resizing
|
167
|
+
#
|
168
|
+
# === Yields
|
169
|
+
#
|
170
|
+
# [Vips::Image] additional manipulations to perform
|
171
|
+
#
|
172
|
+
def resize_to_fill(width, height, _gravity = nil, combine_options: {})
|
173
|
+
width, height = resolve_dimensions(width, height)
|
174
|
+
|
175
|
+
vips! do |builder|
|
176
|
+
builder.resize_to_fill(width, height).apply(combine_options)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Resize the image to fit within the specified dimensions while retaining
|
182
|
+
# the original aspect ratio. If necessary, will pad the remaining area
|
183
|
+
# with the given color, which defaults to transparent (for gif and png,
|
184
|
+
# white for jpeg).
|
185
|
+
#
|
186
|
+
# See https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsCompassDirection
|
187
|
+
# for gravity options.
|
188
|
+
#
|
189
|
+
# === Parameters
|
190
|
+
#
|
191
|
+
# [width (Integer)] the width to scale the image to
|
192
|
+
# [height (Integer)] the height to scale the image to
|
193
|
+
# [background (List, nil)] the color of the background as a RGB, like [0, 255, 255], nil indicates transparent
|
194
|
+
# [gravity (String)] how to position the image
|
195
|
+
# [alpha (Boolean, nil)] pad the image with the alpha channel if supported
|
196
|
+
# [combine_options (Hash)] additional vips options to apply before resizing
|
197
|
+
#
|
198
|
+
# === Yields
|
199
|
+
#
|
200
|
+
# [Vips::Image] additional manipulations to perform
|
201
|
+
#
|
202
|
+
def resize_and_pad(width, height, background=nil, gravity='centre', alpha=nil, combine_options: {})
|
203
|
+
width, height = resolve_dimensions(width, height)
|
204
|
+
|
205
|
+
vips! do |builder|
|
206
|
+
builder.resize_and_pad(width, height, background: background, gravity: gravity, alpha: alpha)
|
207
|
+
.apply(combine_options)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
# Returns the width of the image in pixels.
|
213
|
+
#
|
214
|
+
# === Returns
|
215
|
+
#
|
216
|
+
# [Integer] the image's width in pixels
|
217
|
+
#
|
218
|
+
def width
|
219
|
+
vips_image.width
|
220
|
+
end
|
221
|
+
|
222
|
+
##
|
223
|
+
# Returns the height of the image in pixels.
|
224
|
+
#
|
225
|
+
# === Returns
|
226
|
+
#
|
227
|
+
# [Integer] the image's height in pixels
|
228
|
+
#
|
229
|
+
def height
|
230
|
+
vips_image.height
|
231
|
+
end
|
232
|
+
|
233
|
+
# Process the image with vip, using the ImageProcessing gem. This
|
234
|
+
# method will build a "convert" vips command and execute it on the
|
235
|
+
# current image.
|
236
|
+
#
|
237
|
+
# === Gotcha
|
238
|
+
#
|
239
|
+
# This method assumes that the object responds to +current_path+.
|
240
|
+
# Any class that this module is mixed into must have a +current_path+ method.
|
241
|
+
# CarrierWave::Uploader does, so you won't need to worry about this in
|
242
|
+
# most cases.
|
243
|
+
#
|
244
|
+
# === Yields
|
245
|
+
#
|
246
|
+
# [ImageProcessing::Builder] use it to define processing to be performed
|
247
|
+
#
|
248
|
+
# === Raises
|
249
|
+
#
|
250
|
+
# [CarrierWave::ProcessingError] if processing failed.
|
251
|
+
def vips!
|
252
|
+
builder = ImageProcessing::Vips.source(current_path)
|
253
|
+
builder = yield(builder)
|
254
|
+
|
255
|
+
result = builder.call
|
256
|
+
result.close
|
257
|
+
|
258
|
+
FileUtils.mv result.path, current_path
|
259
|
+
|
260
|
+
if File.extname(result.path) != File.extname(current_path)
|
261
|
+
move_to = current_path.chomp(File.extname(current_path)) + File.extname(result.path)
|
262
|
+
file.content_type = Marcel::Magic.by_path(move_to).try(:type)
|
263
|
+
file.move_to(move_to, permissions, directory_permissions)
|
264
|
+
end
|
265
|
+
rescue ::Vips::Error
|
266
|
+
message = I18n.translate(:"errors.messages.processing_error")
|
267
|
+
raise CarrierWave::ProcessingError, message
|
268
|
+
end
|
269
|
+
|
270
|
+
private
|
271
|
+
|
272
|
+
def resolve_dimensions(*dimensions)
|
273
|
+
dimensions.map do |value|
|
274
|
+
next value unless value.instance_of?(Proc)
|
275
|
+
value.arity >= 1 ? value.call(self) : value.call
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def vips_image
|
280
|
+
::Vips::Image.new_from_buffer(read, "")
|
281
|
+
end
|
282
|
+
|
283
|
+
end # Vips
|
284
|
+
end # CarrierWave
|