Getting "is invalid" error with Arc library in Phoenix application when using transform

I am using the Arc library for uploading images to my website, and right now I can upload the original image just fine, but when I use an imagemagick transform to try to get a thumbnail from an image, I get an “is invalid” error.

Here is what the form looks like for uploading an image

  <div class="form-group">
    <%= label f, "Profile picture", class: "control-label" %>
    <%= file_input f, :avatar, class: "form-control" %>
    <%= error_tag f, :avatar %>
  </div>

And here is my Arc definition

  use Arc.Definition

  # Include ecto support (requires package arc_ecto installed):
  use Arc.Ecto.Definition

  def __storage, do: Arc.Storage.Local

  @versions [:original, :thumb]

  # To add a thumbnail version:
  # @versions [:original, :thumb]

  # Whitelist file extensions:
  def validate({file, _}) do
    ~w(.jpg .jpeg .gif .png) |> Enum.member?(Path.extname(file.file_name))
  end

  # Define a thumbnail transformation:
  def transform(:thumb, _) do
    {:convert, "-strip -thumbnail 100x100^ -gravity center -extent 100x100"}
  end

If I comment out the transform the image uploads fine. Do I need imagemagick installed on my computer in order to do a transform? I installed it but no luck. There is no documentation saying it needs to be installed either, so is it built into the library or as a dependency of the library?

What’s the error that you are getting? Is it an ecto changeset “error” or an actual error?

The error appears in the error_tag for the file_input field in the form that just says “is invalid”. Debug in the console shows no issues.

Could you maybe put an IO.inspect into this function?

def validate({file, _}) do
  IO.inspect(file, label: "validate")
  ~w(.jpg .jpeg .gif .png) |> Enum.member?(Path.extname(file.file_name))
end

Since the changeset error is just “is invalid”, this validate/1 might be returning false (instead of true, then there would be no error).

In case you are not quite yet familiar with elixir’s “ecosystem”, the changeset I keep referring to is https://hexdocs.pm/ecto/Ecto.Changeset.html. arc_ecto uses it to tie up your web form with your database via your app logic in your second code snippet.

I get

validate: %Arc.File{
  binary: nil,
  file_name: "1509807073408.jpg",
  path: "C:\\Users\\Name\\AppData\\Local\\Temp/plug-1522/multipart-1522007094-204586561876438-4"
}

When I leave the validate there and only comment out the transform and remove the :thumb version it works just fine, so I don’t think it’s the validate.

Hm, it does have the right extension (".jpg"), so the validate/1 should return true … I expected there to be two calls to this function, with one of them being with an “invalid” extension (from transform/1).

Here is the schema and changeset where I am storing the avatar if it happens to be happening here at all.

schema "users" do
    field :email, :string
    field :password_hash, :string
    field :username, :string
    field :nickname, :string
    field :avatar, WatchTogether.Avatar.Type
    #has_one :avatar, WatchTogether.Accounts.Avatar
    has_one :room, WatchTogether.Rooms.Room
    # virtual fields
    field :password, :string, virtual: true

    timestamps()
  end

  @doc false
  def changeset(user, attrs) do
    user
    |> cast(attrs, [:email, :username, :password])
    |> cast_assoc(:room, required: true)
    |> cast_attachments(attrs, [:avatar])
    #|> cast_assoc(:avatar)
    |> validate_required([:email, :username, :password])
    |> unique_constraint(:email)
    |> unique_constraint(:username)
    |> downcase_username
    |> downcase_email
    |> hash_password
  end

And :avatar is the field which gets the “invalid” error? I don’t see any problems here.

Yes. I just tried uploading an exe to see if the application responds different and it responds in the same way.

try to change the @versions to only original and try again, remove :thumb
if the error is gone, the changes are big that it is a imagemagick problem.

Arc calls convert (imagemagick) to resize the images

@versions [:original]

I have changed it to just :original and it works fine like that, but the problem is there is no documentation saying I need imagemagick installed or how it needs to be setup or anything. I used the installer from the website but it hasn’t fixed anything. How can I begin to debug it as an imagemagick problem?

It needs to be installed, try to run convert from the command line

on my machine …

➜ $ convert
Version: ImageMagick 7.0.7-22 Q16 x86_64 2018-01-22 http://www.imagemagick.org
Copyright: © 1999-2018 ImageMagick Studio LLC

I just ran magick convert 1509807073408.jpg -strip -thumbnail 100x100^ -gravity center -extent 100x100 output.jpg and it worked just fine. So it is in my path and works there.

magick convert is not convert…

{:convert, "-strip -thumbnail 100x100^ -gravity center -extent 100x100"}

This will call convert.

I guess You are on windows because You send exe files.

http://documentation.veremes.net/public/veremap.pro/installation/ImageMagick/ImageMagick-win.html

If You do install imagemagick for windows, You should have the convert command too.

Also

    |> unique_constraint(:email)
    |> unique_constraint(:username)
    |> downcase_username
    |> downcase_email

You might not catch unique constraint correctly like this. One way is to revert order in pipe, or use citext extension for postgresql.

I am on windows. Convert is a program on windows to convert filesystem types so that is definitely NOT what I want to be running. Will the syntax be different if I am running off of windows rather than :convert?

Maybe

{:magick, "convert -strip -thumbnail 100x100^ -gravity center -extent 100x100"}

But I am not a windows user…

You could also find the convert.exe, rename it, and use new name?!

I actually just tried to change it to {:magick, "convert -strip -thumbnail 100x100^ -gravity center -extent 100x100"} but now I am getting ** (Arc.MissingExecutableError) Cannot locate executable: magick in git-bash but if I run the application from CMD I get same error with is invalid

On Unix, You can

$ which convert
/usr/local/bin/convert

I think the windows equivalent is where. Try

where /?
where convert.*

Windows 10 will apparently not let me modify the name of a system32 executable, even as admin unfortunately.

Problem solved. Changed my transform function to

def transform(:thumb, _) do
  {:magick, fn(input, output) -> "convert #{input} -strip -thumbnail 100x100^ -gravity center -extent 100x100 #{output}" end}
end

But now my application won’t be multiplatform, will it?