This tutorial shows how to load, display, and save images using the LEADTOOLS SDK in a C/C++ Windows API Application.
Overview | |
---|---|
Summary | This tutorial covers how to load, display, and save images in a Windows C DLL Application. |
Completion Time | 30 minutes |
Visual Studio Project | Download tutorial project (18 KB) |
Platform | Windows C DLL Application |
IDE | Visual Studio 2017, 2019 |
Development License | Download LEADTOOLS |
Before working on the Load, Display, and Save Images - Windows C DLL tutorial, get familiar with the basic steps of creating a project by reviewing the Add References and Set a License tutorial.
Start with a copy of the 64-bit Windows API project created in the Add References and Set a License tutorial. If the project is not available, create it by following the steps in that tutorial.
In order to load, display, and save images, LEADTOOLS requires additional DLLs. Add the required libraries by opening the pre-compiled header file, either pch.h
or stdafx.h
depending on the Visual Studio version used, and add the following lines:
#pragma comment (lib, "C:\\LEADTOOLS21\\Lib\\CDLL\\x64\\Ltfil_x.lib") // file loading and saving
#pragma comment (lib, "C:\\LEADTOOLS21\\Lib\\CDLL\\x64\\Ltdis_x.lib") // image display
Note
For a complete list of which DLL files are required for your application, refer to Files to be Included with your Application.
The License unlocks the features needed for the project. It must be set before any toolkit function 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.
Now that the LEADTOOLS references have been added and the license has been set, coding can begin.
The steps below are for Visual Studio 2019; they could be different for other versions of Visual Studio.
Go to the Solution Explorer and double-click the resources file (.rc)
Expand the menu in the resources tree and double-click the menu resource to open it in the designer interface.
In the empty item below the Exit item, click and type &Open. Drag the new item above Exit. This should cause the item's ID to become ID_FILE_OPEN
.
Go to the main CPP file of the project, which contains the WndProc()
function for the main window. Add the following declaration to the global variables near the top:
BITMAPHANDLE LEADBmp;
Navigate to the WndProc
function and under the switch (wmId)
statement, that is below the WM_COMMAND
case, add a new case:
switch (wmId)
{
case ID_FILE_OPEN:
{
TCHAR szFileName[260] = TEXT(""); // File name
if (SUCCESS != GetBitmapLoadingName(hWnd, szFileName, sizeof(szFileName)))
break;
if (LEADBmp.Flags.Allocated)
L_FreeBitmap(&LEADBmp);
L_LoadBitmap(szFileName, &LEADBmp, sizeof(LEADBmp), 24, ORDER_BGR, NULL, NULL);
InvalidateRect(hWnd, NULL, TRUE);
}
break;
// Keep rest of the code as is
The GetBitmapLoadingName()
function can be any function that fills the szFileName
variable with a valid image file name (including full path, if needed). To display a File Open dialog to obtain the file name, add the following code:
L_INT GetBitmapLoadingName(HWND hwnd, TCHAR* pszFileName, DWORD nLen)
{
OPENFILENAME OpenFileName = { 0 };
OpenFileName.lStructSize = sizeof(OpenFileName);
OpenFileName.hwndOwner = hwnd;
OpenFileName.lpstrFile = pszFileName;
OpenFileName.nMaxFile = nLen;
OpenFileName.lpstrFilter = TEXT("All\0*.*\0Jpeg\0*.jpg\0");
OpenFileName.nFilterIndex = 1;
OpenFileName.lpstrFileTitle = NULL;
OpenFileName.nMaxFileTitle = 0;
OpenFileName.lpstrInitialDir = NULL;
OpenFileName.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Show the File Open dialog box
if (!GetOpenFileName(&OpenFileName))
return FAILURE;
return SUCCESS;
}
Whenever an image is allocated in a BITMAPHANDLE
structure, the programmer must call L_FreeBitmap
to free it when it is no longer needed. Since loading a bitmap allocates such an image, call LEADBmp.Flags.Allocated
to check before exiting the application.
Modify the case that handles WM_DESTROY
in the WndProc()
function to become:
case WM_DESTROY:
if (LEADBmp.Flags.Allocated)
L_FreeBitmap(&LEADBmp);
PostQuitMessage(0);
break;
Modify the case that handles WM_PAINT
in the WndProc()
function to become:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
RECT rc = { 0, 0, BITMAPWIDTH(&LEADBmp), BITMAPHEIGHT(&LEADBmp) };
if (LEADBmp.Flags.Allocated)
L_PaintDC(hdc, &LEADBmp, NULL, NULL, &rc, NULL, SRCCOPY);
EndPaint(hWnd, &ps);
}
break;
Important Note
The loading code in this tutorial forces the image to load at 24 bits per pixel, which means it will not have a palette after it gets loaded. If it is required to display images that are between 1 and 8 bits per pixel, the palette must be handled in the painting code as shown in the code example for L_PaintDC.
Add a Save menu item under the File menu. To do that, use steps similar to those in the Add the Bitmap Loading Code section above, but set the menu item text to &Save instead of &Open, which should cause the new item's ID to become ID_FILE_SAVE
.
Go to the WndProc
function, and under the switch (wmId)
statement that is below the WM_COMMAND
case, add a new case:
switch (wmId)
{
case ID_FILE_SAVE:
{
if (!LEADBmp.Flags.Allocated)
{
MessageBox(hWnd, TEXT("Cannot save. No image loaded"), TEXT("LEADTOOLS Demo"), MB_ICONERROR);
break;
}
TCHAR szFileName[260] = TEXT(""); // File name
if (SUCCESS != GetBitmapSavingName(hWnd, szFileName, sizeof(szFileName)))
break;
L_SaveBitmap(szFileName, &LEADBmp, FILE_JPEG_411, 24, 15, NULL);
}
break;
// Keep rest of the code as is
The GetBitmapSavingName()
function can be any function that fills the szFileName
variable with a valid image file name (including full path, if needed). To display a File Save dialog to obtain the file name, add the following code:
L_INT GetBitmapSavingName(HWND hwnd, TCHAR* pszFileName, DWORD nLen)
{
OPENFILENAME OpenFileName = { 0 };
OpenFileName.lStructSize = sizeof(OPENFILENAME);
OpenFileName.hwndOwner = hwnd;
OpenFileName.lpstrFilter = TEXT("Jpeg\0*.jpg\0");
OpenFileName.lpstrFile = pszFileName;
OpenFileName.nMaxFile = nLen;
OpenFileName.lpstrDefExt = TEXT("jpg");
OpenFileName.lpstrFileTitle = NULL;
OpenFileName.nMaxFileTitle = 0;
OpenFileName.lpstrInitialDir = NULL;
OpenFileName.Flags = OFN_OVERWRITEPROMPT;
// Show the File Save dialog box
if (!GetSaveFileName(&OpenFileName))
return FAILURE;
return SUCCESS;
}
Important Note
The code above saves the image as 24-bit JPEG. To save other types, pass a different value instead of
FILE_JPEG_411
. More details are in the LEADTOOLS Image Formats help topic.
Run the project by pressing F5, or by selecting Debug -> Start Debugging.
If the steps are followed correctly, the application should run and enable the user to load any image on the machine that is supported by the LEADTOOLS codec filters. The image will display in the main window. Press the Save menu item to save the displayed image as a JPEG in the output location specified using the Save Dialog.
This tutorial covered how to add the necessary DLLs to load, display, and save images. It also covered how to use the BITMAPHANDLE
structure with
the L_LoadBitmap
, L_SaveBitmap
, L_PaintDC
and L_FreeBitmap
functions.