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

时间:2018-04-18 13:50:43

标签: ruby-on-rails image-processing imagemagick carrierwave webp

我想转换用户在webp上传图片以获取网站效果。我知道webp现在只支持两种浏览器,Google ChromeOpera

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

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

image-magick有图书馆libwebp,可以将图片转换为webp

铁轨中是否有任何宝石?

如何将图片转换为carrierwave并保存。 <{1}}以外的解决方案也有效。

2 个答案:

答案 0 :(得分:0)

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

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

首先,您需要安装requirements gem的README文件中指定的webp-ffi

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

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

您可以将此方法移至项目中的某个模块(确保正确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

但是,如果您需要存储文件的原始版本并在上载器中创建版本,则需要使用此技巧:

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

我以示例使用Checkout carrierwave-webp宝石来创建此问题的解决方案(出于某种原因,该宝石对我不起作用)。

还要结帐我为演示有效解决方案而制作的simple app

答案 1 :(得分: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

,并根据浏览器提供不同的格式 宝石“浏览器”

观看次数:

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