如何将用户上传的图像转换为 Ruby on rails 中的 webp



我想转换用户上传的图像,以提高网站性能webp。我知道webp现在只支持两种浏览器,Google ChromeOpera

我正在使用carrierwave将图像上传到s3

carrierwave中找不到将图像转换为webp的任何支持。

image-magick有库libwebp可以将图像转换为webp

轨道上有这样的宝石吗?

如何将图像转换为carrierwave并保存它。carrierwave以外的解决方案也有效。

我有类似的任务,但没有上传到 S3。 我使用 webp-ffi gem 来编写自定义转换器。

这是我帮助我的解决方案。

首先,您需要安装 webp-ffi gem 的自述文件中指定的要求。

之后,将 webp-ffi gem 添加到您的项目中:

gem 'webp-ffi'

如果您不需要存储原始图像,则可以将自定义方法添加到上传器中,并使用CarrierWave的处理方法调用它。这是我将图像转换为 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

您可以将此方法移动到项目中的某个模块(确保它会自动正确加载)。例如,我将这段代码放在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 对我不起作用)。

另请查看我为演示工作解决方案而制作的简单应用程序。

module WebPConverter
private
def build_webp_full_filename(filename, version_name)
return "#{version_name}_#{filename}" if filename.split('.').last == 'webp'
"#{version_name}_#{filename}.webp"
end
end

和在图像上传器

class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
include CarrierWave::WebP::Converter
include WebPConverter
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :thumb do
process resize_to_fit: [50, 50]
end

version :img_quality do
process resize_to_fit: [600, 600]
process quality: 60
end
version :webp do
process convert_to_webp: [{ quality: 60, method: 5 }]
process resize_to_fit: [600, 600]
def full_filename(file)
build_webp_full_filename(file, version_name)
end
end
def extension_whitelist
%w[jpg jpeg gif png]
end
end

并根据浏览器提供不同的格式 宝石"浏览器">

在视图中:

<%= image_tag set_browser(deals_first(@category).brand.logo) %>

助手

def set_browser(object)
browser.chrome? || browser.opera? || browser.platform.android? ? 
object.webp.url : object.quality.url
end

相关内容

  • 没有找到相关文章

最新更新