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
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform(image)
|
def transform(image, &block)
|
||||||
result = variation.transform(image, format: format)
|
variation.transform(image, format: format, &block)
|
||||||
|
|
||||||
begin
|
|
||||||
yield result
|
|
||||||
ensure
|
|
||||||
result.close!
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload(file)
|
def upload(file)
|
||||||
|
|
|
@ -47,13 +47,9 @@ class ActiveStorage::Variation
|
||||||
# saves the transformed image into a temporary file. If +format+ is specified
|
# 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
|
# it will be the format of the result image, otherwise the result image
|
||||||
# retains the source format.
|
# retains the source format.
|
||||||
def transform(file, format: nil)
|
def transform(file, format: nil, &block)
|
||||||
ActiveSupport::Notifications.instrument("transform.active_storage") do
|
ActiveSupport::Notifications.instrument("transform.active_storage") do
|
||||||
if processor
|
transformer.transform(file, format: format, &block)
|
||||||
image_processing_transform(file, format)
|
|
||||||
else
|
|
||||||
mini_magick_transform(file, format)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,63 +59,22 @@ class ActiveStorage::Variation
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
# Applies image transformations using the ImageProcessing gem.
|
def transformer
|
||||||
def image_processing_transform(file, format)
|
if ActiveStorage.variant_processor
|
||||||
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]
|
|
||||||
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
|
begin
|
||||||
require "image_processing"
|
require "image_processing"
|
||||||
rescue LoadError
|
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.")
|
ActiveSupport::Deprecation.warn <<~WARNING
|
||||||
return nil
|
Generating image variants will require the image_processing gem in Rails 6.1.
|
||||||
end
|
Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.
|
||||||
|
WARNING
|
||||||
|
|
||||||
ImageProcessing.const_get(ActiveStorage.variant_processor.to_s.camelize) if ActiveStorage.variant_processor
|
ActiveStorage::Transformers::MiniMagickTransformer.new(transformations)
|
||||||
|
else
|
||||||
|
ActiveStorage::Transformers::ImageProcessingTransformer.new(transformations)
|
||||||
end
|
end
|
||||||
|
else
|
||||||
def pass_transform_argument(command, method, argument)
|
ActiveStorage::Transformers::MiniMagickTransformer.new(transformations)
|
||||||
if argument == true
|
|
||||||
command.public_send(method)
|
|
||||||
elsif argument.present?
|
|
||||||
command.public_send(method, argument)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -50,4 +50,12 @@ module ActiveStorage
|
||||||
mattr_accessor :variable_content_types, default: []
|
mattr_accessor :variable_content_types, default: []
|
||||||
mattr_accessor :content_types_to_serve_as_binary, default: []
|
mattr_accessor :content_types_to_serve_as_binary, default: []
|
||||||
mattr_accessor :service_urls_expire_in, default: 5.minutes
|
mattr_accessor :service_urls_expire_in, default: 5.minutes
|
||||||
|
|
||||||
|
module Transformers
|
||||||
|
extend ActiveSupport::Autoload
|
||||||
|
|
||||||
|
autoload :Transformer
|
||||||
|
autoload :ImageProcessingTransformer
|
||||||
|
autoload :MiniMagickTransformer
|
||||||
|
end
|
||||||
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