Display preview of images to be uploaded

In Elm, I had an image upload app where I would convert the image files to base64 using the FileReader.readAsDataURL function. After the file is selected, I would call through a port into JS-land to do the FileReader operation, and then call back into the Elm app to return the base-64-converted value via a Message to the Elm app.

I’ve been trying to do a similar thing in Seed, but I’m failing in different ways

My last attempt was this JavaScript function:

<script>
function read_base64(file) {
    return new Promise((resolve, reject) => {
        var fr = new FileReader();  
        fr.onload = (function(event) {
            var base64encoded = event.target.result;
            resolve(i, base64encoded);
        });
        fr.readAsDataURL(file);
    });
};
</script>

But I can’t seem to manage to call it from Rust:

extern "C" {
    fn read_base64(i: usize, file: seed::prelude::web_sys::File) -> js_sys::Promise;
}
...
let base64 =
  wasm_bindgen_futures::JsFuture::from(unsafe { read_base64(i, file) })
  .await
  .expect("read file")
  .as_string()
  .expect("cast file text to String");;

Right now, I’m wondering… is this even worth the effort to try to show image previews before uploading, or should I just upload to a temporary folder on the server and show the preview from there? This would mean having to clean out the temporary files on the server regularly and potentially placing a higher load on the server, but it would be trivial to implement and could make the actual file upload operation complete faster (pretty much instantly, as all uploads already happened for the preview) from the perspective of the user.

Mostly, I’m looking for opinions on how image upload preview should be done in general, both from a perspective of having maintainable code and from the perspective of giving a good experience to the user who does the image upload.

One thing that I’m pretty sure about is that users should be able to drag and drop images from a folder of their Desktop computer right into the page, so I need to handle multiple uploads.

Hi @sabine!

I’ve modified the older example drop_zone to show multiple image previews instead of texts - https://github.com/seed-rs/seed/compare/master...MartinKavik:demo/image_previews. (You can clone it and run with cargo make start drop_zone from the repo root.)

There are only a few edge-cases where you have to write JS scripts (e.g. some workers) - try to use Rust everywhere.

Normally, I would suggest to use web_sys::FileReader::read_as_data_url, however it’s a bit painful to use because of weird JS API design decisions. Fortunately there is a wrapper for Blob / File / FileList and FileReader that wraps functions like read_as_data_url to callbacks and especially to Futures - crate gloo_file. (gloo-file is also used to improve Seed WebSocket API). See the linked example above for inspiration.

Hope it helps!
Martin

That helps a lot, thanks!

Exactly, I didn’t manage to do this with web_sys::FileReader::read_as_data_url and felt that everything I tried was too complicated anyways (more complicated than just writing JavaScript and trying to call that from Rust, any case - but even that turned out to be not as trivial as I guessed).