我想在 webp
中转换用户上传的图像以提高网站性能。我知道 webp
现在只支持两种浏览器, Google Chrome
和 Opera
。
我正在使用 carrierwave
将图像上传到 s3
。
在 webp
中找不到任何将图像转换为 carrierwave
的支持。image-magick
有库 libwebp
可以将图像转换为 webp
。
Rails 中有这样的 gem 吗?
如何将图像转换为 carrierwave
并保存。carrierwave
以外的解决方案也有效。
最佳答案
我有类似的任务,但没有上传到 S3。
我使用 webp-ffi gem 编写自定义转换器。
这是我的解决方案,对我有帮助。
首先,您需要安装 requirements gem 的 README 文件中指定的 webp-ffi。
之后将 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 = {})
# Build path for new file
webp_path = "#{path}.webp"
# Encode (convert) image to webp format with passed options
WebP.encode(path, webp_path, options)
# HACK: Changing of this two instance variables is the only way
# I found to make CarrierWave save new file that was created
# by encoding original image.
@filename = webp_path.split('/').pop
@file = CarrierWave::SanitizedFile.new(
tempfile: webp_path,
filename: webp_path,
content_type: 'image/webp'
)
end
end
您可以将此方法移动到位于项目中的某个模块(确保它正确地 autoload)。例如,我将此代码放在
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
但是如果你需要存储文件的原始版本并在上传器中创建一个版本,你将需要使用这个 hack:
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 对我不起作用)。
还可以查看我为演示工作解决方案而制作的 simple app。
关于ruby-on-rails - 如何在 ruby on rails 中将用户上传的图像转换为 webp,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49901480/