mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Extract transformers
This commit is contained in:
parent
924f443716
commit
697f4a93ad
6 changed files with 146 additions and 70 deletions
|
@ -101,14 +101,8 @@ class ActiveStorage::Variant
|
|||
end
|
||||
end
|
||||
|
||||
def transform(image)
|
||||
result = variation.transform(image, format: format)
|
||||
|
||||
begin
|
||||
yield result
|
||||
ensure
|
||||
result.close!
|
||||
end
|
||||
def transform(image, &block)
|
||||
variation.transform(image, format: format, &block)
|
||||
end
|
||||
|
||||
def upload(file)
|
||||
|
|
|
@ -47,13 +47,9 @@ class ActiveStorage::Variation
|
|||
# saves the transformed image into a temporary file. If +format+ is specified
|
||||
# it will be the format of the result image, otherwise the result image
|
||||
# retains the source format.
|
||||
def transform(file, format: nil)
|
||||
def transform(file, format: nil, &block)
|
||||
ActiveSupport::Notifications.instrument("transform.active_storage") do
|
||||
if processor
|
||||
image_processing_transform(file, format)
|
||||
else
|
||||
mini_magick_transform(file, format)
|
||||
end
|
||||
transformer.transform(file, format: format, &block)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -63,63 +59,22 @@ class ActiveStorage::Variation
|
|||
end
|
||||
|
||||
private
|
||||
# Applies image transformations using the ImageProcessing gem.
|
||||
def image_processing_transform(file, format)
|
||||
operations = transformations.each_with_object([]) do |(name, argument), list|
|
||||
if name.to_s == "combine_options"
|
||||
ActiveSupport::Deprecation.warn("The ImageProcessing ActiveStorage variant backend doesn't need :combine_options, as it already generates a single MiniMagick command. In Rails 6.1 :combine_options will not be supported anymore.")
|
||||
list.concat argument.keep_if { |key, value| value.present? }.to_a
|
||||
elsif argument.present?
|
||||
list << [name, argument]
|
||||
def transformer
|
||||
if ActiveStorage.variant_processor
|
||||
begin
|
||||
require "image_processing"
|
||||
rescue LoadError
|
||||
ActiveSupport::Deprecation.warn <<~WARNING
|
||||
Generating image variants will require the image_processing gem in Rails 6.1.
|
||||
Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.
|
||||
WARNING
|
||||
|
||||
ActiveStorage::Transformers::MiniMagickTransformer.new(transformations)
|
||||
else
|
||||
ActiveStorage::Transformers::ImageProcessingTransformer.new(transformations)
|
||||
end
|
||||
end
|
||||
|
||||
processor
|
||||
.source(file)
|
||||
.loader(page: 0)
|
||||
.convert(format)
|
||||
.apply(operations)
|
||||
.call
|
||||
end
|
||||
|
||||
# Applies image transformations using the MiniMagick gem.
|
||||
def mini_magick_transform(file, format)
|
||||
image = MiniMagick::Image.new(file.path, file)
|
||||
|
||||
transformations.each do |name, argument_or_subtransformations|
|
||||
image.mogrify do |command|
|
||||
if name.to_s == "combine_options"
|
||||
argument_or_subtransformations.each do |subtransformation_name, subtransformation_argument|
|
||||
pass_transform_argument(command, subtransformation_name, subtransformation_argument)
|
||||
end
|
||||
else
|
||||
pass_transform_argument(command, name, argument_or_subtransformations)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
image.format(format) if format
|
||||
|
||||
image.tempfile.tap(&:open)
|
||||
end
|
||||
|
||||
# Returns the ImageProcessing processor class specified by `ActiveStorage.variant_processor`.
|
||||
def processor
|
||||
begin
|
||||
require "image_processing"
|
||||
rescue LoadError
|
||||
ActiveSupport::Deprecation.warn("Using mini_magick gem directly is deprecated and will be removed in Rails 6.1. Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.")
|
||||
return nil
|
||||
end
|
||||
|
||||
ImageProcessing.const_get(ActiveStorage.variant_processor.to_s.camelize) if ActiveStorage.variant_processor
|
||||
end
|
||||
|
||||
def pass_transform_argument(command, method, argument)
|
||||
if argument == true
|
||||
command.public_send(method)
|
||||
elsif argument.present?
|
||||
command.public_send(method, argument)
|
||||
else
|
||||
ActiveStorage::Transformers::MiniMagickTransformer.new(transformations)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,4 +50,12 @@ module ActiveStorage
|
|||
mattr_accessor :variable_content_types, default: []
|
||||
mattr_accessor :content_types_to_serve_as_binary, default: []
|
||||
mattr_accessor :service_urls_expire_in, default: 5.minutes
|
||||
|
||||
module Transformers
|
||||
extend ActiveSupport::Autoload
|
||||
|
||||
autoload :Transformer
|
||||
autoload :ImageProcessingTransformer
|
||||
autoload :MiniMagickTransformer
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "image_processing"
|
||||
|
||||
module ActiveStorage
|
||||
module Transformers
|
||||
class ImageProcessingTransformer < Transformer
|
||||
private
|
||||
def process(file, format:)
|
||||
processor.
|
||||
source(file).
|
||||
loader(page: 0).
|
||||
convert(format).
|
||||
apply(operations).
|
||||
call
|
||||
end
|
||||
|
||||
def processor
|
||||
ImageProcessing.const_get(ActiveStorage.variant_processor.to_s.camelize)
|
||||
end
|
||||
|
||||
def operations
|
||||
transformations.each_with_object([]) do |(name, argument), list|
|
||||
if name.to_s == "combine_options"
|
||||
ActiveSupport::Deprecation.warn <<~WARNING
|
||||
Active Storage's ImageProcessing transformer doesn't support :combine_options,
|
||||
as it always generates a single ImageMagick command. Passing :combine_options will
|
||||
not be supported in Rails 6.1.
|
||||
WARNING
|
||||
|
||||
list.concat argument.keep_if { |key, value| value.present? }.to_a
|
||||
elsif argument.present?
|
||||
list << [ name, argument ]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "mini_magick"
|
||||
|
||||
module ActiveStorage
|
||||
module Transformers
|
||||
class MiniMagickTransformer < Transformer
|
||||
private
|
||||
def process(file, format:)
|
||||
image = MiniMagick::Image.new(file.path, file)
|
||||
|
||||
transformations.each do |name, argument_or_subtransformations|
|
||||
image.mogrify do |command|
|
||||
if name.to_s == "combine_options"
|
||||
argument_or_subtransformations.each do |subtransformation_name, subtransformation_argument|
|
||||
pass_transform_argument(command, subtransformation_name, subtransformation_argument)
|
||||
end
|
||||
else
|
||||
pass_transform_argument(command, name, argument_or_subtransformations)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
image.format(format) if format
|
||||
|
||||
image.tempfile.tap(&:open)
|
||||
end
|
||||
|
||||
def pass_transform_argument(command, method, argument)
|
||||
if argument == true
|
||||
command.public_send(method)
|
||||
elsif argument.present?
|
||||
command.public_send(method, argument)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
42
activestorage/lib/active_storage/transformers/transformer.rb
Normal file
42
activestorage/lib/active_storage/transformers/transformer.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ActiveStorage
|
||||
module Transformers
|
||||
# A Transformer applies a set of transformations to an image.
|
||||
#
|
||||
# The following concrete subclasses are included in Active Storage:
|
||||
#
|
||||
# * ActiveStorage::Transformers::ImageProcessingTransformer:
|
||||
# backed by ImageProcessing, a common interface for MiniMagick and ruby-vips
|
||||
#
|
||||
# * ActiveStorage::Transformers::MiniMagickTransformer:
|
||||
# backed by MiniMagick, a wrapper around the ImageMagick CLI
|
||||
class Transformer
|
||||
attr_reader :transformations
|
||||
|
||||
def initialize(transformations)
|
||||
@transformations = transformations
|
||||
end
|
||||
|
||||
# Applies the transformations to the source image in +file+, producing a target image in the
|
||||
# specified +format+. Yields an open Tempfile containing the target image. Closes and unlinks
|
||||
# the output tempfile after yielding to the given block. Returns the result of the block.
|
||||
def transform(file, format:)
|
||||
output = process(file, format: format)
|
||||
|
||||
begin
|
||||
yield output
|
||||
ensure
|
||||
output.close!
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
# Returns an open Tempfile containing a transformed image in the given +format+.
|
||||
# All subclasses implement this method.
|
||||
def process(file, format:) #:doc:
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue