HEIC to JPG on Android, Chromebook and Linux

You do not need an app on any of the three. One page in Chrome, one file at a time — here is what that actually costs on a phone-sized screen.

Nothing to install 688,921 bytes first load Fits a 412 px screen

Short answer: open the converter in Chrome on the Android phone, the Chromebook or the Linux machine, pick the HEIC file and download the JPG. There is nothing to install on any of the three, because the decoder is not software you install — it is a JavaScript file the page fetches once. I measured that first load today at 688,921 bytes across six requests, of which 679,228 bytes are the decoder itself (2,999,737 bytes once uncompressed). That file is an Emscripten build shipped with isWasm2js set — libheif compiled to WebAssembly and then translated into JavaScript — and it makes no call to the browser’s WebAssembly API anywhere in its 2,999,737 bytes.

What I measured on this site: I drove a real Chrome against the live converter with a phone-sized screen (412×915), an Android user-agent and touch emulation, and pushed a 12 MP HEIC through it — 4,032×3,024, 1,267,632 bytes in. It came back as a 1,708,595-byte JPG in 3,175–6,527 ms across eight runs, and all eight output files were byte-identical (SHA-256 1fca374ec67e5fd5…). The upload box starts 333 px from the top on that screen, so it is visible without scrolling, and nothing overflows sideways.

Why these three systems are where HEIC hurts

All three fail on HEIC for different reasons, and the difference matters.

The browser route is the same on all three for one reason: it does not ask the operating system for a HEIC decoder. It ships one.

Measured: the first load, and where the upload box lands

On a phone the first question is data, and on a small screen the second is whether you have to scroll to reach the file box. I measured both with cache disabled, one fresh load each:

ScreenUpload box starts atVisible without scrollingSideways overflow
412×915 (Android emulation)333 pxYes — box ends at 497 pxNone
1,264×805 (desktop window)288 pxYes — box ends at 468 pxNone
1,366×768 (Chromebook emulation)288 pxYes — box ends at 468 pxNone
1,600×900 (Linux emulation)288 pxYes — box ends at 468 pxNone

At every one of those widths the page’s scroll width equalled the viewport width, so nothing is cut off and nothing slides sideways. On the first load the browser fetched six resources totalling 688,921 bytes; the decoder alone was 679,228 bytes on the wire (2,999,737 bytes decoded) and took 161 ms, with the document itself finishing in 438 ms. After that first load the decoder is cached, which is why the page keeps working with the network off — measured separately in the offline test.

Measured: one 12 MP photo, eight runs

I used a single 4,032×3,024 HEIC of 1,267,632 bytes and ran it through the live converter at the default 85% quality, twice at each CPU setting, on the 412×915 Android emulation. Same bytes every time — only the file name changed, because the file input ignores a second pick of an identical path:

CPU settingFileJPG outTimeSHA-256 of output
1× (no throttle)r1a.heic1,708,595 bytes6,527 ms1fca374ec67e5fd5…
1× (no throttle)r1b.heic1,708,595 bytes4,881 ms1fca374ec67e5fd5…
4× throttler4a.heic1,708,595 bytes3,279 ms1fca374ec67e5fd5…
4× throttler4b.heic1,708,595 bytes3,799 ms1fca374ec67e5fd5…
8× throttler8a.heic1,708,595 bytes3,565 ms1fca374ec67e5fd5…
8× throttler8b.heic1,708,595 bytes3,793 ms1fca374ec67e5fd5…
20× throttler20a.heic1,708,595 bytes3,261 ms1fca374ec67e5fd5…
20× throttler20b.heic1,708,595 bytes3,175 ms1fca374ec67e5fd5…

The same file run in a plain desktop window with no emulation finished in 5,128 ms and produced the same 1,708,595 bytes with the same hash. So the phone-sized screen and the Android user-agent change nothing about the result — the JPG is bit-for-bit the same file you would get on a laptop.

Why I cannot give you a “seconds per photo on a Pixel” number

I tried, and the experiment did not do what I wanted. Throttling the CPU 4×, 8× and 20× did not slow the conversion down: the same file actually came out faster at 20× (3,175 ms) than at 1× (4,881 ms). Two measurements explain that:

That means the numbers in the table above are desktop-PC numbers wearing a phone costume. I did not run this on a real phone today, so I am not going to publish a phone timing. What I can say from today’s runs: on my machine a 12 MP photo lands somewhere between 3.2 and 6.5 seconds, and a small one is quick — a 700×476 photo of 41,465 bytes converted to 38,078 bytes in 909 ms on the Android emulation. Where a real phone falls inside that, I have not measured.

One number worth knowing if you are worried about a phone running out of memory: across all fifteen 12 MP runs today, the page’s JavaScript heap peaked at 158.5 MiB and came back down afterwards; after the small photo it sat at 12.3 MiB. Nothing crashed and nothing was refused.

On Android: the steps that actually work

  1. Open Chrome and load the converter once while you still have a connection.
  2. Tap the upload box. Android’s own file picker opens — the box does not open the camera, because the file input has no capture attribute (I checked).
  3. Pick the HEIC. If your picker hides it, the input only advertises .heic,.heif,image/heic,image/heif, so switch the picker to a file manager and browse to the file.
  4. Pick a quality, convert, and tap Download JPG. The file lands in your Downloads folder with the same name and a .jpg ending.

Two limits, both measured rather than guessed: the input is single-select (multiple is false), and when I pushed five files in at once the browser kept one — so it is one photo per round, with no cap on how many rounds you do. The cost of two hundred rounds on a desktop is in the 200-file run, and the volume you get at each quality setting is in the file-size measurements.

On a Chromebook

ChromeOS is the easy case: Chrome is already there, the page is a web app, and nothing needs installing or enabling. The upload box lands 288 px from the top at 1,366×768, so it is on screen without scrolling even on a small Chromebook display, and there is no sideways overflow. Use the upload box and pick the file from the Files app. I have not measured dragging a file from the ChromeOS Files app into the tab, so I will not promise that it works — the upload button is the path I know runs.

If the Chromebook is managed and refuses installs, that changes nothing here: the decoder arrives as part of the page.

On Linux

Let me be exact about what I did and did not do. The “Linux” row in my table is a Chrome running on Windows with a Linux user-agent string. That is not a Linux measurement and I am not going to present it as one — it is the same binary, so it only shows the page does not sniff the operating system.

What does carry over to Linux without me needing to measure it: the page’s only requirements are a browser that runs JavaScript and one 679,228-byte download. There is no codec package to install, no libheif to find in your distribution’s repositories, and no version to argue with. The native alternatives — a heif-convert binary from libheif, ImageMagick built with a HEIF delegate, a recent GIMP — are real and are the right answer if you are converting a folder in a script, but I did not run any of them today, so this page carries no timings for them.

Questions

Will this work on my phone with no signal?

After one load with a connection, yes — and that is worth knowing on all three systems. The decoder is cached and the file never leaves the device. The full test, including what breaks after you clear the cache, is in the offline measurement.

Does it work in Firefox on Android, or Samsung Internet?

I have not measured those. Everything in this page was run in Chrome’s engine today, so I will not claim a browser I did not test. What the page needs from a browser is JavaScript and the ability to fetch the decoder; I have not verified that on anything else.

My Android phone is old. Will the page run?

Not measured. What I can say is what the decoder is made of: an Emscripten build with isWasm2js set — libheif built to WebAssembly and then translated into JavaScript — with zero references to the WebAssembly API in the 2,999,737 bytes the page ships. So nothing in it asks the browser for WebAssembly at runtime. Old WebView components I did not test.

Can I convert a whole album on the phone?

One file per round — the input is single-select, and five files pushed in at once left the browser holding one. There is no limit on rounds. Whether a phone survives a hundred of them is something I have not measured; the desktop cost of two hundred is in the 200-file run.

Does the JPG keep the photo’s location data?

No. The output carries no EXIF at all — camera model, GPS and timestamps are dropped. That was measured by opening the output file, in the EXIF test. On Android that also means the JPG you hand over is less revealing than the HEIC you started with.

What I could not measure

Try it on whichever of the three you are holding: open the converter, tap the upload box, and watch the JPG come back without anything leaving the device.

First published: 27 September 2026