File uploads, access File binary

The context is I upload files and I want to access to the File object (the one you normally get in the browser with event.target.files. I want to do some work on it with the Image or Vix library, something like Vix.Vips.Image.new_from_buffer (no idea if this works at this stage).

The file input is captured in the live_file_input under the attribute uploads. I want to access it in the handle_event("validate"...) stage. It must be accessible somehow since it is pre-rendered, probably via a createObjectURL. If I inspect the socket.assigns at this stage, I don’t find any binary, mostly metadata. Is this accessible at this stage? Or if not, where is the binary of the file accessible?

I tried a few of the keys below:

get_in(socket.assigns, [:uploads, :image_list]) |> Map.keys()
[:external, :name, :accept, :chunk_size, :writer, :__struct__, :errors, :ref,
 :max_entries, :max_file_size, :cid, :entries, :auto_upload?, :progress_event,
 :allowed?, :chunk_timeout, :entry_refs_to_metas, :acceptable_types,
 :acceptable_exts, :client_key, :entry_refs_to_pids]

The entries doesn’t seem to include a binary.

  %Phoenix.LiveView.UploadEntry{
    progress: 0,
    preflighted?: false,
    upload_config: :image_list,
    upload_ref: "phx-F4EePzKBzRijVC6C",
    ref: "0",
    uuid: "3b4fa1c5-ba8a-41d5-adbb-ed4b274b12ad",
    valid?: true,
    done?: false,
    cancelled?: false,
    client_name: "Screenshot 2023-08-04 at 21.04.26.png",
    client_relative_path: "",
    client_size: 16701,
    client_type: "image/png",
    client_last_modified: 1691175871713
  }
]

If you’re using live view uploads, then you can get access to the binary in the consume_uploaded_entry(ies) to work with the Image library. That’s one way I know of and how I currently do it in Metamorphic to encrypt the avatar blob for people.

You can also try the method described in this posting, depending on your use case.

On phone :slight_smile:

I tried consume_uploaded_entries from the “save” stage but this expects the progress to be true or equivalent, and fails in the “validate” stage. I will look at the post you mention.

Is that the case with auto_upload: true set?

Yes, in the “validate” stage,

(ArgumentError) cannot consume uploaded files when entries are still in progress

It also appears consumed in the “save” stage. Only meta in entry. It only appears in the client Uploaders.S3 as a {file: File} blob.

Maybe the handle_progress can help.

Files being available to the client doesn‘t mean they‘re available on the server. You need to upload the file (not just select it for upload) before it‘s available on the server.

Depending on what you‘re doing the new UploadWriter support might be useful.

1 Like

Yes, indeed, I was presuming. I don’t necessarily want to save it, but I want to process the image. Plenty of solutions. Could be easier to save it on S3 and use the URL. This UploadWriter could useful too, and I see the Fly.io post talks about it. Thks.

To process it it needs to be stored somewhere. Even if just in memory. It doesn‘t need to be stored permanently though.

Yes, memory, When I meant “save”, it was on disk, local or S3.

@f0rest8 @LostKobrakai, thanks. UploadWriter works like a charm in the handle_progress to do what I want.

@impl true
  def write_chunk(data, state) do
    {:ok,
     state
     |> Map.update!(:total_size, &(&1 + byte_size(data)))
     |> Map.update!(:file, &(&1 <> data))}
  end

and then:

defp handle_progress(:image_list, entry, socket) do
    alias Vix.Vips.Image
    alias Vix.Vips.Operation

    if entry.done? do
      uploaded_file =
        consume_uploaded_entry(
           socket, entry, fn %{file: file, total_size: total_size} -> 
        case entry.client_size == total_size do
           true -> 
             {:ok, img} = Vix.Vips.Image.new_from_buffer(file)
             ....
2 Likes