如何在Ruby on Rails中将用户上传的图像转换为WebP格式

4

我想将用户上传的图像转换为 webp 以提高网站性能。我知道目前只有两个浏览器,Google ChromeOpera 支持 webp 格式。

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

carrierwave 中没有找到任何支持将图像转换为 webp 的功能。

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

是否有适用于 Rails 的相应 gem?

我该如何将图像转换为 carrierwave 并将其保存。除了使用 carrierwave,也可以考虑其他解决方案。


1
也许可以在 https://github.com/rmagick-temp/rmagick 上找到 RMagick,同时还需要下载 https://developers.google.com/speed/webp/download 上的 webp 委托库。 - fmw42
但是在carrierwave中是否支持它呢? - Waqas Ahad
抱歉,我不了解Carrierwave以及它如何使用Imagemagick。 - fmw42
@WaqasAhad,你有进展吗? - Chris Edwards
@ChrisEdwards 还没有...如果你找到了,请也告诉我一声。 - Waqas Ahad
2个回答

7

我曾有类似的任务,但没有上传到 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 = {})
    # 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 对我没有起作用)。

还要查看我制作的 简单应用程序,以演示工作解决方案。


优秀的解决方案,但它没有删除图像。 - cool_php
不行,这是webp格式的图片。我必须使用单独的回调方法来清理它。 - cool_php

0
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

在ImageUploader中

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

根据浏览器提供不同的格式 gem 'browser'

在视图中:

<%= 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接