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 |
|
Get familiar with the basic steps of creating a project and loading/displaying an image by reviewing theAdd References and Set a LicenseandLoad, Display, and Save Imagestutorials, before working on theRead and Write Exif Tags and Comments - Windows C DLLtutorial.
Start with a copy of the project created in theLoad, Display, and Save Imagestutorial. If the project is not available, create it by following the steps in that tutorial.
Open the pre-compiled header file (eitherpch.h
orstdafx.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 toFiles 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 toSetting a Runtime License.
There are two types of runtime licenses:
Note
Adding LEADTOOLS references and setting a license are covered in more detail in theAdd References and Set a Licensetutorial.
With the project created, the references added, the license set, and the load image code added, coding can begin.
In theSolution Explorer, double-click the resources file (.rc).
Add a newExif &Commentmenu item to theFiledrop-down menu, between theOpenandSaveitems. Leave the new menu item's ID asID_FILE_EXIFCOMMENT
.
Open the project's CPP file and navigate to theWndProc
function. Under theswitch (wmId)
statement that is below theWM_COMMAND
case, add a new case and the code below.
switch(wmId)
{
caseID_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.
voidReadAndWriteExifComments(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(inti = 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 =newL_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";
constL_CHAR* pUserComment ="The image has been flipped!";
strcpy_s((char*)CommentToSet + 8,sizeofCommentToSet - 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,sizeofCommentCheck, NULL);
charszMessageA[256] ="Comment read back from file:\n";
strcat_s(szMessageA,sizeofszMessageA, (constchar*)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 theGetBitmapLoadingName()
andGetBitmapSavingName()
functions, called inside the code above, is listed in theLoad, Display, and Save Imagestutorial.
Using theSolution Explorer, navigate back to the resources file (.rc).
Add a newEXIF &Tagmenu item to theFiledrop-down menu, between theOpenandSaveitems. Leave the new menu item's ID asID_FILE_EXIFTAG
.
Go to theWndProc
function and under theswitch (wmId)
statement that is below theWM_COMMAND
case, add a new case and the code below.
switch(wmId)
{
caseID_FILE_EXIFTAG:
ReadAndWriteExifTags(hWnd);
break;
// Keep rest of the code as is
Add the code of theReadAndWriteExifTags
function, which adds a custom text tag to the EXIF file then reads all the tags back from the file.
voidReadAndWriteExifTags(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 =sizeofinfo;
L_FileInfo(szExifFile, &info,sizeofinfo, 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;
charTagData[] ="+1-800-637-4699";
// Set the tag data to be saved
L_SetTag(PhoneNumber, TAG_ASCII,sizeofTagData, 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 =newL_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 pressingF5, or by selectingDebug -> 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 theL_SetComment
,L_ReadFileComment
,L_ReadFileTags
,L_SetTag
andL_WriteFileTag
functions with EXIF files.