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, 2022 |
| Development License | Download LEADTOOLS |
| Try it in another language |
|
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.
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 LTV23_CONFIG#include "C:\LEADTOOLS23\Include\L_Bitmap.h" // use the actual path where LEADTOOLS is installed#pragma comment (lib, "C:\\LEADTOOLS23\\Lib\\CDLL\\x64\\Ltkrn_x.lib")#pragma comment (lib, "C:\\LEADTOOLS23\\Lib\\CDLL\\x64\\Ltfil_x.lib") // file loading and saving#pragma comment (lib, "C:\\LEADTOOLS23\\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
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.
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 fileif (SUCCESS != GetBitmapSavingName(hWnd, szDestFile, ARRAYSIZE(szDestFile)))return;// Load the current comments from the filefor (int i = 0; i < CMNT_LAST; i++){// Clear the commentL_SetComment(i, NULL, 0);// Use the return value to get the length of a comment in the fileL_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 fileL_ReadFileComment(szSrcFile, i, pCommentToGet, CommentLength, NULL);// Set the comment to be savedL_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 workL_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 commentL_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 itMessageBoxA(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.
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 zeroinfo.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" tagL_UINT16 PhoneNumber = 0x8001;char TagData[] = "+1-800-637-4699";// Set the tag data to be savedL_SetTag(PhoneNumber, TAG_ASCII, sizeof TagData, TagData);// Save the the tag into the fileL_WriteFileTag(szExifFile, NULL);// Clear the tag from memoryL_SetTag(0, 0, 0, NULL);// Read the tags from the file and display them in the debugger windowL_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 tagsOutputDebugString(TEXT("Tags\n"));for (L_UINT n = 0; n < uTagCount; n++){pCurrentTag = &pTags[n];// If this tag is of type ASCII, get its dataL_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 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:
This tutorial showed how to use the L_SetComment, L_ReadFileComment, L_ReadFileTags, L_SetTag and L_WriteFileTag functions with EXIF files.