811 lines
20 KiB
C++
811 lines
20 KiB
C++
//
|
|
// Simple test program for imaging library
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <windows.h>
|
|
#include <objbase.h>
|
|
#include <urlmon.h>
|
|
#include <commdlg.h>
|
|
#include <math.h>
|
|
|
|
#include <gdiplus.h>
|
|
#include <gdiplusflat.h>
|
|
|
|
using namespace Gdiplus;
|
|
#include "../gpinit.inc"
|
|
|
|
#define k_DefaultWidth 720
|
|
#define k_DefaultHeight 480
|
|
#define THUMBSIZE 120
|
|
#define MAX_FILENAME 1000
|
|
|
|
CHAR* g_pcProgramName = NULL; // program name
|
|
HINSTANCE g_hAppInstance; // handle to the application instance
|
|
HWND g_hwndMain; // handle to application's main window
|
|
|
|
int g_iTotalNumOfImages;
|
|
int lastS;
|
|
int numX;
|
|
int g_iNumFileNames;
|
|
|
|
Image** g_ppThumbImages;
|
|
CHAR** g_ppcInputFilenames;
|
|
RECT g_ThumbRect;
|
|
|
|
BOOL g_fVerbose = FALSE;
|
|
BOOL g_fHighQualityThumb = FALSE;
|
|
|
|
#define ERREXIT(args) { printf args; exit(-1); }
|
|
#define VERBOSE(args) printf args
|
|
|
|
//
|
|
// Helper class to convert ANSI strings to Unicode strings
|
|
//
|
|
|
|
inline BOOL
|
|
UnicodeToAnsiStr(
|
|
const WCHAR* unicodeStr,
|
|
CHAR* ansiStr,
|
|
INT ansiSize
|
|
)
|
|
{
|
|
return WideCharToMultiByte(CP_ACP, 0, unicodeStr, -1, ansiStr, ansiSize,
|
|
NULL, NULL) > 0;
|
|
}
|
|
|
|
inline BOOL
|
|
AnsiToUnicodeStr(
|
|
const CHAR* ansiStr,
|
|
WCHAR* unicodeStr,
|
|
INT unicodeSize
|
|
)
|
|
{
|
|
return MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, unicodeStr,
|
|
unicodeSize) > 0;
|
|
}
|
|
|
|
|
|
class UnicodeStrFromAnsi
|
|
{
|
|
public:
|
|
|
|
UnicodeStrFromAnsi(const CHAR* ansiStr)
|
|
{
|
|
if (ansiStr == NULL)
|
|
{
|
|
valid = TRUE;
|
|
unicodeStr = NULL;
|
|
}
|
|
else
|
|
{
|
|
// NOTE: we only handle strings with length < MAX_PATH.
|
|
|
|
valid = AnsiToUnicodeStr(ansiStr, buf, MAX_PATH);
|
|
unicodeStr = valid ? buf : NULL;
|
|
}
|
|
}
|
|
|
|
BOOL IsValid() const
|
|
{
|
|
return valid;
|
|
}
|
|
|
|
operator WCHAR*()
|
|
{
|
|
return unicodeStr;
|
|
}
|
|
|
|
private:
|
|
|
|
BOOL valid;
|
|
WCHAR* unicodeStr;
|
|
WCHAR buf[MAX_PATH];
|
|
};
|
|
|
|
//
|
|
// Create thumbnails for the specified list of files
|
|
//
|
|
|
|
VOID
|
|
DrawThumbnails(
|
|
const RECT rect,
|
|
HDC hdc
|
|
)
|
|
{
|
|
if ( (rect.bottom - rect.top <= 0) || (rect.right - rect.left <= 0) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Figure out how many rows and columns we need to divide in order to put
|
|
// "g_iTotalNumOfImages" images within the fixed size "rect"
|
|
// Basically "iNumColumns" * "iNumRows" should >= "g_iTotalNumOfImages"
|
|
|
|
int iWindowWidth = rect.right - rect.left;
|
|
int iWindowHeight = rect.bottom - rect.top;
|
|
|
|
int iSum = 1;
|
|
while ( ((iWindowWidth / iSum) * (iWindowHeight / iSum))
|
|
>= g_iTotalNumOfImages )
|
|
{
|
|
iSum++;
|
|
}
|
|
|
|
iSum--;
|
|
|
|
int iNumColumns = iWindowWidth / iSum;
|
|
int iNumRows = iWindowHeight / iSum;
|
|
|
|
lastS = iSum; // Reset the global
|
|
numX = iNumColumns; // Reset the global
|
|
|
|
Graphics* pGraphics = new Graphics(g_hwndMain);
|
|
|
|
int x = 0;
|
|
int y = 0;
|
|
|
|
for ( int i = 0; i < g_iTotalNumOfImages; i++ )
|
|
{
|
|
if ( NULL == g_ppThumbImages[i] )
|
|
{
|
|
// Bad image. But we still leave the position for it so that it can
|
|
// be easily noticed
|
|
|
|
x++;
|
|
if (x >= iNumColumns)
|
|
{
|
|
x = 0;
|
|
y++;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Copy thumbnail bitmap image data to offscreen memory DC
|
|
|
|
int tx;
|
|
int ty;
|
|
|
|
SizeF size;
|
|
g_ppThumbImages[i]->GetPhysicalDimension(&size);
|
|
|
|
float dAspect = size.Width / size.Height;
|
|
RECT r;
|
|
|
|
if ( dAspect > 1 )
|
|
{
|
|
tx = iSum;
|
|
ty = (int)(iSum / dAspect);
|
|
int d = (iSum - ty) / 2;
|
|
r.left = x * iSum;
|
|
r.top = y * iSum + d;
|
|
r.right = x * iSum + tx;
|
|
r.bottom = y * iSum + ty + d;
|
|
}
|
|
else
|
|
{
|
|
ty = iSum;
|
|
tx = (int)(iSum * dAspect);
|
|
int d = (iSum - tx) / 2;
|
|
r.left = x * iSum + d;
|
|
r.top = y * iSum;
|
|
r.right = x * iSum + tx + d;
|
|
r.bottom = y * iSum + ty;
|
|
}
|
|
|
|
if ( g_fHighQualityThumb == FALSE )
|
|
{
|
|
Rect dstRect(r.left, r.top, tx, ty);
|
|
|
|
pGraphics->DrawImage(g_ppThumbImages[i],
|
|
dstRect,
|
|
0,
|
|
0,
|
|
(UINT)g_ppThumbImages[i]->GetWidth(),
|
|
(UINT)g_ppThumbImages[i]->GetHeight(),
|
|
UnitPixel,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
// Generate high quality thumbnail based on required size
|
|
|
|
Bitmap* dstBmp = new Bitmap(tx, ty, PixelFormat32bppPARGB);
|
|
Graphics* gdst = new Graphics(dstBmp);
|
|
|
|
// Ask the source image for it's size.
|
|
|
|
int width = g_ppThumbImages[i]->GetWidth();
|
|
int height = g_ppThumbImages[i]->GetHeight();
|
|
|
|
// Compute the optimal scale factor without changing the aspect ratio
|
|
|
|
float scalex = (float)width / tx;
|
|
float scaley = (float)height / ty;
|
|
float scale = min(scalex, scaley);
|
|
|
|
Rect dstRect(0, 0, tx, ty);
|
|
|
|
// Set the resampling quality to the bicubic filter
|
|
|
|
gdst->SetInterpolationMode(InterpolationModeHighQualityBicubic);
|
|
|
|
// Set the compositing quality to copy source pixels rather than
|
|
// alpha blending. This will preserve any alpha in the source image.
|
|
|
|
gdst->SetCompositingMode(CompositingModeSourceCopy);
|
|
|
|
ImageAttributes imgAttr;
|
|
imgAttr.SetWrapMode(WrapModeTileFlipXY);
|
|
|
|
// Draw the source image onto the destination with the correct scale
|
|
// and quality settings.
|
|
|
|
GpStatus status = gdst->DrawImage(g_ppThumbImages[i],
|
|
dstRect,
|
|
0,
|
|
0,
|
|
INT((tx * scale) + 0.5),
|
|
INT((ty * scale) + 0.5),
|
|
UnitPixel,
|
|
&imgAttr);
|
|
|
|
if( status != Ok )
|
|
{
|
|
printf("Error drawing the image\n");
|
|
continue;
|
|
}
|
|
|
|
// Draw the result onto the screen
|
|
|
|
Rect drawDstRect(r.left, r.top, tx, ty);
|
|
|
|
pGraphics->DrawImage(dstBmp,
|
|
drawDstRect,
|
|
0,
|
|
0,
|
|
(UINT)dstBmp->GetWidth(),
|
|
(UINT)dstBmp->GetHeight(),
|
|
UnitPixel,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
delete dstBmp;
|
|
delete gdst;
|
|
}
|
|
|
|
x++;
|
|
if (x >= iNumColumns)
|
|
{
|
|
x = 0;
|
|
y++;
|
|
}
|
|
}// Loop through all the thumbnail images to draw
|
|
|
|
delete pGraphics;
|
|
}
|
|
|
|
//
|
|
// Handle window repaint event
|
|
//
|
|
|
|
VOID
|
|
DoPaint(
|
|
HWND hwnd
|
|
)
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
RECT rect;
|
|
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
|
|
GetClientRect(hwnd, &rect);
|
|
|
|
const RECT r = {rect.left, rect.top, rect.right, rect.bottom};
|
|
DrawThumbnails(r, hdc);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
}// DoPaint()
|
|
|
|
//
|
|
// Window callback procedure
|
|
//
|
|
|
|
LRESULT CALLBACK
|
|
MyWindowProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
int index=0;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
DoPaint(hwnd);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
if (lastS == 0)
|
|
{
|
|
lastS = 1;
|
|
}
|
|
index = (HIWORD(lParam) / lastS) * numX + (LOWORD(lParam) / lastS);
|
|
|
|
if (index < g_iNumFileNames)
|
|
{
|
|
char cmdLine[MAX_FILENAME];
|
|
strcpy(cmdLine, "frametest ");
|
|
strcat(cmdLine, g_ppcInputFilenames[index]);
|
|
WinExec(cmdLine, SW_SHOWNORMAL);
|
|
}
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
SendMessage(g_hwndMain, WM_ERASEBKGND, WPARAM(GetDC(g_hwndMain)), NULL);
|
|
|
|
InvalidateRect(g_hwndMain, NULL, FALSE);
|
|
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Create main application window
|
|
//
|
|
|
|
#define MYWNDCLASSNAME "ThumbTst"
|
|
|
|
VOID
|
|
CreateMainWindow(
|
|
VOID
|
|
)
|
|
{
|
|
// Use a hatch brush as background so that we can get transparent info
|
|
// from the source image
|
|
|
|
HBRUSH hBrush = CreateHatchBrush(HS_HORIZONTAL,
|
|
RGB(0, 200, 0));
|
|
|
|
// Register window class
|
|
|
|
WNDCLASS wndClass =
|
|
{
|
|
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
|
|
MyWindowProc,
|
|
0,
|
|
0,
|
|
g_hAppInstance,
|
|
LoadIcon(NULL, IDI_APPLICATION),
|
|
LoadCursor(NULL, IDC_ARROW),
|
|
hBrush,
|
|
NULL,
|
|
MYWNDCLASSNAME
|
|
};
|
|
|
|
RegisterClass(&wndClass);
|
|
|
|
// Calculate default window size
|
|
|
|
INT iWidth = g_ThumbRect.right + 2 * GetSystemMetrics(SM_CXFRAME);
|
|
|
|
INT iHeight = g_ThumbRect.bottom
|
|
+ 2 * GetSystemMetrics(SM_CYFRAME)
|
|
+ GetSystemMetrics(SM_CYCAPTION);
|
|
|
|
// Create application window
|
|
|
|
g_hwndMain = CreateWindow(MYWNDCLASSNAME,
|
|
MYWNDCLASSNAME,
|
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
iWidth,
|
|
iHeight,
|
|
NULL,
|
|
NULL,
|
|
g_hAppInstance,
|
|
NULL);
|
|
}// CreateMainWindow()
|
|
|
|
void
|
|
DisplayImageInfo(
|
|
Image* pImage
|
|
)
|
|
{
|
|
UINT uiImagePixelFormat = pImage->GetPixelFormat();
|
|
UINT uiImageFlags = pImage->GetFlags();
|
|
|
|
VERBOSE(("Width = %d\n", pImage->GetWidth()));
|
|
VERBOSE(("Width = %d\n", pImage->GetHeight()));
|
|
|
|
// Pixel format
|
|
|
|
switch ( uiImagePixelFormat )
|
|
{
|
|
case PixelFormat1bppIndexed:
|
|
VERBOSE(("Color depth: 1 BPP INDEXED\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat4bppIndexed:
|
|
VERBOSE(("Color depth: 4 BPP INDEXED\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat8bppIndexed:
|
|
VERBOSE(("Color depth: 8 BPP INDEXED\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat16bppGrayScale:
|
|
VERBOSE(("Color depth: 16 BPP GRAY SCALE\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat16bppRGB555:
|
|
VERBOSE(("Color depth: 16 BPP RGB 555\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat16bppRGB565:
|
|
VERBOSE(("Color depth: 16 BPP RGB 565\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat16bppARGB1555:
|
|
VERBOSE(("Color depth: 16 BPP ARGB 1555\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat24bppRGB:
|
|
VERBOSE(("Color depth: 24 BPP RGB\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat32bppARGB:
|
|
VERBOSE(("Color depth: 32 BPP ARGB\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat32bppPARGB:
|
|
VERBOSE(("Color depth: 32 BPP PARGB\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat48bppRGB:
|
|
VERBOSE(("Color depth: 48 BPP PARGB\n"));
|
|
|
|
case PixelFormat64bppARGB:
|
|
VERBOSE(("Color depth: 64 BPP ARGB\n"));
|
|
|
|
break;
|
|
|
|
case PixelFormat64bppPARGB:
|
|
VERBOSE(("Color depth: 64 BPP PARGB\n"));
|
|
|
|
break;
|
|
|
|
default:
|
|
VERBOSE(("Unknown color depth\n"));
|
|
break;
|
|
}// Color format
|
|
|
|
// Physical dimension info
|
|
|
|
VERBOSE(("X DPI (dots per inch) = %f\n",pImage->GetHorizontalResolution()));
|
|
VERBOSE(("Y DPI (dots per inch) = %f\n",pImage->GetVerticalResolution()));
|
|
|
|
// Pixel size
|
|
|
|
if ( uiImageFlags & ImageFlagsHasRealPixelSize )
|
|
{
|
|
VERBOSE(("---The pixel size info is from the original image\n"));
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(("---The pixel size info is NOT from the original image\n"));
|
|
}
|
|
|
|
// DPI info
|
|
|
|
if ( uiImageFlags & ImageFlagsHasRealPixelSize )
|
|
{
|
|
VERBOSE(("---The pixel size info is from the original image\n"));
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(("---The pixel size info is NOT from the original image\n"));
|
|
}
|
|
|
|
// Transparency info
|
|
|
|
if ( uiImageFlags & ImageFlagsHasAlpha )
|
|
{
|
|
VERBOSE(("This image contains alpha pixels\n"));
|
|
|
|
if ( uiImageFlags & ImageFlagsHasTranslucent )
|
|
{
|
|
VERBOSE(("---It has non-0 and 1 alpha pixels (TRANSLUCENT)\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(("This image does not contain alpha pixels\n"));
|
|
}
|
|
|
|
// Display color space
|
|
|
|
if ( uiImageFlags & ImageFlagsColorSpaceRGB )
|
|
{
|
|
VERBOSE(("This image is in RGB color space\n"));
|
|
}
|
|
else if ( uiImageFlags & ImageFlagsColorSpaceCMYK )
|
|
{
|
|
VERBOSE(("This image is in CMYK color space\n"));
|
|
}
|
|
else if ( uiImageFlags & ImageFlagsColorSpaceGRAY )
|
|
{
|
|
VERBOSE(("This image is a gray scale image\n"));
|
|
}
|
|
else if ( uiImageFlags & ImageFlagsColorSpaceYCCK )
|
|
{
|
|
VERBOSE(("This image is in YCCK color space\n"));
|
|
}
|
|
else if ( uiImageFlags & ImageFlagsColorSpaceYCBCR )
|
|
{
|
|
VERBOSE(("This image is in YCBCR color space\n"));
|
|
}
|
|
}// DisplayImageInfo()
|
|
|
|
//
|
|
// Create thumbnails for the specified list of files
|
|
//
|
|
|
|
VOID
|
|
CreateThumbnails(
|
|
CHAR** ppcFilenames
|
|
)
|
|
{
|
|
// Generate thumbnails
|
|
|
|
UINT uiTimer;
|
|
if ( g_fVerbose == TRUE )
|
|
{
|
|
uiTimer = GetTickCount();
|
|
}
|
|
|
|
g_ppThumbImages = new Image*[g_iTotalNumOfImages];
|
|
Image* pSrcImage = NULL;
|
|
|
|
// Loop through all the images and generate thumbnail
|
|
|
|
for ( int i = 0; i < g_iTotalNumOfImages; i++ )
|
|
{
|
|
g_ppThumbImages[i] = NULL;
|
|
|
|
// Get a Unicode file name
|
|
|
|
UnicodeStrFromAnsi namestr(ppcFilenames[i]);
|
|
|
|
VERBOSE(("Loading - %s\n", ppcFilenames[i]));
|
|
|
|
if ( namestr.IsValid() == FALSE )
|
|
{
|
|
VERBOSE(("Couldn't open image file: %s\n", ppcFilenames[i]));
|
|
continue;
|
|
}
|
|
else if ( g_fHighQualityThumb == FALSE )
|
|
{
|
|
pSrcImage = new Image(namestr, TRUE);
|
|
|
|
if ( (pSrcImage == NULL) || (pSrcImage->GetLastStatus() != Ok) )
|
|
{
|
|
VERBOSE(("Couldn't open image file: %s\n", ppcFilenames[i]));
|
|
if ( pSrcImage != NULL )
|
|
{
|
|
delete pSrcImage;
|
|
pSrcImage = NULL;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( g_fVerbose == TRUE )
|
|
{
|
|
DisplayImageInfo(pSrcImage);
|
|
}
|
|
|
|
// Get build in thumbnail image if there is one. Otherwise, GDI+
|
|
// will generate one for us
|
|
|
|
g_ppThumbImages[i] = pSrcImage->GetThumbnailImage(0, 0, NULL, NULL);
|
|
delete pSrcImage;
|
|
pSrcImage = NULL;
|
|
}
|
|
else
|
|
{
|
|
// High quality thumbnail images. We don't generate it here
|
|
|
|
g_ppThumbImages[i] = new Image(namestr, TRUE);
|
|
|
|
if ( g_ppThumbImages[i] == NULL )
|
|
{
|
|
VERBOSE(("Couldn't open image file: %s\n", ppcFilenames[i]));
|
|
continue;
|
|
}
|
|
|
|
if ( g_fVerbose == TRUE )
|
|
{
|
|
DisplayImageInfo(g_ppThumbImages[i]);
|
|
}
|
|
}
|
|
}// Loop through all the images
|
|
|
|
if ( g_fVerbose == TRUE )
|
|
{
|
|
uiTimer = GetTickCount() - uiTimer;
|
|
VERBOSE(("Generate %d thumbnails in %dmsec\n", g_iTotalNumOfImages,
|
|
uiTimer));
|
|
}
|
|
}// CreateThumbnails
|
|
|
|
void
|
|
USAGE()
|
|
{
|
|
printf("******************************************************\n");
|
|
printf("Usage: thumbtst [-?] [-v] ImageFileNames\n");
|
|
printf("-v Verbose image information output\n");
|
|
printf("-h Generate higher quality thumbnail\n");
|
|
printf("-? Print this usage message\n");
|
|
printf("ImageFileNames Files to be opened\n\n");
|
|
printf("Sample usage:\n");
|
|
char myChar = '\\';
|
|
printf(" thumbtst.exe c:%cpublic%c*.jpg\n", myChar, myChar);
|
|
}// USAGE()
|
|
|
|
char html_header[1024] = "<html>\n<head>\n <title>My Fun Photo Album</title>\n</head>\n</html>\0";
|
|
|
|
void
|
|
OutputHTML()
|
|
{
|
|
FILE* hFile = fopen("mytest.html", "w");
|
|
if ( hFile == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
fprintf(hFile, "%s", html_header);
|
|
fclose(hFile);
|
|
}// OutputHTML()
|
|
|
|
void
|
|
ValidateArguments(
|
|
int argc,
|
|
char* argv[]
|
|
)
|
|
{
|
|
g_pcProgramName = *argv++;
|
|
argc--;
|
|
g_hAppInstance = GetModuleHandle(NULL);
|
|
|
|
while ( argc > 0 )
|
|
{
|
|
if ( strcmp(*argv, "-v") == 0 )
|
|
{
|
|
argc--;
|
|
argv++;
|
|
|
|
g_fVerbose = TRUE;
|
|
}
|
|
else if ( strcmp(*argv, "-h") == 0 )
|
|
{
|
|
argc--;
|
|
argv++;
|
|
|
|
g_fHighQualityThumb = TRUE;
|
|
}
|
|
else if ( strcmp(*argv, "-?") == 0 )
|
|
{
|
|
USAGE();
|
|
exit(1);
|
|
}
|
|
else
|
|
{
|
|
// Get the pointer to image file list
|
|
|
|
g_ppcInputFilenames = argv;
|
|
g_iNumFileNames = argc;
|
|
|
|
// Total number of images
|
|
// Note: if you do "thumbtst.exe c:\temp\*.jpg", this argc is
|
|
// actually the total number of images in that dir. While in argv,
|
|
// it points to each image under that dir
|
|
|
|
g_iTotalNumOfImages = argc;
|
|
|
|
return;
|
|
}
|
|
}// while (argc > 0 )
|
|
|
|
if ( argc == 0 )
|
|
{
|
|
USAGE();
|
|
exit(1);
|
|
}
|
|
|
|
return;
|
|
}// ValidateArguments()
|
|
|
|
//
|
|
// Main program entrypoint
|
|
//
|
|
|
|
INT _cdecl
|
|
main(
|
|
INT argc,
|
|
CHAR** argv
|
|
)
|
|
{
|
|
ValidateArguments(argc, argv);
|
|
|
|
g_ThumbRect.left = 0;
|
|
g_ThumbRect.top = 0;
|
|
g_ThumbRect.right = k_DefaultWidth;
|
|
g_ThumbRect.bottom = k_DefaultHeight;
|
|
|
|
// Generate thumbnail images and store it in g_ppThumbImages
|
|
|
|
CreateThumbnails(g_ppcInputFilenames);
|
|
|
|
// Create the main application window
|
|
|
|
CreateMainWindow();
|
|
|
|
// OutputHTML();
|
|
|
|
// Main message loop
|
|
|
|
MSG msg;
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
// Clean up
|
|
// Note: above while loop won't finish until we don't have any messages
|
|
|
|
for ( int i = 0; i < g_iTotalNumOfImages; i++ )
|
|
{
|
|
if ( NULL != g_ppThumbImages[i] )
|
|
{
|
|
delete g_ppThumbImages[i];
|
|
}
|
|
}
|
|
|
|
delete [] g_ppThumbImages;
|
|
|
|
return (INT)(msg.wParam);
|
|
}// main()
|