Transferring photos from an iPhone to a Windows PC or Linux desktop often ends the same way: thumbnails fail to generate, the default viewer asks for a codec or throws an error code such as 0x88982f8a, and web forms reject files ending in .heic or .heif.

The quickest fix most people reach for is a free online converter. That means uploading family pictures, ID scans, receipts, and embedded GPS coordinates to a server you know nothing about.

This guide explains how Apple’s HEIC container is built, why Windows and Linux can’t decode it out of the box, gives local command-line workflows for Windows, Linux, and macOS, and shows how client-side WebAssembly converts HEIC in a browser tab without uploading the file.


The Anatomy of Apple’s Image Format: Why iPhones Shoot in HEIC

Starting with iOS 11 and macOS High Sierra, Apple switched default camera capture from JPEG to HEIC (High Efficiency Image Container). HEIC is Apple’s flavor of the HEIF standard (ISO/IEC 23008-12), developed by the Moving Picture Experts Group (MPEG), with images compressed by the HEVC codec.

HEIF is not just an image format; it is a media container built on the ISO Base Media File Format (ISOBMFF, ISO/IEC 14496-12), the same structural foundation used by MP4 video.

flowchart TD
    subgraph Container["ISO/IEC 23008-12 ISOBMFF Container (.heic)"]
        direction TB
        FTYP["ftyp Box<br/>Major Brand: 'heic'<br/>Compatible Brands: 'mif1', 'miaf', 'heic'"]
        META["meta Box (Item Index)<br/>• hdlr: Handler ('pict')<br/>• iloc: Item Location Table<br/>• iinf: Item Info (image tiles, EXIF, XMP, depth)<br/>• iprp: Item Properties (hvcC, irot, colr ICC)"]
        MDAT["mdat Box (Media Data)<br/>HEVC Intra-Coded Tiles (NAL Units)"]
    end

    FTYP --> META
    META --> MDAT

    subgraph OSBehavior["Cross-Platform Parsing"]
        MDAT -->|No HEVC decoder| Win["Windows Photos: Codec Prompt<br/>(Requires $0.99 HEVC Extension)"]
        MDAT -->|No libheif + libde265| Lin["Linux Desktop: Unknown Format<br/>(Eye of GNOME / Gwenview Fail)"]
        MDAT -->|WASM libheif| Util["Utiliome In-Browser Decoder<br/>(/tools/convert-heic-jpg/)"]
    end

1. Box-Structured Container Architecture

An .heic file is a sequence of nested blocks called boxes:

  • ftyp (File Type Box): Declares the major brand and compatible specifications. iPhone photos use major brand heic (8-bit HEVC Main profile) with compatible brands such as mif1, miaf, and MiHB; heix signals 10-bit or extended-range HEVC.
  • meta (Metadata Box): Indexes every item in the file. The Item Location Box (iloc) maps byte offsets for image tiles, thumbnails, and auxiliary images, while item properties carry the HEVC decoder configuration (hvcC), rotation (irot), and ICC color profile (colr). EXIF and XMP are stored as separate items referenced from here.
  • mdat (Media Data Box): Stores the compressed payloads. Unlike JPEG, where metadata segments sit in front of a single scan stream, HEIF keeps a structured index separate from the raw media blocks.

iPhone cameras don’t store the main photo as one big frame. They store a grid derived image made of 512×512 HEVC-coded tiles, which the decoder has to decode and stitch back together. That is one reason simple “rename to .jpg” tricks never work.

2. H.265 / HEVC Intra-Frame Compression

The pixel data inside an Apple HEIC file is compressed with High Efficiency Video Coding (HEVC / H.265) using intra-coded frames, the same technique video encoders use for keyframes.

Compared to JPEG’s fixed 8×8 Discrete Cosine Transform (DCT) blocks, HEVC intra-coding adds several tools:

  • Coding Tree Units (CTUs): Quadtree partitioning with CTUs of up to 64×64 pixels, so flat areas (clear skies) take few bits while detailed textures get finer subdivisions.
  • 35 Intra Prediction Modes: 33 angular directions plus planar and DC modes (H.264 offers 9 modes for 4×4 blocks; baseline JPEG only predicts the DC coefficient), shrinking the residual that has to be coded.
  • Variable Transform Sizes: Integer DCT transforms from 4×4 to 32×32, plus a Discrete Sine Transform (DST) for 4×4 intra luma blocks.

Apple cites roughly half the file size of an equivalent-quality JPEG. HEIF also supports 10-bit color, alpha channels, portrait depth maps, and multiple images in one container.


The Missing Codec Problem: Why Windows and Linux Break

If HEIF is an ISO standard, why can’t non-Apple operating systems open iPhone photos? The container isn’t the problem. Patent licensing for the HEVC codec inside it is.

Windows: The $0.99 Store Extension and Error 0x88982f8a

On a stock Windows 10 or Windows 11 install, opening an .heic file in the Photos app prompts you to install the HEVC Video Extensions before it will show the image.

Microsoft splits HEIC support into two separate Store packages:

  1. HEIF Image Extensions (free): The container parser and Windows Imaging Component (WIC) codec that reads the ftyp/meta structure.
  2. HEVC Video Extensions ($0.99): The actual H.265 decoder that turns the compressed tiles into pixels.

If one of these packages is missing, outdated, or partly registered, apps built on WIC can fail with 0x88982f8a. That HRESULT is WINCODEC_ERR_INVALIDREGISTRATION: Windows found a codec entry for the format, but the component’s registration is broken. Updating or reinstalling both extensions from the Microsoft Store is the standard fix.

HEVC is covered by several royalty-bearing patent pools, mainly Access Advance and Via LA (formerly MPEG LA). Rather than include a licensed HEVC decoder in every Windows copy, Microsoft sells it separately, so the $0.99 cost falls on the user.

Linux: Decoders Exist, but Often Aren’t Installed

On Linux, the open-source pieces are libheif (the HEIF container library) plus an HEVC decoder plugin, usually libde265. Both are open-source (LGPL), but because HEVC is patent-encumbered, distributions handle them differently:

  • Debian, Ubuntu, and Arch package libheif and libde265 in their regular repositories, but many desktop images don’t install the HEVC decoder plugin or viewer loaders by default.
  • Fedora and RHEL-based distributions ship libheif without the HEVC decoder. HEVC support comes from the separate libheif-freeworld package in the RPM Fusion repository.

Desktop viewers such as Eye of GNOME (eog) and Shotwell load images through gdk-pixbuf, which needs libheif’s pixbuf loader (heif-gdk-pixbuf on Debian/Ubuntu). Gwenview on KDE uses the KImageFormats HEIF plugin. If these loaders or the HEVC plugin are missing, you get broken thumbnails and “unrecognized image format” errors.


The Privacy Trap: What Free Cloud Converters Expose

The usual workaround for a codec error is to search for an online converter. That sends your iPhone photos to a third-party cloud service, which creates real privacy and compliance problems.

flowchart LR
    subgraph CloudModel["Traditional Cloud Converter Architecture"]
        direction LR
        Dev1["User Device"] -->|"HTTP POST (Full Upload)"| Cloud["Cloud Load Balancer & Object Storage"]
        Cloud --> Worker["Server Worker (Reads GPS & EXIF)"]
    end

    subgraph LocalModel["Utiliome In-Browser WASM Architecture"]
        direction LR
        Dev2["File in Browser Memory"] -->|"WASM libheif (Zero Upload)"| Canvas["Canvas 2D Re-encode"]
        Canvas --> LocalSave["Local Download (No Network Transfer)"]
    end

1. Embedded Location Data & EXIF Leakage

iPhone HEIC files carry an EXIF item referenced from the meta box. It typically includes:

  • GPS Coordinates: Latitude, longitude, altitude, and heading, often accurate enough to identify a home, office, or school.
  • Device Details: Phone make and model, lens, focal length, and iOS software version.
  • Timestamps: Capture date and time down to sub-seconds, plus time zone offset.
  • Apple MakerNote Data: Proprietary tags such as burst and Live Photo identifiers.

For a deeper look at what these tags reveal, read What Is EXIF Data & Why You Must Remove It for Privacy. Before sharing converted files, you can check what metadata survived with the Image Metadata Viewer or remove location tags with Remove EXIF Metadata.

2. Multi-Tenant Storage, Retention, and AI Training

Dropping photos onto a cloud converter sends the full file to a third-party server in an HTTP POST request.

Even when a provider says files are “deleted after 1 hour”, the images still pass through shared object storage (such as Amazon S3 or Google Cloud Storage), server memory queues, backups, and logs. Unless the terms of service say otherwise, you also can’t rule out uploaded content being used to train machine-learning models. For legal teams, clinics, or companies, sending client photos, whiteboard shots, or employee badges to an unvetted service without a data processing agreement can conflict with GDPR Article 28, the HIPAA Security Rule, and client NDAs.


Method 1: Local Command-Line & Native Workflows (Windows, Linux, macOS)

If you can install software, local tools convert files offline with no network access at all.

Windows: Install the Codec or Use ImageMagick

Option A: Microsoft Store extensions (simplest for a few files). Install HEIF Image Extensions (free) and HEVC Video Extensions ($0.99), then open the photo in Paint and choose File → Save as → JPEG picture. This works one file at a time and needs a Microsoft account to buy the extension.

Option B: ImageMagick (free, scriptable batch conversion). The official Windows builds of ImageMagick 7 include libheif, so they read HEIC without the Store extensions. In PowerShell:

# Install ImageMagick 7 (open a new terminal afterwards so PATH updates)
winget install ImageMagick.Q16-HDRI

# Confirm HEIC is listed as a supported format
magick -list format | findstr /i heic

# Convert a single photo
magick IMG_4092.HEIC -quality 92 IMG_4092.jpg

# Batch convert every HEIC file in the current folder (originals are kept)
magick mogrify -format jpg -quality 92 *.heic

ImageMagick copies EXIF and GPS data into the JPG by default. Add -strip before the output name if you want it removed.

Linux: Native Conversion with libheif and ImageMagick

On Debian, Ubuntu, Linux Mint, and derivatives, install libheif’s command-line tools. The package is libheif-examples on current LTS releases and was renamed libheif-tools on newer ones:

sudo apt update
sudo apt install libheif-examples   # or: sudo apt install libheif-tools

On Debian 12+ and Ubuntu 23.04+, HEVC decoding lives in a separate plugin (libheif-plugin-libde265), which apt normally pulls in as a recommended dependency. Install it explicitly if heif-convert reports that no decoder is available.

On Fedora, enable the RPM Fusion Free repository first, because Fedora’s own libheif cannot decode HEVC:

sudo dnf install libheif-tools libheif-freeworld

Single File Conversion

Convert one .heic file to JPEG, setting output quality from 0 to 100 (the default is 92):

heif-convert -q 92 IMG_4092.heic IMG_4092.jpg

Batch Directory Processing via Bash Loop

Convert a whole folder, matching both lowercase and uppercase extensions:

for file in *.[hH][eE][iI][cC]; do
  # Skip if the glob matched nothing
  [ -f "$file" ] || continue
  filename="${file%.*}"
  echo "Processing: $file -> ${filename}.jpg"
  heif-convert -q 92 "$file" "${filename}.jpg"
done

Alternative: ImageMagick

If ImageMagick was built with the heic delegate:

# Verify delegate support
magick -version | grep -i heic

# Convert a single image
magick input.heic -quality 92 output.jpg

# Batch convert a directory (writes new .jpg files next to the originals)
magick mogrify -format jpg -quality 92 *.heic

Debian and Ubuntu still package ImageMagick 6, where the commands are convert and mogrify instead of magick and magick mogrify.

To fix thumbnails and viewing in GNOME instead of converting, install the pixbuf loader and thumbnailer: sudo apt install heif-gdk-pixbuf heif-thumbnailer.

macOS: Native Conversion with sips

macOS ships with sips (Scriptable Image Processing System), which uses Apple’s ImageIO framework (the same HEIC decoder as Preview). Nothing needs to be installed.

Single File Conversion

sips -s format jpeg input.heic --out output.jpg

Output:

/Users/admin/input.heic
  /Users/admin/output.jpg

Setting Compression Quality

sips uses its default JPEG quality unless you set formatOptions (low, normal, high, best, or a percentage):

sips -s format jpeg -s formatOptions 90 input.heic --out output.jpg

Batch Directory Processing on macOS

Convert every HEIC file in the current folder:

for img in *.[hH][eE][iI][cC]; do
  [ -f "$img" ] || continue
  sips -s format jpeg "$img" --out "${img%.*}.jpg"
done

Method 2: Utiliome’s In-Browser Client-Side Decoder (convert-heic-jpg)

Terminal scripts work well, but they need package installs and often admin rights, which locked-down work laptops and Chromebooks don’t give you.

The HEIC to JPG Converter runs the whole decode-and-encode pipeline inside the browser tab. Here is what the widget source actually does.

sequenceDiagram
    autonumber
    actor User as User (Browser Tab)
    participant Engine as heic-to (libheif WASM)
    participant Cache as decodedImgCacheRef (Map)
    participant Canvas as Canvas 2D Encoder
    participant Zip as JSZip Packager

    User->>Engine: Drop .heic / .heif file (File object)
    alt WASM decode succeeds
        Engine->>Engine: Parse ISOBMFF boxes and decode HEVC tiles
        Engine->>Cache: Lossless PNG intermediate loaded as HTMLImageElement
    else WASM decode throws
        Engine->>Cache: Fallback to native browser decode of original file (only where HEIC is supported, e.g. Safari)
    end

    User->>Canvas: Change format or quality (92% default, presets 95 / 85 / 70)
    Canvas->>Cache: Reuse cached image (no re-decode)
    Canvas->>Canvas: JPG only: fill white matte before drawing
    Canvas->>Canvas: toBlob(format, quality)
    Canvas-->>User: Pre-decode new blob, then swap preview

    User->>Zip: Download All as ZIP (2+ files)
    Zip-->>User: converted-heic-images.zip saved locally

Architectural Deep Dive: How the Converter Works Locally

The converter has no backend conversion server. The page loads a client-side pipeline built from WebAssembly, Canvas 2D, and Blob URLs:

1. WebAssembly-First Decoding with a Native Fallback

Files are treated as HEIC when the name ends in .heic/.heif or the MIME type is image/heic, image/heif, or one of their -sequence variants. For those files the widget lazy-loads heic-to, a WebAssembly build of libheif, which parses the ISOBMFF boxes, decodes the HEVC tiles, and returns a lossless PNG intermediate. This runs in every modern browser, including Chrome, Edge, Firefox, and Brave on Windows and Linux.

Only if the WebAssembly decode throws does the widget fall back to handing the original file to the browser’s own image decoder. That fallback only succeeds in browsers with native HEIC support, such as Safari on macOS and iOS.

2. Decode Once, Re-Encode Instantly (decodedImgCacheRef)

Decoding HEVC is the expensive step. Re-running it every time you nudge a setting would freeze the interface.

The widget keeps a decodedImgCacheRef (Map<File, { img: HTMLImageElement; refUrl: string }>), so the WebAssembly decode runs once per file. Switching output format (JPG, PNG, or WebP), dragging the 10%–100% quality slider, or clicking the Max (95%), Balanced (85%), and Compact (70%) presets only re-encodes the cached image on a canvas. New files start at 92% quality, and the slider is hidden for PNG because PNG is lossless.

3. Flicker-Free Preview Swaps

Each time a setting changes, the new output blob is loaded into an off-screen Image() first, and only then is its URL swapped into the Before/After comparison view. This prevents the preview from flashing black while the browser decodes the new image.

4. White Matte for Transparent Images

JPEG has no alpha channel. If a transparent image is encoded to JPEG on a canvas, browsers fill the transparent areas with black. HEIF can carry alpha (iPhone camera photos are normally opaque, but stickers and edited cutouts may not be), so for JPG output the widget fills the canvas with #FFFFFF before drawing the image. PNG and WebP output keep transparency.

5. Sequential Batch Queue and ZIP Export

You can drop many photos at once. They are decoded one after another rather than in parallel, keeping memory use predictable, and each file tab shows its status (queued, processing, done, or error). Apply to all copies the current format and quality settings to every file.

With one file, the main button downloads it directly. With two or more, it becomes Download All as ZIP: JSZip packs every converted image into converted-heic-images.zip in browser memory and triggers a normal download. A secondary button still lets you download just the current image.

6. Known Trade-Offs

  • 8-bit output: Canvas 2D works in 8-bit RGBA, so 10-bit HEIC color depth is reduced to 8 bits. That is also true of any JPG.
  • No metadata carried over: Because the pixels are redrawn on a canvas, the output contains no EXIF, GPS, or MakerNote data. That is good for privacy, but use a CLI tool if you need to keep capture dates.
  • Memory-bound: Very large batches are limited by the RAM available to the browser tab. For thousands of files, the heif-convert loop above is the better tool.

Technical Comparison: Native OS vs. Cloud vs. CLI vs. Utiliome WASM

Evaluation CriteriaWindows 10/11 Store CodecsThird-Party Cloud ConvertersOffline CLI (ImageMagick / heif-convert / sips)Utiliome In-Browser WASM (convert-heic-jpg)
Data Privacy & Uploads🔒 Local decoding⚠️ High Risk (full file uploaded to a third party)🔒 100% Local (offline execution)🔒 100% Local (no server uploads, runs in the browser tab)
Financial Cost$0.99 HEVC Video ExtensionsFree with limits, or paid plansFree & open sourceFree, no file limits
Platform AvailabilityWindows onlyAny browser (internet required)Windows, Linux, macOS (terminal required)Any modern browser (Windows, Linux, macOS, ChromeOS)
Installation FrictionMicrosoft account and Store purchaseNonewinget, apt, or dnf install (RPM Fusion on Fedora); sips is preinstalled on macOSNone
Batch Processing & ExportManual one-at-a-time savingOften capped per day or per uploadUnlimited (scriptable loops)Sequential batch queue with ZIP export
Live Quality AdjustmentNoneUsually noneRe-run with a new flagBefore/After slider, 10–100% quality, 95/85/70 presets
Metadata HandlingOriginal file untouchedUnknown; server can read all EXIFEXIF copied by default (-strip removes it in ImageMagick)Stripped on canvas re-encode; verify with Image Metadata Viewer

Pre-Flight Checklist Before Sharing Converted Photos

Whichever method you use, run through these checks before the files leave your machine:

  1. Pick the method that fits your environment: Use ImageMagick on Windows or heif-convert on Linux for large or recurring batches. Use sips on a Mac. Use the browser converter on locked-down machines where you can’t install anything.
  2. Choose a sensible quality: JPEG quality 85–92 is visually indistinguishable from the source for screens and most prints. Going to 100 mostly inflates file size.
  3. Check what metadata survived: CLI tools keep GPS coordinates. Strip them with magick mogrify -strip *.jpg (this edits files in place) or Remove EXIF Metadata before posting publicly.
  4. Confirm nothing was uploaded: With any browser tool, open DevTools (F12) → Network while converting; a local converter shows no request carrying your photo.
  5. Avoid the problem on future transfers: On the iPhone, go to Settings → Photos → Transfer to Mac or PC and choose Automatic. iOS then converts photos to JPEG when they are imported over USB, while keeping the space-saving HEIC originals on the phone.