如何在不使用磁盘临时文件的情况下结合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格式
- SVG文件调用ActiveStorage的
- 当前实现痛点:通过异步任务处理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
相关产品推荐
相关产品推荐

