Read and Write Exif Tags and Comments - Windows C DLL

This tutorial shows how to read and write Exif tags and comments in a Windows C/C++ API application using the LEADTOOLS SDK.

Overview  
Summary This tutorial covers how to work with Exif tags and comments in a Windows C DLL application.
Completion Time 30 minutes
Visual Studio Project Download tutorial project (20 KB)
Platform Windows C DLL Application
IDE Visual Studio 2017, 2019
Development License Download LEADTOOLS
Try it in another language

Required Knowledge

Get familiar with the basic steps of creating a project and loading/displaying an image by reviewing the Add References and Set a License and Load, Display, and Save Images tutorials, before working on the Read and Write Exif Tags and Comments - Windows C DLL tutorial.

Create the Project and Add LEADTOOLS References

Start with a copy of the project created in the Load, Display, and Save Images tutorial. If the project is not available, create it by following the steps in that tutorial.

Open the pre-compiled header file (either pch.h or stdafx.h, depending on the version of Visual Studio used) and ensure the below lines are added.

#define LTV22_CONFIG  
#include "C:\LEADTOOLS22\Include\L_Bitmap.h" // use the actual path where LEADTOOLS is installed  
 
#pragma comment (lib, "C:\\LEADTOOLS22\\Lib\\CDLL\\x64\\Ltkrn_x.lib")  
#pragma comment (lib, "C:\\LEADTOOLS22\\Lib\\CDLL\\x64\\Ltfil_x.lib") // file loading and saving  
#pragma comment (lib, "C:\\LEADTOOLS22\\Lib\\CDLL\\x64\\Ltdis_x.lib") // image display 

Note

For a complete list of DLLs that are required for specific application features, refer to Files to be Included with your Application - C API

Set the License File

The License unlocks the features needed for the project. It must be set before any toolkit functionality is called. For details, including tutorials for different platforms, refer to Setting a Runtime License.

There are two types of runtime licenses:

Note

Adding LEADTOOLS references and setting a license are covered in more detail in the Add References and Set a License tutorial.

Add the Read/Write Exif Comments Code

With the project created, the references added, the license set, and the load image code added, coding can begin.

In the Solution Explorer, double-click the resources file (.rc).

Add a new Exif &Comment menu item to the File drop-down menu, between the Open and Save items. Leave the new menu item's ID as ID_FILE_EXIFCOMMENT.

Open the project's CPP file and navigate to the WndProc function. Under the switch (wmId) statement that is below the WM_COMMAND case, add a new case and the code below.

switch (wmId) 
{ 
   case ID_FILE_EXIFCOMMENT: 
      ReadAndWriteExifComments(hWnd); 
      break; 
      // Keep rest of the code as is 

Add the ReadAndWriteExifComments function below to flip the loaded image, write a comment to the file stating that the image has been flipped, and then read the user comment created.

void ReadAndWriteExifComments(HWND hWnd) 
{ 
   L_TCHAR szSrcFile[260] = TEXT(""), szDestFile[260] = TEXT(""); 
   if (SUCCESS != GetBitmapLoadingName(hWnd, szSrcFile, ARRAYSIZE(szSrcFile))) 
      return; 
   if(LEADBmp.Flags.Allocated) 
      L_FreeBitmap(&LEADBmp); 
   L_LoadBitmap(szSrcFile, &LEADBmp, sizeof(LEADBmp), 24, ORDER_BGR, NULL, NULL); 
   InvalidateRect(hWnd, NULL, TRUE); 
   MessageBox(hWnd, TEXT("Image loaded and will be flipped.\nSelect output file"), TEXT("LEADTOOLS Demo"), MB_ICONINFORMATION); 
   // Flip the image. 
   L_FlipBitmap(&LEADBmp); 
   InvalidateRect(hWnd, NULL, TRUE); 
 
   // Specify output file 
   if (SUCCESS != GetBitmapSavingName(hWnd, szDestFile, ARRAYSIZE(szDestFile))) 
      return; 
 
   // Load the current comments from the file 
   for (int 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 
      L_INT CommentLength = L_ReadFileComment(szSrcFile, i, NULL, 0, NULL); 
      if (CommentLength > 0) 
      { 
         L_UCHAR* pCommentToGet = new L_UCHAR[CommentLength](); // parentheses initialize array to zeros 
         // Get the comment from the file 
         L_ReadFileComment(szSrcFile, i, pCommentToGet, CommentLength, NULL); 
         // Set the comment to be saved 
         L_SetComment(i, pCommentToGet, CommentLength); 
         delete[] pCommentToGet; 
      } 
   } 
 
   // Create the CMNT_USERCOMMENT comment as a byte array 
   // When writing a user comment, the first 8 bytes must contain the "ASCII" word.   
 
   L_SetComment(CMNT_USERCOMMENT, NULL, 0); 
   // IMPORTANT: initializing CommentToSet array causes remainder of array to contain null characters, which is needed for rest of code to work 
   L_UCHAR CommentToSet[80] = "ASCII"; 
   const L_CHAR* pUserComment = "The image has been flipped!"; 
   strcpy_s((char *)CommentToSet + 8, sizeof CommentToSet - 8, pUserComment); 
   // Set the CMNT_USERCOMMENT comment 
   L_SetComment(CMNT_USERCOMMENT, CommentToSet, (L_UINT)strlen(pUserComment) + 9); 
   L_SaveBitmap(szDestFile, &LEADBmp, FILE_EXIF, 24, 0, NULL); 
   L_UCHAR CommentCheck[80] = ""; 
   L_ReadFileComment(szDestFile, CMNT_USERCOMMENT, CommentCheck, sizeof CommentCheck, NULL); 
   char szMessageA[256] = "Comment read back from file:\n"; 
   strcat_s(szMessageA, sizeof szMessageA, (const char *)CommentCheck + 8); 
   // The returned string is in ASCII, so the "MessageBoxA" function is used to display it 
   MessageBoxA(hWnd, szMessageA, "LEADTOOLS Demo", MB_OK); 
} 

The code for the GetBitmapLoadingName() and GetBitmapSavingName() functions, called inside the code above, is listed in the Load, Display, and Save Images tutorial.

Add the Read/Write Exif Tags Code

Using the Solution Explorer, navigate back to the resources file (.rc).

Add a new EXIF &Tag menu item to the File drop-down menu, between the Open and Save items. Leave the new menu item's ID as ID_FILE_EXIFTAG.

Go to the WndProc function and under the switch (wmId) statement that is below the WM_COMMAND case, add a new case and the code below.

switch (wmId) 
{ 
case ID_FILE_EXIFTAG: 
   ReadAndWriteExifTags(hWnd); 
   break; 
   // Keep rest of the code as is 

Add the code of the ReadAndWriteExifTags function, which adds a custom text tag to the EXIF file then reads all the tags back from the file.

void ReadAndWriteExifTags(HWND hWnd) 
{ 
   L_TCHAR szExifFile[260] = TEXT(""); 
   if (SUCCESS != GetBitmapLoadingName(hWnd, szExifFile, ARRAYSIZE(szExifFile))) 
      return; 
 
   FILEINFO info = { 0 }; // Important: Must initialize to zero 
   info.uStructSize = sizeof info; 
   L_FileInfo(szExifFile, &info, sizeof info, 0, NULL); 
   if (!L_TagsSupported(info.Format)) 
   { 
      MessageBox(hWnd, TEXT("File Format Does Not Support Tags"), TEXT("LEADTOOLS Demo"), MB_ICONERROR); 
      return; 
   } 
 
   // Add a private (custom) "Phone Number" tag 
   L_UINT16 PhoneNumber = 0x8001; 
   char TagData[] = "+1-800-637-4699"; 
   // Set the tag data to be saved 
   L_SetTag(PhoneNumber, TAG_ASCII, sizeof TagData, TagData); 
   // Save the the tag into the file 
   L_WriteFileTag(szExifFile, NULL); 
   // Clear the tag from memory 
   L_SetTag(0, 0, 0, NULL); 
 
   // Read the tags from the file and display them in the debugger window 
   L_UINT uTagCount = 0; 
   pLEADFILETAG pTags = NULL, pCurrentTag; 
   L_SIZE_T uTagDataSize = 0; 
   L_UCHAR* pTagsData = NULL; 
   L_ReadFileTags(szExifFile, 0, &uTagCount, &pTags, &uTagDataSize, &pTagsData, NULL); 
 
   if (uTagCount > 0) 
   { 
      // Show the tags 
      OutputDebugString(TEXT("Tags\n")); 
      for (L_UINT n = 0; n < uTagCount; n++) 
      { 
         pCurrentTag = &pTags[n]; 
 
         // If this tag is of type ASCII, get its data 
         L_CHAR* pszAscii = NULL; 
         if (pCurrentTag->uType == TAG_ASCII) 
         { 
            pszAscii = new L_CHAR[pCurrentTag->uDataSize + 1](); 
            memcpy(pszAscii, pTagsData + pCurrentTag->uDataOffset, pCurrentTag->uDataSize); 
         } 
         else 
         { 
            pszAscii = NULL; 
         } 
         CHAR szMessage[1024]; 
         wsprintfA(szMessage, "Id: 0x%X, data length: %u, data: %s\n", pCurrentTag->uTag, pCurrentTag->uDataSize, pszAscii != NULL ? pszAscii : "Binary data"); 
         if (pszAscii) 
            delete[] pszAscii; 
         OutputDebugStringA(szMessage); 
      } 
      L_FreeFileTags(uTagCount, pTags, uTagDataSize, pTagsData); 
   } 
} 

Run the Project

Run the project by pressing F5, or by selecting Debug -> Start Debugging.

If the steps are followed correctly, the application runs and gives the user the ability to execute the following commands:

Wrap-up

This tutorial showed how to use the L_SetComment, L_ReadFileComment, L_ReadFileTags, L_SetTag and L_WriteFileTag functions with EXIF files.

See Also

Help Version 22.0.2022.9.29
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2022 LEAD Technologies, Inc. All Rights Reserved.


Products | Support | Contact Us | Intellectual Property Notices
© 1991-2022 LEAD Technologies, Inc. All Rights Reserved.