Page 1 of 1

Win32 Image Editing Program Part3. Rate Topic: -----

#1 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 768
  • View blog
  • Posts: 2,237
  • Joined: 20-March 10

Posted 06 November 2012 - 09:58 PM

Win32 Image Editing Program Part 3


In this final part of our Image Editor I will discuss how to load other graphic file formats.

There are headers and libraries that come with the Microsoft Compiler that make this very easy.

However it will not work with MinGW derivatives such as code::blocks or Dev-C++ as these compilers
do not come with those headers or libraries.

The traditional way to deal with this subject is to use an image library to load the images such as

libpng

or

libjpeg

but Windows already has the ability to load several common graphic file formats
such as :-

.jpg
.png
.gif
.ico
.tif
and of course
.bmp

We just have to find a cross compiler compatible way to access these Windows functions.

In Windows these functions reside in a .dll.

To be specific Gdiplus.dll

As before I am not going to go over old ground and as usual I will post the whole code then
explain the new bits piece by piece.

link to

gdi32
user32
kernel32
winspool
comdlg32
opengl32


This is not a Unicode build so please
if you are using Visual Studio change the character set to
Multi-Byte.



main.cpp




#include "resource.h"
#include "WinProc.h"



/*   variables  */
char szClassName[ ] = "Snoopy's Image Editing Demo";




/*  Declare  procedures  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

HBITMAP MakeBitmapFromFile(HMODULE hWinLib, WCHAR* Name);

HDC GetPrinterDC (HWND Hwnd);
BOOL OpenFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName);
BOOL SaveFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName);
void InitialiseDialog(HWND hwnd);
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp, PBITMAPINFO pbmi);
void SaveBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);
bool BitmapToClipboard(HBITMAP hBM, HWND hWnd);
HBITMAP CopyScreenToBitmap(HWND hwnd,int x1, int y1, int nWidth, int nHeight);
void PaintLoadBitmap(HWND hwnd,SCROLLINFO si, BITMAP bitmap, int pcxsize, int pcysize, int xMaxScroll,int xCurrentScroll, int xMinScroll,int yMaxScroll, int yCurrentScroll ,int yMinScroll);
void DrawBoundingBox(HDC hdc, int StartxPos, int EndxPos, int StartyPos, int EndyPos);
void Cut(HDC hdc, HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double oWidth, double oHeight, double StartxPos, double EndxPos, double StartyPos, double EndyPos, int xCurrentScroll, int yCurrentScroll);
void Paste(HWND hwnd, HBITMAP hBitmap, double Width, double Height , double oWidth, double oHeight ,HDC hdc, HDC hdcMem, double StartxPos, double EndxPos, double xCurrentScroll, double StartyPos, double EndyPos, int yCurrentScroll, double zoom, double cZoom);
void ZeroScrollbars(HWND hwnd, SCROLLINFO *si, BITMAP bitmap, int cxsize, int cysize,int xCurrentScroll, int yCurrentScroll, int xMaxScroll, int yMaxScroll, int xMinScroll, int yMinScroll);
HBITMAP fadetogrey(HDC hdc,HDC hdcMem, HBITMAP Hbitmap, double Width, double Height, double Width2, double Height2, int xCurrentScroll, int yCurrentScroll);
HBITMAP fadetoyellow(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll);
HBITMAP flipvertical(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll);
HBITMAP fliphorizontal(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll);
HBITMAP RedeyeReduction(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll,double StartxPos, double EndxPos, double StartyPos, double EndyPos);
HBITMAP RotateRight(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll);
HBITMAP RotateLeft(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll);
HBITMAP DuoTone(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll);
void SetScrollBars(HWND hwnd, RECT WinRect, SCROLLINFO *si, double bxWidth2, double bxHeight2, double cxsize, double cysize, int xMaxScroll, int xMinScroll, int* xCurrentScroll, int yMaxScroll, int yMinScroll, int* yCurrentScroll, int xDelta, int yDelta);
/*Start of Program Entry point*/

int WINAPI WinMain (HINSTANCE hThisInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpszArgument,
	int nCmdShow)
{
	HWND hwnd;               /* This is the handle for our window */
	MSG messages;            /* Here messages to the application are saved */
	WNDCLASSEX wincl;        /* Data structure for the windowclass */

	/* The Window structure */
	wincl.hInstance = hThisInstance;
	wincl.lpszClassName = szClassName;
	wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
	wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
	wincl.cbSize = sizeof (WNDCLASSEX);

	/* Use default icon and mouse-pointer */
	wincl.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1));
	wincl.hIconSm = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1));
	wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
	wincl.lpszMenuName = MAKEINTRESOURCE(hMenu);                 /* No menu */
	wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
	wincl.cbWndExtra = 0;                      /* structure or the window instance */
	/* Use Windows's default colour as the background of the window */
	wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

	/* Register the window class, and if it fails quit the program */
	if (!RegisterClassEx (&wincl))
		return 0;

	/* The class is registered, let's create the program*/
	/* The class is registered, let's create the program*/
	hwnd = CreateWindowEx (
		0,                   /* Extended possibilites for variation */
		szClassName,         /* Classname */
		szClassName,       /* Title Text */
		WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCROLL, /* default window */
		CW_USEDEFAULT,       /* Windows decides the position */
		CW_USEDEFAULT,       /* where the window ends up on the screen */
		544,                 /* The programs width */
		375,                 /* and height in pixels */
		HWND_DESKTOP,        /* The window is a child-window to desktop */
		NULL,                /* menu */
		hThisInstance,       /* Program Instance handler */
		NULL                 /* No Window Creation data */
		);

	/* Make the window visible on the screen */
	ShowWindow (hwnd, SW_MAXIMIZE);

	/* Run the message loop. It will run until GetMessage() returns 0 */
	while (GetMessage (&messages, NULL, 0, 0))
	{
		/* Translate virtual-key messages into character messages */
		TranslateMessage(&messages);
		/* Send message to WindowProcedure */
		DispatchMessage(&messages);
	}

	/* The program return-value is 0 - The value that PostQuitMessage() gave */
	return messages.wParam;
}









WinProc.h



#ifndef WINPROC_H_INCLUDED
#define WINPROC_H_INCLUDED

#include "Functions.h"
#include "resource.h"
#include "Loader.h"
#include <Winspool.h>
#include <CommDlg.h>
#include <CommCtrl.h>
#include <cmath>
#include <algorithm>

HPALETTE hpal;
PBITMAPINFO pbmi;
DWORD Token;
HMENU menu;
HBITMAP hBitmap;
double bxWidth, bxHeight;
double OrigWidth, OrigHeight;
double bxWidth2, bxHeight2;
double zoom =0;
double cZoom =0;
static int yScroll;
static int xScroll;
bool fZoom = false;
int cxsize = 544,cxpage = 0;
int cysize = 375,cypage = 0;

RECT rect,WinRect;
SCROLLINFO si;
BITMAP bitmap;
double StartxPos;
double StartyPos;
double EndxPos;
double EndyPos;


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	PAINTSTRUCT ps;
	HMODULE hWinLib = LoadLibrary("gdiplus.dll");


	// These variables are required by BitBlt.



	static BOOL fBlt;
	static BOOL fLoad;           // TRUE if BitBlt occurred
	static BOOL fScroll;         // TRUE if scrolling occurred
	static BOOL fSize;           // TRUE if fBlt & WM_SIZE

	static BOOL mmov;
	static BOOL cut;
	static BOOL greyscale;
	static BOOL bbox;
	static BOOL redeye;
	static BOOL flipv;
	static BOOL fliph;
	static BOOL sepia;
	static BOOL rRight;
	static BOOL rLeft;
	static BOOL fDuo;
	static BOOL Undo;
	static BOOL paste;

	// These variables are required for horizontal scrolling.
	static int xMinScroll;       // minimum horizontal scroll value
	static int xCurrentScroll;   // current horizontal scroll value
	static int xMaxScroll;       // maximum horizontal scroll value
	static int xDelta;           // difference in x scrolling
	// These variables are required for vertical scrolling.
	static int yMinScroll;       // minimum vertical scroll value
	static int yCurrentScroll;   // current vertical scroll value
	static int yMaxScroll;       // maximum vertical scroll value
	static int yDelta;           // difference in y scrolling
	static HWND hwndViewer;

	switch (message)                  /* handle the messages */
	{
	case WM_CREATE:
		{
		
		
        InitialiseDialog(hwnd);
		hwndViewer = SetClipboardViewer(hwnd);

		menu = GetMenu(hwnd);


		// Initialize the flags.
		fBlt = FALSE;
		fScroll = FALSE;
		fSize = FALSE;
		yScroll = 0;
		xScroll = 0;
		// Initialize the horizontal scrolling variables.
		xMinScroll = 0;
		xCurrentScroll = 0;
		xMaxScroll = 0;

		// Initialize the vertical scrolling variables.
		yMinScroll = 0;
		yCurrentScroll = 0;
		yMaxScroll = 0;



		return 0;
		}
	case WM_LBUTTONDOWN:
		{
			StartxPos = LOWORD(lParam);
			StartyPos = HIWORD(lParam);



			return 0;
		}

	case WM_LBUTTONUP:
		{
			EndxPos = LOWORD(lParam);
			EndyPos = HIWORD(lParam);

			mmov = true;
			InvalidateRect(hwnd,&rect,true);
			return 0;
		}



	case WM_QUERYNEWPALETTE:
		{
		if (!hpal)
			return FALSE;
		HDC hdce = GetDC(hwnd);
		SelectPalette (hdce, hpal, FALSE);
		RealizePalette (hdce);
		InvalidateRect(hwnd,NULL,TRUE);
		ReleaseDC(hwnd,hdce);
		return TRUE;
		}

	case WM_PALETTECHANGED:
		{
		HDC hdce = GetDC(hwnd);
		if (!hpal || (HWND)wParam == hwnd)
			break;
		
		SelectPalette (hdce, hpal, FALSE);
		RealizePalette (hdce);
		UpdateColors(hdce);
		ReleaseDC(hwnd,hdce);
		break;
		}
	case WM_DRAWCLIPBOARD:
		{

			if (hwndViewer)
			{
				SendMessage(hwndViewer,message, wParam, lParam);
			}

			EnableMenuItem(menu, IDM_PASTE, MF_ENABLED);
			InvalidateRect(hwnd, NULL, true);
			return 0;
		}

	case WM_CHANGECBCHAIN:
		{
			if((HWND)wParam == hwndViewer)
			{
				hwndViewer = (HWND)lParam;
			}
			else if(hwndViewer)
			{
				SendMessage(hwndViewer,message,wParam, lParam);
			}

			return 0;
		}



	case WM_COMMAND:
		switch LOWORD(wParam)
		{

		case IDM_OPEN_BM:
			{


				
				
				OpenFileDialog(hwnd, szFileName, (TCHAR*)"Open an Image File.");
				
				if(szFileName!= 0)
				{
					ZeroMemory(&hBitmap, sizeof(HBITMAP));


					HDC hdc = GetDC(hwnd);
					WCHAR* outFileName;
					outFileName= (WCHAR*)malloc(500);
					ZeroMemory(outFileName,500);
					MultiByteToWideChar(CP_ACP, MB_COMPOSITE,szFileName,-1,outFileName,500);
					
					hBitmap = MakeBitmapFromFile(hWinLib,outFileName);
					
					free(outFileName);
					


					if(hBitmap != NULL)
					{

						EnableMenuItem(menu, IDM_SAVE_BM, MF_ENABLED);
						EnableMenuItem(menu, IDM_PRINT_BM, MF_ENABLED);
						EnableMenuItem(menu, IDM_ZOOMIN, MF_ENABLED);
						EnableMenuItem(menu, IDM_ZOOMOUT, MF_ENABLED);
						cxpage = GetDeviceCaps (hdc, HORZRES);
						cypage = GetDeviceCaps (hdc, VERTRES);
						GetObject(hBitmap,sizeof(BITMAP),&bitmap);
						bxWidth = bitmap.bmWidth;
						bxHeight = bitmap.bmHeight;
						OrigWidth = bxWidth;
						OrigHeight = bxHeight;
						bxWidth2 = bxWidth;
						bxHeight2 = bxHeight;
						rect.left = 0;
						rect.top =0;
						rect.right = (long)&cxpage;
						rect.bottom = (long)&cypage;
						GetWindowRect(hwnd, &WinRect);
						cxsize = WinRect.right;
						cysize = WinRect.bottom;
						xCurrentScroll = 0;
						yCurrentScroll = 0;
						zoom =0;
						fZoom =false;
						fBlt = TRUE;
						fLoad = TRUE;
						fSize = FALSE;
						
						if(IsClipboardFormatAvailable(CF_BITMAP))
						{
							EnableMenuItem(menu, IDM_PASTE, MF_ENABLED);
						}






						ReleaseDC(hwnd,hdc);

						InvalidateRect(hwnd,NULL,TRUE);
					}
				}
				return 0;
			}

		case IDM_PRINT_BM:
			{
				DOCINFO di= { sizeof (DOCINFO), TEXT ("Printing Picture...")};

				HDC prn;



				prn = GetPrinterDC(hwnd);
				cxpage = GetDeviceCaps (prn, HORZRES);
				cypage = GetDeviceCaps (prn, VERTRES);
				HDC hdcMem = CreateCompatibleDC(prn);
				HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);

				StartDoc (prn, &di);
				StartPage (prn) ;
				SetMapMode (prn, MM_ISOTROPIC);
				SetWindowExtEx(prn, cxpage,cypage, NULL);
				SetViewportExtEx(prn, cxpage, cypage,NULL);

				SetViewportOrgEx(prn, 0, 0, NULL);
				StretchBlt(prn, 0, 0, cxpage, cypage, hdcMem, 0, 0, (int)bxWidth, (int)bxHeight, SRCCOPY);
				EndPage (prn);
				EndDoc(prn);
				DeleteDC(prn);
				SelectObject(hdcMem, hbmOld);
				DeleteDC(hdcMem);

				return 0;
			}

		case IDM_SAVE_BM:
			{
				
				char szFileName[1000];
				ZeroMemory(szFileName,1000);
				
				BOOL result = SaveFileDialog(hwnd,szFileName,(TCHAR*)"Save an Image.");
				if(result != false)
				{
					PBITMAPINFO pbi = CreateBitmapInfoStruct(hwnd, hBitmap, pbmi);
					HDC hdce= GetDC(hwnd);


					SaveBMPFile(hwnd, szFileName, pbi, hBitmap, hdce);
                    ReleaseDC(hwnd,hdce);
					

				}
				return 0;
			}

		case IDM_EXIT:
			{
				SendMessage(hwnd,WM_CLOSE,0,0);
				return 0;

			}

		case IDM_COPY:
			{

				cZoom = zoom;
				int cutwidth = (int)abs(StartxPos - EndxPos);
				int cutheight = (int)abs(StartyPos - EndyPos);

				HBITMAP hbmp;

				int oldxpos = (int)StartxPos;
				int oldendpos = (int)EndxPos;
				int oldypos = (int)StartyPos;
				int oldendypos = (int)EndyPos;

				if (StartxPos > EndxPos)
				{
					StartxPos = oldendpos;
					EndxPos = oldxpos;
					StartyPos = oldendypos;
					EndyPos = oldypos;
				}

				ZeroMemory(&hbmp, sizeof(HBITMAP));


				hbmp = CopyScreenToBitmap(hwnd,(int)StartxPos,(int)StartyPos,cutwidth,cutheight);
				if(hbmp == NULL)
				{
					MessageBox(hwnd,"Copy not created properly","Error",MB_OK);
				}


				BitmapToClipboard(hbmp, hwnd);
				DeleteBitmap(hbmp);


				return 0;
			}

		case IDM_CUT:
			{

				cZoom = zoom;
				int oldxpos = (int)StartxPos;
				int oldendpos = (int)EndxPos;
				int oldypos = (int)StartyPos;
				int oldendypos = (int)EndyPos;

				if (StartxPos > EndxPos)
				{
					StartxPos = oldendpos;
					EndxPos = oldxpos;
					StartyPos = oldendypos;
					EndyPos = oldypos;
				}

				int cutwidth = (int)abs(EndxPos - StartxPos);
				int cutheight = (int)abs(EndyPos - StartyPos);
				HBITMAP hbmp;
				ZeroMemory(&hbmp, sizeof(HBITMAP));
				hbmp = CopyScreenToBitmap(hwnd,(int)StartxPos,(int)StartyPos,cutwidth,cutheight);


				if(hbmp == NULL)
				{
					MessageBox(hwnd,"Copy not created properly","Error",MB_OK);
				}
				OpenClipboard(hwnd);
				EmptyClipboard();
				CloseClipboard();

				BitmapToClipboard(hbmp, hwnd);
				DeleteBitmap(hbmp);


				cut = true;
				InvalidateRect(hwnd,NULL,true);
				return 0;
			}
		case IDM_PASTE:
			{
				paste = true;

				InvalidateRect(hwnd,NULL,true);
				return 0;
			}

		case IDM_UNDO:
			{
				Undo = TRUE;
				GetWindowRect(hwnd, &WinRect);

				SetScrollBars(hwnd, WinRect,&si,bxWidth2,bxHeight2,cxsize,cysize,xMaxScroll,xMinScroll,&xCurrentScroll,yMaxScroll,yMinScroll,&yCurrentScroll, xDelta, yDelta);
				InvalidateRect(hwnd,NULL,TRUE);

				return 0;
			}

		case IDM_ZOOMOUT:
			{
				zoom = zoom - 25;
				if (zoom < -75)
				{
					zoom = -75;
				}

				bxWidth2 = bxWidth + (bxWidth*(zoom/100));
				bxHeight2 = bxHeight + (bxHeight*(zoom/100));

				fZoom = TRUE;




				SetScrollBars(hwnd, WinRect,&si,bxWidth2,bxHeight2,cxsize,cysize,xMaxScroll,xMinScroll,&xCurrentScroll,yMaxScroll,yMinScroll,&yCurrentScroll, xDelta, yDelta);


				InvalidateRect(hwnd,NULL,TRUE);
				return 0;
			}

		case IDM_ZOOMIN:
			{


				zoom = zoom + 25;
				if (zoom >  75)
				{
					zoom = 75;
				}
				GetWindowRect(hwnd, &WinRect);
				bxWidth2 = bxWidth + (bxWidth*(zoom/100));
				bxHeight2 = bxHeight + (bxHeight*(zoom/100));

				fZoom = TRUE;


				SetScrollBars(hwnd, WinRect,&si,bxWidth2,bxHeight2,cxsize,cysize,xMaxScroll,xMinScroll,&xCurrentScroll,yMaxScroll,yMinScroll,&yCurrentScroll, xDelta, yDelta);

				InvalidateRect(hwnd,NULL,TRUE);

				return 0;
			}
		case IDM_GRAY:
			{
				greyscale = TRUE;

				InvalidateRect(hwnd,NULL,TRUE);
				return 0;
			}

		case IDM_REDEYE:
			{
				redeye = TRUE;

				InvalidateRect(hwnd,NULL,TRUE);
				return 0;
			}

		case IDM_FLIPV:
			{
				flipv = TRUE;

				InvalidateRect(hwnd,NULL,true);
				return 0;
			}
		case IDM_FLIPH:
			{
				fliph = TRUE;

				InvalidateRect(hwnd,NULL,true);
				return 0;
			}
		case IDM_SEPIA:
			{
				sepia = TRUE;

				InvalidateRect(hwnd,NULL,true);
				return 0;
			}

		case IDM_ROTATERIGHT:
			{
				rRight = TRUE;
				GetWindowRect(hwnd, &WinRect);


				SetScrollBars(hwnd, WinRect,&si,bxWidth2,bxHeight2,cxsize,cysize,xMaxScroll,xMinScroll,&xCurrentScroll,yMaxScroll,yMinScroll,&yCurrentScroll, xDelta, yDelta);

				InvalidateRect(hwnd, NULL, TRUE);


				return 0;
			}

		case IDM_ROTATELEFT:
			{
				rLeft = TRUE;

				GetWindowRect(hwnd, &WinRect);

				SetScrollBars(hwnd, WinRect,&si,bxWidth2,bxHeight2,cxsize,cysize,xMaxScroll,xMinScroll,&xCurrentScroll,yMaxScroll,yMinScroll,&yCurrentScroll, xDelta, yDelta);

				InvalidateRect(hwnd,NULL,TRUE);

				return 0;
			}
		case IDM_DUOTONE:
			{
				fDuo = TRUE;
				InvalidateRect(hwnd,NULL,true);
				return 0;
			}
			break;
		}

	case WM_PAINT:
		{


			HDC hdc = BeginPaint(hwnd, &ps);


			HDC hdcMem = CreateCompatibleDC(hdc);
			

			if (fLoad)
			{
				bxWidth2 = bxWidth;
				bxHeight2 = bxHeight;
				SetGraphicsMode(hdc,GM_ADVANCED);
				PaintLoadBitmap(hwnd, &si, bitmap, (int)bxWidth, (int)bxHeight, xMaxScroll, xCurrentScroll, 0, yMaxScroll, yCurrentScroll, 0);
				ZeroScrollbars(hwnd,si,bitmap,cxsize,cysize,xCurrentScroll,yCurrentScroll,xMaxScroll,yMaxScroll,xMinScroll,yMinScroll);
				SelectObject(hdcMem, hBitmap);
				
				PBITMAPINFO info = CreateBitmapInfoStruct(hwnd, hBitmap, pbmi);
				SaveBMPFile(hwnd,(char*)"temporarypicture.bmp",info,hBitmap,hdc);
				
				BitBlt(hdc,0,0,(int)bxWidth, (int)bxHeight,hdcMem,0,0,SRCCOPY);
				fLoad= FALSE;


			}
			if (fBlt)
			{
				//hdc = GetDC(hwnd);
				RECT Rect;
				GetWindowRect(hwnd, &Rect);
				FillRect(hdc, &Rect,(HBRUSH) COLOR_BACKGROUND);
				SelectObject(hdcMem, hBitmap);
				SetStretchBltMode(hdc,HALFTONE);

				StretchBlt(hdc, 0, 0,(int)bxWidth2,(int)bxHeight2, hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight, SRCCOPY);

			}

			// If the window has been resized and the user has
			// captured the screen, use the following call to
			// BitBlt to paint the window's client area.

			if (fSize)
			{

				
				SelectObject(hdcMem, hBitmap);
				SetStretchBltMode(hdc,HALFTONE);

				StretchBlt(hdc, 0, 0, (int)bxWidth2 ,(int)bxHeight2, hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight, SRCCOPY);

				fSize = FALSE;

			}

			// If scrolling has occurred, use the following call to
			// StretchBlt to paint the invalid rectangle.
			//
			// The coordinates of this rectangle are specified in the
			// RECT structure to which prect points.
			//
			// Note that it is necessary to increment the seventh
			// argument (prect->left) by xCurrentScroll and the
			// eighth argument (prect->top) by yCurrentScroll in
			// order to map the correct pixels from the source bitmap.
			if (fScroll)
			{
				SelectObject(hdcMem, hBitmap);
				SetStretchBltMode(hdc,HALFTONE);

				StretchBlt(hdc, 0, 0, (int)bxWidth2 ,(int)bxHeight2, hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight, SRCCOPY);
				fScroll = FALSE;


			}

			if(fZoom == TRUE)
			{
				hdc = GetDC(hwnd);
				RECT Rect;
				GetWindowRect(hwnd, &Rect);
				FillRect(hdc, &Rect,(HBRUSH) COLOR_BACKGROUND);
				SelectObject(hdcMem,hBitmap);
				SetStretchBltMode(hdc,HALFTONE);
				StretchBlt(hdc,0,0,(int)bxWidth2,(int)bxHeight2,hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight,SRCCOPY);

				fZoom = FALSE;
				InvalidateRect(hwnd, NULL, TRUE);

			}



			if (bbox == TRUE && redeye == TRUE)
			{

				hBitmap = RedeyeReduction(hdc,hdcMem,hBitmap,bxWidth,bxHeight,bxWidth2,bxHeight2,xCurrentScroll,yCurrentScroll,StartxPos,EndxPos,StartyPos,EndyPos);
				redeye = false;
			}

			if(mmov)
			{
				DrawBoundingBox(hdc, (int)StartxPos, (int)EndxPos, (int)StartyPos, (int)EndyPos);
				mmov = false;
				bbox = true;
				EnableMenuItem(menu, IDM_COPY, MF_ENABLED);
				EnableMenuItem(menu, IDM_CUT, MF_ENABLED);

			}

			if(cut)
			{


				Cut(hdc, hdcMem, hBitmap, (int)bxWidth2, (int)bxHeight2, (int)bxWidth, (int)bxHeight, StartxPos, EndxPos, StartyPos, EndyPos, xCurrentScroll, yCurrentScroll);

				cut = false;


			}

			if(paste)
			{

				int oldxpos = (int)StartxPos;
				int oldendpos = (int)EndxPos;
				int oldypos = (int)StartyPos;
				int oldendypos = (int)EndyPos;

				if (StartxPos > EndxPos)
				{
					StartxPos = oldendpos;
					EndxPos = oldxpos;
					StartyPos = oldendypos;
					EndyPos = oldypos;
				}



				Paste(hwnd, hBitmap, bxWidth2, bxHeight2 ,bxWidth, bxHeight ,hdc, hdcMem, StartxPos, EndxPos, xCurrentScroll, StartyPos, EndyPos, yCurrentScroll, zoom, cZoom );


				//Reset Scrollbars to zero
				ZeroScrollbars(hwnd, si, bitmap, cxsize, cysize, xCurrentScroll, yCurrentScroll, xMaxScroll, yMaxScroll, xMinScroll, yMinScroll);


				paste = false;

			}

			if (Undo)
			{

				RECT Rect;
				GetWindowRect(hwnd, &Rect);
				FillRect(hdc, &Rect,(HBRUSH) COLOR_BACKGROUND);
				//DeleteObject(hBitmap);

				hBitmap = (HBITMAP)LoadImage(NULL,"temporarypicture.bmp",IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);

				bxWidth = bxWidth2 = OrigWidth;
				bxHeight = bxHeight2 = OrigHeight;



				SelectObject(hdcMem, hBitmap);


				SetStretchBltMode(hdc,HALFTONE);
				StretchBlt(hdc,0,0,(int)bxWidth,(int)bxHeight,hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight,SRCCOPY);




				Undo = FALSE;

			}
			if(greyscale == TRUE)
			{

				hBitmap = fadetogrey(hdc,hdcMem,hBitmap,bxWidth,bxHeight, bxWidth2, bxHeight2,xCurrentScroll,yCurrentScroll);
				greyscale = false;

			}

			if(sepia == TRUE)
			{

				hBitmap = fadetoyellow(hdc,hdcMem,hBitmap,bxWidth,bxHeight, bxWidth2, bxHeight2,xCurrentScroll,yCurrentScroll);
				sepia = false;

			}

			if (flipv)
			{
				hBitmap = flipvertical(hdc,hdcMem,hBitmap,bxWidth,bxHeight, bxWidth2, bxHeight2,xCurrentScroll,yCurrentScroll);
				flipv = false;

			}

			if (fliph == TRUE)
			{
				hBitmap = fliphorizontal(hdc,hdcMem,hBitmap,bxWidth,bxHeight, bxWidth2, bxHeight2,xCurrentScroll,yCurrentScroll);
				fliph = false;

			}

			if (rRight == TRUE)
			{
				RECT Rect;

				GetWindowRect(hwnd,&Rect);
				FillRect(hdc, &Rect,(HBRUSH) COLOR_BACKGROUND);

				double TWidth=bxWidth, THeight = bxHeight, TWidth2 = bxWidth2, THeight2 = bxHeight2;
				hBitmap = RotateRight(hdc, hdcMem, hBitmap, bxWidth, bxHeight, bxWidth2, bxHeight2, xCurrentScroll, yCurrentScroll);
				bxWidth = THeight;
				bxHeight = TWidth;
				bxWidth2 = THeight2;
				bxHeight2 = TWidth2;

				rRight = FALSE;
				InvalidateRect(hwnd,NULL,TRUE);
			}

			if (rLeft == TRUE)
			{
				RECT Rect;

				GetWindowRect(hwnd,&Rect);

				FillRect(hdc, &Rect,(HBRUSH) COLOR_BACKGROUND);

				double TWidth=bxWidth, THeight = bxHeight, TWidth2 = bxWidth2, THeight2 = bxHeight2;
				hBitmap = RotateLeft(hdc, hdcMem, hBitmap, bxWidth, bxHeight, bxWidth2, bxHeight2, xCurrentScroll, yCurrentScroll);
				bxWidth = THeight;
				bxHeight = TWidth;
				bxWidth2 = THeight2;
				bxHeight2 = TWidth2;
				rLeft = FALSE;
				InvalidateRect(hwnd,NULL,TRUE);

			}

			if (fDuo == TRUE)
			{
				hBitmap = DuoTone(hdc, hdcMem, hBitmap, bxWidth, bxHeight, bxWidth2, bxHeight2, xCurrentScroll, yCurrentScroll);
				fDuo = FALSE;
			}
			
			DeleteDC(hdcMem);
            EndPaint(hwnd, &ps);
			

			return 0;
		}



	case  WM_SIZE:
		{

			GetWindowRect(hwnd, &WinRect);
			cxsize = (int)LOWORD(lParam);
			cysize = (int)HIWORD(lParam);
			if((bxWidth2-cxsize) >0)
			{
				ShowScrollBar(hwnd, SB_HORZ, TRUE);
			}
			else if ((bxWidth2-cxsize) <0)
			{
				ShowScrollBar(hwnd, SB_HORZ, FALSE);
			}

			if((bxHeight2-cysize) >0)
			{
				ShowScrollBar(hwnd, SB_VERT, TRUE);
			}
			else if ((bxHeight2-cysize) <0)
			{
				ShowScrollBar(hwnd, SB_VERT, FALSE);
			}

			SetScrollBars(hwnd, WinRect, &si ,bxWidth2, bxHeight2, cxsize, cysize, xMaxScroll, xMinScroll, &xCurrentScroll, yMaxScroll, yMinScroll, &yCurrentScroll, xDelta, yDelta);


			fSize = TRUE;

			InvalidateRect(hwnd,NULL,TRUE);

			return 0;
		}

	case WM_HSCROLL:
		{
			int xDelta = 0;     // xDelta = new_pos - current_pos
			int xNewPos = 0;    // new position
			int yDelta = 0;

			switch (LOWORD(wParam))
			{
				// User clicked the scroll bar shaft left of the scroll box.
			case SB_PAGELEFT:
				xNewPos = xCurrentScroll - 50;
				xDelta = -50;
				break;

				// User clicked the scroll bar shaft right of the scroll box.
			case SB_PAGERIGHT:
				xNewPos = xCurrentScroll + 50;
				xDelta = 50;
				break;

				// User clicked the left arrow.
			case SB_LINELEFT:
				xNewPos = xCurrentScroll - 15;
				xDelta = -15;
				break;

				// User clicked the right arrow.
			case SB_LINERIGHT:
				xNewPos = xCurrentScroll + 15;
				xDelta = 15;
				break;

				// User dragged the scroll box.
			case SB_THUMBPOSITION:
				xNewPos = HIWORD(wParam);
				xDelta = xNewPos;
				break;

			default:
				xNewPos = xCurrentScroll;
			}

			// New position must be between 0 and the screen width.
			xMaxScroll =(int) bxWidth2;
			xNewPos = max(0, xNewPos);
			xNewPos = min(xMaxScroll, xNewPos);
			xCurrentScroll = min(xCurrentScroll, xMaxScroll);
			// If the current position does not change, do not scroll.
			if (xNewPos == xCurrentScroll)
				break;

			// Set the scroll flag to TRUE.
			fScroll = TRUE;



			// Reset the current scroll position.
			xCurrentScroll = xNewPos;

			// Scroll the window. (The system repaints most of the
			// client area when ScrollWindowEx is called; however, it is
			// necessary to call UpdateWindow in order to repaint the
			// rectangle of pixels that were invalidated.)


			// Reset the scroll bar.
			SetScrollBars(hwnd, WinRect, &si,bxWidth2, bxHeight2, cxsize, cysize, xMaxScroll, xMinScroll, &xCurrentScroll, yMaxScroll, yMinScroll, &yCurrentScroll, xDelta, yDelta);

			ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
				(CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
				SW_ERASE);

			InvalidateRect(hwnd,NULL,TRUE);
			break;
		}


	case WM_VSCROLL:
		{
			int xDelta = 0;
			int yDelta;     // yDelta = new_pos - current_pos
			int yNewPos;    // new position

			switch (LOWORD(wParam))
			{
				// User clicked the scroll bar shaft above the scroll box.
			case SB_PAGEUP:
				yNewPos = yCurrentScroll - 50;
				break;

				// User clicked the scroll bar shaft below the scroll box.
			case SB_PAGEDOWN:
				yNewPos = yCurrentScroll + 50;
				break;

				// User clicked the top arrow.
			case SB_LINEUP:
				yNewPos = yCurrentScroll - 15;
				break;

				// User clicked the bottom arrow.
			case SB_LINEDOWN:
				yNewPos = yCurrentScroll + 15;
				break;

				// User dragged the scroll box.
			case SB_THUMBPOSITION:
				yNewPos = HIWORD(wParam);
				break;

			default:
				yNewPos = yCurrentScroll;
				break;
			}

			// New position must be between 0 and the screen height.
			yMaxScroll = (int)bxHeight2-cysize;
			yNewPos = max(0, yNewPos);
			yNewPos = min(yMaxScroll, yNewPos);
			yCurrentScroll = min(yCurrentScroll, yMaxScroll);
			// If the current position does not change, do not scroll.
			if (yNewPos == yCurrentScroll)
				break;

			// Set the scroll flag to TRUE.
			fScroll = TRUE;

			// Determine the amount scrolled (in pixels).
			yDelta = abs(yNewPos - yCurrentScroll);

			// Reset the current scroll position.
			yCurrentScroll = yNewPos;

			// Scroll the window. (The system repaints most of the
			// client area when ScrollWindowEx is called; however, it is
			// necessary to call UpdateWindow in order to repaint the
			// rectangle of pixels that were invalidated.)

			// Reset the scroll bar.

			SetScrollBars(hwnd, WinRect, &si,bxWidth2, bxHeight2, cxsize, cysize, xMaxScroll, xMinScroll, &xCurrentScroll, yMaxScroll, yMinScroll, &yCurrentScroll, xDelta, yDelta);



			ScrollWindowEx(hwnd,-xDelta, -yDelta, (CONST RECT *) NULL,
				(CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
				SW_ERASE);

			InvalidateRect(hwnd,NULL,TRUE);
			break;
		}

	case WM_CLOSE:
		{

			ChangeClipboardChain(hwnd, hwndViewer);

			DeleteFile("temporarypicture.bmp");
			DeleteObject(hbmReturn);
			DeleteObject(hBitmap);
			
			DeleteObject(&bitmap);
			
		    free(pbmi);
			BOOL libresult= FreeLibrary(hWinLib);
			if(libresult ==0)
			{
				MessageBox(hwnd,"Free Library Error","Error",MB_OK);
			}
			Sleep(500);
			DestroyWindow(hwnd);
			return 0;
		}
	case WM_DESTROY:


		PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
		return 0;
	default:                      /* for messages that we don't deal with */
		return DefWindowProc (hwnd, message, wParam, lParam);

	}
	return 0;

}


#endif // WINPROC_H_INCLUDED











resource.h


#define WINVER 0x0500
#define _WIN32_WINNT 0x0500

#include <windows.h>

#define ICO1           100

#define hMenu           1000
#define IDM_OPEN_BM     1001
#define IDM_PRINT_BM    1002
#define IDM_SAVE_BM     1003
#define IDM_EXIT        1004
#define IDM_COPY        1005
#define IDM_CUT         1006
#define IDM_PASTE       1007
#define IDM_ZOOMIN      1008
#define IDM_ZOOMOUT     1009
#define IDM_GRAY        1010
#define IDM_REDEYE      1011
#define IDM_FLIPV       1012
#define IDM_FLIPH       1013
#define IDM_UNDO        1016
#define IDM_SEPIA       1014
#define IDM_ROTATELEFT  1015
#define IDM_ROTATERIGHT 1017
#define IDM_DUOTONE     1018









resource.rc


#include "resource.h"


ICO1 ICON DISCARDABLE "snoopy.ico"


//Menu creation
hMenu MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "Open Image",  IDM_OPEN_BM
MENUITEM "Print Image", IDM_PRINT_BM, GRAYED
MENUITEM "Save Bitmap",  IDM_SAVE_BM, GRAYED
MENUITEM SEPARATOR
MENUITEM "Exit Program", IDM_EXIT
END

POPUP "&Edit"
BEGIN
MENUITEM "Undo",  IDM_UNDO
MENUITEM "Copy",  IDM_COPY,  GRAYED
MENUITEM "Cut",   IDM_CUT,   GRAYED
MENUITEM "Paste", IDM_PASTE, GRAYED
END





POPUP "&Zoom"
BEGIN
MENUITEM SEPARATOR
MENUITEM "Zoom In",  IDM_ZOOMIN, GRAYED
MENUITEM SEPARATOR
MENUITEM "Zoom Out",   IDM_ZOOMOUT, GRAYED
END

POPUP "&Image Effects"
BEGIN
MENUITEM "Convert to Grayscale",  IDM_GRAY
MENUITEM "Red Eye Reduction", IDM_REDEYE
MENUITEM "Flip Image Verticallly", IDM_FLIPV
MENUITEM "Flip Image Horizontallly", IDM_FLIPH
MENUITEM "Convert to Sepia", IDM_SEPIA
MENUITEM "Rotate 90 Right", IDM_ROTATERIGHT
MENUITEM "Rotate 90 Left", IDM_ROTATELEFT
MENUITEM "Convert to DuoTone", IDM_DUOTONE
END



END








Functions.h


#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED

#include <fstream>
#include <windows.h>
#include <windowsx.h>

using namespace std;

static OPENFILENAME ofn;
char szFileName[500]= "\0";



template <typename T> 
T **AllocateArray( int x, int y)
{
	T **dynamicArray;

	dynamicArray = new T*[x];
	for( int i = 0 ; i < x ; i++ )
		dynamicArray[i] = new T [y];

	return dynamicArray;
}

template <typename T>
void FreeArray(T** dArray)
{
	delete [] *dArray;
	delete [] dArray;
}


HDC GetPrinterDC (HWND Hwnd)
{

	// Initialize a PRINTDLG structure's size and set the PD_RETURNDC flag set the Owner flag to hwnd.
	// The PD_RETURNDC flag tells the dialog to return a printer device context.
	HDC hdc;
	PRINTDLG pd = {0};
	pd.lStructSize = sizeof( pd );
	pd.hwndOwner = Hwnd;
	pd.Flags = PD_RETURNDC;

	// Retrieves the printer DC
	PrintDlg(&pd);
	hdc =pd.hDC;
	return hdc ;


}

BOOL OpenFileDialog(HWND hwnd, char* pFileName ,LPTSTR pTitleName)

{
   
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hInstance = GetModuleHandle(NULL);
	ofn.lpstrCustomFilter = NULL;
	ofn.nMaxCustFilter = 0;
	ofn.nFilterIndex = 0;

	ofn.hwndOwner = hwnd;
	ofn.lpstrFile = pFileName;
	ofn.lpstrFileTitle = NULL;
	ofn.lpstrTitle = pTitleName;
	ofn.Flags = OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
	ofn.lpstrFilter = TEXT("Bitmap\0*.bmp\0JPEG\0*.jpg\0PNG\0*.png\0GIF\0*.gif\0Icon\0*.ico\0TIFF\0*.tif\0\0");



	return GetOpenFileName(&ofn);

	
}

BOOL SaveFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName)

{
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hInstance = GetModuleHandle(NULL);
	ofn.lpstrCustomFilter = NULL;
	ofn.nMaxCustFilter = 0;
	ofn.nFilterIndex = 0;

	ofn.hwndOwner = hwnd;
	ofn.lpstrFile = pFileName;
	ofn.lpstrFileTitle = NULL;
	ofn.lpstrTitle = pTitleName;
	ofn.Flags = OFN_EXPLORER|OFN_OVERWRITEPROMPT;
	ofn.lpstrFilter = TEXT("Bitmap Files (*.bmp)\0*.bmp\0\0");



	return GetSaveFileName(&ofn);
}

void InitialiseDialog(HWND hwnd )
{
	
	ZeroMemory(&ofn, sizeof(ofn));

	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = hwnd;
	ofn.hInstance = NULL;
	ofn.lpstrCustomFilter = NULL;
	ofn.nMaxCustFilter = 0;
	ofn.nFilterIndex = 0;
	ofn.lpstrFile = szFileName;
	ofn.lpstrFile[0] = '\0';
	ofn.nMaxFile = sizeof(szFileName);
	ofn.lpstrFileTitle = NULL;
	ofn.nMaxFileTitle = MAX_PATH;
	ofn.lpstrInitialDir = NULL;
	ofn.lpstrTitle = NULL;
	ofn.Flags = 0;
	ofn.nFileOffset = 0;
	ofn.nFileExtension = 0;
	ofn.lpstrDefExt = NULL;
	ofn.lCustData = 0L;
	ofn.lpfnHook = NULL;
	ofn.lpTemplateName = NULL;
}


void SaveBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
{
	std::ofstream hf;                  // file handle
	BITMAPFILEHEADER hdr;       // bitmap file-header
	PBITMAPINFOHEADER pbih;     // bitmap info-header
	LPBYTE lpBits;              // memory pointer
	DWORD cb;                   // incremental count of bytes
	BYTE *hp;                   // byte pointer


	pbih = (PBITMAPINFOHEADER) pbi;
	lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

	if (!lpBits)
	{
		MessageBox(hwnd,"GlobalAlloc","Error", MB_OK );
	}
	// Retrieve the color table (RGBQUAD array) and the bits
	// (array of palette indices) from the DIB.
	if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,DIB_RGB_COLORS))
	{
		MessageBox(hwnd,"GetDIBits","Error",MB_OK );
	}
	// Create the .BMP file.
	hf.open(pszFile,std::ios::binary);
	if (hf.fail() == true)
	{
		MessageBox( hwnd,"CreateFile","Error", MB_OK);
	}

	hdr.bfType = 0x4d42;  // File type designator "BM" 0x42 = "B" 0x4d = "M"
	// Compute the size of the entire file.
	hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD) + pbih->biSizeImage);
	hdr.bfReserved1 = 0;
	hdr.bfReserved2 = 0;
	// Compute the offset to the array of color indices.
	hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD);
	// Copy the BITMAPFILEHEADER into the .BMP file.
	hf.write((char*) &hdr, sizeof(BITMAPFILEHEADER));
	if (hf.fail() == true )
	{
		MessageBox(hwnd,"WriteFileHeader","Error",MB_OK );
	}
	// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
	hf.write((char*) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD));
	if (hf.fail() == true )
	{
		MessageBox(hwnd,"WriteInfoHeader","Error",MB_OK );
	}
	// Copy the array of color indices into the .BMP file.
	cb = pbih->biSizeImage;
	hp = lpBits;
	hf.write((char*) hp, (int) cb);
	if (hf.fail() == true )
	{
		MessageBox(hwnd,"WriteData","Error",MB_OK );
	}
	// Close the .BMP file.
	hf.close();
	if (hf.fail() == true)
	{
		MessageBox(hwnd,"CloseHandle","Error",MB_OK );
	}

	// Free memory.
	GlobalFree((HGLOBAL)lpBits);
}
//End of BMP Save


PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp, PBITMAPINFO pbmi)
{
	BITMAP bmp;
	
	WORD cClrBits;
	// Retrieve the bitmap color format, width, and height.
	if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
	{
		MessageBox(hwnd,"GetObject","Error",MB_OK );
	}
	// Convert the color format to a count of bits.
	cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
	if (cClrBits == 1)
		cClrBits = 1;
	else if (cClrBits <= 4)
		cClrBits = 4;
	else if (cClrBits <= 8)
		cClrBits = 8;
	else if (cClrBits <= 16)
		cClrBits = 16;
	else if (cClrBits <= 24)
		cClrBits = 24;
	else cClrBits = 32;

	// Allocate memory for the BITMAPINFO structure. (This structure
	// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
	// data structures.)

	if (cClrBits != 24)
	{
		pbmi = (PBITMAPINFO) LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits));
	}
	// There is no RGBQUAD array for the 24-bit-per-pixel format.
	else
		pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));

	// Initialize the fields in the BITMAPINFO structure.
	pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	pbmi->bmiHeader.biWidth = bmp.bmWidth;
	pbmi->bmiHeader.biHeight = bmp.bmHeight;
	pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
	pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
	if (cClrBits < 24)
	{
		pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
	}
	// If the bitmap is not compressed, set the BI_RGB flag.
	pbmi->bmiHeader.biCompression = BI_RGB;

	// Compute the number of bytes in the array of color
	// indices and store the result in biSizeImage.
	// For Windows NT, the width must be DWORD aligned unless
	// the bitmap is RLE compressed. This example shows this.
	// For Windows 95/98/Me, the width must be WORD aligned unless the
	// bitmap is RLE compressed.
	pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 * pbmi->bmiHeader.biHeight;
	// Set biClrImportant to 0, indicating that all of the
	// device colors are important.
	pbmi->bmiHeader.biClrImportant = 0;

	return pbmi; //return BITMAPINFO
}

bool BitmapToClipboard(HBITMAP hBM, HWND hWnd)
{
	if (!OpenClipboard(hWnd))
		return false;
	EmptyClipboard();

	BITMAP bm;
	GetObject(hBM, sizeof(bm), &bm);

	BITMAPINFOHEADER bi;
	ZeroMemory(&bi, sizeof(BITMAPINFOHEADER));
	bi.biSize = sizeof(BITMAPINFOHEADER);
	bi.biWidth = bm.bmWidth;
	bi.biHeight = bm.bmHeight;
	bi.biPlanes = 1;
	bi.biBitCount = bm.bmBitsPixel;
	bi.biCompression = BI_RGB;
	if (bi.biBitCount <= 1)	// make sure bits per pixel is valid
		bi.biBitCount = 1;
	else if (bi.biBitCount <= 4)
		bi.biBitCount = 4;
	else if (bi.biBitCount <= 8)
		bi.biBitCount = 8;
	else // if greater than 8-bit, force to 24-bit
		bi.biBitCount = 24;

	// Get size of color table.
	SIZE_T dwColTable = (bi.biBitCount <= 8) ? (1 << bi.biBitCount) * sizeof(RGBQUAD) : 0;

	// Create a device context with palette
	HDC hDC = GetDC(NULL);
	HPALETTE hPal = static_cast<HPALETTE>(GetStockObject(DEFAULT_PALETTE));
	HPALETTE hOldPal = SelectPalette(hDC, hPal, FALSE);
	RealizePalette(hDC);

	// Use GetDIBits to calculate the image size.
	GetDIBits(hDC, hBM, 0, static_cast<UINT>(bi.biHeight), NULL,
		reinterpret_cast<LPBITMAPINFO>(&bi), DIB_RGB_COLORS);
	// If the driver did not fill in the biSizeImage field, then compute it.
	// Each scan line of the image is aligned on a DWORD (32bit) boundary.
	if (0 == bi.biSizeImage)
		bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

	// Allocate memory
	HGLOBAL hDIB = GlobalAlloc(GMEM_MOVEABLE, sizeof(BITMAPINFOHEADER) + dwColTable + bi.biSizeImage);
	if (hDIB)
	{
		union tagHdr_u
		{
			LPVOID             p;
			LPBYTE             pByte;
			LPBITMAPINFOHEADER pHdr;
			LPBITMAPINFO       pInfo;
		} Hdr;

		Hdr.p = GlobalLock(hDIB);
		// Copy the header
		CopyMemory(Hdr.p, &bi, sizeof(BITMAPINFOHEADER));
		// Convert/copy the image bits and create the color table
		int nConv = GetDIBits(hDC, hBM, 0, static_cast<UINT>(bi.biHeight),
			Hdr.pByte + sizeof(BITMAPINFOHEADER) + dwColTable,
			Hdr.pInfo, DIB_RGB_COLORS);
		GlobalUnlock(hDIB);
		if (!nConv)
		{
			GlobalFree(hDIB);
			hDIB = NULL;
		}
	}
	if (hDIB)
		SetClipboardData(CF_DIB, hDIB);
	CloseClipboard();
	SelectPalette(hDC, hOldPal, FALSE);
	ReleaseDC(NULL, hDC);
	return NULL != hDIB;
}



HBITMAP CopyScreenToBitmap(HWND hwnd,int x1, int y1, int nWidth, int nHeight)
{

	HBITMAP hxBitmap, hOldBitmap; // handles to deice-dependent bitmaps
	HDC hScrDC,hMemDC; 




	// create a DC for the screen and create
	hScrDC = GetDC(hwnd);
	// a memory DC compatible to screen DC
	hMemDC = CreateCompatibleDC(hScrDC);

	// create a bitmap compatible with the screen DC
	if((hxBitmap = CreateCompatibleBitmap(hScrDC, nWidth-1, nHeight-1))==NULL)
	{
		MessageBox(NULL,"Can not create compatible Bitmap","Error",MB_OK);

		return NULL;
	}

	// select new bitmap into memory DC
	hOldBitmap = (HBITMAP)SelectObject(hMemDC, hxBitmap);

	if(hOldBitmap == NULL)
	{
		MessageBox(NULL,"Can not select Bitmap","Error",MB_OK);
		return NULL;
	}

	// bitblt screen DC to memory DC
	if(!BitBlt(hMemDC, 0, 0, nWidth-2, nHeight-2, hScrDC, x1+1, y1+1, SRCCOPY))
	{
		MessageBox(NULL,"Can not read screen memory","Error",MB_OK);
		return NULL;
	}

	// select old bitmap back into memory DC and get handle to bitmap of the screen

	//hxBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
	if(hxBitmap == NULL)
	{
		MessageBox(NULL,"Can not select object","Error",MB_OK);
		return NULL;
	}

	// return handle to the bitmap

	return hxBitmap;
}


void PaintLoadBitmap(HWND hwnd,SCROLLINFO *si, BITMAP bitmap, int pcxsize, int pcysize, int xMaxScroll,int xCurrentScroll, int xMinScroll,int yMaxScroll, int yCurrentScroll ,int yMinScroll)
{


	// The horizontal scrolling range is defined by
	// (bitmap_width) - (client_width). The current horizontal
	// scroll value remains within the horizontal scrolling range.
	int t1 = bitmap.bmWidth;
	xMaxScroll = max(t1,0);
	xCurrentScroll = 0;
	si->cbSize = sizeof(si);
	si->fMask  = SIF_ALL;
	si->nMax   = t1;
	si->nPage  = t1/pcxsize;
	si->nPos   = xCurrentScroll;
	SetScrollInfo(hwnd, SB_HORZ, si, TRUE);

	// The vertical scrolling range is defined by
	// (bitmap_height) - (client_height). The current vertical
	// scroll value remains within the vertical scrolling range.
	int t2 = bitmap.bmHeight;
	yMaxScroll = max(t2, 0);
	yCurrentScroll = 0;
	si->cbSize = sizeof(si);
	si->fMask  = SIF_ALL;
	si->nMin   = 0;
	si->nMax   = t2;
	si->nPage  = t2/pcysize;
	si->nPos   = yCurrentScroll;
	SetScrollInfo(hwnd, SB_VERT, si, TRUE);
}

void DrawBoundingBox(HDC hdc, int StartxPos, int EndxPos, int StartyPos, int EndyPos)
{
	HPEN greenPen=CreatePen(PS_SOLID, 1, RGB(0,255,0));
	SelectObject(hdc, greenPen);

	SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));


	MoveToEx(hdc, StartxPos, StartyPos, NULL);
	Rectangle(hdc, StartxPos, StartyPos , EndxPos, EndyPos);

	DeleteObject(greenPen);


}

void Cut(HDC hdc, HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double oWidth, double oHeight, double StartxPos, double EndxPos, double StartyPos, double EndyPos, int xCurrentScroll, int yCurrentScroll)
{
	RECT crect;
	StartxPos = ((StartxPos)*(oWidth/Width));
	StartyPos = ((StartyPos)*(oHeight/Height));
	EndxPos = ((EndxPos)*(oWidth/Width));
	EndyPos = ((EndyPos)*(oHeight/Height));

	crect.left = (long)StartxPos+xCurrentScroll;
	crect.top =  (long)StartyPos+yCurrentScroll;
	crect.right = (long)EndxPos+xCurrentScroll;
	crect.bottom = (long)EndyPos+yCurrentScroll;

	SelectObject(hdcMem, hBitmap);

	FillRect(hdcMem, &crect, GetStockBrush(LTGRAY_BRUSH));
	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc, 0, 0, (int)Width,(int)Height, hdcMem,xCurrentScroll,yCurrentScroll,(int)oWidth,(int)oHeight, SRCCOPY);

}

void Paste(HWND hwnd, HBITMAP hBitmap,double Width,double Height ,double oWidth, double oHeight ,HDC hdc, HDC hdcMem, double StartxPos, double EndxPos, int xCurrentScroll, double StartyPos, double EndyPos, int yCurrentScroll, double zoom, double cZoom)
{
	HBITMAP clip;
	BITMAP clipmap;
	HDC MemoryDC2;
	HDC MemoryDC;
	
	StartxPos = ((StartxPos)*(oWidth/Width));
	StartyPos = ((StartyPos)*(oHeight/Height));
	EndxPos = ((EndxPos)*(oWidth/Width));
	EndyPos = ((EndyPos)*(oHeight/Height));

	ZeroMemory(&clip, sizeof(HBITMAP));




	OpenClipboard(hwnd);
	MemoryDC = CreateCompatibleDC(hdcMem);
	MemoryDC2 = CreateCompatibleDC(hdcMem);
	clip = (HBITMAP)GetClipboardData(CF_BITMAP);

	GetObject(clip, sizeof(BITMAP), &clipmap);
	SelectObject(MemoryDC, clip);
	SelectObject(hdcMem,hBitmap);






	BitBlt(hdcMem, (int)StartxPos+xCurrentScroll, (int)StartyPos+yCurrentScroll ,(int)oWidth,
		(int)oHeight, MemoryDC ,0,0,SRCCOPY);
	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc, 0, 0, (int)Width,(int)Height, hdcMem,xCurrentScroll,yCurrentScroll, (int)oWidth, (int)oHeight, SRCCOPY);


	CloseClipboard();
	DeleteBitmap(clip);
	DeleteDC(MemoryDC);
	DeleteDC(MemoryDC2);
}

void ZeroScrollbars(HWND hwnd, SCROLLINFO si, BITMAP bitmap, int cxsize, int cysize,int xCurrentScroll, int yCurrentScroll, int xMaxScroll, int yMaxScroll, int xMinScroll, int yMinScroll)
{
	int t1 =(bitmap.bmWidth-cxsize);
	xMaxScroll = max(t1,0);
	xCurrentScroll = min(xCurrentScroll, xMaxScroll);
	si.cbSize = sizeof(si);
	si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
	si.nMin   = xMinScroll;
	si.nMax   = bitmap.bmWidth;
	si.nPage  = cxsize;
	si.nPos   = 0;
	SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

	// The scrolling range is defined by
	// (bitmap_height) - (client_height). The current
	// scroll value remains within the scrolling range.
	int t2 = bitmap.bmHeight - cysize;
	yMaxScroll = max(t2, 0);
	yCurrentScroll = min(yCurrentScroll, yMaxScroll);
	si.cbSize = sizeof(si);
	si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
	si.nMin   = yMinScroll;
	si.nMax   = bitmap.bmHeight;
	si.nPage  = cysize;
	si.nPos   = 0;
	SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
	xCurrentScroll = 0;
	yCurrentScroll =0;
}



HBITMAP fadetogrey(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll) 
{
	HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

	SelectObject(hdcMem,hBitmap);

	COLORREF color;
	BYTE Red, Green, Blue, Luminance;
	for (int x = 0; x < Width; x++)
	{
		for (int y = 0; y < Height; y++)
		{
			color = GetPixel(hdcMem, x, y);
			Red = GetRValue(color);
			Green = GetGValue(color);
			Blue = GetBValue(color);

			Luminance = ((30*Red)+(59*Green)+(11*Blue))/100;

			Red = Luminance;
			Green = Red;
			Blue = Green;

			SetPixel(hdcMem, x, y, RGB(Red, Green, Blue));
		}


	}

	SetCursor(hOldCursor);
	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc,0,0,(int)Width2,(int)Height2,hdcMem,xCurrentScroll,yCurrentScroll,(int)Width,(int)Height,SRCCOPY);

	return hBitmap;

}

HBITMAP fadetoyellow(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll) 
{
	HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
	SelectObject(hdcMem,hBitmap);
	COLORREF color;
	BYTE Red, Green, Blue, Average;
	for (int x = 0; x < Width; x++)
	{
		for (int y = 0; y < Height; y++)
		{
			color = GetPixel(hdcMem, x, y);
			Red = GetRValue(color);
			Green = GetGValue(color);
			Blue = GetBValue(color);

			Average = ((Red)+(Green)+(Blue))/3;

			Red = (BYTE)Average;
			Green = (BYTE)Average;
			Blue = (BYTE)(Average*0.5);

			SetPixel(hdcMem, x, y, RGB(Red, Green, Blue));
		}


	}

	SetCursor(hOldCursor);
	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc,0,0,(int)Width2,(int)Height2,hdcMem,0,0,(int)Width,(int)Height,SRCCOPY);


	return hBitmap;
}

HBITMAP flipvertical(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll)
{
	HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
	int BytesPerLine, BytesPerRow, LimitRow, LimitLine;
	SelectObject(hdcMem,hBitmap);

	BytesPerLine = (int)Width;
	BytesPerRow = (int)Height;
	LimitRow = BytesPerRow/2;
	LimitLine = BytesPerLine;

	//Allocate 3 COLORREF buffers for the bitmap
	COLORREF **hBufferdata;
	COLORREF **lpTopRow;
	COLORREF **lpBottomRow;

	hBufferdata = AllocateArray<COLORREF>(LimitLine,LimitRow);
	lpTopRow = AllocateArray<COLORREF>(LimitLine,LimitRow);
	lpBottomRow = AllocateArray<COLORREF>(LimitLine,LimitRow);



	for(int row = 0; row < LimitRow; row++)
	{
		for(int line=0; line < LimitLine; line++)
		{
			lpTopRow[line][row] = GetPixel(hdcMem,line,row);
			lpBottomRow[line][row] = GetPixel(hdcMem,line,BytesPerRow-row-1);


		}
	}



	for(int row =0; row < LimitRow; row++)
	{
		for(int line=0; line < LimitLine; line++)
		{
			hBufferdata[line][row] = lpTopRow[line][row];
			lpTopRow[line][row] = lpBottomRow[line][row];
			lpBottomRow [line][row] = hBufferdata[line][row];

			SetPixel(hdcMem,line,row,lpTopRow[line][row]);
			SetPixel(hdcMem,line,BytesPerRow-row-1,lpBottomRow[line][row]);

		}
	}



	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc,0,0,(int)Width2,(int)Height2,hdcMem,xCurrentScroll,yCurrentScroll,(int)Width,(int)Height,SRCCOPY);

	SetCursor(hOldCursor);





	FreeArray<COLORREF>(hBufferdata);
	FreeArray<COLORREF>(lpTopRow);
	FreeArray<COLORREF>(lpBottomRow);

	return hBitmap;
}

HBITMAP fliphorizontal(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll)
{
	HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
	int BytesPerLine, BytesPerRow, LimitRow, LimitLine;
	SelectObject(hdcMem,hBitmap);
	BytesPerLine = (int)Width;
	BytesPerRow = (int)Height;
	LimitRow = BytesPerRow;
	LimitLine = BytesPerLine/2;

	//Allocate 3 COLORREF buffers for the bitmap
	COLORREF **hBufferdata;
	COLORREF **lpLeftline;
	COLORREF **lpRightline;

	hBufferdata = AllocateArray<COLORREF>(LimitLine,LimitRow);
	lpLeftline = AllocateArray<COLORREF>(LimitLine,LimitRow);
	lpRightline = AllocateArray<COLORREF>(LimitLine,LimitRow);



	for(int row = 0; row < LimitRow; row++)
	{
		for(int line=0; line < LimitLine; line++)
		{
			lpLeftline[line][row] = GetPixel(hdcMem,line,row);
			lpRightline[line][row] = GetPixel(hdcMem,BytesPerLine-1-line,row);


		}
	}



	for(int row =0; row < LimitRow; row++)
	{
		for(int line=0; line < LimitLine; line++)
		{
			hBufferdata[line][row] = lpLeftline[line][row];
			lpLeftline[line][row] = lpRightline[line][row];
			lpRightline [line][row] = hBufferdata[line][row];

			SetPixel(hdcMem,line,row,lpLeftline[line][row]);
			SetPixel(hdcMem,BytesPerLine-1-line,row,lpRightline[line][row]);

		}
	}



	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc,0,0,(int)Width2,(int)Height2,hdcMem,xCurrentScroll,yCurrentScroll,(int)Width,(int)Height,SRCCOPY);

	SetCursor(hOldCursor);





	FreeArray<COLORREF>(hBufferdata);
	FreeArray<COLORREF>(lpLeftline);
	FreeArray<COLORREF>(lpRightline);

	return hBitmap;
}

HBITMAP RedeyeReduction(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll,double StartxPos, double EndxPos, double StartyPos, double EndyPos) 
{
	int oldxpos = (int)StartxPos;
	int oldendpos = (int)EndxPos;
	int oldypos = (int)StartyPos;
	int oldendypos = (int)EndyPos;

	if (StartxPos > EndxPos)
	{
		StartxPos = oldendpos;
		EndxPos = oldxpos;
		StartyPos = oldendypos;
		EndyPos = oldypos;
	}

	StartxPos = ((StartxPos+xCurrentScroll)*(Width/Width2));
	StartyPos = ((StartyPos+yCurrentScroll)*(Height/Height2));
	EndxPos = ((EndxPos+xCurrentScroll)*(Width/Width2));
	EndyPos = ((EndyPos+yCurrentScroll)*(Height/Height2));


	SelectObject(hdcMem,hBitmap);

	COLORREF color;
	BYTE Red, Green, Blue;
	float Intensity;
	for (int x = (int)StartxPos; x < (EndxPos); x++)
	{
		for (int y = (int)StartyPos; y < (EndyPos); y++)
		{ 
			color = GetPixel(hdcMem, x, y);
			Red = GetRValue(color);
			Green = GetGValue(color);
			Blue = GetBValue(color); 
			Intensity = ((float)Red / ((Green + Blue) / 2));
			if (Intensity > 1.5f)  // 1.5 because it gives the best results
			{
				// reduce red to the average of blue and green
				SetPixel(hdcMem, x, y, RGB((Green + Blue) / 2, Green, Blue));
			}
		}
	}

	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc,0,0,(int)Width2,(int)Height2,hdcMem,xCurrentScroll,yCurrentScroll,(int)Width,(int)Height,SRCCOPY);
	return hBitmap;
}

HBITMAP RotateRight(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll)
{
	HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
	HBITMAP Temp;
	HPALETTE hpal = static_cast<HPALETTE>(GetStockObject(DEFAULT_PALETTE));
	BITMAP temp;
	HDC hdcTemp;
	hdcTemp = CreateCompatibleDC(hdcMem);
	Temp = CreateCompatibleBitmap(hdcMem,(int)Height,(int)Width);
	GetObject(Temp,sizeof(BITMAP),&temp);

	SelectPalette (hdcTemp, hpal, TRUE);
	RealizePalette (hdcTemp);
	UpdateColors(hdcTemp);
	SelectObject(hdcTemp, Temp);


	int BytesPerLine, BytesPerRow, LimitRow, LimitLine;
	SelectObject(hdcMem,hBitmap);
	BytesPerLine = (int)Width;
	BytesPerRow = (int)Height;
	LimitRow = BytesPerRow;
	LimitLine = BytesPerLine;

	//Allocate 2 COLORREF buffers for the bitmap

	COLORREF **lpLeftline;
	COLORREF **lpRightline;


	lpLeftline = AllocateArray<COLORREF>(LimitLine,LimitRow);
	lpRightline = AllocateArray<COLORREF>(LimitRow,LimitLine);




	for(int line=0; line < LimitLine; line++)
	{
		for(int row = 0; row < LimitRow; row++)
		{
			lpLeftline[line][row] = GetPixel(hdcMem,line,row);
			lpRightline[BytesPerRow-1-row][line] = lpLeftline[line][row];


		}
	}




	for(int line=0; line < LimitLine; line++)
	{
		for(int row =0; row < LimitRow; row++)
		{

			SetPixel(hdcTemp,row,line,lpRightline[row][line]);

		}
	}





	hBitmap = CreateCompatibleBitmap(hdcTemp,(int)Height,(int)Width);
	SelectObject(hdcMem,hBitmap);
	SetStretchBltMode(hdcMem,HALFTONE);
	StretchBlt(hdcMem,0,0,(int)Height,(int)Width,hdcTemp,0,0,temp.bmWidth,temp.bmHeight,SRCCOPY);

	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc,0,0,(int)Height2,(int)Width2,hdcMem,xCurrentScroll,yCurrentScroll,(int)Height,(int)Width,SRCCOPY);

	SetCursor(hOldCursor);




	DeleteBitmap(Temp);
	DeleteDC(hdcTemp);



	FreeArray<COLORREF>(lpLeftline);
	FreeArray<COLORREF>(lpRightline);

	return hBitmap;
}

HBITMAP RotateLeft(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll)
{
	HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
	HBITMAP Temp;
	HPALETTE hpal = static_cast<HPALETTE>(GetStockObject(DEFAULT_PALETTE));
	BITMAP temp;
	HDC hdcTemp;
	hdcTemp = CreateCompatibleDC(hdcMem);
	Temp = CreateCompatibleBitmap(hdcMem,(int)Height,(int)Width);
	GetObject(Temp,sizeof(BITMAP),&temp);


	SelectPalette (hdcTemp, hpal, TRUE);
	RealizePalette (hdcTemp);
	UpdateColors(hdcTemp);
	SelectObject(hdcTemp, Temp);


	int BytesPerLine, BytesPerRow, LimitRow, LimitLine;
	SelectObject(hdcMem,hBitmap);
	BytesPerLine = (int)Width;
	BytesPerRow = (int)Height;
	LimitRow = BytesPerRow;
	LimitLine = BytesPerLine;

	//Allocate 2 COLORREF buffers for the bitmap

	COLORREF **lpLeftline;
	COLORREF **lpRightline;


	lpLeftline = AllocateArray<COLORREF>(LimitLine,LimitRow);
	lpRightline = AllocateArray<COLORREF>(LimitRow,LimitLine);




	for(int line=0; line < LimitLine; line++)
	{
		for(int row = 0; row < LimitRow; row++)
		{
			lpLeftline[line][row] = GetPixel(hdcMem,line,row);

		}
	}

	for(int line=0; line < LimitLine; line++)
	{
		for(int row = 0; row < LimitRow; row++)
		{
			lpRightline[row][line] = lpLeftline[BytesPerLine-1-line][row];

		}
	}



	for(int line=0; line < LimitLine; line++)
	{
		for(int row =0; row < LimitRow; row++)
		{

			SetPixel(hdcTemp,row,line,lpRightline[row][line]);

		}
	}




	hBitmap = CreateCompatibleBitmap(hdcTemp,(int)Height,(int)Width);
	SelectObject(hdcMem,hBitmap);
	SetStretchBltMode(hdcMem,HALFTONE);
	StretchBlt(hdcMem,0,0,(int)Height,(int)Width,hdcTemp,0,0,temp.bmWidth,temp.bmHeight,SRCCOPY);

	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc,0,0,(int)Height2,(int)Width2,hdcMem,xCurrentScroll,yCurrentScroll,(int)Height,(int)Width,SRCCOPY);

	SetCursor(hOldCursor);




	DeleteBitmap(Temp);
	DeleteDC(hdcTemp);

	FreeArray<COLORREF>(lpLeftline);
	FreeArray<COLORREF>(lpRightline);

	return hBitmap;
}

HBITMAP DuoTone(HDC hdc,HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double Width2, double Height2,int xCurrentScroll, int yCurrentScroll)

{
	HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
	HBITMAP Temp= NULL;
	SelectObject(hdcMem, hBitmap);

	HDC hdcTemp;
	hdcTemp = CreateCompatibleDC(hdcMem);
	Temp = CreateCompatibleBitmap(hdcMem,(int)Width,(int)Height);
	int BytesPerLine, BytesPerRow;

	BytesPerLine = (int)Width;
	BytesPerRow = (int)Height;
	SelectObject(hdcTemp, Temp);

	//Allocate a COLORREF buffer for the bitmap

	COLORREF **Buffer;
	float Luminance;
	BYTE Red, Green, Blue;
	Buffer = AllocateArray<COLORREF>(BytesPerLine,BytesPerRow);




	for(int row = 0; row < BytesPerRow; row++)
	{
		for(int line=0; line < BytesPerLine; line++)
		{

			Buffer[line][row] = GetPixel(hdcMem,line,row);
			Red = GetRValue(GetPixel(hdcMem,line,row));
			Green = GetGValue(GetPixel(hdcMem,line,row));
			Blue = GetBValue(GetPixel(hdcMem,line,row));
			Luminance = (float)((30*Red)+(59*Green)+(11*Blue))/100;
			if(Luminance >114.0f)
			{

				SetPixel(hdcTemp,line,row,RGB(255,255,255));
			}
			else
			{
				SetPixel(hdcTemp,line,row,RGB(0,0,0));
			}
		}
	}



	hBitmap = CreateCompatibleBitmap(hdcTemp,(int)Width,(int)Height);
	SelectObject(hdcMem,hBitmap);

	BitBlt(hdcMem,0,0,(int)Width,(int)Height,hdcTemp,0,0,SRCCOPY);
	SetStretchBltMode(hdc,HALFTONE);
	StretchBlt(hdc,0,0,(int)Width2,(int)Height2,hdcMem,xCurrentScroll,yCurrentScroll,(int)Width,(int)Height,SRCCOPY);

	SetCursor(hOldCursor);
	DeleteBitmap(Temp);
	DeleteDC(hdcTemp);

	FreeArray<COLORREF>(Buffer);

	return hBitmap;
}


void SetScrollBars(HWND hwnd, RECT WinRect, SCROLLINFO *si,double bxWidth2, double bxHeight2, int cxsize, int cysize, int xMaxScroll, int xMinScroll, int* xCurrentScroll, int yMaxScroll, int yMinScroll, int* yCurrentScroll, int xDelta, int yDelta)
{



	int t1 = (int)bxWidth2-cxsize-*xCurrentScroll;


	xMaxScroll = max(t1,0);
	*xCurrentScroll = min(*xCurrentScroll, xMaxScroll);
	si->cbSize = sizeof(si);
	si->fMask  = SIF_ALL; 
	si->nMin   = xMinScroll;
	si->nMax   = xMaxScroll;
	si->nPage  = (cxsize*xMaxScroll)/ (int)bxWidth2;
	si->nPos   = *xCurrentScroll;
	SetScrollInfo(hwnd, SB_HORZ, si, TRUE);

	// The vertical scrolling range is defined by
	// (bitmap_height) - (client_height). The current vertical
	// scroll value remains within the vertical scrolling range.
	int t2 = (int)bxHeight2-cysize-*yCurrentScroll;


	yMaxScroll = max(t2, 0);
	*yCurrentScroll = min(*yCurrentScroll, yMaxScroll);
	si->cbSize = sizeof(si);
	si->fMask  = SIF_ALL; 
	si->nMin   = yMinScroll;
	si->nMax   = yMaxScroll;
	si->nPage  = (cysize*yMaxScroll)/(int)bxHeight2;
	si->nPos   = *yCurrentScroll;
	SetScrollInfo(hwnd, SB_VERT, si, TRUE);



}
#endif // FUNCTIONS_H_INCLUDED





and finally a new file


Loader.h



#ifndef LOADER_H_INCLUDED
#define LOADER_H_INCLUDED
#include <windows.h>
#include <wingdi.h>


#define ALPHA_SHIFT 24
#define RED_SHIFT   16
#define GREEN_SHIFT 8
#define BLUE_SHIFT  0
#define ALPHA_MASK  ((ARGB) 0xff << ALPHA_SHIFT)
#define MAKEARGB(a, r, g, B)/> \
	(((ARGB) ((a) & 0xff) << ALPHA_SHIFT)| \
	((ARGB) ((r) & 0xff) << RED_SHIFT)  | \
	((ARGB) ((g) & 0xff) << GREEN_SHIFT)| \
	((ARGB) ((B)/> & 0xff) << BLUE_SHIFT))

typedef DWORD ARGB;
typedef struct{

	ULONG token;
}gdiplusToken;


typedef struct{
	HBITMAP picture;
}gdiToken;
typedef struct
{
	int value;
}IntPtr;

typedef enum  {
	Ok                          = 0,
	GenericError                = 1,
	InvalidParameter            = 2,
	OutOfMemory                 = 3,
	ObjectBusy                  = 4,
	InsufficientBuffer          = 5,
	NotImplemented              = 6,
	Win32Error                  = 7,
	WrongState                  = 8,
	Aborted                     = 9,
	FileNotFound                = 10,
	ValueOverflow               = 11,
	AccessDenied                = 12,
	UnknownImageFormat          = 13,
	FontFamilyNotFound          = 14,
	FontStyleNotFound           = 15,
	NotTrueTypeFont             = 16,
	UnsupportedGdiplusVersion   = 17,
	GdiplusNotInitialized       = 18,
	PropertyNotFound            = 19,
	PropertyNotSupported        = 20,
	ProfileNotFound             = 21
} Status;


enum DebugEventLevel
{
	DebugEventLevelFatal,
	DebugEventLevelWarning
};


typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);
typedef DWORD (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);




typedef struct {
	UINT32           GdiplusVersion;
	DebugEventProc DebugEventCallback;
	BOOL             SuppressBackgroundThread;
	BOOL             SuppressExternalCodecs;
} GdiplusStartupInput;

typedef struct {
	NotificationHookProc   NotificationHook;
	NotificationUnhookProc NotificationUnhook;
} GdiplusStartupOutput;

Status(WINAPI* GdiplusStartup)(gdiplusToken*, GdiplusStartupInput*, GdiplusStartupOutput*);
Status(WINAPI* GdipCreateBitmapFromFile)(WCHAR* filename,gdiplusToken* bitmap);
Status(WINAPI* GdipCreateHBITMAPFromBitmap)(ULONG bitmap, gdiToken* hbmReturn, ARGB background);
Status(WINAPI* GdipDisposeImage)(ULONG bitmap);
Status(WINAPI* GdiplusShutdown)(ULONG token);
HBITMAP hbmReturn;



HBITMAP MakeBitmapFromFile(HMODULE hWinLib, WCHAR* Name)
{

	 GdiplusStartup = (Status(WINAPI*)(gdiplusToken*, GdiplusStartupInput*, GdiplusStartupOutput*))GetProcAddress(hWinLib, "GdiplusStartup");
		GdiplusStartupInput gdiplusStartupInput;
		gdiplusStartupInput.GdiplusVersion = 1;
		gdiplusStartupInput.DebugEventCallback = NULL;
		gdiplusStartupInput.SuppressBackgroundThread = FALSE;
		gdiplusStartupInput.SuppressExternalCodecs= FALSE;


		GdiplusStartupOutput* gdiplusStartupOutput;
		gdiplusStartupOutput= (GdiplusStartupOutput*)malloc(1000);
		
		gdiplusToken token;

		Status st = GdiplusStartup(&token, &gdiplusStartupInput,gdiplusStartupOutput );
		ULONG Shutdown = token.token;
		if(st != Ok)
		{
			MessageBox(NULL,"GDI Plus Startup Error","ERROR",MB_OK);
		}



	//Status st;


	GdipCreateBitmapFromFile = (Status(WINAPI*)(WCHAR*,gdiplusToken*))GetProcAddress(hWinLib, "GdipCreateBitmapFromFile");

	gdiplusToken Bitmap;
	st=GdipCreateBitmapFromFile(Name,&Bitmap);

	if(st != Ok)
	{
		MessageBox(NULL,"GDI Plus Create Bitmap","ERROR",MB_OK);
	}

	ULONG Map = Bitmap.token;






	gdiToken Image;

	GdipCreateHBITMAPFromBitmap = (Status(WINAPI*)(ULONG ,gdiToken*,ARGB))GetProcAddress(hWinLib, "GdipCreateHBITMAPFromBitmap");
	ARGB rgb;
	rgb = MAKEARGB(0,200,200,200);// set background color for transparency ie light gray

	st = GdipCreateHBITMAPFromBitmap(Map,&Image,rgb);
	hbmReturn = Image.picture;
	if(st != Ok)
	{
		MessageBox(NULL,"GDI Plus Create HBITMAP","ERROR",MB_OK);
	}


	GdipDisposeImage = (Status(WINAPI*)(ULONG ))GetProcAddress(hWinLib, "GdipDisposeImage");
	st = GdipDisposeImage(Map);

	if(st != Ok)
	{
		MessageBox(NULL,"GDI Plus Delete Bitmap","ERROR",MB_OK);
	}

	free(gdiplusStartupOutput);
	
	GdiplusShutdown = (Status(WINAPI*)(ULONG))GetProcAddress(hWinLib, "GdiplusShutdown");
			st = GdiplusShutdown(Shutdown);

			if(st != Ok)
			{
				MessageBox(NULL,"GDI Plus Shutdown","ERROR",MB_OK);
			}
	return hbmReturn;

}





#endif // LOADER_H_INCLUDED






The Explanation Bit.

Let us first look at Loader.h and see what we are doing here.

I make some defines for use in the macro MAKEARGB.

This macro is used for the background transparency in PNG etc files.

Since our Window colour is gray we set this later on to gray.

I create two structs....

gdiPlusToken which deals with Startups, gdi-plus Bitmaps and Shutdowns etc

and

gdiToken which holds a ordinary gdi HBITMAP.

I then define the values of Status through an enum.

We only really need 'Ok' but the rest of the Status codes are put in for completeness.

I am going to basically access 5 functions which are in Gdiplus.dll

these are :-


GdiplusStartup
GdipCreateBitmapFromFile
GdipCreateHBITMAPFromBitmap
GdipDisposeImage
GdiplusShutdown


They are all used in the function :- MakeBitmapFromFile.

This function returns an ordinary gdi HBITMAP.

But in reality it uses a gdiplus Bitmap::Bitmap to load
the different graphic file formats.

How can we access this Bitmap::Bitmap object in a cross compiler way is the question ?

It would be easy if we could just include gdiplus.h and link to libgdiplus.a in MinGW

but alas there is no such header or Library in MinGW.

But there is another way, access the dll directly...

Now this can be quite dangerous as gdiplus memory leaks are quite common so

if you modify this code in anyway there is a good chance it will lead to a memory leak.

But if you go through it piece by piece there is no reason you cannot replicate .jpeg etc loading

in your own programs.

I start with GdiplusStartup of course and get the shutdown Token from this call.

I then use GdipCreateBitmapFromFile
this function takes a WCHAR* as the Unicode file string and returns a Bitmap::Bitmap object....

Now I am not going to replicate an entire gdiplus Bitmap::Bitmap object ...

I dont really need to, the first parameter of a Bitmap::Bitmap object is a pointer to a memory block
where the Image:: data resides.

Now a Bitmap::Bitmap object is not to be confused with a gdi BITMAP they are two very different beasts.

So anyway I only need to get the first parameter and I can safely ignore the rest.

I then can use a nice little function called

GdipCreateHBITMAPFromBitmap

This function takes the pointer to the memory block where the image data resides and returns an

ordinary gdi HBITMAP object which is a God send... as we can use this HBITMAP in our other routines

ie

Red Eye Reduction etc etc...

I know it seems to good to be true but there it is....

I then very importantly dispose of the Bitmap::Bitmap Object

Not doing this properly will cause a massive memory leak and reduce your program

and entire computer to a grinding halt.

I shutdown gdiplus and dispose of objects allocated earlier.


WinProc.h

I am not going to go over the entire WinProc.h file as I have already done that I am
just going to go over this code.


case IDM_OPEN_BM:
			{


				
				
				OpenFileDialog(hwnd, szFileName, (TCHAR*)"Open an Image File.");
				
				if(szFileName!= 0)
				{
					ZeroMemory(&hBitmap, sizeof(HBITMAP));


					HDC hdc = GetDC(hwnd);
					WCHAR* outFileName;
					outFileName= (WCHAR*)malloc(500);
					ZeroMemory(outFileName,500);
					MultiByteToWideChar(CP_ACP, MB_COMPOSITE,szFileName,-1,outFileName,500);
					
					hBitmap = MakeBitmapFromFile(hWinLib,outFileName);
					
					free(outFileName);
					


					if(hBitmap != NULL)
					{

						EnableMenuItem(menu, IDM_SAVE_BM, MF_ENABLED);
						EnableMenuItem(menu, IDM_PRINT_BM, MF_ENABLED);
						EnableMenuItem(menu, IDM_ZOOMIN, MF_ENABLED);
						EnableMenuItem(menu, IDM_ZOOMOUT, MF_ENABLED);
						cxpage = GetDeviceCaps (hdc, HORZRES);
						cypage = GetDeviceCaps (hdc, VERTRES);
						GetObject(hBitmap,sizeof(BITMAP),&bitmap);
						bxWidth = bitmap.bmWidth;
						bxHeight = bitmap.bmHeight;
						OrigWidth = bxWidth;
						OrigHeight = bxHeight;
						bxWidth2 = bxWidth;
						bxHeight2 = bxHeight;
						rect.left = 0;
						rect.top =0;
						rect.right = (long)&cxpage;
						rect.bottom = (long)&cypage;
						GetWindowRect(hwnd, &WinRect);
						cxsize = WinRect.right;
						cysize = WinRect.bottom;
						xCurrentScroll = 0;
						yCurrentScroll = 0;
						zoom =0;
						fZoom =false;
						fBlt = TRUE;
						fLoad = TRUE;
						fSize = FALSE;
						
						if(IsClipboardFormatAvailable(CF_BITMAP))
						{
							EnableMenuItem(menu, IDM_PASTE, MF_ENABLED);
						}






						ReleaseDC(hwnd,hdc);

						InvalidateRect(hwnd,NULL,TRUE);
					}
				}
				return 0;





I use OpenFileDialog to get the FileName to be opened.

If szFileName is different to zero start loading the Image File.

Use MultiByteToWideChar to convert from Ansi to Unicode.

Use MakeBitmapFromFile and clean up allocated objects.

Usual settings follow for program initial load settings.

So there you go using Windows directly to achieve Image Loading.

That I think concludes this Tutorial series.

Thank you very much for those who took the time to
sit through all three parts.

Snoopy.

Is This A Good Question/Topic? 0
  • +

Page 1 of 1