我曾有类似的任务,但没有上传到 S3。我使用 webp-ffi gem 编写了自定义转换器。
这是帮助我的解决方案。
首先,您需要安装 webp-ffi gem 中 README 文件中指定的 requirements。
之后,将 webp-ffi gem 添加到您的项目中:
gem 'webp-ffi'
如果您不需要存储原始图像,您可以向上传程序添加自定义方法,并使用CarrierWave的process方法调用它。这是我将图像转换为WebP格式的技巧:
class MyImageUploader < CarrierWave::Uploader::Base
storage :file
process convert_to_webp: [{ quality: 80, method: 5 }]
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
private
def convert_to_webp(options = {})
webp_path = "#{path}.webp"
WebP.encode(path, webp_path, options)
@filename = webp_path.split('/').pop
@file = CarrierWave::SanitizedFile.new(
tempfile: webp_path,
filename: webp_path,
content_type: 'image/webp'
)
end
end
您可以将此方法移动到位于项目中的某个模块中(确保它能够正确地自动加载)。例如,我将此代码放在app/services/web_p_converter.rb
中:
module WebPConverter
def convert_to_webp(options = {})
webp_path = "#{path}.webp"
WebP.encode(path, webp_path, options)
@filename = webp_path.split('/').pop
@file = CarrierWave::SanitizedFile.new(
tempfile: webp_path,
filename: webp_path,
content_type: 'image/webp'
)
end
end
现在我可以在需要WebP转换的每个上传器中包含此模块:
class MyImageUploader < CarrierWave::Uploader::Base
include WebPConverter
storage :file
process convert_to_webp: [{ quality: 80, method: 5 }]
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
但是,如果您需要存储文件的原始版本并在上传程序中创建一个版本,则需要使用此技巧:
class MyImageUploader < CarrierWave::Uploader::Base
include WebPConverter
storage :file
version :webp do
process convert_to_webp: [{ quality: 80, method: 5 }]
def full_filename(file)
return "#{version_name}_#{filename}" if filename.split('.').last == 'webp'
"#{version_name}_#{file}.webp"
end
end
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
这必须完成,因为CarrierWave使用原始图像名称来构建其他版本的路径。
另外,您可以将#full_filename中的逻辑移到方法中。例如,我将构建完整文件名的逻辑移动到WebPConverter模块中,因此它看起来像这样:
module WebPConverter
def build_webp_full_filename(filename, version_name)
return "#{version_name}_#{filename}" if filename.split('.').last == 'webp'
"#{version_name}_#{filename}.webp"
end
end
从现在开始,我可以将需要转换为webp的版本使用它:
class MyImageUploader < CarrierWave::Uploader::Base
include WebPConverter
storage :file
version :webp do
process convert_to_webp: [{ quality: 80, method: 5 }]
def full_filename(file)
build_webp_full_filename(file, version_name)
end
end
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
请查看我用作示例来创建解决此问题的解决方案的 carrierwave-webp gem(由于某些原因,这个 gem 对我没有起作用)。
还要查看我制作的 简单应用程序,以演示工作解决方案。