iPhones save photos as HEIC by default. They are about half the size of JPG, but many websites, forms and Windows apps cannot open them. A common request is "let users upload an iPhone photo", and most upload forms reject .heic.
You can convert HEIC to JPG entirely in the browser, with no server. Here is a small, working approach using the heic2any library.
Why not just use a canvas?
Normally you would draw an image onto a canvas and call toBlob(). That fails for HEIC in most browsers, because only Safari can decode HEIC natively. Chrome, Firefox and Edge cannot load a .heic file into an <img>. So you need a decoder, and heic2any ships one compiled to WebAssembly.
Minimal code
<input type="file" id="file" accept=".heic,.heif,image/heic,image/heif" multiple> <ul id="list"></ul> <script src="heic2any.min.js"></script> <script> document.getElementById('file').addEventListener('change', async (e) => { const list = document.getElementById('list'); list.innerHTML = ''; for (const file of e.target.files) { try { const result = await heic2any({ blob: file, toType: 'image/jpeg', quality: 0.9 }); const blob = Array.isArray(result) ? result[0] : result; const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = file.name.replace(/\.[^.]+$/, '') + '.jpg'; a.textContent = 'Download ' + a.download; const li = document.createElement('li'); li.appendChild(a); list.appendChild(li); } catch (err) { console.error(file.name, err); } } }); </script> Details that matter
- The library is large (about 1.3 MB). Load it lazily, only after the user picks a HEIC file, so normal page loads stay fast.
-
heic2anycan return an array. A multi-image HEIC (like a Live Photo burst) gives several blobs, so always checkArray.isArray(result). - File type can be empty. On some systems the browser reports an empty
file.typefor.heic, so also check the file name extension, not just the MIME type. - Convert files one at a time. Decoding is memory-heavy, so a loop with
awaitis safer thanPromise.allon a big batch. - Quality 0.9 is a good default. You rarely see a difference from 1.0, and the JPG is much smaller.
- No upload needed. The file is read locally, which is good for private photos.
Try it without writing code
I turned this into a small free tool: HEIC to JPG converter (there is also HEIC to PNG). It converts several photos at once and runs entirely in your browser. A step-by-step guide for non-developers is here: how to convert HEIC to JPG.
Questions or edge cases you have run into with HEIC? Happy to discuss in the comments.