⚠️ 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.
- What are Data URLs?
- What the f* is a
MIME type?
- Encoding an image as
base64
- Decoding
base64 to an image
- Strip slashes from a json string.
curl post example
curl multi-part /form-data example
- What is a binary file?
- 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.
Helpful links
MIMEtype?base64base64to an imagecurlpost examplecurlmulti-part /form-data examplebase64compared tomulti-partI knew nothing of how files are actually stored and transferred so all this is new to me.
base64is a way to represent files as a string of charactersPOSTmethodMultipart
You can upload your
base64string usingHttp.stringPartso you don't have to change your implementation too much. I've uploaded files of up to3mbbut you'll have some lag (seconds or minutes) before thebase64string uploads. Alternatively,multipartallows you to upload files in bits withHttp.filePart, so you don't have to convert the image tobase64, but it's quite nice to be able to switch betweenHttp.postandHttp.requestwith minimal refactoring.For either option you can show the
<progress>of the file upload to the user usingHttp.track.Which do I use?
It depends on the server you're sending to ...
Both freeimage.host and imagebb seem to only require the
base64<data-string>(or an existing image url) to work. Attempting to send@filename.jpgor@base64data.txthasn't worked in my experience (seecurlpost example in helpful links).For freeimage.host you MUST url encode the data (curl uses
--data-urlencode), becausebase64uses characters like+,/,=which can interfere with the URL (+is a space character, for instance.There's another option calledBase64Urlbase64urldoesn't seem to work freeimage.host.A working API call:
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
200kbor so. Anywhere near1mband you'll likely run into problems (slow uploads or failure) — see "file size is too big" below.You could potentially chain multiple images with
--next.Base64 encode with curl
encode:
base64 filename.jpg > base64.txtdecode:
pbpaste | base64 -d > filename.jpg(copiesbase64from clipboard)Base64 encode with Elm Lang
File.toUrland then strip thedata:..,part.Url.Builder.crossOriginto url (percent) encode the<data-string>.Other problems
File size is too big
Mac's Terminal struggles to paste it. So sending
base64files over a certain size isn't realistic (use multipart instead). It takes Terminal around 3-5 minutes to paste the thing.Query strings
Allowing Cross-Origin