Search code examples
image-processingbytecodexmpheicheif

Reading byte by byte HEIF/HEIC images XMP metadata


I am trying to build a native byte parser that given an HEIF image it returns back its metadata (mainly width and height of the image). I am struggling a lot at the moment finding the right documentation and specs to use for parsing such info. I have to do such thing for both XMP and EXIF metadata, but let's focus only on XMP for now.

What I need is the exact byte structure of where to find what. According to the HEIF international standard doc (here):

For image items, XMP metadata shall be stored as an item of item_type value 'mime' and content type'application/rdf+xml'. The body of the item shall be a valid XMP document, in XML form.

Perfect, if I analyse a sample image I can find such marker:

enter image description here

From now on I can't find anywhere how to get the info I need. I would expect something saying "the first 2 bytes are the header, with marker 0xFF 0xCE (just an example), the next 2 bytes are the width, and following 2 bytes the height...etc". In my case I am going by intuition. My sample image is of dimensions 8736x5856. If in the tool I look for Big-Endian 2 byte integer 8736, I can find it:

enter image description here

And hey, 2 bytes later there is the 5856 height as well:

enter image description here

But again, I arrived here by luck and intuition. I need a proper schema that tells me where to find what in such a way that I can traslate it to code.


Solution

  • What I think you'r seeing is a "mime" and "ispe" mp4 box as HEIF is ISOBMFF based. I would recommend looking at the file using a mp4 capable tool like mp4dump, HexFiend or fq (note: my tool). The "ispe" (Image Spatial Extents) box i probably what you want to read.

    fq does no support ispe box yet but you could read it like this:

    $ fq 'grep_by(.type=="ispe").data | tobytes | [.[-8:-4], .[-4:] | tonumber]' file.heif
    [
      8736,
      5856
    ]
    

    So what you need is probably a basic ISOBMFF reader and then look for the "ispe" box and decode it. If you'r only looking for the first of a specific box you can probably ignore that ISOBMFF is a tree structure.