Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File.toUrl and uploading images to the server #43

Open
badlydrawnrob opened this issue Oct 5, 2024 · 0 comments
Open

File.toUrl and uploading images to the server #43

badlydrawnrob opened this issue Oct 5, 2024 · 0 comments

Comments

@badlydrawnrob
Copy link
Owner

badlydrawnrob commented Oct 5, 2024

⚠️ If API docs are unhelpful, or customer service is slow — walk away!
🔍 Search for more server options that are reliable (for end-users or devs)

Helpful links

File.toUrl creates a data url: data:[<mediatype>][;base64],<data-string>.
Some services accept this, some only the <data-string> part.

  1. What are Data URLs?
  2. What the f* is a MIME type?
  3. Encoding an image as base64
  4. Decoding base64 to an image
  5. Strip slashes from a json string.
  6. curl post example
  7. curl multi-part /form-data example
  8. What is a binary file?
  9. CORS tester (see "Allowing Cross Origin")

base64 compared to multi-part

I'm not going to get heavy into technical stuff, but read about them in layman's terms, here, or here

I knew nothing of how files are actually stored and transferred so all this is new to me.

base64 is a way to represent files as a string of characters

It can be pasted into the browser search bar, or used in html or css.
Base64 seems a bit simpler to understand than multipart (to me anyway)
You can use a simple Http.post with a url including the image=<base64-string>.

  • It helps a file be transferred within a url with POST method
  • It comes with some downsides:
    • Adds up to 30% to the file-size
    • Will fail with larger file-sizes

Multipart

Is a way to upload files/data to a server in the form of parts which are in bytes.
You can send everything in a multi-part form, including "regular" data also.

You can upload your base64 string using Http.stringPart so you don't have to change your implementation too much. I've uploaded files of up to 3mb but you'll have some lag (seconds or minutes) before the base64 string uploads. Alternatively, multipart allows you to upload files in bits with Http.filePart, so you don't have to convert the image to base64, but it's quite nice to be able to switch between Http.post and Http.request with minimal refactoring.

For either option you can show the <progress> of the file upload to the user using Http.track.

Which do I use?

It depends on the server you're sending to ...

I'm preferring base64 for now which works with both free image server APIs.
We require the <data-string> part, NOT the metadata.

Both freeimage.host and imagebb seem to only require the base64 <data-string> (or an existing image url) to work. Attempting to send @filename.jpg or @base64data.txt hasn't worked in my experience (see curl post example in helpful links).

For freeimage.host you MUST url encode the data (curl uses --data-urlencode), because base64 uses characters like +, /, = which can interfere with the URL (+ is a space character, for instance. There's another option called Base64Url base64url doesn't seem to work freeimage.host.

A working API call:

⚠️ Free Image Host has a big fat CORS error even with an API key (see "Allowing Cross Origin").
This means it's probably not going to work with elm/http (it works with curl).
ImageBB (with your API key) does work (you can test it here).

This was a real trial and error. I guess data urls aren't fully supported, or you don't need the data: part when posting to an API. Also, some browsers only accept certain files, or certain file sizes.

So far seems fine for images of 200kb or so. Anywhere near 1mb and you'll likely run into problems (slow uploads or failure) — see "file size is too big" below.

# freeimage.host
# It seems you MUST url encode the base64 data
curl -d 'key=<YOUR-API-KEY>' 
        --data-urlencode 'source=<DATA-STRING>'
        -d 'format=json' https://freeimage.host/api/1/upload

# For an existing image url
curl -d 'key=<YOUR-API-KEY>' 
        -d 'source=<HTTP-IMAGE-URL>'
        -d 'format=json' https://freeimage.host/api/1/upload

# imagebb.com
# No need to url encode as it's posting as a form
curl --location --request POST "https://api.imgbb.com/1/upload?expiration=600&key=<YOUR-API-KEY>" --form "image={DATA-STRING | HTTP-IMAGE-URL}"

You could potentially chain multiple images with --next.

Base64 encode with curl

encode: base64 filename.jpg > base64.txt
decode: pbpaste | base64 -d > filename.jpg (copies base64 from clipboard)

Base64 encode with Elm Lang

File.toUrl and then strip the data:.., part.
Url.Builder.crossOrigin to url (percent) encode the <data-string>.

Other problems

File size is too big

Terminal crashes (or is very slow) if large file size

Mac's Terminal struggles to paste it. So sending base64 files over a certain size isn't realistic (use multipart instead). It takes Terminal around 3-5 minutes to paste the thing.

Query strings

⚠️ No support for query strings.
You may run into problems if you have a ? query string after the <data-string>.

Allowing Cross-Origin

Allow cross-origin resource sharing.
Other people seem to have had this problem with freeimage.host too.

# Console log
Access to XMLHttpRequest at 'https://freeimage.host/api/1/upload?key=<API-KEY>&source=<HTTP-IMAGE-URL>&format=json' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant