Skip to content

[Bug]: HEIC preview generation fails when identified as JPEG #65411

Open

Description

@RichardPillay

⚠️ This issue respects the following points: ⚠️

  • This is not a troubleshooting question, general support matter, or webserver/proxy problem, but likely a bug (if unsure, ask the Community Help Forum).
  • This issue is not already reported on Github OR solved at the Community Help Forum (I've searched!).
  • I'm using a maintained major version of Nextcloud Server and tested against the latest patch level. (Supported major versions and current patch levels).
  • I agree to follow Nextcloud's Code of Conduct.
  • I've tried my best to provide clear reproduction steps that someone unfamiliar with this bug could use to reproduce it.

Bug description

I am experiencing a HEIC preview-generation failure on Nextcloud Server 34.0.4 - The affected files originate directly from an iPhone 15 running the latest firmware as of Oct 26. I can vouch for them - they have not passed through any untrusted computer.

Nextcloud identifies the files as image/heic based on their filename and MIME-type handling, but PHP Imagick's automatic format detection identifies the image content as image/jpeg.

The HEIC preview provider then fails because it forces Imagick to use the HEIC decoder explicitly. Removing that forced decoder prefix allows Imagick to process the affected files successfully and Nextcloud to generate previews.

This appears to be a compatibility defect in the HEIC preview provider: it assumes that files classified as HEIC by Nextcloud must be readable through the forced HEIC decoder, even when Imagick can successfully identify and process the actual image content using automatic format detection.

Not all HEIC files return image/jpeg when Imagick performs automatic format detection. Some files are identified as HEIC and can be processed normally through the HEIC preview provider. The failure appears to affect files for which Imagick identifies the underlying image content as JPEG despite Nextcloud classifying the file as image/heic.

Since these files came directly from the iPhone 15, this suggests that the Nextcloud provider's assumptions about the relationship between the filename, container format and decoded image format may be too restrictive, or possibly too fixated on filename/extention, while Imagick is more relaxed.

Steps to reproduce

  1. Take a picture with the iPhone 15 using the latest OS version.
  2. Let it upload to Nextcloud via the standard sync, or upload it via the Files app
  3. Try to view the image in File or Memories after allowing the automatic processing to run.

Related issues and security context

This report appears closely related to:

Expected behavior

The files should be viewable seamlessly, the same way an image from an Android device would be.

Nextcloud Server version

34

Operating system

Debian/Ubuntu

PHP engine version

PHP 8.5

Web server

Apache (supported)

Database engine version

PostgreSQL

Is this bug present after an update or on a fresh install?

None

Are you using the Nextcloud Server Encryption module?

None

What user-backends are you using?

  • Default user-backend (database)
  • LDAP/ Active Directory
  • SSO - SAML
  • Other

Configuration report

## Environment

* Nextcloud Server: 34.0.4
* Operating system: Debian
* PHP Imagick: 3.8.1
* ImageMagick: 7.1.1-43 Q16 x86_64
* Preview provider: `OC\Preview\HEIC`, explicitly enabled
* Application affected: Memories, with preview generation also failing through the Nextcloud preview-generation command

List of activated Apps

Nextcloud Signing status

Nextcloud Logs

Additional info

Observed behaviour

For an affected file, IMG_9231.HEIC, PHP Imagick can successfully identify the image using automatic format detection:

$p = "/Data/NextCloud/data/RichardP/files/Photos/Phone/Photos/2024/12/IMG_9231.HEIC[0]";
$i = new Imagick();
$i->pingImage($p);

echo $i->getImageMimeType() . " "
    . $i->getImageWidth() . "x"
    . $i->getImageHeight() . PHP_EOL;

This reports image/jpeg and the image dimensions.

However, forcing the HEIC decoder fails:

$i->pingImage('heic:' . $p);

This produces:

ImagickException: ImageTypeNotSupported
error/heic.c/ReadHEICImage/664

The equivalent test with the heif: prefix also fails.

Nextcloud's occ preview:generate command consequently reports that no provider successfully handled preview generation.

Workaround tested

In lib/private/Preview/HEIC.php, I temporarily modified two lines in getResizedPreview().

Original line:

$bp->pingImage('heic:' . $tmpPath . '[0]');

Changed to:

$bp->pingImage($tmpPath . '[0]');

Original line:

$bp->readImage('heic:' . $tmpPath . '[0]');

Changed to:

$bp->readImage($tmpPath . '[0]');

No other changes were required for this test. With these two prefixes removed, preview generation worked for all three affected HEIC files tested, along with two jpg files also off the iPhone 15.

The remaining processing steps, including MIME-type validation, auto-orientation, JPEG output and resizing, were retained.

Activity

  1. changed the title [-][Bug]: HEIC preview generation fails identified as JPEG[/-] [+][Bug]: HEIC preview generation fails when identified as JPEG[/+] on Oct 12, 2026
  2. invario commented on Oct 12, 2026

    @invario
    Contributor

    This sounds to me like it may be because your HEIC files have embedded JPEG data which is intended for apps to use as the preview instead of having to decompress the HEVC compressed image to generate a preview. ImageMagick will only process one set of data in the HEIC container so it appears to be grabbing the JPEG data instead of the actual HEVC data.

    ImageMagick/ImageMagick#1391

    Perhaps a fix should (instead) be to specify [0] for the image and continue to force image/heic.

    Edit: Sorry, I wrote that when I was tired. Had another look at it and see it already uses [0]. Apparently, forcing/overriding it causes instant failure before the [0] even has a chance to be evaluated.

    I think forcing it with heic was done to mitigate some sort of vulnerability though...

  3. aftertaf commented on Oct 26, 2026

    @aftertaf

    I have the same issue.
    Heic extension but imagemagick sees as jpeg - result is no preview.

    preview generator V 5.15.0 and Nextcloud 35.0.2, on Debian 13.

  4. RichardPillay commented on Oct 26, 2026

    @RichardPillay
    Author

    7. I think forcing it with heic was done to mitigate some sort of vulnerability though...

    Forcing it to be treated as heic is not an issue, I don't think. It's probably the right thing to do. Heic is just a container, not a format. Jpeg is a format - so it says that the file content can be decoded in a certain manner. Heic, though is a container - meaning "this is a file which contains images and or video. Before you know how to read them, you have to read the metadata" This is where the problem lies, I believe. ImageMagick is doing this properly. But when we have the issue, what is happening is probably that Nextcloud is reading the metadata, seeing that it contains a jpg (which may be just one of many images inside the heic), then telling ImageMagick to process the heic file as a jpg.

  5. invario commented on Oct 26, 2026

    @invario
    Contributor

    Do you have a sample problematic image you can share? I'd like to look at this a bit more.

  6. RichardPillay commented on Oct 26, 2026

    @RichardPillay
    Author

    10. Do you have a sample problematic image you can share? I'd like to look at this a bit more.

    Try this one. It's not the original file I used in testing the issue, but it doesn't have any people in it. Let me know if it doesn't show the issue. We've had a few versions of nextcloud since the issue was raised. I'll go back to the iPhone (it's someone else's, not mine) and try the test again. I'll post if the problem has since been solved (or even if it's no longer an issue)

    IMG_9226.zip

  7. invario commented on Oct 26, 2026

    @invario
    Contributor

    Also, there's been some change between 34 and 35, notably they moved code from HEIC.php into a separate HEIF.php and added a method formatHint that is used for the image type but in this case, it's still forced to HEIC.

    I've been reading up on this a bit and here's what Gemini is spitting back at me.

    Why It Fails

    1. Strict ISO BMFF Container Requirement (libheif)
      ImageMagick handles HEIC and AVIF files through an external delegate library called libheif.

    When you force the format to HEIC:, ImageMagick hands the byte stream directly to libheif.

    libheif expects a valid ISO Base Media File Format (ISO BMFF) container structure, which begins with specific box atoms like ftyp (file type box) and meta (metadata box).

    A standard JPEG file or a file with an embedded JPEG preview starts with JPEG binary markers (like FF D8). Because it lacks the ISO BMFF box architecture, libheif rejects the file immediately during parsing, throwing an Invalid input or format error.

    1. How [0] Interacts with HEIF/HEIC Structures
      In ImageMagick, appending [0] tells the decoder to select the first image item or sequence frame from a multi-item container (such as a HEIC container holding a primary image and a thumbnail/auxiliary map).

    However, frame indexing like [0] is evaluated after the format decoder successfully parses the container.

    Because the HEIC decoder (coders/heic.c) fails at the initial ingestion phase on a non-HEIF/non-container file, ImageMagick never reaches the stage where it can evaluate [0].

    1. Embedded Previews Are Not HEIF Items
      An embedded JPEG preview (whether stored in EXIF metadata, a JFIF APP marker, or a camera raw maker note) is wrapped inside a completely different container structure than a HEIF file.

    HEIF stores multiple images as discrete items referenced in an item property table (iprp).

    Even if a file is a true HEIC container that happens to have a secondary JPEG preview item, forcing the type away from its native format or misapplying the coercion prevents ImageMagick from mapping those internal item IDs to standard sequence frames.

    Which is why in my previous reply, I said that I think it's not able to read from the HEVC data contained in [0]... It fails before even getting to the [0].

    Thanks for the sample image, I'm going to play around with it!

  8. invario commented on Oct 26, 2026

    @invario
    Contributor

    I ran your file through magick identify as well as exiftool and ffprobe. It's not an HEIC at all by all accounts. It's entirely a JPEG file with an extension of HEIC. This really makes me wonder how that came to pass being that the file came directly from the iPhone 15. An actual HEIC file's first few bytes would look like this:

    @@@\ftypheic@@@@mif1heictmap@-▒▒mdat@@
    

    Contrasted to the file you gave me which is a JPEG

    ▒▒▒▒@PJFIF@AA@@A@A@@▒▒$▒Exif
    
  9. RichardPillay commented on Oct 27, 2026

    @RichardPillay
    Author

    What I do know about the iPhone is that it's a moving target. Apple is notorious for changing things without notification. But HEIC is merely a container and what is inside could be anything, which in this particular case, is merely a collection of jpg images. The iPhone in later years started taking a series of shots, marking one as the preview, and showing all of them in succession if you hold your finger on the image. This is entirely dependent on what this particular owner's settings are.

  10. invario commented on Oct 27, 2026

    @invario
    Contributor

    Yes I understand that HEIC is a container. But your file is definitely not an HEIC. It is merely a JPEG with the wrong file extension on it. The first few bytes (the magicbytes https://en.wikipedia.org/wiki/List_of_file_signatures) show you exactly what the file type is.

  11. invario commented on Oct 27, 2026

    @invario
    Contributor
    ffprobe from an actual HEIC off my samsung GS25+ with motion photo/video embedded
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '20261003_123558.heic':
      Metadata:
        major_brand     : heic
        minor_version   : 0
        compatible_brands: mif1heictmap
      Duration: N/A, start: 0.000000, bitrate: N/A
      Stream group #0:0[0x31]: Tile Grid: hevc (Main Still Picture) (hvc1 / 0x31637668), yuvj420p(pc, bt470bg/bt470bg/smpte170m), 4000x3000 (default)
        Side data:
          EXIF metadata: (921 bytes)
          ICC Profile: (632 bytes)
      Stream group #0:1[0x37]: Tile Grid: hevc (Main Still Picture) (hvc1 / 0x31637668), yuvj420p(pc), 1000x750
      Stream #0:48[0x32]: Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, bt470bg/bt470bg/smpte170m), 512x384, 1 fps, 1 tbr, 1 tbn
        Side data:
          ICC Profile: (632 bytes)
    
    ffprobe from your file:
    Input #0, jpeg_pipe, from 'IMG_9226.HEIC':
     Duration: N/A, bitrate: N/A
     Stream #0:0: Video: mjpeg (Baseline), yuvj420p(pc, bt470bg/unknown/unknown), 4032x3024 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 25 tbn
    
    You can also check if with exiftool. Your file is definitely a JPEG that's named improperly.

    edit:
    https://heic.fyi/samples/thumbnail-embedded.heic

    Here is an actual HEIC file (container) with an embedded thumbnail (albeit the thumbnail is in HEVC format).

    Output from ffprobe:
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'thumbnail-embedded.heic':
      Metadata:
        major_brand     : heic
        minor_version   : 0
        compatible_brands: mif1heicmiaf
      Duration: N/A, start: 0.000000, bitrate: N/A
      Stream #0:0[0x1]: Video: hevc (Main Still Picture) (hvc1 / 0x31637668), yuvj420p(pc, smpte170m/bt709/iec61966-2-1), 1600x1200, 1 fps, 0.04 tbr, 1 tbn (default)
      Stream #0:1[0x2]: Video: hevc (Main Still Picture) (hvc1 / 0x31637668), yuvj420p(pc, smpte170m/bt709/iec61966-2-1), 320x240, 1 fps, 0.04 tbr, 1 tbn
    

    Note the multiple streams.

  12. aftertaf commented on Oct 27, 2026

    @aftertaf
  13. aftertaf commented on Oct 27, 2026

    @aftertaf

    2 photos.
    1 with 'live' mode and one not.
    exported unmodified originals AND saved to phone ( 2 different iOS options).
    the zip contains the results of both actions.

    trying to attach zip now...😁

  14. aftertaf commented on Oct 27, 2026

    @aftertaf
  15. invario commented on Oct 27, 2026

    @invario
    Contributor

    Thanks. I got your samples. Yours are indeed HEIC files, but they contain regular HEVC encoded image data (not JPEG data.)

    Additionally, your sample files generated preview files just fine when uploaded into my NC34.

    Image
  16. aftertaf commented on Oct 27, 2026

    @aftertaf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    0. Needs triagePending check for reproducibility or if it fits our roadmap34-feedbackbug

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions