HEIC to JPG Converter

Turn iPhone .heic photos into JPG — decoded right here in your browser, nothing uploaded. Rotated shots come out upright, transparent areas are flattened onto a colour you pick, and you choose the JPEG quality.

Convert HEIC files to JPG

Drop .heic or .heif files, pick a quality, and download verified JPGs with real before/after sizes.

or drag and drop .heic files here

Up to 40 files · 100 MB each · 300 MB per selection

    This page runs one conversion plan: HEIC into JPEG. Three things happen before any pixel moves — the file's bytes are identified, the self-hosted libheif module decodes the primary image, and a pure planning function decides the flatten, the quality parameter and the output name. Every result below was computed at build time by that same engine on illustrative inputs; the input limits are quoted in the terms the methodology page states.

    Guide: HEIC and AVIF: decoding and licensing. This page documents the HEIC-to-JPEG plan alone. The guide follows the same box parser across all six HEIC and AVIF lanes, states what each decoder is licensed under, and explains why the site encodes AVIF but never HEIC. The other guides cover the pipeline, flattening, quality parameters and metadata in the same build-time-computed style.

    What the detector sees in a .heic file

    Nothing on this page trusts the filename. A HEIC file begins with an ISO-BMFF ftyp box: a four-byte big-endian size, the FourCC ftyp, a four-byte major brand, a four-byte minor version, then compatible brands four bytes each to the end of the box. The detector parses that structure — it never substring-searches the file — and asks whether the brands declare HEVC-coded HEIF: heic, heix, hevc or hevx settle it, while the structural brands mif1 and msf1 count only when no AV1 brand is also present. The table runs the detector on boxes constructed at build time from illustrative brand lists, plus one input that is not a box at all.

    Constructed leading bytes Brands parsed Verdict Accepted here
    major heic; compatibles mif1, heic heic mif1 heic HEIC yes
    major mif1; compatibles mif1, heic, hevc mif1 mif1 heic hevc HEIC yes
    major mif1; compatibles mif1, avif, miaf mif1 mif1 avif miaf AVIF no
    major abcd; the minor-version bytes spell heic; no compatibles abcd unrecognized no
    FF D8 FF E0 — not a box at all no ftyp box JPEG no

    Two rows carry the lesson. The fourth box has the ASCII letters heic sitting in its minor-version field, where a substring search would find them; the parser reads brands only from the major and compatible positions, so it reports abcd and the verdict is unrecognized — the file is refused as not an image this site reads. The third box is the same container with an AV1 brand: the verdict is AVIF, which this page does not accept, so the row says so and links to AVIF to JPG instead of converting under a false label. The first two boxes are both HEIC, whichever position the HEVC brand occupies. The guide's table adds the precedence and hostile-size cases.

    The filename is then compared with that verdict, never trusted. The extension map reads .heic and .heif as claims of HEIC — a name ending .heif claims HEIC — and .jpg as a claim of JPEG. On the HEIC bytes above, an invented IMG_2048.HEIC produces no mismatch (no), because the comparison lower-cases the extension; IMG_2048.heif produces none either (no); and IMG_2048.jpg produces actual HEIC, claimed JPEG, mismatch yes — the row shows a notice and the conversion runs from the HEIC content. An AVIF body named IMG_2048.heic reports actual AVIF, claimed HEIC, mismatch yes, and is routed, not converted.

    Decoding: the one third-party decoder on the site

    Every other converter on this site decodes with the browser's own codecs. HEIC is the exception, because no browser ships a HEIC decoder: this page loads libheif — © struktur AG and contributors, licensed LGPL-3.0 — compiled to WebAssembly from pinned upstream source, together with its libde265 HEVC decoder from the same upstream family, also LGPL. The codec source is compiled without source modifications, self-hosted from this site's own origin under /vendor/libheif/, and loaded at runtime as a separately replaceable module in a dedicated worker — never compiled into the site's own JavaScript. The full licence text ships alongside the module at /vendor/libheif/LICENSE.txt; exact versions, commits, checksums and the reproducible build recipe are in the project's provenance record, and every vendored file's size and SHA-256 is pinned by automated tests, so served bytes cannot drift silently. The build is decode-only. The methodology page gives the reason for carrying a third-party decoder at all: "convert my iPhone photo" is the single most common conversion request there is, and the alternative — uploading a camera roll to someone's server — is exactly what this site exists to avoid.

    Three facts about the decode step shape the result. First, the decoder applies the rotation stored as a transform inside the container while it decodes, so the pixels handed to the canvas are already upright; the orientation metadata is then discarded with the rest, and the JPEG comes out upright without carrying an orientation tag. Second, a HEIC container can hold several images. The worker decodes the primary image — the one the container marks as primary, or the first when none is marked — and counts the others; the file row then notes that the container held other images (bursts and Live Photo sequences do this) and that the primary is the one converted. Nothing is silently picked, and no picker is offered. Third, decoding runs under a timeout in its own worker, so a malformed or very expensive file fails on its row rather than freezing the tab. The module is fetched from this site only: the site's Content-Security-Policy sets connect-src 'self', so page scripts cannot send data to any other origin — confirm it in the Network tab as the methodology page describes.

    The plan for this pair

    After decoding, a pure planning function takes the detected source, the target and the two controls above, and returns the plan the canvas follows. Asked for HEIC into JPEG with the controls at their defaults it returns: MIME type image/jpeg; flatten onto a background: yes, with the background #ffffff; encode quality 0.92 on the engine's 0–1 scale, which is 92 on the encoder's whole-number scale and the position the slider starts at; and animation dropping to the first frame: no. Each flag follows from the capability table for JPEG output — can it carry per-pixel transparency: no; does its encoder take a quality parameter: yes — combined with two facts about the source. A HEIF image can carry an alpha auxiliary plane, so HEIC counts as an alpha-capable source and every JPEG plan from it flattens. And HEIC is not on the engine's list of animatable containers, so the "first frame only" caveat that GIF, WebP and AVIF sources receive never appears here — the multi-image note above is a separate report from the decoder, not that flag.

    The controls change only two fields. Move the slider and pick a dark background, and the plan for the same pair becomes: flatten yes, background #1f2a44, quality 0.8 (encoder 80), first frame only no. The flags that come from the format pair do not move; only the values you supplied do. The planner also refuses rather than guesses. Handed a background written as the word white instead of a hex colour it answers "Enter the background as a hex color like #ffffff."; handed a quality of 0.02 it answers "Quality must be between 0.05 and 1."; handed 1.5 it answers "Quality must be between 0.05 and 1.". The colour picker and the slider on this page cannot produce those inputs, but the refusals are there so that nothing downstream ever runs on a half-formed plan.

    For contrast, the plan for the same HEIC into PNG — the HEIC to PNG page — sets flatten to no and carries no quality parameter; ask it for a quality and it answers "This output format is lossless and has no quality setting.". That single difference is the whole reason the two HEIC pages exist separately. In the other direction there is nothing: the engine's producible formats are PNG, JPEG, WebP, AVIF, its source-only list is GIF, BMP, HEIC, and HEIC is on it (yes) while also being decodable (yes) — producing a HEIC would need an HEVC encoder that browsers do not ship and this site's libheif build does not contain. The guide states the licensing reason in the methodology's words.

    Flattening, on this page specifically

    Flattening means compositing. Before the decoded image is drawn, the canvas is filled with the background colour, then the image is drawn over it: a fully transparent pixel becomes the background, a semi-transparent pixel becomes a blend of its own colour and the background in proportion to its alpha, and an opaque pixel is unchanged. The result has no alpha channel left for the JPEG encoder to lose. Because the decision is made from the format pair rather than by scanning pixels, the composite runs for every HEIC on this page — including fully opaque photographs, where it changes nothing — and the file row's note naming the colour appears for every file too. It records what the pipeline did, not whether your image had transparent pixels. The default is #ffffff; if the image will sit on another surface, pick that colour before converting, because the flatten cannot be undone from the JPEG. To keep the alpha, use HEIC to PNG; the Transparency and flattening guide covers the same decision for every output format the site produces.

    The quality parameter — and what the tool cannot know

    The slider's value is handed to the plan as the encode quality and from there to the browser's own JPEG encoder through the canvas. There is no vendored encoder on this page: the decoder is third-party, the encoder is the browser's. The one self-hosted JPEG encoder on the site, MozJPEG, is used by the Compress JPEG lane only. The quality number is the encoder's parameter on its own scale — the slider's 92 is the engine's 0.92 multiplied out — not a percentage of the original's fidelity, and no setting is correct in the abstract. The pixels the encoder receives have already been through the HEVC compression inside the HEIC, which the decoder reproduces and cannot undo; the JPEG encode is a second lossy pass over them. The tool has no measure of visual difference. It measures bytes and dimensions, and that is what it reports.

    The size change on each row is arithmetic on the two true byte counts and nothing else. As arithmetic on invented numbers — these are not predictions for any real file — a 2,400,000-byte HEIC becoming a 1,700,000-byte JPEG reads "29% smaller"; the same input becoming 3,900,000 bytes reads "63% larger — keep your original"; becoming 2,380,000 bytes reads "0.8% smaller". Growth is stated in the same breath as shrinkage, and the site publishes no blanket compression percentage anywhere, because no percentage is true for every image. To land under a given size rather than at a given quality, run the JPG through the Image Compressor, whose compress-to-target search measures rather than predicts.

    What re-encoding strips

    Drawing to a canvas and encoding again discards all embedded metadata: EXIF — including GPS location, camera model and timestamps — colour-profile tags, and text chunks. That is a feature when the JPEG is going to be published, because it cannot leak where the photo was taken, and a caveat when copyright fields or an embedded profile matter, so keep the original HEIC. Orientation survives in effect but not in bytes: the rotation is applied to the pixels during decoding, before the metadata is thrown away. Nothing is written back into the JPEG — no EXIF block, no profile — and the HEIC itself is never modified; the download is a new file built from decoded pixels. The full account is in What re-encoding does to metadata.

    How the output is verified and named

    The download button is earned, not asserted. After the encoder returns its bytes, the output is treated like a stranger's file: its leading bytes are sniffed with the same detector that read the input and must identify as JPEG — bytes of type image/jpeg behind a .jpg extension — then the blob is decoded again and its pixel dimensions compared with the canvas that produced it. A browser that quietly produced another format, a file that will not decode, or a dimension that disagrees is reported as an error, never offered as a mislabelled download. The size beside the badge is the output blob's true byte count. The filename keeps your stem and swaps in the canonical extension — on invented names: IMG_2048.HEIC becomes IMG_2048.jpg, IMG_2048.heif becomes IMG_2048.jpg, kitchen.final.heic keeps its inner dots and becomes kitchen.final.jpg, and a path such as camera/2026/IMG_2048.heic yields IMG_2048.jpg. When the swap would reproduce the input name — the misnamed IMG_2048.jpg that was really HEIC — the engine writes IMG_2048-converted.jpg so the download cannot shadow your original.

    Limits on this page

    Inputs are limited to 50 megapixels, 100 MB per file, and 40 files or 300 MB per selection, in the terms the methodology page states; the worker applies the same dimension bound to the HEIC's primary image before allocating pixels for it. Files in a selection are processed one after another, so one large file cannot stall the tab's memory at once. Dimensions are not changed here — the JPEG has exactly the pixel size of the decoded image, which verification confirms — so a photo that also needs fewer pixels should go through the Image Resizer afterwards.

    Common misreadings

    • "The row says transparent areas were flattened, so my photo had transparency." Not necessarily. The note follows the plan's flatten flag, which is yes for every HEIC → JPEG conversion. It tells you the composite ran and which colour it used.
    • "Quality 92 means the JPEG keeps 92% of the photo." No. It is the encoder's quality parameter on its own scale. The tool makes no measurement of fidelity and claims none.
    • "The JPG is larger, so the conversion failed." No. The conversion succeeded and the row reported the measured result, labelled "larger — keep your original". Whether a JPEG is smaller than the HEIC it came from depends on the image and the quality you chose; the tool measures it rather than predicting it.
    • "Every image in the burst was converted." Only the primary image is decoded and converted; the row says how many other images the container held. The plan's first-frame flag (no) is a different mechanism and is never set for HEIC.
    • "It ends in .heic, so it is HEIC." Only the bytes decide. The illustrative IMG_2048.heic whose box carries an AV1 brand is reported as AVIF and sent to the AVIF converter, not converted as HEIC.
    • "My photo was uploaded so the decoder could run." No. The decoder is fetched from this site into your tab; the photo is decoded in a worker there, and the security policy forbids sending it anywhere.
    • "I can convert the JPG back to HEIC later." Not here. HEIC is source-only (yes) — the site never produces it — so the HEIC you drop is the only HEIC you will have. Keep it.

    Keep transparency or plan further editing? HEIC to PNG is the lossless landing place. If the JPG needs to hit a size limit — "under 200 KB" upload forms — run it through the Image Compressor, or scale its dimensions with the Image Resizer. Photos already in JPG go the other direction at JPG to PNG. The box parser, the licensed decoder facts and the reason the site encodes AVIF but never HEIC are in HEIC and AVIF: decoding and licensing; the rest of the guides cover detection, the pipeline, flattening, quality parameters and metadata in the same build-time-computed style.

    Frequently asked questions

    Which files does this page accept?

    Files whose bytes are HEIC — the detector's verdict, not the extension. Both .heic and .heif names claim HEIC (a name ending .heif claims HEIC), but the claim is only compared with the bytes. An AVIF body named IMG_2048.heic is reported as AVIF, not converted here, and the row links to the AVIF to JPG converter; a HEIC body named IMG_2048.jpg is reported as HEIC and converted from what it actually is.

    Does the conversion happen on a server?

    No. Browsers cannot decode HEIC natively, so this page loads a decoder (libheif, compiled to WebAssembly) into your own browser tab and decodes there. The site’s security policy blocks requests to other origins — your photo is never transmitted, and you can verify that in your browser’s network inspector.

    What does the quality slider actually set?

    It sets the quality parameter the plan hands to the browser's JPEG encoder. The slider's starting position matches the planner's default for JPEG output, 92 on the encoder's whole-number scale (0.92 on the engine's 0–1 scale). The tool does not recommend a setting, because it cannot see what the photo is for; it reports the true output byte count for whatever you pick, so you can compare runs with real numbers.

    Will the photo come out sideways?

    No. Rotation is stored as a transform inside the HEIC container, and the decoder applies it while decoding — so the JPG comes out upright. The orientation metadata itself is then discarded along with the rest of the metadata, which is why the JPG is upright without carrying an orientation tag.

    What happens to Live Photos and bursts?

    A HEIC container can hold several images. This tool converts the primary image — the still your camera roll shows — and tells you on the file row when it detected additional images in the container rather than silently picking one.

    Is any quality or metadata lost?

    Yes, and the page says so rather than hiding it. The JPEG target is lossy — the planner's capability table records it as such — so the decoded pixels go through a second lossy encode on top of the HEVC compression already inside the HEIC. Canvas re-encoding strips all embedded metadata: EXIF including GPS location, camera model and timestamps, colour-profile tags, and text chunks — a privacy win for sharing, a reason to keep your originals. And JPEG has no alpha channel, so any transparent areas are composited onto the background colour you chose.

    My photo has no transparent pixels — why does the row say transparent areas were flattened?

    Because the decision is made from the format pair, not by scanning pixels: every HEIC → JPEG plan carries the flatten flag (yes), so the composite runs for every file and the note reports the colour used — #ffffff unless you change it. For a fully opaque photo the composite changes nothing; the note is a record of what the pipeline did, not a claim about your pixels.

    Why is the JPG a different size from the HEIC?

    Because that is what the two byte counts said. The row shows the input and output sizes as true byte counts and a percent change computed from them alone; a larger result is labelled "larger — keep your original". The site publishes no blanket compression percentage, because no percentage is true for every image. As arithmetic on invented byte counts only: 2,400,000 bytes becoming 1,700,000 bytes reads "29% smaller", and the same input becoming 3,900,000 bytes reads "63% larger — keep your original".

    Local processing: your photos are decoded, converted, and verified inside your browser and never transmitted. HEIC decoding by libheif, LGPL-3.0, self-hosted and used unmodified — see the methodology page for the full attribution and how to verify the no-upload claim yourself.