You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用磁盘临时文件的情况下结合Active Storage Blob与image_processing

问题背景
  • 技术栈:Rails 7.2.1.1、Ruby 3.3.5,Gemfile引入gem "image_processing", "~> 1.13.0"
  • 业务需求:表单支持上传jpeg、png、gif、webp、svg格式的公司logo
  • 待解决的技术问题:
    • SVG文件调用ActiveStorage的.variant方法时,会抛出ActiveStorage::InvariableError,需将SVG转换为PNG
    • .jfif格式文件(内容类型为image/jpeg)通过Vips调整尺寸时失败,需转换为标准JPEG格式
  • 当前实现痛点:通过异步任务处理S3存储的图片时,必须创建并删除两个本地临时文件,既冗余又低效
现有代码实现

Company模型代码

class Company < ApplicationRecord # :nodoc:
  has_one_attached :logo do |attachable|
    attachable.variant :medium, resize_to_fit: [300, nil]
    attachable.variant :large, resize_to_fit: [700, nil]
  end

  after_save :company_logos_job, if: :logos_changed?

  private
    def company_logos_job
      CompanyLogoJob.perform_later(id)
    end

    def logos_changed?
      true # implement later, slightly tricky
    end
end

CompanyLogoJob任务代码

# This job runs after any change to the logo on a company object.
# It will convert the image to a png if it is an svg, and create the variants.
class CompanyLogoJob < ApplicationJob
  queue_as :latency_5m

  def perform(id)
    company = Company.find(id)

    if company.logo_light.attached?
      convert_svg_to_png(company.logo_light) if company.logo_light.content_type == "image/svg+xml"

      company.logo_light :medium
      company.logo_light :large
    end
  end

  def convert_svg_to_png(image)
    filename = image.filename.to_s

    # I've had to create a tempfile to get the image accepted by .source
    Tempfile.create(["temp_image", ".svg"]) do |tempfile|
      tempfile.write(image.download)
      tempfile.rewind

      # use VIPS to convert svg to png
      png = ImageProcessing::Vips.source(tempfile.path)
        .loader(loader: :svg)
        .convert("png")
        .resize_to_fit(700, nil)
        .call

      png_file = File.open(png.path, "rb")
      image.purge
      image.attach(io: StringIO.new(png_file.read), filename: "#{filename}.png", content_type: "image/png")

      png_file.close
      File.delete(png.path)
      tempfile.close
      File.delete(tempfile.path)
    end
  end
end
核心疑问

是否存在无需保存本地临时文件,直接将Blob数据传入ImageMagick或Vips进行处理的方案?可选用Vips、ImageMagick,甚至弃用image_processing gem,需要相关实现思路或具体方案。

内容的提问来源于stack exchange,提问作者NGobin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 06:42:41