Troubleshooting

WordPress HEIC Upload: What Core Does and Why It Fails

WordPress has allowed .heic uploads since 6.7 and converts them to JPEG on the way in, but only when the server has a HEIC-capable Imagick. Here is what core actually does with the file, why the same site answers differently through a browser and through WP-CLI, and which fix stops the problem instead of managing it.

WordPress HEIC Upload: What Core Does and Why It Fails

Someone sends you a photo straight off an iPhone. You drag it into the media library and one of three things happens. It gets rejected. It uploads and the grid shows a grey rectangle where the thumbnail should be. Or it uploads, looks perfect on your Mac, and a reader emails to say the image is broken.

All three trace back to one file format and one missing piece on the server. The format is HEIC. The missing piece is a decoder, and whether you have one is decided by your host, not by WordPress.

A WordPress HEIC upload has been allowed since 6.7, and core converts the file to JPEG on the way in. That is new behaviour, it is not what most of the guides on this subject describe, and it only runs when the server can open the file at all.

What follows is what the code does, read out of WordPress 7.0.4 rather than out of release notes, with this server as the worked example.

The format, in one paragraph

HEIC is an HEVC-encoded image inside an ISO base media container, the still-image sibling of the video codec. An iPhone has written photos this way by default since iOS 11, under Settings, Camera, Formats, High Efficiency. The files are markedly smaller than a JPEG of comparable quality, which is why Apple picked it. Safari on recent macOS and iOS renders one inside an img tag. Chrome, Firefox and Edge do not, and there is little sign of that changing given how HEVC licensing works. A HEIC in a public web page is a file that a minority of your visitors can see. For the longer argument about what to publish in, the comparison of JPEG, PNG, WebP and AVIF covers the tradeoffs.

What core does with a .heic upload now

Start with the allow list. wp_get_mime_types() in wp-includes/functions.php carries four HEIC entries: heic maps to image/heic, heif to image/heif, heics to image/heic-sequence and heifs to image/heif-sequence. The extension passes validation with no filter of yours involved.

wp_check_filetype_and_ext() then sniffs the file’s real type and, for HEIC specifically, rewrites the filename extension. The map behind the getimagesize_mimes_to_exts filter sends all four HEIC mime types to a single .heic extension, with a comment in core admitting this is a compatibility compromise rather than a correct mapping. A file arriving as IMG_4021.heif is stored as IMG_4021.heic, and the attachment is recorded as image/heic whichever of the four it really was. That normalisation is what makes the later equality check work.

Then wp_generate_attachment_metadata() in wp-admin/includes/image.php makes an explicit exception for the format. Its condition tests for image/heic first, then falls back to the normal check that the mime starts with image/ and that file_is_displayable_image() agrees. HEIC needs the first half because it fails the second: the displayable list inside file_is_displayable_image() is GIF, JPEG, PNG, BMP, ICO, WebP and AVIF. IMAGETYPE_HEIF is not on it.

From there wp_create_image_subsizes() decides what the file becomes. Two conditions can rewrite it, and they are mutually exclusive rather than cumulative:

  • Width or height above big_image_size_threshold, 2560 pixels by default, sets the scale-down branch. A full size phone photo clears that on the long edge without effort.
  • Only if the image is under the threshold does core consult the output format map. wp_get_image_editor_output_format() in wp-includes/media.php returns all four HEIC mime types mapped to image/jpeg as its default. The image_editor_output_format filter has existed since 5.8 but returned an empty array until 6.7.

The conversion happens either way, because the format map is applied at save time rather than in the branch. WP_Image_Editor::get_output_format() rewrites both the mime type and the extension of whatever filename it was handed. So generate_filename( 'scaled' ) produces IMG_4021-scaled.heic and save() writes IMG_4021-scaled.jpg at quality 82, the default from get_default_quality(). A HEIC that happens to sit under 2560 pixels takes the convert branch, which saves with an empty suffix and gives you a plain IMG_4021.jpg. Core anticipates the resulting name clash: wp_unique_filename() consults the same output map on upload, so an incoming HEIC is renamed if the matching .jpg already sits in that month’s folder.

_wp_image_meta_replace_original() then repoints _wp_attached_file at the JPEG and records the HEIC filename in image_meta['original_image']. The .heic stays on disk and nothing WordPress serves points at it. The sub-sizes are generated from that preserved original rather than from the scaled JPEG, which core does for quality, so every registered size is its own HEIC decode that lands as a .jpg. If the way a single upload turns into a dozen files is still fuzzy, the walkthrough of registered image sizes and what -scaled means is the background reading.

Flow diagram of a .heic upload through WordPress 7.0.4, from the mime allow list to the metadata exception, the image editor check, sub-size creation and the swap that makes the JPEG the attached file.

The encoder decides whether any of that happens

Everything above is conditional on wp_get_image_editor() returning an object rather than a WP_Error. Underneath it, _wp_image_editor_choose() walks the registered implementations and asks each one two questions: does ::test() pass, and does ::supports_mime_type() say yes for this mime type.

WP_Image_Editor_GD::supports_mime_type() is a switch statement with five cases, each one checked against the imagetypes() bitmask: image/jpeg, image/png, image/gif, image/webp and image/avif. Anything else falls through to return false. There is no HEIC case, and no PHP build option adds one. GD cannot open a HEIC, on any server, in any version.

WP_Image_Editor_Imagick::supports_mime_type() resolves the mime to a file extension, uppercases it and calls Imagick::queryFormats( 'HEIC' ), after refusing anything other than JPEG when Imagick::setIteratorIndex() is missing. So HEIC support in WordPress means precisely one thing: the Imagick extension, compiled against an ImageMagick that has a working libheif delegate. There is no second route and no fallback.

queryFormats() is optimistic. It lists coders ImageMagick has registered, which is not the same as delegates that actually function. The honest check is to ask WordPress the question WordPress will ask itself, with wp_image_editor_supports(). Which is where the real trap opens up, because that command almost certainly did not run on the PHP your site runs on.

Web PHP and shell PHP are two different servers

This site sits on a Plesk box, and the values below are the real ones, not an illustration.

# the PHP the site itself runs on
/opt/plesk/php/8.5/bin/php -v
# PHP 8.5.9 (cli), imagick 3.8.1, ImageMagick 6.9.12-98 Q16

# the PHP that WP-CLI picks up by default
wp --info
# PHP binary:  /usr/bin/php8.3
# PHP version: 8.3.6      (gd loaded, imagick not present)

# ask WordPress which editor it would choose, under each binary
wp eval 'echo (_wp_image_editor_choose( array( "mime_type" => "image/heic" ) ) ?: "none"), PHP_EOL;'
# none

/opt/plesk/php/8.5/bin/php /usr/local/bin/wp eval 
  'echo (_wp_image_editor_choose( array( "mime_type" => "image/heic" ) ) ?: "none"), PHP_EOL;
   var_dump( wp_image_editor_supports( array( "mime_type" => "image/heic" ) ) );'
# WP_Image_Editor_Imagick
# bool(true)

Two PHP versions, two extension sets, one site. A browser upload runs through 8.5 and Imagick and converts correctly. Anything run from the shell runs through 8.3 and GD, where for image/heic there is no editor at all. Same database, same files, opposite answers.

On this box Imagick::queryFormats( 'HEIC' ) comes back with HEIC, and libheif and libde265, the HEVC decoder, are both installed. Reading is the direction WordPress needs. Writing HEIC fails here and returns a zero byte blob, since no HEVC encoder is present, and that is harmless: core never asks anything to write HEIC, only to read it and write JPEG.

The practical consequence is worth spelling out. wp media regenerate and /opt/plesk/php/8.5/bin/php /usr/local/bin/wp media regenerate are not the same command on this server. Any shell task that has to reopen the preserved original_image, a bulk import that sideloads HEIC files, a migration script, a custom cron job, is running a different image stack than your visitors are. Run wp --info, compare the PHP binary it reports against the one your host panel assigns to the domain, and invoke WP-CLI through the site’s binary when they differ. It is one plain explanation when a regeneration run quietly produces fewer files than you expected.

Table comparing two PHP runtimes on the same Plesk server, PHP 8.5.9 with imagick 3.8.1 serving browser uploads against PHP 8.3.6 with GD only for WP-CLI, and the image editor each one picks for image/heic.

The metadata that survives and the metadata that does not

wp_read_image_metadata() is where WordPress copies EXIF and IPTC into the attachment record. On a server that can decode HEIC it does return an array for one, but a hollow one. It calls exif_read_data() only when the detected image type appears in the list behind the wp_read_image_metadata_types filter, and that list defaults to three entries: IMAGETYPE_JPEG, IMAGETYPE_TIFF_II and IMAGETYPE_TIFF_MM.

A HEIC comes back as IMAGETYPE_HEIF, a constant PHP only defines natively from 8.5 onward and which core otherwise defines as 20 in wp-includes/compat.php. It is not on the list, so no camera model, no shutter speed, no created timestamp and no orientation value reach the database. IPTC does not either: that path needs the APP13 block from the second argument of getimagesize(), which the HEIC route never fills. The one field that does survive is alt text, because wp_get_image_alttext() scans the raw bytes for an x:xmpmeta block and parses it, and that works on any container. If you are cleaning up descriptions in bulk, that is the one field a HEIC still hands you.

Rotation has a subtler failure. maybe_exif_rotate() is called for a HEIC, because the empty metadata array still counts as an array. But WP_Image_Editor::maybe_exif_rotate() only reads the Orientation tag when the editor’s own mime type is image/jpeg. For a HEIC the orientation stays null and the method returns false without touching the pixels. Whether your portrait photo comes out the right way up is decided by how ImageMagick handles the file on open, not by WordPress, and the wp_image_maybe_exif_rotate filter is the only hook that can supply the value.

Now the part that matters more. WP_Image_Editor_Imagick::strip_meta() runs during a resize, gated by the image_strip_meta filter which defaults to true, and it removes every embedded profile except a protected list: icc, icm, iptc, exif and xmp. EXIF is on that list deliberately, because core wants to keep the orientation tag. GPS coordinates live in the EXIF block.

So a HEIC upload lands WordPress in the worst of both positions. It does not read the location into the database, where you could see it in the attachment record and clear it. And it does not strip it out of the JPEG it publishes. If your site takes photo submissions from readers, staff or clients, the piece on EXIF, IPTC and GPS data in uploads is worth reading before you accept another one.

Before you pick a fix, it helps to know what the file in front of you actually is, because .heic is a container name and not a format. The inspector below reads the box structure out of the bytes.

It reports the brand, so you can see whether that photograph is really HEVC in a HEIF container or an AVIF wearing the wrong extension, whether the image is tiled, whether it is one picture or a burst, and what dimensions the header claims. Converting in the browser would need a decoder library from somewhere else, and this tool does not load one, so what it gives you instead is the exact reason your upload failed and the one line that converts the file on your own machine.

HEIC file inspector

Drop a file that WordPress refused and this reads the container itself: the brand, the items inside, the dimensions, the rotation and whether the picture is stored as tiles. It then says in plain words why the upload failed and what to do instead. The file is read in this browser tab with FileReader, it is never uploaded and no request of any kind is made.

Drop a file here
or press Enter to pick one. Any file, not only HEIC. Nothing is uploaded. The bytes are read in this tab and forgotten when you leave the page.
No file read yet
Why the upload fails
  • Before WordPress 6.7 the file never got through the door. Every upload goes through wp_check_filetype_and_ext(), and the result is compared with the list from get_allowed_mime_types(). HEIC was not on that list, so the media library answered Sorry, this file type is not permitted for security reasons. and nothing else happened. Any installation that has not been updated still behaves exactly this way, and retrying the upload will never change it.
  • From WordPress 6.7 core takes the file and converts it for you. All four types are recognised: image/heic, image/heif, image/heic-sequence and image/heif-sequence. The upload is turned into a JPEG on the server, and that JPEG is what the site uses from then on.
  • The original is kept. The HEIC file stays on the server and the attachment page carries a link to download it, so the conversion on upload does not cost you the file you started with.
  • The conversion only runs when the server ImageMagick can read HEIC. That means an Imagick built against libheif. GD cannot read HEIC at all: there is no imagecreatefromheic() and there never will be, because GD has no HEVC decoder. WordPress 6.7 does not add a decoder, it only uses one that is already installed.
  • Check your own server instead of guessing. In the admin open Tools, then Site Health, then Info, then Media Handling, and read the line ImageMagick supported file formats. If HEIC is not among them, the conversion cannot run on your site. That line is the one place an operator can see the answer without asking the host.
  • When it cannot convert, WordPress says so and hands the job back. The upload shows a warning that asks you to convert the file yourself before uploading it. That warning is where people on a current WordPress end up, and the refusal further up is where people on an older one end up. Both are the same missing decoder wearing different clothes, and both are fixed by converting before the upload.
  • A missing decoder also means no intermediate sizes. wp_generate_attachment_metadata() gives up, the media library shows a generic file icon, the_post_thumbnail() has nothing to render and the srcset stays empty. The file may sit in the uploads folder looking fine while every size derived from it is missing.
  • An upload_mimes filter on an older install only moves the failure later. Allowing the type does not add a decoder. The file lands on disk and every step after it still fails, which is harder to find than a refusal at the door.
  • Browsers do not help either. Only Safari shows a HEIC file, so even an upload that goes through leaves most visitors with a broken image unless something converted it first.
What actually works

Stop making them. On the iPhone open Settings, then Camera, then Formats, and choose Most Compatible. New photos are written as JPEG. Photos already on the phone stay HEIC, so the steps below are still worth having.

Convert on the way out of Photos. Select the pictures, then File, then Export, then Export Photos, and set Photo Kind to JPEG. The entry just above it, Export Unmodified Original, hands you the HEIC back, which is the usual reason people think the export did not work.

Let the transfer do it. Settings, then Photos, then Transfer to Mac or PC, set to Automatic. Photos copied over a cable arrive as JPEG. Set to Keep Originals they arrive as HEIC.

On a Mac, one file at a time. sips ships with macOS, nothing to install.

sips -s format jpeg IMG_0001.HEIC --out IMG_0001.jpg

On a Mac, a whole folder. Run this in the folder that holds the files.

for f in *.HEIC; do sips -s format jpeg "$f" --out "${f%.*}.jpg"; done

On Linux. heif-convert comes with the libheif examples package, libheif-examples on Debian and Ubuntu.

heif-convert IMG_0001.HEIC IMG_0001.jpg

With ImageMagick, when the build has libheif. The same command tells you whether it does: without the delegate it refuses the file rather than writing something wrong.

magick IMG_0001.HEIC -quality 82 IMG_0001.jpg

Check what your server can do. Run this on the host before blaming WordPress.

php -r 'print_r(class_exists("Imagick") ? Imagick::queryFormats("HEI*") : "no Imagick");'

Converting HEIC inside this page would need an HEVC decoder, which browsers do not expose to a canvas. The only way round it is a WebAssembly build of libheif fetched from somewhere else, and this tool makes no network requests at all, so it does not offer that. Reading the container needs nothing but the bytes, which is why that part is here.

WunderPaint
The Dynamic Design and Automation Studio
WunderPaint is a layered image editor for your WordPress media library. WunderPaint Studio is the same thing in any browser, free and without an account.

The fixes, ranked by whether the problem comes back

Change the camera format. On the iPhone: Settings, Camera, Formats, then choose Most Compatible instead of High Efficiency. The phone writes JPEG at capture from that moment on and there is no HEIC to handle, on this site or any other site the photos ever reach. Files get larger. Certain high frame rate video modes stay HEVC regardless of the setting. This is the only fix that ends the problem instead of managing it, which is why it belongs first even though it happens nowhere near WordPress.

Change how the phone exports. If you want to keep shooting High Efficiency for the storage saving, Settings, Photos, Transfer to Mac or PC, set to Automatic, converts on the way out to a computer. Keep Originals hands you the raw .heic. This also explains the most maddening version of the bug: uploading through the iOS photo picker in Safari usually hands the site a JPEG, while AirDropping the same shot to a Mac and dragging it in hands the site a HEIC. Two people, same photo, two different formats arriving, both of them convinced the other is doing something wrong.

Convert before upload. For photos that already exist, macOS Preview exports one at a time with the format set to JPEG. In Photos, use the plain File, Export and pick JPEG, because Export Unmodified Original does exactly what it says and gives you the HEIC back. This is the right answer when you cannot change how the photos were taken.

Convert on the server. This is core’s default behaviour in 6.7 and later, it needs no code, and it works provided the encoder check above returns true. If it does not, installing Imagick with libheif comes before every other step in this list. For a library that already holds originals in the wrong format, WunderPaint’s batch image processor converts across a selection rather than one file at a time.

One optional change worth knowing about. If you would rather the derived files be WebP than JPEG, the output map is filterable, and this is the correct place to do it rather than bolting a conversion plugin on top:

add_filter( 'image_editor_output_format', function ( $formats ) {
	$formats['image/heic'] = 'image/webp';
	$formats['image/heif'] = 'image/webp';

	return $formats;
} );

Every sub-size then lands as .webp, at quality 86 rather than 82, because get_default_quality() carries a separate case for WebP. Confirm Imagick::queryFormats( 'WEBP' ) is true first, and note that this applies to uploads made after the filter is active, not retroactively to what is already in the library.

Allowing the mime type without a decoder

Search this problem and an upload_mimes snippet arrives within two results. On 6.7 and later it is redundant, because heic is already in wp_get_mime_types(). On a server without a HEIC-capable Imagick it is considerably worse than redundant.

Walk the failure through. The file passes the allow list and is moved into uploads. The attachment post is created. wp_generate_attachment_metadata() takes the HEIC branch and calls wp_create_image_subsizes(), which begins with wp_getimagesize(). For a HEIC that function asks for an image editor, receives a WP_Error, and returns false. wp_create_image_subsizes() sees an empty size and returns an empty array before it does anything else.

The attachment now exists with no width, no height and no sizes array. Nothing downstream can build a srcset, pick a thumbnail, fill an og:image or hand the block editor a preview. The media grid shows a broken image because the only file that exists is a .heic and the browser will not draw it. A clean rejection tells you something. A silent success gives you a library full of attachments that look complete in the database and render nowhere.

Core does try to warn you. wp_plupload_default_settings() checks wp_image_editor_supports() for image/heic, sets a heic_upload_error flag when the check fails, and the uploader JavaScript then shows: This image cannot be displayed in a web browser. For best results convert it to JPEG before uploading. Two things about that message are worth knowing. It is a warning, not a block: the WebP and AVIF branches sitting next to it in the same handler call removeFile() and abort the upload, while the HEIC branch pushes the error and lets the file through anyway. And the check fires on the browser reporting the file type as exactly image/heic, which not every browser and every drag-and-drop path does.

There is also a second route that is supposed to set the same flag through the plupload_init filter, wp_show_heic_upload_error() in wp-includes/media.php. In 7.0.4 that function assigns to a local $plupload_init variable and then returns $plupload_settings untouched, so on that path it sets nothing. The warning you see in the media modal comes from wp_plupload_default_settings(), not from there.

If you want the rejection to be honest on a server that cannot convert, the useful snippet removes the types rather than adding them. It checks first, so it stays inert on a server that can convert:

add_filter( 'upload_mimes', function ( $mimes ) {
	if ( wp_image_editor_supports( array( 'mime_type' => 'image/heic' ) ) ) {
		return $mimes;
	}

	unset( $mimes['heic'], $mimes['heif'], $mimes['heics'], $mimes['heifs'] );

	return $mimes;
} );

Uploads then fail immediately with “Sorry, you are not allowed to upload this file type.”, which on that server is the truth. Nobody publishes an invisible image and finds out three weeks later.

Two panels listing the files left in the uploads folder after the same HEIC upload, one server producing a scaled JPEG plus four sub-sizes, the other producing only the original .heic.

Symptom and cause

The upload is rejected as a file type you are not allowed to upload. Either the site is older than 6.7, or something is filtering upload_mimes: a security plugin, a hardening snippet in a mu-plugin, a host level rule. On multisite there is a third candidate, the network’s upload_filetypes site option, which falls back to four extensions: jpg, jpeg, png and gif.

The upload succeeds and the thumbnail is blank. The server has no HEIC decoder, so no sub-sizes were created and the attachment metadata is empty. Look in the uploads folder for the month in question: a .heic file with no matching .jpg beside it confirms it in one glance.

The image displays for you and for nobody else. The published URL points at the .heic itself. Safari draws it, everything else shows a broken image. This happens to files uploaded before the site could convert, and to files inserted by URL rather than through the media library.

Browser uploads work and a shell import produces nothing. The web request and WP-CLI are on different PHP binaries with different extension sets. Run wp --info, compare the PHP binary it names against the one your host panel assigns to the domain, and drive WP-CLI through the site’s binary.

The upload dies partway through with an HTTP error. Not a format problem. Decoding a large HEIC through Imagick and re-encoding it costs real memory, and it fails the way any oversized upload does. The causes behind HTTP error on image upload covers the memory ceilings and timeouts involved.

Where that leaves you

This problem is confusing mainly because it moved. For years the answer was that WordPress does not accept HEIC and you should convert first, which was true, simple and easy to write a tutorial about. Since 6.7 the answer depends entirely on your server, and the same site can give different results depending on whether the request came through a browser or a shell, and on whether whoever assembled the PHP stack happened to include libheif.

The diagnostic order is worth internalising because it never changes. First establish whether an image editor exists for image/heic on the PHP that actually serves your pages, because every other behaviour follows from that one answer. Then look at the uploads directory rather than at the media grid, because the filenames tell you exactly which branch of wp_create_image_subsizes() ran: a -scaled.jpg sitting next to the .heic means conversion worked, a lone .heic means it did not. Only after those two checks does it make sense to change any setting.

And the fix that holds is upstream of WordPress entirely. A server that converts today is one host migration or one hardened PHP image away from not converting tomorrow, and nothing in the admin will tell you when that happens. A phone set to Most Compatible keeps sending JPEGs no matter what the server does, and the whole class of problem stops arriving at the door. Fix the server so the library you already have becomes usable, then change the setting on the phone so next year’s photos never need the fix.

WordPress HEIC Upload: What Core Does and Why It Fails

Table of Contents

Learn it by building something

Every week one thing you can make the same afternoon, from dynamic templates to 3D type. Written down step by step.

One mail a week, and then it ends.
Unsubscribe in one click.

WordPress Images

Responsive Hero Images: The Focal Point Decides Everything

Your hero becomes a 3.2:1 strip on desktop and a portrait crop on phones, and object-fit: cover decides what survives. The formula behind the crop, the CSS that steers it, and a simulator that shows all four breakpoints before you publish.

Photo Editing

Content Aware Resize: Changing a Photo’s Shape Without Squashing Anyone

One photograph has to be a wide header, a square thumbnail and a tall story card. Cropping loses the edges, stretching lies about proportions, letterboxing buys space it never uses. Seam carving spends the quiet parts of the frame instead: what a seam is, why the search needs a table, and exactly where the method falls apart.

Print & Craft

QR and Barcode Generator: The Codes People Actually Need

A WiFi QR code generator that runs entirely in your tab, plus the payload syntax, error correction maths and print sizes that decide whether a code scans.

Speed & Performance

Regenerate Thumbnails in WordPress: What It Fixes and What It Leaves Behind

Regenerating thumbnails re-encodes every registered size from the original file. Here is when it is genuinely needed, what each WP-CLI flag really does, why --only-missing quietly keeps the old files, and the order that stops your uploads folder growing.

WordPress Images

WordPress Replace Image: Swap the File, Keep Every Link

WordPress has no replace function, because an attachment is a path plus a cached description of whatever sits at that path. This is why a re-upload becomes hero-1.jpg, what an SFTP overwrite really leaves behind, and the order of operations that swaps a file without breaking twenty references.

Troubleshooting

HTTP Error When Uploading Images to WordPress: The Real Causes

The red bar reading HTTP error is not a verdict on your image. It is the uploader reporting that the POST to async-upload.php came back unusable, and six unrelated failures produce exactly that. Here is how to tell them apart in about ten seconds.

Download the free WunderPaint Plugin for WordPress

The WunderPaint workspace with the layers panel, adjustment sliders, text style presets and the asset library along the bottom

The Image Editor & Design Studio

Everything described here can be done in the browser, on your own site. The live demo runs the full editor with nothing to install.

Free

Chaos Art

Autonomous painters make one-of-a-kind abstract art in 3D space - gestures, art movements, painterly media, and embeds that paint a new original for every visitor.

Pro

Particle Strokes

Paint with swarms of light: twenty-two movements, a stamp you draw yourself, and curves that give a stroke a shape - the swarm keeps painting for a few seconds after you let go.

Pro

City Diorama

Any place on earth as a miniature you could hold: real streets, water and building footprints raised into a 3D diorama - or wrapped around a sphere as your own tiny planet.

Free

Papercut Art

Layered paper pictures with real depth - a photo sliced along its actual depth into up to twenty layers, parametric landscapes, animals and clouds you can shape, letters with real counters, and a look that runs on three dials.

Pro

3D Earth Studio

A hyperrealistic globe - day and night with city lights, live clouds, atmosphere halo, country borders and highlights, click-to-place markers with flight-route arcs, satellite orbits, seamless rotation video and a live website embed.