Skip to content

HEIC

currentMigrated from docs/images/HEIC.mdx at 37c3317fd058; modified for Encode Wiki · CC BY-SA 4.0

HEIC is HEVC (H.265) intra-frame coding stored in a HEIF container. It is the default photo format on iPhones and iPads (Settings ▸ Camera ▸ Formats ▸ High Efficiency), and it is noticeably smaller than JPEG at similar quality. Outside Apple’s ecosystem it is awkward: HEVC is patent-encumbered, so browsers, most Windows installs and many web services do not decode it.

For anything you publish, convert it. AVIF uses the same HEIF container with royalty-free AV1 and has far wider support, and JPEG XL and JPEG cover the other cases. HEIC is a capture and interchange format: read it and convert it, don’t author it for the web.

  • HEIF (ISO/IEC 23008-12) is the container: a primary image, thumbnails, auxiliary images (alpha, depth), grids of tiles, collections, transformations (rotate, crop, mirror), metadata (Exif, XMP, ICC/nclx) and image sequences. HEIC is HEIF carrying HEVC. HEIF can also carry AV1 (AVIF), AVC, JPEG, VVC and others.
  • HEVC profiles. Phones use Main (8-bit 4:2:0) or Main 10 (10-bit 4:2:0, used for HDR). 4:2:2 and 4:4:4 need range-extension profiles that many hardware decoders and viewers lack.
  • Lossless exists (HEVC lossless tools), but it is not widely used and files are large; use PNG or JPEG XL.
  • Alpha and depth are separate auxiliary image items, not a fourth channel. Exporters and converters often drop them, and a plain converted copy loses portrait-mode depth maps and Live Photo relationships.
  • Not royalty-free. HEVC is licensed through patent pools such as Access Advance and others, and some patent holders are not in any pool. Apps that use the operating system’s codec rely on the OS vendor’s licence; an app that ships its own HEVC decoder or encoder may need its own. libheif is LGPL, x265 is GPL, and neither licenses the patents.
PlatformHEIC
Safari, iOS, macOSSafari 17+ displays HEIC (Safari 17 notes); the OS and Photos have supported it for years.
Chrome, Edge, FirefoxNo <img> support (caniuse); serve a JPEG/AVIF/WebP version.
AndroidDecoding since Android 9 (device optional; 10-bit also needs HEVC Main 10), encoding via MediaCodec/HeifWriter from Android 10 (supported formats).
WindowsNeeds the HEIF Image Extensions and HEVC Video Extensions from the Microsoft Store.
LinuxVia libheif with libde265 or FFmpeg for decoding; most distributions package it.

See image and audio support for how to test a given file. Upload forms, CDNs and CMSes frequently reject HEIC even when the OS opens it.

libheif provides heif-enc, heif-dec and heif-info. Codecs are plugins: heif-enc --list-encoders shows what your build has (x265 for HEVC; aom, SVT-AV1 and rav1e for AVIF).

Terminal window
heif-dec photo.heic photo.jpg
heif-dec -q 90 photo.heic photo.jpg
heif-enc -q 75 input.png output.heic
heif-info output.heic

heif-dec chooses the output format from the extension (jpg, png, tif, webp, y4m); -q is the JPEG quality. heif-enc defaults to HEVC through x265 at quality 50; its quality scale is not comparable to JPEG’s or AVIF’s, so pick a value by eye.

OptionWhat it does
-q 0..100Lossy quality (default 50).
-LLossless; also switches to RGB (identity matrix) so pixels survive.
-p chroma=444x265 plugin chroma format (420 default, also 422 or 444).
-b 9..16Bit depth taken from a 16-bit PNG input (default 10); 8-bit inputs stay 8-bit.
-p preset=…, -p tune=…x265 preset (default slow) and tune (default ssim; also psnr, grain, fastdecode).
-p x265:KEY=VALUEPass any x265 parameter through.
-A / --avifEncode AVIF instead; the AV1 plugin parameters are in the AVIF page.
--color-profile, --clliSet nclx colour signalling and HDR light-level metadata.
-t N, --no-alphaEmbed a thumbnail of maximum size N; drop alpha.
-S, --sequenceWrite an image sequence (animation) from several inputs.

ImageMagick (magick in.heic out.jpg) and many photo tools use libheif underneath.

  • Grids. Phone photos are often stored as a grid of tiles; naive extractors give you only one tile. Use libheif-based tools.
  • Metadata on conversion. Exif, ICC and HDR information survive only if the converter carries them over. Check orientation and colour after converting.
  • HDR. Apple’s HDR photos carry an extra gain-map image; a converter that ignores it gives you only the SDR rendering.
  • Chroma. HEVC for stills is almost always 4:2:0. If you encode screenshots, coloured text or line art, use -p chroma=444 or a different format.
  • Licensing for software. Shipping x265-based encoding in a closed-source or commercial product has GPL and patent implications; AVIF avoids both.
  • AVIF is the royalty-free AV1 sibling in the same container and the usual target format.
  • HEVC is the video codec underneath.
  • JPEG XL covers HDR and lossless without patents.
  • x265 is the encoder behind heif-enc.

The tables below are the full heif-enc and plugin parameter references for libheif 1.23.6. Reading option tables explains the Default column.

heif-enc 1.23.6 complete frontend reference

Section titled “heif-enc 1.23.6 complete frontend reference”
INPUT to —avc
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
INPUTpath(s)required for encodingOne or more input images. Several inputs go into one file as separate images, not an animation (use —sequence for that).
OUTPUToptional pathderived from first inputOutput file. The suffix (.heic, .avif) picks the codec when no codec switch is given.
--help, -hactionnot requestedPrint usage. Hides several registered switches that are listed below.
--version, -vactionnot requestedPrint the heif-enc and libheif versions. Lowercase -v is not verbose.
--quality, -qinteger 0–10050Lossy quality passed to the selected encoder plugin. Not comparable across plugins or with avifenc.
--output, -opathderived from first inputOutput filename. Without it, the name is derived from the first input.
--lossless, -LflagfalseLossless coding with identity matrix (RGB). Plugins without lossless support fall back to lossy with a warning.
--thumb, -tpositive maximum dimension0: disabledAdd a thumbnail whose longer side is at most this many pixels.
--verboserepeatable flag0 repetitionsMore codec logging. Repeat for more detail.
--params, -Pactionnot requestedList the selected plugin’s parameters and exit.
--no-alphaflagfalse: master alpha savedDrop the alpha channel from the main image.
--no-thumb-alphaflagfalse: thumbnail alpha savedDrop the alpha channel from the thumbnail only.
--list-encodersactionnot requestedList the encoder plugins in this build, per codec.
--encoder, -eplugin IDhighest-priority plugin for the codecPick an encoder plugin by ID from —list-encoders (for example x265, aom, svt, rav1e).
--bit-depth, -binteger 9–1610Bits kept from 16-bit PNG or TIFF input (9–16). The encoder plugin limits the coded depth (x265: 8, 10 or 12).
--avif, -AflagfalseEncode as AVIF (AV1). Not needed when the output name ends in .avif.
--hevcflagfalse (HEVC is the fallback)Encode as HEVC (HEIC). HEVC is also used when no codec flag is given and the output suffix names no other codec.
--vvcflagfalseEncode VVC. Experimental; needs a VVC plugin.
--avcflagfalseEncode AVC (H.264, x264 plugin). Experimental.
—jpeg to —benchmark
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
--jpegflagfalseStore JPEG-coded data inside HEIF. This does not write a plain .jpg.
--jpeg2000flagfalseStore JPEG 2000 data inside HEIF. Experimental; needs an OpenJPEG plugin.
--htj2kflagfalseStore High Throughput JPEG 2000 data inside HEIF. Experimental; needs an OpenJPH plugin.
--uncompressed, -Ubuild-gated flagfalseStore raw pixels (HEIF uncompressed codec). Only in builds with WITH_UNCOMPRESSED_CODEC.
--unci-compression-methodnone, brotli, deflate, zlibzlibCompression for uncompressed-codec payloads. Needs an uncompressed-codec build.
--component-content-idsbuild-gated flagfalseWrite component content IDs for uncompressed images. Needs uncompressed and experimental builds.
--color-profilecustom, auto, compatible, 601, 709, 2020customNCLX preset: custom uses the flags below, auto guesses from the input, compatible avoids rarely implemented values, 601/709/2020 are fixed presets.
--matrix_coefficientsH.273 integer6NCLX matrix coefficients (H.273) for the custom profile. 6 is BT.601; —lossless forces 0 (identity).
--colour_primariesH.273 integer1NCLX colour primaries (H.273) for the custom profile. 1 is BT.709/sRGB.
--transfer_characteristicH.273 integer13NCLX transfer characteristics (H.273) for the custom profile. 13 is sRGB.
--full_range_flag0 or 11NCLX range for the custom profile: 1 full range, 0 limited.
--enable-two-colr-boxesflagfalseWrite both ICC and NCLX profiles when the input has both.
--cllitwo 16-bit unsigned valuesabsentSet MaxCLL,MaxPALL (cd/m², 16-bit values) content light level metadata. Metadata only; no HDR conversion.
--pasptwo unsigned spacing valuesabsentSet pixel aspect ratio as h,v. Metadata only; pixels aren’t resampled.
--premultiplied-alphaflagfalseTell the encoder the input alpha is already premultiplied. Doesn’t premultiply the input.
--rotate-cw0, 90, 180 or 2700Store a clockwise rotation (0, 90, 180, 270) as a transform; pixels are not rewritten.
--flip-hflagfalseStore a horizontal flip as a transform.
--flip-vflagfalseStore a vertical flip as a transform.
--plugin-directorydirectory pathdefault plugin pathLoad encoder plugins from this directory in addition to the default search path.
--benchmarkflagfalsePrint encoding time, PSNR and output size.
—enable-metadata-compression to —metadata-track-uri
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
--enable-metadata-compressionauto, off, deflate, zlib, brotlioffCompress metadata items. Experimental; listed in —help only in builds with header compression.
--pitm-descriptiontextemptyText description attached to the primary image. Experimental.
--chroma-downsampling, -Cnn, nearest-neighbor, average, sharp-yuvaverage (preferred, not forced)RGB-to-YUV chroma downsampling: nn (nearest-neighbor), average or sharp-yuv (needs libsharpyuv). Without -C, libheif prefers average but may use another method; -C forces the choice.
--cut-tilespositive side length0: disabledSplit the input into square tiles of this many pixels per side and store it as a tiled image.
--tiled-input, -TflagfalseRead a tile set from numbered files (for example tile-01-05.jpg); give one filename and the rest are found.
--tiled-image-widthpositive pixels0: infer from tilesOverride the total width of a tiled image, in pixels.
--tiled-image-heightpositive pixels0: infer from tilesOverride the total height of a tiled image, in pixels.
--tiled-input-x-yflagfalse: filename numbers are y,xRead the first number in tile filenames as x instead of y.
--tiling-methodgrid; build-gated unci/tiligridHow tiles are stored: grid items, tili (experimental builds) or unci (builds with the uncompressed codec).
--add-pyramid-groupflagfalsePut several input images into a multi-resolution pyramid group. Experimental; listed in —help only in experimental builds.
--sequence, -SflagfalseEncode a timed image sequence; a numbered filename pulls in all files with that pattern.
--video, -VflagfalseUse a video track handler for sequence output.
--timebasepositive ticks per second30Sequence clock in ticks per second.
--durationpositive ticks per frame1Frame duration in ticks. Seconds per frame = duration ÷ timebase.
--fpspositive frame rateunsetSet timebase and duration from a frame rate. 29.97 maps to 30000/1001; other fractions are rounded on a 90000-tick clock.
--repetitionspositive integer or infinite1How many times playback repeats, or infinite. 0 is rejected.
--max-framespositive integer0: no limitStop after this many frames. 0 is rejected.
--vmt-metadatabuild-gated file pathnoneVideo metadata track input file. Experimental; needs an experimental-features build.
--binary-metadata-trackbuild-gated flagfalseWrite the metadata track as binary. Experimental.
--metadata-track-uribuild-gated URIvmt:metadataURI identifying the metadata track. Experimental.
—add-mime-item to —
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
--add-mime-itembuild-gated MIME typenoneAttach a generic MIME item of this type. Experimental.
--mime-item-filebuild-gated payload pathnoneFile holding the payload for —add-mime-item. Experimental.
--mime-item-namebuild-gated textemptyName for the MIME item. Experimental.
--turtlebuild-gated file pathnoneRead RDF Turtle content-ID relationships from a file. Experimental.
--embed-turtlebuild-gated flagfalseEmbed the —turtle file as an item. Experimental.
--gop-structureintra-only, low-delay/p, unrestricted/blow-delayPrediction structure for sequences: intra-only, low-delay (P) or unrestricted (B). The plugin must support it.
--min-keyframe-distancenonnegative integer0: undefinedMinimum frames between keyframes in a sequence. 0 leaves it to the encoder.
--max-keyframe-distancenonnegative integer0: undefinedMaximum frames between keyframes in a sequence. 0 leaves it to the encoder.
--set-gimi-track-idtext IDnoneGIMI track ID for the visual track of a sequence. Experimental; listed in —help only in experimental builds.
--sai-data-filefile pathnoneFile with SAI (sample auxiliary information) data for sequence frames. Listed in —help only in experimental builds.
--omaf-image-projectionequirectangular or cube-mapabsentMark the image as equirectangular or cube-map for OMAF viewers. Doesn’t warp pixels.
--add-compatible-brandfour-character brand, repeatableno added brandsAdd a four-character compatible brand to the file. Repeatable; only add brands the file really conforms to.
--unifflagfalseUse one ID namespace for items and tracks and add the unif brand.
--miniflagfalseUse the compact mini box layout. Readers need explicit support.
--rawflagfalseTreat the input as raw pixel data even without a .raw/.img suffix.
--raw-widthpositive pixels0: derived from file sizeRaw input width in pixels. Give width, height or both; a missing one is computed from the file size.
--raw-heightpositive pixels0: derived from file sizeRaw input height in pixels. Give width, height or both; a missing one is computed from the file size.
--raw-typeuint8/sint8/uint16/sint16/uint32/sint32/float32/float64noneRaw sample type: uint8, sint8, uint16, sint16, uint32, sint32, float32 or float64. Required for raw input.
--raw-endianlittle or biglittleByte order of raw samples, little or big.
-pNAME=VALUE, repeatablenoneSet an encoder plugin parameter as NAME=VALUE. Repeatable; prefix with the encoder name (x265:ctu=64) to reach the library’s own options.
--separatornot usedEnd of options; everything after is an input filename.
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
qualityinteger 0–10050Lossy quality, mapped to x265 CRF.
losslessbooleanfalsex265 lossless mode. Use chroma=444 for exact RGB.
presetx265 preset nameslowx265 speed preset. Slower presets compress better.
tunepsnr, ssim, grain, fastdecodessimx265 tune. ssim is the plugin default, not x265’s own default.
tu-intra-depthinteger 1–42Maximum intra transform-unit split depth. Higher is slower.
complexityinteger 0–100unsetExtra effort, 0–100: 60+ enables rd 6 and rd-refine, 70+ cu-lossless, 90+ turns off WPP. Slower for small gains.
chroma420, 422 or 444420Chroma subsampling of the coded image.

Optional libheif Kvazaar plugin parameters

Section titled “Optional libheif Kvazaar plugin parameters”
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
qualityinteger 0–10050Lossy quality.
losslessbooleanfalseLossless mode. The plugin only accepts 4:2:0 for colour input, so RGB isn’t preserved exactly.