Page 1 of 1

Win32 Image Editing Program Part2 Rate Topic: -----

#1 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 815
  • View blog
  • Posts: 2,411
  • Joined: 20-March 10

Posted 22 September 2012 - 08:52 AM

Win32 Image Editing Program Part 2.



In Part Two of this three part series I cover image effects
we will cover how to rotate an image and how to flip an image.

We will cover how to do red eye reduction, how to convert images to grayscale, sepia effects and DuoTone.

As with the previous Tutorial I will post all the code first and then explain it line by line.

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 Bitmap",  IDM_OPEN_BM
MENUITEM "Print Bitmap", 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





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);

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);
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, HDC MemoryDC, 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;
}










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, 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_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
	ofn.lpstrFilter = TEXT("Bitmap Files (*.bmp)\0*.bmp\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.nMaxFile = 500;
	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)
{
	BITMAP bmp;
	PBITMAPINFO pbmi;
	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);


}

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, HDC MemoryDC, double StartxPos, double EndxPos, int xCurrentScroll, double StartyPos, double EndyPos, int yCurrentScroll, double zoom, double cZoom)
{
	HBITMAP clip;
	BITMAP clipmap;
	HDC MemoryDC2;

	double Width2=0, Height2=0;
	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 >110.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






WinProc.h
#ifndef WINPROC_H_INCLUDED
#define WINPROC_H_INCLUDED

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

HPALETTE hpal;
HMENU menu;
HBITMAP hBitmap,hOrigBitmap;
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;
HDC hdc,hdcMem;
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;
	HDC hdcOrig;

	// 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 = GetDC(hwnd);
		SelectPalette (hdc, hpal, FALSE);
		RealizePalette (hdc);
		InvalidateRect(hwnd,NULL,TRUE);
		ReleaseDC(hwnd,hdc);
		return TRUE;

	case WM_PALETTECHANGED:
		if (!hpal || (HWND)wParam == hwnd)
			break;
		hdc = GetDC(hwnd);
		SelectPalette (hdc, hpal, FALSE);
		RealizePalette (hdc);
		UpdateColors(hdc);
		ReleaseDC(hwnd,hdc);
		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 a Bitmap File.");

				if(szFileName!= NULL)
				{
					ZeroMemory(&hBitmap, sizeof(HBITMAP));
					ZeroMemory(&hOrigBitmap, sizeof(HBITMAP));
					hBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
					hOrigBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
					if(hBitmap)
					{
						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);
						}

						UpdateWindow(hwnd);


					}

				}

				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);
				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:
			{
				BOOL result = SaveFileDialog(hwnd,szFileName,(TCHAR*)"Save an Image.");
				if(result != false)
				{
					PBITMAPINFO pbi = CreateBitmapInfoStruct(hwnd, hBitmap);
					hdc= GetDC(hwnd);


					SaveBMPFile(hwnd, szFileName, pbi, hBitmap, hdc);
					hOrigBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
				}
				return 0;
			}

		case IDM_EXIT:
			{
				PostQuitMessage(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 = BeginPaint(hwnd, &ps);


			HDC hdcMem = CreateCompatibleDC(hdc);
			HDC MemoryDC = 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);
				hdcOrig = CreateCompatibleDC(hdcMem);
				BitBlt(hdcOrig,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)
			{

				hdc = GetDC(hwnd);
				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, MemoryDC, 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);
				hBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
				
				bxWidth = bxWidth2 = OrigWidth;
				bxHeight = bxHeight2 = OrigHeight;
				SelectObject(hdcOrig, hOrigBitmap); 
				
				
				SelectObject(hdcMem, hBitmap);
				
				SetStretchBltMode(hdcMem,HALFTONE);
				StretchBlt(hdcMem,0,0,(int)bxWidth,(int)bxHeight,hdcOrig,0,0,(int)OrigWidth,(int)OrigHeight,SRCCOPY);

				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;
			}
			
			EndPaint(hwnd, &ps);
			DeleteDC(hdcMem);

			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;     // xDelta = new_pos - current_pos
			int xNewPos;    // 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_DESTROY:
		ChangeClipboardChain(hwnd, hwndViewer);
		DeleteBitmap(hBitmap);
		DeleteBitmap(hOrigBitmap);
		DeleteDC(hdc);
		PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
		break;
	default:                      /* for messages that we don't deal with */
		return DefWindowProc (hwnd, message, wParam, lParam);

	}
	return 0;

}


#endif // WINPROC_H_INCLUDED









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.

Its been tested under Code::Blocks and Visual Studio.
It compiles fine with no errors or warnings under both.

For those who are impatient you can now hit build & compile.

For the rest of you, it's the explanation part.

The Explanation Part.


Part 1.

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);

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);
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, HDC MemoryDC, 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;
}









Most of this will be familiar to you from Part 1 but there are a few
new additions.

HBITMAP fadetogrey converts an image to greyscale or grayscale depending which side of the Atlantic you are on.

HBITMAP fadetoyellow converts an image to sepia.

HBITMAP flipvertical flips an image in the vertical axis.

HBITMAP fliphorizontal flips an image in the horizontal axis.

HBITMAP RedeyeReduction removes red-eye from flash photography images.

HBITMAP RotateRight rotates an image 90 degree's to the right.

HBITMAP RotateLeft rotates an image 90 degree's to the left.

HBITMAP DuoTone converts an image to DuoTone ie black & white.

void SetScrollBars updates ScrollBar Positions.


Part 2.



WinMain
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;
}




This is the entry point of our program it registers a new class and sets up a new window hwnd.

It shows the window maximised as this makes more sense for loading picture files.

It sets up a message loop which it intercepts
dialog messages for our program the ones not
acted on are passed back to the OS.

It names WindowProcedure as the callback procedure where some of these messages will be acted on.

Part3 WinProc.h

WM_CREATE
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;




This has remained unchanged from Part 1.

Part3 WM_COMMAND:
case WM_COMMAND:
		switch LOWORD(wParam)
		{

		case IDM_OPEN_BM:
			{



				OpenFileDialog(hwnd, szFileName, (TCHAR*)"Open a Bitmap File.");

				if(szFileName!= NULL)
				{
					ZeroMemory(&hBitmap, sizeof(HBITMAP));
					ZeroMemory(&hOrigBitmap, sizeof(HBITMAP));
					hBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
					hOrigBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
					if(hBitmap)
					{
						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);
						}

						UpdateWindow(hwnd);


					}

				}

				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);
				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:
			{
				BOOL result = SaveFileDialog(hwnd,szFileName,(TCHAR*)"Save an Image.");
				if(result != false)
				{
					PBITMAPINFO pbi = CreateBitmapInfoStruct(hwnd, hBitmap);
					hdc= GetDC(hwnd);


					SaveBMPFile(hwnd, szFileName, pbi, hBitmap, hdc);
					hOrigBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
				}
				return 0;
			}

		case IDM_EXIT:
			{
				PostQuitMessage(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;
		}




I wont cover what has already been covered in Part One, besides
there are pleny new additions to go over these are.

1.case IDM_GRAY: Convert To GrayScale. Sets greyscale flag to TRUE
updates window.

2.case IDM_REDEYE: If the selection tool (green bounding box) is active
do redeye reduction. redeye flag is set to TRUE and the window is updated.

3.case IDM_FLIPV: Flip the image in the vertical axis, sets flipv flag to true and updates the window.

4.case IDM_FLIPH: Flip the image in the horizontal axis, sets fliph flag to true and updates the window, again.

5.case IDM_SEPIA: Converts an image to sepia by balancing the r,g,b values we will go into more detail later in the Functions.h section, sets sepia flag to true and updates the window.

6.case IDM_ROTATERIGHT: rotates an image 90 degrees to the right, sets flag rRight to true we then take the window rectangle update the window, set the scrollbars and update the window again so we get a good scrollbar fit.

7.case IDM_ROTATELEFT: rotates an image 90 degrees to the left, sets flag rLeft to true we then take the window rectangle update the window, set the scrollbars and update the window again so we get a good scrollbar fit, again.

8.case IDM_DUOTONE: sets the fDuo flag to true and updates the window as with all flags in this section we deal with it in the WM_PAINT section.

As a special case I would like to cover IDM_ZOOMIN and IDM_ZOOMOUT again as they have changed (been improved).

case IDM_ZOOMOUT: takes 25 away from the variable zoom, if zoom is less than -75 then zoom is to remain at -75.

bxWidth2 and bxHeight2 are then adjusted for zooming factors according to the equation Original Height and Width Original Height and Width mulitiplied by variable zoom divided by 100.
The flag fZoom is set to TRUE and we get the current window rectangle.
we use a function that we will discuss later in Functions.h that sets the position of the scrollbars if required after zooming out.
We update and repaint the window.

case IDM_ZOOMIN: adds 25 to the variable zoom, if zoom is more than 75 then zoom is to remain at 75.

bxWidth2 and bxHeight2 are then adjusted for zooming factors according to the equation Original Height and Width plus Original Height and Width mulitiplied by variable zoom divided by 100.
The flag fZoom is set to TRUE and we get the current window rectangle.
we use a function that we will discuss later in Functions.h that sets the position of the scrollbars if required after zooming in.
We update and repaint the window.

Part 4. WM_PAINT
hdc = BeginPaint(hwnd, &ps);


			HDC hdcMem = CreateCompatibleDC(hdc);
			HDC MemoryDC = 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);
				hdcOrig = CreateCompatibleDC(hdcMem);
				BitBlt(hdcOrig,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)
			{

				hdc = GetDC(hwnd);
				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, MemoryDC, 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);
				hBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
				
				bxWidth = bxWidth2 = OrigWidth;
				bxHeight = bxHeight2 = OrigHeight;
				SelectObject(hdcOrig, hOrigBitmap); 
				
				
				SelectObject(hdcMem, hBitmap);
				
				SetStretchBltMode(hdcMem,HALFTONE);
				StretchBlt(hdcMem,0,0,(int)bxWidth,(int)bxHeight,hdcOrig,0,0,(int)OrigWidth,(int)OrigHeight,SRCCOPY);

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


				
				
				Undo = FALSE;
				
			}





First of all I use BeginPaint to prepare the window for painting.
I get a hdc of the window from this function as well,

I then create two Memory based hdc's hdcMem and MemoryDC from the original
window hdc.

If the fLoad flag is TRUE then I set bxWidth2 and bxHeight2, set the graphics mode, call PaintLoadBitmap and call ZeroScrollbars.

finally fLoad is set to FALSE.

fBlt , fSize , fScroll and fZoom have really remained unchanged so no further instruction is required there.
We call the function RedeyeReduction if bbox and redeye flags are set to TRUE.

It returns a HBITMAP of the processed image.
We then reset the redeye flag back to FALSE.

next up deals with drawing a bounding box on screen if conditions are met.
we also set the bbox flag to true here. We also enable cut, copy and paste facilities here.

After this we can call cut, copy or paste routines if conditions are met, we used these in Part 1 so again they have been reasonably well explained.

Next up is the new Undo facility this works by taking a copy of the original
image and just reverting back to this when Undo is selected from the menu
and reverting back to it's original dimensions this original is only updated
when it's saved.

Lets go into it in detail.
I get the Window Rectangle with GetWindowRect.
I fill the Window with the background color to wipe everything out.

I go on to set bxWidth(2) and bxHeight(2) to the Original Width and Height.
I create a local temporary hdc called hdcTemp.
I let our standard bitmap container hBitmap equal a new bitmap with the Original Height and Width, this is now an empty bitmap.
I select hBitmap into hdcMem and also select the original bitmap into hdcTemp.
I set the stretchmode to HALFTONE as this gives the best results.

I blit hdcTemp to hdcMem in doing so I change the contents of hBitmap which is
our standard container throughout the program.
I then blit hdcMem to the screen hdc making everything ok again.

I delete the local memory dc hdcTemp.

I set the undo flag to 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;
			}
			
			EndPaint(hwnd, &ps);
			DeleteDC(hdcMem);

			return 0;
		}




if flag greyscale evaluates to TRUE call the function fadetogrey this function returns a modified HBITMAP.

if flag sepia evaluates to TRUE call the function fadetoyellow this function returns a modified HBITMAP.

if flag flipv is set to TRUE call the function flipvertical this function returns a modified HBITMAP.

if flag fliph is set to TRUE call the function fliphorizontal this function returns a modified HBITMAP.

if flag rRight is TRUE clear the screen, set up new width and height variables in preparation for calling function RotateRight, call the function RotateRight this returns a modified bitmap, change all the width and height variables to the new
width and height finally set flag to false.

if flag rLeft is TRUE clear the screen, set up new width and height variables in preparation for calling function RotateLeft, call the function RotateLeft this returns a modified bitmap, change all the width and height variables to the new
width and height finally set flag to false.

if flag fDuo is TRUE call the function DuoTone this returns a modified bitmap, set the flag to false.
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;
		}




sets cxsize and cysize to new sizes calls the function SetScrollBars, set the flag to true redraw the screen.



Part 5 WM_HSCROLL.

case WM_HSCROLL:
		{
			int xDelta;     // xDelta = new_pos - current_pos
			int xNewPos;    // 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;
		}



xDelta is the difference between the the current position of the scroll bar and the new position of the scroll bar we use it later in ScrollWindowEx.

Depending on whether we clicked or dragged the scroll bar we do something
appropriate.

we set some defaults and do some testing to see if we need to scroll at all.

we then call ScrollWindowEx to scroll everything across.
we paint the window with InvalidateRect.


case WM_VSCROLL and case WM_DESTROY

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_DESTROY:
		ChangeClipboardChain(hwnd, hwndViewer);
		DeleteBitmap(hBitmap);
		DeleteBitmap(hOrigBitmap);
		DeleteDC(hdc);
		PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
		break;
	default:                      /* for messages that we don't deal with */
		return DefWindowProc (hwnd, message, wParam, lParam);

	}
	return 0;

}




yDelta is the difference between the the current position of the scroll bar and the new position of the scroll bar we use it later in ScrollWindowEx.

Depending on whether we clicked or dragged the scroll bar we do something
appropriate.

we set some defaults and do some testing to see if we need to scroll at all.

we then call ScrollWindowEx to scroll everything down.
we paint the window with InvalidateRect.

With case WM_DESTROY we disconnect ourselves from the chain of clipboard viewers and do a cleanup of objects not yet deleted like hBitmap etc, we make sure we have deleted everything so we are not leaking memory.

That ends our WinProc.h header and we can go on to our more interesting
Functions.h header where the really interesting stuff lives.


Part 6 Function.h

Now I am not going to go over old ground I am just going to cover the new stuff from Part 2, this includes the functions

fadetogrey
fadetoyellow
flipvertical
fliphorizontal
RedeyeReduction
RotateRight
RotateLeft
DuoTone
and
SetScrollBars

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 >110.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);



}





fadetogrey function

The first thing we do is set our cursor to a wait cursor setting via
SetCursor we select hBitmap into our memory dc hdcMem
, set up a COLORREF variable and some BYTE variables to hold the Red, Green , Blue and Luminance information of the pixels.

We set up some loops that are the width and height of the image.

We get the Red, Green and Blue information and calculate the Luminance as follows :- Equation for Luminance = ((30*Red)+(59*Green)+(11*Blue))/100.

for grayscale we then set the Red, Green and Blue information to Luminance,
this will then produce the desired effect we set the pixel with the new values.

After this operation is complete we reset the cursor to its old original configuration.

we then blit the whole thing to the screen and return the modified BITMAP.


fadetoyellow function

This function produces a sepia like effect.
I set the cursor to wait again.
Then I select our BITMAP hBitmap into our memory dc hdcMem once more.

I set up a COLORREF variable to hold the pixel data and 4 BYTE values Red, Green, Blue and Average.

I loop through width and height reading each pixel and modifying the RGB information through the Equation Average = (Red+Green+Blue)/3 this gets an average value of the pixel and produces that sepia like effect.

I set the pixel for each pixel in hBitmap.

I restore the cursor again to its former self,
blit the whole thing to the screen hdc and return the BITMAP.

function flipvertical

As you can imagine this function flips the image in the vertical axis.

We need to discuss how I go about doing that.
What I do is split the picture into lines and rows, each line going across the way each row going down the way.

like this :-

Posted Image


the line at the bottom is colored black on purpose, we are going to move this line to the top of our
picture like so..


Posted Image

this will end up in an image like this

Posted Image

we basically do this until the whole image is flipped upside down.

Well almost to speed things up I am going to split the image in half and flip each half in turn then join the whole thing together.

Back to the code.

I set the cursor to wait.
I set up some variables to flip the image.
I select the BITMAP hBitmap into our memory dc hdcMem once again.
I allocate three buffers for the bitmap data these are :-

hBufferdata
lpTopRow
lpBottomRow

we use the template AllocateArray to handle the memory allocation, I will go over this template later, all you need to know at this point is it handles
the memory allocation for the bitmap data.

I then set up a double loop
outer loop is half the image height,
inner loop is the full image width.

I copy image data into lpTopRow and lpBottomRow these are the two halves.

I then loop through again,
hBufferData is set to lpTopRow as a temporary storage buffer
lpTopRow is set to lpBottomRow
lpBottomRow is set to hBufferData to complete the cycle.

I then use setPixel to write the data to the BITMAP.

Finally I use StretchBlt to write the modified BITMAP to the screen,
I clean up using the template FreeArray to deallocate memory.

I return the BITMAP hBitmap as a modified flipped bitmap.


fliphorizontal function

This function flips the image in the horizontal axis.

We need to discuss how I go about doing that.
What I do is split the picture into lines and rows, each line going across the way each row going down the way.

like this :-

Posted Image

This time I split the lines into two halves instead of the rows...

Again I set up buffers for the bitmap data using AllocateArray.

This time though its lpLeftline and lpRightline our temporary storage buffer is still called hBufferData.

flipped image

Posted Image

first half of flipped image is like so this is lpLeftline

Posted Image

second half of flipped image is like this, we call this lpRightline.

Posted Image

we then join together in the middle of the image to get our resultant flipped image.

I set the cursor to wait.
I set up some variables to flip the image.
I select the BITMAP hBitmap into our memory dc hdcMem once again.
I allocate three buffers for the bitmap data these are :-

hBufferdata
lpLeftline
lpRightline

we use the template AllocateArray to handle the memory allocation, I will go over this template later, all you need to know at this point is it handles
the memory allocation for the bitmap data.

I then set up a double loop
outer loop is the full image height,
inner loop is half the image width.

I copy image data into lpLeftline and lpRightline these are the two halves.

I then loop through again,
hBufferData is set to lpLeftline as a temporary storage buffer
lpLeftline is set to lpRightline
lpRightline is set to hBufferData to complete the cycle.

I then use setPixel to write the data to the BITMAP.

Finally I use StretchBlt to write the modified BITMAP to the screen,
I clean up using the template FreeArray to deallocate memory.

I return the BITMAP hBitmap as a modified flipped bitmap.


function RedeyeReduction

First of all I get the bounding box co-ords
convert them if necessary in case of right to left drag instead of left to right drag.

I set up some variables, with facilities for splitting the pixel data into
its component RGB array.

I set up some loops to loop through the area of the bounding box.

I get the component RGB pixel data.

I get the intensity of the Red color channel via the expression

R/(( G + B )/2)

if the intensity of the red is over 1.5
I equalise the Red color channel by using the sum of both the Green and Blue channels

I use 1.5 as it seems to work best at eliminating red eye, this is largely trial and error and is subjective.

I blit the whole thing to screen and return the corrected bitmap.

I include a sample redeye picture for you to play about with at the end of this tutorial.

function RotateRight

I set the cursor to wait.

I set up a temporary HBITMAP, BITMAP and HDC.
I get the default palette.
I create a blank temporary monochrome bitmap.
I select the BITMAP into the HBTMAP.

I then select the default palette into the temporary hdc,
in turn select the HBITMAP into the temporary hdc.
Now when I draw on this temporary hdc the HBITMAP and BITMAP will
be drawn on to in the correct colors as well.

I set up some variables like I did with the flip functions and
set up some COLORREF arrays.

I allocate memory to these arrays.

I loop through the image and rotate everything 90 degrees to the right.

I then loop through the image again and set each pixel to the reformed image.

I make our standard HBITMAP variable hBitmap which is used a standard container
throughtout the program equal a blank bitmap which is compatible with the new temporary HDC.

I select hBitmap into hdcMem now when I draw on hdcMem everything will also be drawn on hBitmap.

I blit everything from hdcTemp which contains our rotated bitmap to hdcMem this updates our container HBITMAP for saving and other routines etc..

I am basically making sure of compatibility here.

I then blit everything across from hdcMem to the screen hdc.

I set the cursor back to its original state.

I delete the bitmaps and hdc that I set up as temporary, I no longer need them so I release resources.

I delete the Arrays that I set up to stop memory leaks.

Finally I return the modified, rotated bitmap.


function RotateLeft

Basically the same again except I am rotating 90 degrees to the left this time.


function DuoTone

I am going to loop through the image checking if luminosity is above a certain value and setting pixels to white and if below a certain value set that pixel to black.

The value I have chosen is 110.0f as this seems to work best but again its largely subjective.

I start off by setting the cursor to wait again. Then set up a temporary bitmap and select our image into a memory dc.
I then set up a temporary DC, create the temporary bitmap, set up some variables
and select the temporary blank bitmap into memory.

I allocate memory for a buffer, set up a float variable for 'Luminance' then set up BYTE variables Red, Green and Blue to hold the RGB information.

I loop through the image calculating the luminance value from the RGB information then if the luminace is over 110.0f set that pixel to white else set that pixel to black, you can get interesting effects by for instance not using white but Blue for instance to get a black and blue picture.
I set our bitmap container hBitmap to a blank bitmap. I then Select this bitmap into hdcMem which is our memory device context. I then blit hdcTemp into hdcMem which will write into hBitmap.
I set the StretchBlt Mode to HALFTONE and write hdcMem into our Screen device context hdc.

I reset the cursor back to its original state and delete our temporary bitmap and device context.

I free the memory allocated to Buffer and return the modified Bitmap.

Templates.

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;
}





In our Templates we have AllocateArray and FreeArray they pretty much do what it says
On the tin.

One Allocates memory the other free’s memory associated with a 2 dimensional array.

Since images are indeed 2 dimenisional array they are perfect for allocating memory
For image Buffers etc.


References.

MSDN.

Photographic Imaging Techniques in C++ for Windows
Craig. A. Lindley



Now our Image Editor is taking shape but to be useful it should load .jpg , .gif and .png files
In Part 3 we will go over how to do that without using the Microsoft Specific Headers and Libraries in GDI+… We will do this in a totally cross compiler way.

Part 3 will be covered soon again However I am very busy with work and family commitments but it will happen.

I have included a new snoopy.ico and also a redeye.bmp to try out the redeye reduction function of the program.

Attached File(s)



Is This A Good Question/Topic? 0
  • +

Page 1 of 1