Implementing Exif Features

The Exif file format supports more complex comments than other formats. For a list of the comments, refer to Exif File Comments.

This example demonstrates how to handle Exif comments that are not stored as strings. (For a simpler example for saving strings, refer to the L_SetComment function.)

This example does the following:

1.

Loads a bitmap.

2.

Updates the comment array by loading comments from the existing file.

3.

Reverses the image and creates an ASCII CMNT_USERCOMMENT comment that says that the image has been reversed.

4.

Saves the file. (All of the comments are saved, including the one that we updated.)

5.

Reads and displays two of the comments from the saved file. One of them is the comment that we created. The other is comment that uses the Exif RATIONAL data type.

6.

Cleans up the comment array.

BITMAPHANDLE LeadBitmap;   /* Bitmap handle for the image */ 

void TestFunction(HWND hWnd, L_TCHAR *szFilename )
{
   L_CHAR  * pCommentToGet; /* Comment string that we will get */
   HGLOBAL hCommentToGet;        /* Handle for memory management */
   L_INT CommentLength;          /* Length of the string */
   L_UCHAR CommentToSet[80]; /* Comment string that we will set */
   L_CHAR  * pCommentToSet = CommentToSet;
   L_UCHAR szUserComment[80]; /* User comment that we will add */
   L_CHAR  * pUserComment = szUserComment;
   L_UINT32  * pDistance;       /* Pointer for the Exif RATIONAL */
   L_UINT32 Numerator, Denominator; /* Components of the Exif RATIONAL */
   float fDistance; /* Result of the distance calculation */
   L_TCHAR szMessage[256]; /* MessageBox string */

   L_TCHAR szBuf[80];
   L_INT i; /* Loop counter */
   /* Load the bitmap */
   L_LoadBitmap (szFilename, &LeadBitmap, sizeof(BITMAPHANDLE), 0, ORDER_BGR, NULL, NULL);
   /* Load the current comments from the file */
   for(i = 0 ; i < CMNT_LAST ; i++ )
   {
      /* Clear the comment */
      L_SetComment(i, NULL, 0);
      /* Use the return value to get the length of a comment in the file */
      CommentLength = L_ReadFileComment(szFilename, i, NULL, 0, NULL);
      if (CommentLength > 0)
      {
         /* Allocate and lock a zero-filled buffer for the comment */
         hCommentToGet = GlobalAlloc(GHND, CommentLength);
         pCommentToGet = (L_UCHAR  *)GlobalLock( hCommentToGet );
         /* Get the comment from the file */
         L_ReadFileComment(szFilename, i, pCommentToGet, CommentLength, NULL);
         /* Set the comment to be saved */
         L_SetComment(i, pCommentToGet, CommentLength);
         /* Unlock and free memory */
         GlobalUnlock( hCommentToGet );
         GlobalFree(hCommentToGet);
      }
   }
   /* Reverse the image */
   L_ReverseBitmap(&LeadBitmap);
   /* Create the CMNT_USERCOMMENT comment as a byte array */
   L_SetComment(CMNT_USERCOMMENT, NULL, 0);
   pUserComment = "The image has been reversed.";
   pCommentToSet[0] = 'A';
   pCommentToSet[1] = 'S';
   pCommentToSet[2] = 'C';
   pCommentToSet[3] = 'I';
   pCommentToSet[4] = 'I';
   pCommentToSet[5] = '\0';
   pCommentToSet[6] = '\0';
   pCommentToSet[7] = '\0';
   for( i = 0; pUserComment[i] != '\0'; i++)
   {
      pCommentToSet[i+8] = pUserComment[i];
   }
   pCommentToSet[i+8] = '\0';
   /* Set the CMNT_USERCOMMENT comment  */
   L_SetComment(CMNT_USERCOMMENT, pCommentToSet, strlen(pUserComment) + 9);
   /* Save the image as an Exif file */
   L_SaveBitmap(szFilename, &LeadBitmap, FILE_EXIF, 24, 0, NULL);
   /* Initialize the message string */
   szMessage[0] = '\0';
   /* Use the return value to get the length of the CMNT_SUBJECTDISTANCE comment */
   /* This shows how to translate the Exif RATIONAL data type */
   CommentLength = L_ReadFileComment(szFilename, CMNT_SUBJECTDISTANCE, NULL, 0, NULL);
   if (CommentLength > 0)
   {
      /* Allocate and lock a zero-filled buffer for the comment */
      hCommentToGet = GlobalAlloc(GPTR, CommentLength);
      pCommentToGet = (L_UCHAR  *)GlobalLock( hCommentToGet );
      /* Get the actual comment from the file */
      L_ReadFileComment(szFilename, CMNT_SUBJECTDISTANCE, pCommentToGet, CommentLength, NULL);
      pDistance = (L_UINT32  *)pCommentToGet;
      Numerator = pDistance[0];
      Denominator = pDistance[1];
      fDistance = (float)Numerator / (float)Denominator;
      wsprintf (szMessage, TEXT("Subject distance: %.6f\n"),fDistance );
      /* Unlock and free memory */
      GlobalUnlock( hCommentToGet );
      GlobalFree(hCommentToGet);
   }
   /* Use the return value to get the length of the CMNT_USERCOMMENT comment */
   CommentLength = L_ReadFileComment(szFilename, CMNT_USERCOMMENT, NULL, 0, NULL);
   if (CommentLength > 0)
   {
      /* Allocate and lock a zero-filled buffer for the comment */
      hCommentToGet = GlobalAlloc(GPTR, CommentLength);
      pCommentToGet = (L_UCHAR  *)GlobalLock( hCommentToGet );
      /* Get the actual comment from the file */
      L_ReadFileComment(szFilename, CMNT_USERCOMMENT, pCommentToGet, CommentLength, NULL);
      /* If the prefix is ASCII, move the pointer and update the message string */
      if (strcmp(pCommentToGet,"ASCII")== 0)
      {
         pCommentToGet = pCommentToGet + 8;
      }

      wsprintf (szBuf, TEXT("%hs"), pCommentToGet);
      lstrcat(szMessage, szBuf);
      /* Unlock and free memory */
      GlobalUnlock( hCommentToGet );
      GlobalFree(hCommentToGet);
   }
   /* Show the two comments */
   MessageBox (NULL, szMessage, TEXT("Notice"), MB_OK);
   /* Clear the comments */
   for(i = 0 ; i < CMNT_LAST ; i++ )
      L_SetComment(i, NULL, 0);
   /* Force a repaint */
   SendMessage (hWnd, WM_QUERYNEWPALETTE, 0, 0L);
   return;
}