Exif infos in HEIC files

Just starting out? Need help? Post your questions and find answers here.
dige
Addict
Addict
Posts: 1391
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Exif infos in HEIC files

Post by dige »

I have found a javascript project that can read exifos on HEIC files.

https://exif-heic-js.github.io/exif-heic-js/example/

But I fail at the conversion to Purebasic. Probably because I'm doing something wrong with the unsigned data types.

This is the javascript code to find the exif items:

Code: Select all

function findEXIFinHEIC(data)
{
    var dataView = new DataView(data);
    var ftypeSize = dataView.getUint32(0); // size of ftype box
    var metadataSize = dataView.getUint32(ftypeSize); //size of metadata box

    //Scan through metadata until we find (a) Exif, (b) iloc
    var exifOffset = -1;
    var ilocOffset = -1;
    for (var i = ftypeSize; i < metadataSize + ftypeSize; i++)
    {
        if (getStringFromDB(dataView, i, 4) == "Exif")
        {
            exifOffset = i;
        } else if (getStringFromDB(dataView, i, 4) == "iloc")
        {
            ilocOffset = i;
        }
    }

    if (exifOffset == -1 || ilocOffset == -1)
    {
        return null;
    }

    var exifItemIndex = dataView.getUint16(exifOffset - 4);

    //Scan through ilocs to find exif item location
    for (var i = ilocOffset + 12; i < metadataSize + ftypeSize; i += 16)
    {
        var itemIndex = dataView.getUint16(i);
        if (itemIndex == exifItemIndex)
        {
            var exifLocation = dataView.getUint32(i + 8);
            var exifSize = dataView.getUint32(i + 12);
            //Check prefix at exif exifOffset
            var prefixSize = 4 + dataView.getUint32(exifLocation);
            var exifOffset = exifLocation + prefixSize;

            return readEXIFData(dataView, exifOffset);
        }
    }

    return null;
}

My first attempt. Seems that the value for 'exifLocation ' is determined incorrectly

Code: Select all

Procedure LoadHEICtoMem(file.s)
  Protected mem
  
  If ReadFile(0, file)
    mem = AllocateMemory(Lof(0))
    ReadData(0, mem, Lof(0))
  EndIf
  
  ProcedureReturn mem
EndProcedure


Procedure findEXIFinHEIC(mem)
  
  exifOffset = -1
  ilocOffset = -1
  
  Debug PeekS(mem + 4, 8, #PB_Ascii)
  
  If PeekS(mem + 4, 8, #PB_Ascii) = "ftypheic"
    
    For i = mem + 12 To mem + MemorySize(mem)
      If PeekS(i, 4, #PB_Ascii) = "Exif"
        exifOffset = i
        
      ElseIf PeekS(i, 4, #PB_Ascii) = "iloc"
        ilocOffset = i
        Break
      EndIf
    Next
    
  EndIf 
  
  Debug exifOffset
  Debug ilocOffset
  
  If exifOffset = -1 Or ilocOffset = -1
    ProcedureReturn 
  EndIf
  
  exifItemIndex.w = PeekW(exifOffset - 4) & $FFFF
  
  For i = ilocOffset + 12 To mem + MemorySize(mem) Step 16
   
    itemIndex.w = PeekW(i)  & $FFFF
    
    If itemIndex = exifItemIndex
      exifLocation = PeekL(i + 8)  & $FFFFFFFF
      exifSize     = PeekL(i + 12) & $FFFFFFFF
      
      Debug "Filesize      : " + StrU(MemorySize(mem))
      Debug "Memorypointer :" + StrU(mem)
      Debug "ExifLocation  : " + StrU(exifLocation)
      
      ;Check prefix at exif exifOffset
      prefixSize = 4 + PeekL(exifLocation)    ; <--- Illegal memory access
      exifOffset = exifLocation + prefixSize
      
      Debug exifOffset
      
       ;Return readEXIFData(dataView, exifOffset);
    EndIf
  Next
EndProcedure


Does anyone want to help?
"Daddy, I'll run faster, then it is not so far..."
dige
Addict
Addict
Posts: 1391
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Re: Exif infos in HEIC files

Post by dige »

Comparing to the result in the browser, I've found out that the data representation is in Motorola format and still needs to be swapped.

Now I already have the position of the Exif data :-)

Code: Select all

Procedure LoadHEICtoMem(file.s)
  Protected mem
  
  If ReadFile(0, file)
    mem = AllocateMemory(Lof(0))
    ReadData(0, mem, Lof(0))
  EndIf
  
  ProcedureReturn mem
EndProcedure

Procedure SwapLong(l.l) 
  ProcedureReturn (l & $FF) << 24 + (l & $FF00) << 8 + (l >> 8) & $FF00 + (l >> 24) & $FF 
EndProcedure
Procedure SwapWord(w.w) 
  ProcedureReturn (w & $FF) << 8 + (w >> 8) & $FF
EndProcedure

Procedure findEXIFinHEIC(mem)
  
  
  exifOffset = -1
  ilocOffset = -1

  
  If PeekS(mem + 4, 8, #PB_Ascii) = "ftypheic"
    
    ftypeSize    = SwapLong(PeekL(mem))
    metadataSize = SwapLong(PeekL(mem + ftypeSize))
    
    For i = mem + ftypeSize To mem + ftypeSize + metadataSize
      If PeekS(i, 4, #PB_Ascii) = "Exif"
        exifOffset = i - mem
        
      ElseIf PeekS(i, 4, #PB_Ascii) = "iloc"
        ilocOffset = i - mem
        Break
      EndIf
    Next
    
  EndIf 
  
  If exifOffset = -1 Or ilocOffset = -1
    ProcedureReturn 
  EndIf
  
  exifItemIndex.w = SwapWord(PeekW(mem + exifOffset - 4) & $FFFF)
  
  For i = mem + ilocOffset + 12 To mem + ftypeSize + metadataSize Step 16
   
    itemIndex.w = SwapWord(PeekW(i)  & $FFFF)
    
    If itemIndex = exifItemIndex
      exifLocation = SwapLong(PeekL(i + 8)  & $FFFFFFFF)
      exifSize     = SwapLong(PeekL(i + 12) & $FFFFFFFF)
      
      ;Check prefix at exif exifOffset
      prefixSize = 4 + SwapLong(PeekL(mem + exifLocation))
      exifOffset = exifLocation + prefixSize
      
      Debug "ExifOffset @" + StrU(mem + exifOffset)
      
       ;Return readEXIFData(dataView, exifOffset);
    EndIf
  Next
EndProcedure

findEXIFinHEIC(LoadHEICtoMem("C:\Temp\Heic.heic"))
  

"Daddy, I'll run faster, then it is not so far..."
Post Reply