|
|
//
// 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 <imaging.h>
#include <initguid.h>
#include <imgguids.h>
#include "rsrc.h"
CHAR* programName; // program name
HINSTANCE appInstance; // handle to the application instance
HWND hwndMain; // handle to application's main window
IImagingFactory* imgfact; // pointer to IImageingFactory object
IImage* curImage; // pointer to IImage object
CHAR curFilename[MAX_PATH]; // current image filename
INT scaleMethod = IDM_SCALE_NEIGHBOR;
//
// Display an error message dialog
//
BOOL CheckHRESULT( HRESULT hr, INT line ) { if (SUCCEEDED(hr)) return TRUE;
CHAR buf[1024];
sprintf(buf, "Error on line %d: 0x%x\n", line, hr); MessageBoxA(hwndMain, buf, programName, MB_OK);
return FALSE; }
#define CHECKHR(hr) CheckHRESULT(hr, __LINE__)
#define LASTWIN32HRESULT HRESULT_FROM_WIN32(GetLastError())
#if DBG
#define VERBOSE(args) printf args
#else
#define VERBOSE(args)
#endif
//
// 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]; };
//
// Get scale method strings and interpolation hints
//
const CHAR* GetScaleMethodStr() { switch (scaleMethod) { case IDM_SCALE_GDI: return "GDI"; case IDM_SCALE_GDIHT: return "GDI + Halftone"; case IDM_SCALE_NEIGHBOR: return "Nearest Neighbor"; case IDM_SCALE_BILINEAR: return "Bilinear"; case IDM_SCALE_AVERAGING: return "Averaging"; case IDM_SCALE_BICUBIC: return "Bicubic"; default: return "Unknown"; } }
InterpolationHint GetScaleMethodInterp() { switch (scaleMethod) { case IDM_SCALE_BILINEAR: return INTERP_BILINEAR; case IDM_SCALE_AVERAGING: return INTERP_AVERAGING; case IDM_SCALE_BICUBIC: return INTERP_BICUBIC; case IDM_SCALE_NEIGHBOR: return INTERP_NEAREST_NEIGHBOR; case IDM_SCALE_GDI: case IDM_SCALE_GDIHT: default: return INTERP_DEFAULT; } }
//
// Get pixel format strings
//
const CHAR* GetPixelFormatStr( PixelFormatID pixfmt ) { switch (pixfmt) { case PIXFMT_1BPP_INDEXED: return "1bpp indexed"; case PIXFMT_4BPP_INDEXED: return "4bpp indexed"; case PIXFMT_8BPP_INDEXED: return "8bpp indexed"; case PIXFMT_16BPP_GRAYSCALE: return "16bpp grayscale"; case PIXFMT_16BPP_RGB555: return "16bpp RGB 5-5-5"; case PIXFMT_16BPP_RGB565: return "16bpp RGB 5-6-5"; case PIXFMT_16BPP_ARGB1555: return "16bpp ARGB 1-5-5-5"; case PIXFMT_24BPP_RGB: return "24bpp RGB"; case PIXFMT_32BPP_RGB: return "32bpp RGB"; case PIXFMT_32BPP_ARGB: return "32bpp ARGB"; case PIXFMT_32BPP_PARGB: return "32bpp premultiplied ARGB"; case PIXFMT_48BPP_RGB: return "48bpp RGB"; case PIXFMT_64BPP_ARGB: return "64bpp ARGB"; case PIXFMT_64BPP_PARGB: return "64bpp premultiplied ARGB"; case PIXFMT_UNDEFINED: default: return "Unknown"; } }
//
// Force a refresh of the image window
//
VOID RefreshImageDisplay() { InvalidateRect(hwndMain, NULL, FALSE);
// Update window title
CHAR title[2*MAX_PATH]; CHAR* p = title;
strcpy(p, curFilename); p += strlen(p);
HRESULT hr; SIZE size; IBitmapImage* bmp;
hr = curImage->QueryInterface(IID_IBitmapImage, (VOID**) &bmp);
if (FAILED(hr)) { // Decoded image
hr = curImage->GetPhysicalDimension(&size);
if (SUCCEEDED(hr)) { sprintf(p, ", Dimension: %0.2fx%0.2fmm", size.cx / 100.0, size.cy / 100.0); p += strlen(p); } } else { // In-memory bitmap image
hr = bmp->GetSize(&size);
if (CHECKHR(hr)) { sprintf(p, ", Size: %dx%d", size.cx, size.cy); p += strlen(p); }
PixelFormatID pixfmt;
hr = bmp->GetPixelFormatID(&pixfmt);
if (CHECKHR(hr)) { sprintf(p, ", Pixel Format: %s", GetPixelFormatStr(pixfmt)); p += strlen(p); }
bmp->Release(); }
sprintf(p, ", Scale Method: %s", GetScaleMethodStr()); p += strlen(p);
SetWindowText(hwndMain, title); }
//
// Set the current image
//
VOID SetCurrentImage( IUnknown* unk, const CHAR* filename = NULL ) { IImage* image;
if (filename != NULL) { // Decoded image
image = (IImage*) unk; strcpy(curFilename, filename); } else { // In-memory bitmap image
HRESULT hr;
hr = unk->QueryInterface(IID_IImage, (VOID**) &image); unk->Release();
if (!CHECKHR(hr)) return;
strcpy(curFilename, "In-memory Bitmap"); }
if (curImage) curImage->Release();
curImage = image; RefreshImageDisplay(); }
//
// Resize the window so it fits the image
//
#define MINWINWIDTH 200
#define MINWINHEIGHT 100
#define MAXWINWIDTH 1024
#define MAXWINHEIGHT 768
VOID DoSizeWindowToFit( HWND hwnd, BOOL strict = FALSE ) { HRESULT hr; IBitmapImage* bmp; SIZE size;
// Check if the current image is a bitmap image
// in that case, we'll get the pixel dimension
hr = curImage->QueryInterface(IID_IBitmapImage, (VOID**) &bmp);
if (SUCCEEDED(hr)) { hr = bmp->GetSize(&size); bmp->Release(); }
// Otherwise, try to get device-independent image dimension
if (FAILED(hr)) { hr = curImage->GetPhysicalDimension(&size); if (FAILED(hr)) return;
size.cx = (INT) (size.cx * 96.0 / 2540.0 + 0.5); size.cy = (INT) (size.cy * 96.0 / 2540.0 + 0.5); }
if (SUCCEEDED(hr)) { // Figure out window border dimensions
RECT r1, r2; INT w, h;
w = size.cx; h = size.cy;
if (!strict) { if (w < MINWINWIDTH) w = MINWINWIDTH; else if (w > MAXWINWIDTH) w = MAXWINWIDTH;
if (h < MINWINHEIGHT) h = MINWINHEIGHT; else if (h > MAXWINHEIGHT) h = MAXWINHEIGHT; }
GetWindowRect(hwnd, &r1); GetClientRect(hwnd, &r2);
w += (r1.right - r1.left) - (r2.right - r2.left); h += (r1.bottom - r1.top) - (r2.bottom - r2.top);
// Resize the window
do { SetWindowPos( hwnd, NULL, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER);
GetClientRect(hwnd, &r2); h += GetSystemMetrics(SM_CYMENU); } while (r2.bottom == 0); } }
//
// Convert current image to a bitmap image
//
IBitmapImage* ConvertImageToBitmap( IImage* image, INT width = 0, INT height = 0, PixelFormatID pixfmt = PIXFMT_DONTCARE, InterpolationHint hint = INTERP_DEFAULT ) { if (!image) return NULL;
HRESULT hr; IBitmapImage* bmp;
hr = image->QueryInterface(IID_IBitmapImage, (VOID**) &bmp);
if (SUCCEEDED(hr)) { SIZE size; PixelFormatID fmt;
// Current image is already a bitmap image and
// its dimension and pixel format are already as expected
hr = bmp->GetSize(&size); if (!CHECKHR(hr)) return NULL;
hr = bmp->GetPixelFormatID(&fmt); if (!CHECKHR(hr)) return NULL;
if ((width == 0 || size.cx == width) && (height == 0 || size.cy == height) && (pixfmt == PIXFMT_DONTCARE || pixfmt == fmt)) { return bmp; }
bmp->Release(); }
// Convert the current image to a bitmap image
if (width == 0 && height == 0) { ImageInfo imageInfo; hr = image->GetImageInfo(&imageInfo);
// If the source image is scalable, then compute
// the appropriate pixel dimension for the bitmap
if (SUCCEEDED(hr) && (imageInfo.Flags & IMGFLAG_SCALABLE)) { width = (INT) (96.0 * imageInfo.Width / imageInfo.Xdpi + 0.5); height = (INT) (96.0 * imageInfo.Height / imageInfo.Ydpi + 0.5); } }
hr = imgfact->CreateBitmapFromImage( image, width, height, pixfmt, hint, &bmp);
return SUCCEEDED(hr) ? bmp : NULL; }
//
// Create an image object from a file
//
VOID OpenImageFile( const CHAR* filename ) { HRESULT hr; IImage* image; IStream* stream; static BOOL useUrlMon = FALSE;
if (useUrlMon) { // Use URLMON.DLL to turn file into stream
CHAR fullpath[MAX_PATH]; CHAR* p;
if (!GetFullPathName(filename, MAX_PATH, fullpath, &p)) return;
hr = URLOpenBlockingStreamA(NULL, fullpath, &stream, 0, NULL);
if (!CHECKHR(hr)) return;
hr = imgfact->CreateImageFromStream(stream, &image); stream->Release(); } else { // Use filename directly
UnicodeStrFromAnsi namestr(filename);
if (namestr.IsValid()) hr = imgfact->CreateImageFromFile(namestr, &image); else hr = E_FAIL; }
// Set the new image as the current image
if (CHECKHR(hr)) { SetCurrentImage(image, filename); DoSizeWindowToFit(hwndMain); } }
//
// Save the current image to a file
//
VOID SaveImageFile( const CHAR* filename, const CLSID* clsid ) { if (!curImage) return;
// Create an encoder object
HRESULT hr; IImageEncoder* encoder; UnicodeStrFromAnsi namestr(filename);
if (namestr.IsValid()) hr = imgfact->CreateImageEncoderToFile(clsid, namestr, &encoder); else hr = E_FAIL;
if (!CHECKHR(hr)) return;
// Get an IImageSink interface to the encoder
IImageSink* sink;
hr = encoder->GetEncodeSink(&sink);
#if defined(ROTATION_TEST)
// Rotation test
EncoderParams* pMyEncoderParams;
pMyEncoderParams = (EncoderParams*)malloc ( sizeof(EncoderParams) + sizeof(EncoderParam));
pMyEncoderParams->Params[0].paramGuid = ENCODER_ROTATION; pMyEncoderParams->Params[0].Value = "90"; pMyEncoderParams->Count = 1; hr = encoder->SetEncoderParam(pMyEncoderParams); free(pMyEncoderParams); #endif
if (CHECKHR(hr)) { hr = curImage->PushIntoSink(sink); CHECKHR(hr);
sink->Release(); }
encoder->TerminateEncoder(); encoder->Release(); }
//
// Handle window repaint event
//
VOID DoPaint( HWND hwnd ) { HDC hdc; PAINTSTRUCT ps; RECT rect; DWORD timer; HRESULT hr = E_FAIL;
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
if (scaleMethod == IDM_SCALE_GDIHT) SetStretchBltMode(hdc, HALFTONE); else SetStretchBltMode(hdc, COLORONCOLOR);
VERBOSE(("Scale method: %d, ", scaleMethod)); timer = GetTickCount();
if (scaleMethod == IDM_SCALE_GDI || scaleMethod == IDM_SCALE_GDIHT) { hr = curImage->Draw(hdc, &rect, NULL);
VERBOSE(("GDI time: %dms\n", GetTickCount() - timer)); } else { IBitmapImage* bmp;
bmp = ConvertImageToBitmap( curImage, rect.right, rect.bottom, PIXFMT_DONTCARE, GetScaleMethodInterp());
if (!bmp) goto endPaint;
VERBOSE(("Stretch time: %dms, ", GetTickCount() - timer));
IImage* image;
hr = bmp->QueryInterface(IID_IImage, (VOID**) &image); bmp->Release();
if (FAILED(hr)) goto endPaint; timer = GetTickCount(); hr = image->Draw(hdc, &rect, NULL); VERBOSE(("GDI time: %dms\n", GetTickCount() - timer));
image->Release(); }
endPaint:
if (FAILED(hr)) FillRect(hdc, &rect, (HBRUSH) GetStockObject(BLACK_BRUSH));
EndPaint(hwnd, &ps); }
//
// Convert the current image to a bitmap
//
VOID DoConvertToBitmap( HWND hwnd, INT menuCmd ) { // Map menu selection to its corresponding pixel format
PixelFormatID pixfmt;
switch (menuCmd) { case IDM_CONVERT_RGB555: pixfmt = PIXFMT_16BPP_RGB555; break; case IDM_CONVERT_RGB565: pixfmt = PIXFMT_16BPP_RGB565; break; case IDM_CONVERT_RGB24: pixfmt = PIXFMT_24BPP_RGB; break; case IDM_CONVERT_RGB32: pixfmt = PIXFMT_32BPP_RGB; break; case IDM_CONVERT_ARGB: default: pixfmt = PIXFMT_32BPP_ARGB; break; }
// Convert the current image to a bitmap image
IBitmapImage* bmp = ConvertImageToBitmap(curImage, 0, 0, pixfmt);
// Set the bitmap image as the current image
if (bmp) SetCurrentImage(bmp); }
//
// Compose a file type filter string given an array of
// ImageCodecInfo structures
//
#define SizeofWSTR(s) (sizeof(WCHAR) * (wcslen(s) + 1))
#define SizeofSTR(s) (strlen(s) + 1)
CHAR* MakeFilterFromCodecs( UINT count, const ImageCodecInfo* codecs, BOOL open ) { static const CHAR allFiles[] = "All Files\0*.*\0";
// Figure out the total size of the filter string
UINT index, size;
for (index=size=0; index < count; index++) { size += SizeofWSTR(codecs[index].FormatDescription) + SizeofWSTR(codecs[index].FilenameExtension); }
if (open) size += sizeof(allFiles); size += sizeof(CHAR);
// Allocate memory
CHAR *filter = (CHAR*) malloc(size); CHAR* p = filter; const WCHAR* ws;
if (!filter) return NULL;
for (index=0; index < count; index++) { ws = codecs[index].FormatDescription; size = SizeofWSTR(ws);
if (UnicodeToAnsiStr(ws, p, size)) p += SizeofSTR(p); else break;
ws = codecs[index].FilenameExtension; size = SizeofWSTR(ws);
if (UnicodeToAnsiStr(ws, p, size)) p += SizeofSTR(p); else break; }
if (index < count) { free(filter); return NULL; }
if (open) { size = sizeof(allFiles); memcpy(p, allFiles, size); p += size; }
*((CHAR*) p) = '\0'; return filter; }
//
// Open image file
//
VOID DoOpen( HWND hwnd ) { OPENFILENAME ofn; CHAR filename[MAX_PATH];
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.hInstance = appInstance; ofn.lpstrFile = filename; ofn.nMaxFile = MAX_PATH; ofn.lpstrTitle = "Open Image File"; ofn.lpstrInitialDir = "."; ofn.Flags = OFN_FILEMUSTEXIST; filename[0] = '\0';
// Make up the file type filter string
HRESULT hr; ImageCodecInfo* codecs; UINT count;
hr = imgfact->GetInstalledDecoders(&count, &codecs);
if (!CHECKHR(hr)) return;
CHAR* filter = MakeFilterFromCodecs(count, codecs, TRUE);
if (codecs) CoTaskMemFree(codecs);
if (!filter) { CHECKHR(LASTWIN32HRESULT); return; }
ofn.lpstrFilter = filter; // Present the file/open dialog
if (GetOpenFileName(&ofn)) OpenImageFile(filename);
free(filter); }
//
// Save image file
//
VOID DoSave( HWND hwnd ) { OPENFILENAME ofn; CHAR filename[MAX_PATH];
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.hInstance = appInstance; ofn.lpstrFile = filename; ofn.nMaxFile = MAX_PATH; ofn.lpstrTitle = "Save Image File"; ofn.lpstrInitialDir = "."; ofn.Flags = OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT; filename[0] = '\0';
// Make up the file type filter string
HRESULT hr; ImageCodecInfo* codecs; UINT count;
hr = imgfact->GetInstalledEncoders(&count, &codecs);
if (!CHECKHR(hr)) return;
CHAR* filter = MakeFilterFromCodecs(count, codecs, FALSE);
if (!filter) { CHECKHR(LASTWIN32HRESULT); } else { ofn.lpstrFilter = filter;
// Present the file/save dialog
if (GetSaveFileName(&ofn)) { UINT index = ofn.nFilterIndex;
if (index == 0 || index > count) index = 0; else index--;
SaveImageFile(filename, &codecs[index].Clsid); }
free(filter); }
CoTaskMemFree(codecs); }
//
// Crop the image
//
// NOTE: We're not spending time here to do a fancy UI.
// So we'll just inset the image by 5 pixels each time.
//
VOID DoCrop( HWND hwnd ) { IBitmapImage* bmp;
if (bmp = ConvertImageToBitmap(curImage)) { HRESULT hr; IBasicBitmapOps* bmpops = NULL; SIZE size;
hr = bmp->QueryInterface(IID_IBasicBitmapOps, (VOID**) &bmpops);
if (CHECKHR(hr)) hr = bmp->GetSize(&size);
if (CHECKHR(hr)) { RECT r = { 5, 5, size.cx - 5, size.cy - 5 }; IBitmapImage* newbmp;
hr = bmpops->Clone(&r, &newbmp, TRUE);
if (CHECKHR(hr)) SetCurrentImage(newbmp); }
if (bmp) bmp->Release(); if (bmpops) bmpops->Release(); } }
//
// Resize the image to the current window size, using bilinear scaling
//
VOID DoResize( HWND hwnd ) { RECT rect; HRESULT hr; IBitmapImage* bmp;
GetClientRect(hwnd, &rect);
bmp = ConvertImageToBitmap( curImage, rect.right, rect.bottom, PIXFMT_DONTCARE, INTERP_BILINEAR);
if (bmp) SetCurrentImage(bmp); }
//
// Flip or rotate the image
//
VOID DoFlipRotate( HWND hwnd, INT menuCmd ) { IBitmapImage* bmp; IBitmapImage* newbmp; IBasicBitmapOps* bmpops; HRESULT hr;
bmp = ConvertImageToBitmap(curImage);
if (!bmp) return;
hr = bmp->QueryInterface(IID_IBasicBitmapOps, (VOID**) &bmpops);
if (CHECKHR(hr)) { switch (menuCmd) { case IDM_BMP_FLIPX: hr = bmpops->Flip(TRUE, FALSE, &newbmp); break; case IDM_BMP_FLIPY: hr = bmpops->Flip(FALSE, TRUE, &newbmp); break; case IDM_BMP_ROTATE90: hr = bmpops->Rotate(90, INTERP_DEFAULT, &newbmp); break; case IDM_BMP_ROTATE270: hr = bmpops->Rotate(270, INTERP_DEFAULT, &newbmp); break; }
bmpops->Release();
if (CHECKHR(hr)) { SetCurrentImage(newbmp);
if (menuCmd == IDM_BMP_ROTATE90 || menuCmd == IDM_BMP_ROTATE270) { DoSizeWindowToFit(hwnd); } } }
bmp->Release(); }
//
// Perform point operation on the image
//
VOID DoPointOps( HWND hwnd, INT menuCmd ) { IBitmapImage* bmp; IBitmapImage* newbmp; IBasicBitmapOps* bmpops; HRESULT hr;
bmp = ConvertImageToBitmap(curImage);
if (!bmp) return;
hr = bmp->QueryInterface(IID_IBasicBitmapOps, (VOID**) &bmpops);
if (CHECKHR(hr)) { switch (menuCmd) { case IDM_BRIGHTEN: hr = bmpops->AdjustBrightness(0.1f); break; case IDM_DARKEN: hr = bmpops->AdjustBrightness(-0.1f); break; case IDM_INCCONTRAST: hr = bmpops->AdjustContrast(-0.1f, 1.1f); break; case IDM_DECCONTRAST: hr = bmpops->AdjustContrast(0.1f, 0.9f); break; case IDM_INCGAMMA: hr = bmpops->AdjustGamma(1.1f); break; case IDM_DECGAMMA: hr = bmpops->AdjustGamma(0.9f); break; }
bmpops->Release();
if (CHECKHR(hr)) SetCurrentImage(bmp); }
if (FAILED(hr)) bmp->Release(); }
VOID DisplayProperties( IPropertySetStorage *propSetStg ) { HRESULT hresult; IPropertyStorage *propStg; IEnumSTATPROPSTG *enumPS;
hresult = propSetStg->Open(FMTID_ImageInformation, STGM_READ | STGM_SHARE_EXCLUSIVE, &propStg); if (FAILED(hresult)) { //printf("DisplayProperties: failed to open propSetStg\n");
return; }
hresult = propStg->Enum(&enumPS); if (FAILED(hresult)) { printf("DisplayProperties: failed to create enumerator\n"); return; }
hresult = enumPS->Reset(); if (FAILED(hresult)) { printf("DisplayProperties: failed to reset enumerator\n"); return; }
STATPROPSTG sps; while ((enumPS->Next(1, &sps, NULL)) == S_OK) { if (sps.lpwstrName) { wprintf(sps.lpwstrName); CoTaskMemFree(sps.lpwstrName);
PROPSPEC propSpec[1]; PROPVARIANT propVariant[1]; propSpec[0].ulKind = PRSPEC_PROPID; propSpec[0].propid = sps.propid;
hresult = propStg->ReadMultiple(1, propSpec, propVariant); if (FAILED(hresult)) { printf("DisplayProperties: failed in ReadMultiple\n"); }
switch(propVariant[0].vt) { case VT_BSTR: wprintf(L" : %s\n", propVariant[0].bstrVal); break;
case VT_I4: wprintf(L" : %d\n", propVariant[0].lVal); break;
case VT_R8: wprintf(L" : %f\n", (FLOAT) propVariant[0].dblVal); break;
default: wprintf(L"Unknown VT type\n"); break; }
PropVariantClear(&propVariant[0]); } }
enumPS->Release(); propStg->Release(); }
//
// Handle menu commands
//
VOID DoMenuCommand( HWND hwnd, INT menuCmd ) { switch (menuCmd) { case IDM_OPEN: DoOpen(hwnd); break;
case IDM_SAVE: DoSave(hwnd); break;
case IDM_QUIT: PostQuitMessage(0); break;
case IDM_FIT_WINDOW: DoSizeWindowToFit(hwnd, TRUE); break;
case IDM_CONVERT_RGB555: case IDM_CONVERT_RGB565: case IDM_CONVERT_RGB24: case IDM_CONVERT_RGB32: case IDM_CONVERT_ARGB: DoConvertToBitmap(hwnd, menuCmd); break;
case IDM_SCALE_GDI: case IDM_SCALE_GDIHT: case IDM_SCALE_NEIGHBOR: case IDM_SCALE_BILINEAR: case IDM_SCALE_AVERAGING: case IDM_SCALE_BICUBIC: scaleMethod = menuCmd; RefreshImageDisplay(); break;
case IDM_BMP_CROP: DoCrop(hwnd); break;
case IDM_BMP_RESIZE: DoResize(hwnd); break;
case IDM_BMP_FLIPX: case IDM_BMP_FLIPY: case IDM_BMP_ROTATE90: case IDM_BMP_ROTATE270: DoFlipRotate(hwnd, menuCmd); break; case IDM_BRIGHTEN: case IDM_DARKEN: case IDM_INCCONTRAST: case IDM_DECCONTRAST: case IDM_INCGAMMA: case IDM_DECGAMMA: DoPointOps(hwnd, menuCmd); break; } }
//
// Window callback procedure
//
LRESULT CALLBACK MyWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch (uMsg) { case WM_COMMAND: DoMenuCommand(hwnd, LOWORD(wParam)); break;
case WM_PAINT: DoPaint(hwnd); break;
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, uMsg, wParam, lParam); }
return 0; }
//
// Create main application window
//
#define MYWNDCLASSNAME "ImgTest"
VOID CreateMainWindow( VOID ) { HBRUSH hBrush = CreateSolidBrush(RGB(255, 250, 250)); //
// Register window class
//
WNDCLASS wndClass = { CS_HREDRAW|CS_VREDRAW, MyWindowProc, 0, 0, appInstance, LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW), hBrush, MAKEINTRESOURCE(IDR_MAINMENU), MYWNDCLASSNAME };
RegisterClass(&wndClass);
hwndMain = CreateWindow( MYWNDCLASSNAME, MYWNDCLASSNAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, appInstance, NULL);
if (!hwndMain) { CHECKHR(HRESULT_FROM_WIN32(GetLastError())); exit(-1); } }
//
// Create a new test bitmap object from scratch
//
#define STEPS 16
VOID CreateNewTestBitmap() { IBitmapImage* bmp; BitmapData bmpdata; HRESULT hr;
hr = imgfact->CreateNewBitmap( STEPS, STEPS, PIXFMT_32BPP_ARGB, &bmp);
if (!CHECKHR(hr)) return;
hr = bmp->LockBits( NULL, IMGLOCK_WRITE, PIXFMT_DONTCARE, &bmpdata);
if (!CHECKHR(hr)) { bmp->Release(); return; }
// Make a horizontal blue gradient
UINT x, y; ARGB colors[STEPS];
for (x=0; x < STEPS; x++) colors[x] = MAKEARGB(255, 0, 0, x * 255 / (STEPS-1));
for (y=0; y < STEPS; y++) { ARGB* p = (ARGB*) ((BYTE*) bmpdata.Scan0 + y*bmpdata.Stride);
for (x=0; x < STEPS; x++) *p++ = colors[(x+y) % STEPS]; }
bmp->UnlockBits(&bmpdata); SetCurrentImage(bmp); }
//
// Main program entrypoint
//
INT _cdecl main( INT argc, CHAR **argv ) { programName = *argv++; argc--; appInstance = GetModuleHandle(NULL); CoInitialize(NULL);
//
// Create an IImagingFactory object
//
HRESULT hr;
hr = CoCreateInstance( CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (VOID**) &imgfact);
if (!CHECKHR(hr)) exit(-1);
//
// Create the main application window
//
CreateMainWindow();
//
// Create a test image
//
if (argc != 0) OpenImageFile(*argv); if (!curImage) CreateNewTestBitmap();
if (!curImage) exit(-1);
DoSizeWindowToFit(hwndMain); ShowWindow(hwndMain, SW_SHOW);
//
// Main message loop
//
MSG msg; HACCEL accel;
accel = LoadAccelerators(appInstance, MAKEINTRESOURCE(IDR_ACCELTABLE));
while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, accel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
curImage->Release(); imgfact->Release();
CoUninitialize(); return (INT)(msg.wParam); }
|