如何在Phoenix/Elixir中通过Waffle-Ecto Changeset调整图片尺寸后上传AWS
如何在Waffle-Ecto的Changeset中上传前用ImageMagick处理图片?
你的Schema代码如下:
defmodule App.Images.Image do use Ecto.Schema import Ecto.Changeset use Waffle.Ecto.Schema schema "images" do field(:image, App.ImageUploader.Type) end def changeset(listing, attrs) do listing |> cast_attachments(attrs, [:image]) end end
要实现上传前调整图片尺寸,核心是在Waffle上传器中定义转换逻辑,而非直接修改Changeset。具体步骤如下:
1. 添加依赖
在mix.exs中添加封装ImageMagick的mogrify库:
defp deps do [ {:waffle, "~> 1.1"}, {:waffle_ecto, "~> 0.0.11"}, {:mogrify, "~> 0.9.3"}, {:ex_aws, "~> 2.4"}, {:ex_aws_s3, "~> 2.4"}, {:hackney, "~> 1.18"}, {:sweet_xml, "~> 0.7.3"} ] end
执行mix deps.get安装依赖,同时确保服务器已安装ImageMagick(Ubuntu可执行apt install imagemagick,Mac用brew install imagemagick)。
2. 修改Waffle上传器
调整App.ImageUploader,通过transform/2方法实现图片尺寸转换:
defmodule App.ImageUploader do use Waffle.Definition use Waffle.Ecto.Definition @storage Waffle.Storage.S3 # 验证允许的图片格式 def validate({file, _}) do ext = file.file_name |> Path.extname() |> String.downcase() Enum.member?([".jpg", ".jpeg", ".png", ".gif"], ext) end # 上传前调整图片尺寸:保持宽高比,缩放到最大800x800 def transform(:original, {file, _}) do with {:ok, img} <- Mogrify.open(file.path), {:ok, resized_img} <- Mogrify.resize(img, "800x800>") do {:ok, resized_img.path} else _ -> :skip # 转换失败时上传原文件,可根据需求改为抛出错误 end end # 自定义文件名规则 def filename(version, {file, _}) do "#{version}_#{Path.basename(file.file_name, Path.extname(file.file_name))}" end # S3存储目录 def storage_dir(_version, {_file, _scope}) do "uploads/images" end end
3. 调整Changeset(可选)
如果需要添加必填验证或其他规则,修改原Changeset:
def changeset(listing, attrs) do listing |> cast_attachments(attrs, [:image]) |> validate_required([:image]) end
说明
transform/2会在文件上传到S3前触发,返回处理后的文件路径,Waffle自动上传处理后的版本Mogrify.resize的参数"800x800>"表示保持宽高比,仅当图片超过800x800时才缩放- 若转换失败,当前逻辑会跳过转换直接上传原文件,可根据业务需求调整为抛出错误
内容的提问来源于stack exchange,提问作者mastari
相关产品推荐
相关产品推荐

