/**************************************************************/
/*  Author: Alex Slusarek with help from Jake Mueller's code  */
/*          Dr.McVey's sample bitmap image program was used   */
/*          as a starting point / template                    */
/*                                                            */
/*  Function:  open, close and save 24-bit bitmap files as    */
/*             as well as scale them in different dimensions  */
/*             using a variety of image scaling algorithms    */
/*                                                            */
/*  Input:  any 24-bit bitmap file                            */
/*                                                            */
/*  Output:  screen: shows bitmap picture in program window   */
/*           file: save currently viewed picture to bmp file  */
/**************************************************************/

#include <afxwin.h>
#include <afxdlgs.h>         //For predefined dialog box code
#include "CImageWin.h"       //for functions used in program
#include "ImageConstants.h"  //for ID_ constants
#include "BMPEdit24.h"       //for functions used from Jake's code
#include "SmoothDialog.h"    //for smooth bresenham popup dialog window
#include "Windows.h"         //for "micro-time" timing functions

/*************************************************************/
/*  Author: Alex Slusarek                                    */
/*                                                           */
/*  Function:  sets up the window of the program as well as  */
/*             initializing variables used                   */
/*                                                           */
/*  Input:  nothing, constructor called to create window     */
/*                                                           */
/*  Output:  nothing specifically, program window is shown   */
/*************************************************************/
CImageWin::CImageWin()
{
  
	// call create function to create the window for the application
	Create( NULL, "Image Scaling", WS_OVERLAPPEDWINDOW| WS_VSCROLL | WS_HSCROLL,
	   CRect( 0, 0, 1000, 700 ), NULL, "MyMenu" );

	// get a pointer to application window
    CClientDC dc( this );

	// set up memory device contextes
    CrudeMemDC.CreateCompatibleDC( &dc );
    SmoothMemDC.CreateCompatibleDC( &dc );
    CurrentMemDC.CreateCompatibleDC( &dc );
    BresenhamMemDC.CreateCompatibleDC( &dc ); 

    // instantiate an image object
	image = new BMPImage; 
   
    // set default values for all pertinent variables
    FileOpen = false;
    FileChanged = false; 

    LastHeight = 0;
    LastWidth = 0;

    OriginalHeight = 0;
    OriginalWidth = 0;

    CurrentHeight = 0;
    CurrentWidth = 0;

    CrudeHeight = 0;
    CrudeWidth = 0;

    SmoothHeight = 0;
    SmoothWidth = 0;

}  //CImageWin



/*************************************************************/
/*  Author: Alex Slusarek                                    */
/*                                                           */
/*  Function:  deletes and unallocates all memory and        */
/*             variables used in program                     */
/*                                                           */
/*  Input:  nothing, deconstructor called to delete window   */
/*                                                           */
/*  Output:  nothing, program is closing now                 */
/*************************************************************/
CImageWin::~CImageWin(){

	// Garbage collection....

	// delete any dynamically allocated objects here
	
	// remove the old image data
	delete image;	   
		
	// delete all dynamic arrays created for program
	for (unsigned long g=0; g < LastHeight; g++)
	{
		delete []LastColors[g];
	}

	delete []LastColors;

	for (g=0; g < OriginalHeight; g++)
	{
		delete []OriginalColors[g];
	}

	delete []OriginalColors;

	for (g=0; g < CurrentHeight; g++)
	{
		delete []CurrentColors[g];
	}

	delete []CurrentColors;
	
}  //~CImageWin


/***************************************************************/
/*  Author: Alex Slusarek                                      */
/*                                                             */
/*  Function:  performs tasks that must complete upon          */
/*             creation of the main window - could initialize  */
/*             variables here                                  */
/*                                                             */
/*  Input:  nothing                                            */
/*                                                             */
/*  Output:  nothing                                           */
/***************************************************************/
int CImageWin::OnCreate(LPCREATESTRUCT lpcs) {

	if(CFrameWnd::OnCreate (lpcs) == -1)
		return -1;

	
	return 0; 

}  //OnCreate


/****************************************************************/
/*  Author: Alex Slusarek                                       */
/*                                                              */
/*  Function:  opens a bitmap file, checks to see if there is   */
/*             an unsaved picture present.  Will ask to save    */
/*             if necessary, then calls funtion in Jake's code  */
/*                                                              */
/*  Input:  nothing                                             */
/*                                                              */
/*  Output:  prompt to save file (if necessary)                 */
/*           prompt to open file                                */
/*           displays newly opened file on screen               */
/****************************************************************/
void CImageWin::OnFileOpen ()
{
	// check to see if file current bitmap has changed
	// and not been saved since changing
	if(FileChanged) 
	{
		// current bitmap is different and needs to be saved

		// ask user if they would like to save current picture
		int reply = AfxMessageBox( "Save Changes?", MB_YESNOCANCEL, 0);
		
		//user wants to save the file
		if (reply == IDYES)
		{ 
			// save file by calling SaveAs function
			OnFileSaveAs();
				
		}
		// user canceled out of FileOpen function
		else if(reply == IDCANCEL)
		{  
			return;  //nothing to do, return and wait for user
		}	
	}

	// create predefined file dialog box
	// to prompt user for file to open
	CFileDialog FDlgBox (TRUE, _T ("bmp"), _T("*.bmp"), 
	 OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, 
	 "BITMAP files|*.bmp|");

	// they chose a file, continue on
	if (FDlgBox.DoModal () == IDOK) 
	{	
		// get pathname of file from dialong box data
		strcpy(filename, FDlgBox.GetPathName () );

		// call Jake's function to open file, validate the 24-bit format
		// and read it bitmap file into BMPImage class
		int file_open_check = image->BMPRead(filename);

		// Jake's code didn't like the file, wonder why?
		if ( file_open_check < 0)
		{ 

			// run through possible errors
			switch (file_open_check)
			{
				// there was an error in opening the file
				case -1:		
					{
						// clear out old image data
						delete image;

						// create new image data
						image = new BMPImage;

						// inform the user of the error
						MessageBox("Cannot open file...", "File Error", MB_OK);
						break;

					}// case -1

				// the file was not a bitmap file
				case -2:		
					{
						// clear out old image data
						delete image;

						// create new image data
						image = new BMPImage;

						// inform the user of the error
						MessageBox("File is NOT a bitmap", "File Error", MB_OK);
						break;

					}// case -2

				// the file was not a 24-bit bmp file
				case -3:		
					{
						// clear out old image data
						delete image;

						// create new image data
						image = new BMPImage;	
						
						// inform the user of the error
						MessageBox("Bitmap is NOT 24-bit RGB. CANNOT process file...", "File Error", MB_OK);
						break;

					}// case -3

				// the file was a compressed bmp file
				case -4:	
					{
						// clear out old image data
						delete image;

						// create new image data
						image = new BMPImage;

						// inform the user of the error
						MessageBox("Cannot process compressed data...", "File Error", MB_OK);
						break;

					}// case -4

				// the file must have been a-OK
				default:
					{
						// file read is successful, continue
						break; 
						
					}  // default

			}  //switch(file_open_check)

			return;	

		}//if ( file_open_check < 0)

		// create a DC to work with
		CClientDC dc (this);		

		// get dimensions of bmp picture
		OriginalHeight = image->GetBMPHeight() - 1;
		OriginalWidth = image->GetBMPWidth();

		// for now current picture = original picture
		CurrentHeight = OriginalHeight;
		CurrentWidth = OriginalWidth;

		// and last picture = current picture
		LastHeight = CurrentHeight;
		LastWidth = CurrentWidth;

		// set up dynamic arrays for pictures
		OriginalColors = new COLORREF * [OriginalHeight];
		CurrentColors = new COLORREF * [CurrentHeight];
		LastColors = new COLORREF * [LastHeight];

		// making the 2D dynamic arrays to hold pixel color data
		for (unsigned long g=0; g < OriginalHeight; g++)
		{
			OriginalColors[g] = new COLORREF [OriginalWidth];
			CurrentColors[g] = new COLORREF [CurrentWidth];
			LastColors[g] = new COLORREF [LastWidth];
		}


		// make a bitmap of the specified size to work with...
	    CurrentBitmap.CreateCompatibleBitmap( &dc, CurrentWidth, CurrentHeight);
		
		// and select it...
	    CBitmap * oldCurrent = CurrentMemDC.SelectObject(&CurrentBitmap);

		// initialize variables before use
	    unsigned long x = 0;
	    unsigned long y = 0;
	    COLORREF TempColor;

		// nested for loops to put pixel color data into arrays
	    for (unsigned long i = OriginalHeight; i > 0; i--)
		{

			for(unsigned long j = 0; j<OriginalWidth; j++)
			{

				// get color data for picture from BMPImage class
				TempColor = image -> BMPGetColor(i,j);

				// save the color into the arrays
				OriginalColors[y][x] = TempColor;
				CurrentColors[y][x] = TempColor;
				LastColors[y][x] = TempColor;
				
				// move through the arrays
				x++;
							
			}  //for (OriginalWidth)
			
			// move through the arrays
			y++;
			x = 0;

		}  //for (OriginalHeight)

		// nested for loops to put pixel color data into MemDC
		for (x=0; x<OriginalWidth; x++)
		{
			
		    for (y=0; y<OriginalHeight; y++)
			{
				// set pixel in MemDC with color data from array
			    CurrentMemDC.SetPixel(x,y,CurrentColors[y][x]);

			}  //for (OriginalHeight)

		}  //for (OriginalWidth

        // force a call to OnPaint() to display picture
		Invalidate(); 

		// deselect and delete bitmap object
		CurrentMemDC.SelectObject(&oldCurrent);
		CurrentBitmap.DeleteObject();

		// change status of file to "Opened" and "Saved"
		FileOpen = true;
		FileChanged = false;

	}  //if (FDlgBox.DoModal () == IDOK) 
	
}  //OnFileOpen


/*****************************************************************/
/*  Author: Alex Slusarek                                        */
/*                                                               */
/*  Function:  scales the picture in both dimensions as defined  */
/*             by the user through a popup modal dialog window   */
/*             must scale in each dimension separately           */
/*             any pixel can be copied, duplicated or skipped    */
/*                                                               */
/*  Input:  uses newly acquired dimensions from dialong window   */
/*          and current picture and scales it to size            */
/*                                                               */
/*  Output:  prompt to define height and width                   */
/*           displays newly scaled picture on screen             */
/*****************************************************************/
afx_msg void CImageWin::ImageScaleBresenham()
{
	// variable used to count total number of new pixels placed
	unsigned long TotalPixels = 0;
	
	// check to make sure a file has actuall been opened
	// and a picture is available to scale
	if(FileOpen)
	{
		// yup, some file is open and something is on the screen,
		// scale it to size...

		// the modal dialog to define new width and height for picture
		SmoothDialog c("SmoothDialog", this, CurrentWidth, CurrentHeight, false);
		
		// everything is ok, continue on
		if ( c.DoModal() == IDOK)
		{
			// create a dc to work with
			CClientDC dc( this );
			
			//get the new dimensions from dialog data
			BresenhamWidth = c.GetWidth();
			BresenhamHeight = c.GetHeight();
			
			// create a temporary dynamic array to aid in scaling
			// used to scale in one direction first
			COLORREF ** TempColors;
			TempColors = new COLORREF * [CurrentHeight];

			for (unsigned long g=0; g < CurrentHeight; g++)
			{
				// make dynamic array into 2 dimensions
				TempColors[g] = new COLORREF [BresenhamWidth];

			}  //for (CurrentHeight)

			// set up the final dynamic array while we are at it
			COLORREF ** BresenhamColors;
			BresenhamColors = new COLORREF * [BresenhamHeight];

			for (g=0; g < BresenhamHeight; g++)
			{
				// make dynamic array into two dimensions
				BresenhamColors[g] = new COLORREF [BresenhamWidth];

			}  //for (BresenhamHeight)

			// all the variables necessary for bresenham algorithm
			unsigned long targetwidth, sourcewidth, numpixels;
			unsigned long e, x, IntPart, FractPart;
			COLORREF currentcolor;  // color of pixel

			// make a bitmap of the specified size to work with...
			BresenhamBitmap.CreateCompatibleBitmap( &dc, BresenhamWidth, BresenhamHeight);
			
			// and select it...
			CBitmap * oldBresenham = BresenhamMemDC.SelectObject(&BresenhamBitmap);

			
			// the horizontal stretch...
			

			// get the tick count to start the timer
			start = GetTickCount();

			// initialize the variables
			targetwidth = BresenhamWidth;  // new width
			sourcewidth = CurrentWidth;    // old width
			e = 0;                         // error overflow counter
			x = 0;                         // position counter
			numpixels = targetwidth;       // loop counter
			
			// variables used to manipulate through arrays
			IntPart = sourcewidth / targetwidth;
			FractPart = sourcewidth % targetwidth;

			// the nested for loops to fit the colors  
			// from the old array into the new array 
			for (unsigned long y=0; y<CurrentHeight; y++)
			{
				// reset variables for each run through
				e = 0;
				x = 0;

				// for loop to run through length of new array
				for (unsigned long p=0; p<numpixels; p++)
				{
					// get pixel color from old array
					currentcolor = CurrentColors[y][x];
					
					// set pixel color to new array
					TempColors[y][p] = currentcolor;
					
					// another pixel has been placed
					TotalPixels++;

					// move x down the road
					x = x + IntPart;

					// account for error of moving down the road
					e = e + FractPart;

					// if error is high enough, move again
					while ( e >= targetwidth )
					{
						// reset error overflow counter
						e = e - targetwidth;
						x++;
					}  //while

				}  //for (numpixels)

			}  //for (CurrentHeight)
			
			
			// the verticle stretch


			// initialize the variables
			targetwidth = BresenhamHeight;  // new height
			sourcewidth = CurrentHeight;    // old height
			e = 0;                          // error overflow counter
			x = 0;                          // position counter
			numpixels = targetwidth;        // loop counter

			// variables used to manipulate through arrays
			IntPart = sourcewidth / targetwidth;
			FractPart = sourcewidth % targetwidth;

			// the nested for loops to fit the colors  
			// from the old array into the new array 
			for (y=0; y<BresenhamWidth; y++)
			{
				// reset variables for each run through
				e = 0;
				x = 0;

				// for loop to run through length of new array
				for (unsigned long p=0; p<numpixels; p++)
				{
					// get pixel color from old array
					currentcolor = TempColors[x][y];
					
					// set pixel color to new array
					BresenhamColors[p][y] = currentcolor;
					
					// another pixel has been placed
					TotalPixels++;

					// move x down the road
					x = x + IntPart;

					// account for error of moving down the road
					e = e + FractPart;

					// if error is high enough, move again
					while ( e >= targetwidth )
					{
						// reset error overflow counter
						e = e - targetwidth;
						x++;
					
					}  //while

				}  //for (numpixels)

			}  //for (BresenhamWidth)

			// get the tick count to stop the timer
			finish = GetTickCount();

			// calculate time of algorithm
			duration = (double)(finish - start)/1000.0;
	
			// output the total number of pixels placed
			char t[10];
			itoa(TotalPixels,t,10);
			MessageBox(t,"Number of Total Pixels");


			// delete old color array
			for (g=0; g < LastHeight; g++)
			{
				delete []LastColors[g];
			}

			delete []LastColors;

			// delete temp color array
			for (g=0; g < CurrentHeight; g++)
			{
				delete []TempColors[g];
			}

			delete []TempColors;

			// set up new last dimensions and color array
			LastWidth = CurrentWidth;
			LastHeight = CurrentHeight;
			LastColors = CurrentColors;
			
			// set up new current dimensoins and color array
			CurrentWidth = BresenhamWidth;
			CurrentHeight = BresenhamHeight;
			CurrentColors = BresenhamColors;

			// nested for loops to set pixels on BresenhmMemDC
			for (x=0; x<BresenhamWidth; x++)
			{

			   for (y=0; y<BresenhamHeight; y++)
			   {
					// set pixel in MemDC with color data from array
				    BresenhamMemDC.SetPixel(x,y,BresenhamColors[y][x]);

			   }  //for (BresenhamHeight)

			}  //for (BresenhamWidth

			// deselect and delete bitmap object
			BresenhamMemDC.SelectObject(&oldBresenham);
			BresenhamBitmap.DeleteObject();

			// make a bitmap of the specified size and select it...
			CurrentBitmap.CreateCompatibleBitmap( &dc, CurrentWidth, CurrentHeight);
			CBitmap * oldCurrent = CurrentMemDC.SelectObject(&CurrentBitmap);

			// copy BresenhamMemDC to CurrentMemDC to be displayed
			CurrentMemDC.BitBlt( 0, 0, CurrentWidth, CurrentHeight, &BresenhamMemDC, 0, 0, SRCCOPY );

			// deselect and delete bitmap object
			CurrentMemDC.SelectObject(&oldCurrent);
			CurrentBitmap.DeleteObject();

			// the picture has been changed and not saved
			FileChanged = true;

			// force a call to OnPaint() to display picture
			Invalidate();

		}  //if (IDOK)

	}  //if (FileOpen)
	else
	{
		// a file hasn't been opened yet
		MessageBox("You must open a file first");

	}  //else FileOpen

}  //ImageScaleBresenham


/*****************************************************************/
/*  Author: Alex Slusarek                                        */
/*                                                               */
/*  Function:  scales the picture in both dimensions as defined  */
/*             by the user through a popup modal dialog window   */
/*             must scale in each dimension separately           */
/*             any pixel can be copied, duplicated or averaged   */
/*                                                               */
/*  Input:  uses newly acquired dimensions from dialong window   */
/*          and current picture and scales it to size            */
/*                                                               */
/*  Output:  prompt to define height and width                   */
/*           displays newly scaled picture on screen             */
/*****************************************************************/
afx_msg void CImageWin::ImageScaleSmoothBresenham()
{
	// variable to check status of checkbox on modal dialog window
	int Checked;

	// variables used to count total number of new pixels placed
	// and total number of pixels placed as an average of pixels
	unsigned long TotalPixels = 0;
	unsigned long AveragedPixels = 0;

	// initialize check stats to not checked
	Checked = 0;

	// check to make sure a file has actuall been opened
	// and a picture is available to scale
	if(FileOpen)
	{
		// yup, some file is open and something is on the screen,
		// scale it to size...

		// the modal dialog to define new width and height for picture
		SmoothDialog c("SmoothDialog", this, CurrentWidth, CurrentHeight, true);
		
		// everything is ok, continue on
		if ( c.DoModal() == IDOK)
		{
			// create a dc to work with
			CClientDC dc( this );
			
			//get the new dimensions and check status from dialog data
			SmoothWidth = c.GetWidth();
			SmoothHeight = c.GetHeight();
			Checked = c.GetButtonStatus();

			// create a temporary dynamic array to aid in scaling
			// used to scale in one direction first
			COLORREF ** TempColors;
			TempColors = new COLORREF * [CurrentHeight];

			for (unsigned long g=0; g < CurrentHeight; g++)
			{
				// make dynamic array into two dimensions
				TempColors[g] = new COLORREF [SmoothWidth];
			}

			// set up the final dynamic array while we are at it
			COLORREF ** SmoothColors;
			SmoothColors = new COLORREF * [SmoothHeight];

			for (g=0; g < SmoothHeight; g++)
			{
				// make dynamic array into two dimensions
				SmoothColors[g] = new COLORREF [SmoothWidth];
			}

			// all the variables necessary for smooth bresenham algorithm
			unsigned long midval, targetwidth, sourcewidth, numpixels, e, x;
			COLORREF currentcolor, nextcolor, avgcolor;
			int red, green, blue, red2, blue2, green2;

			// make a bitmap of the specified size and select it...
			SmoothBitmap.CreateCompatibleBitmap( &dc, SmoothWidth, SmoothHeight);
			CBitmap * oldSmooth = SmoothMemDC.SelectObject(&SmoothBitmap);

			// the horizontal stretch...

			// get the tick count to start the timer
			start = GetTickCount();

			// initialize the variables
			targetwidth = SmoothWidth;  // new width
			sourcewidth = CurrentWidth;  // old widty
			midval = targetwidth / 2;   // mid value - determines when to average
			e = 0;						// error overflow counter
			x = 0;						// position counter
			numpixels = targetwidth;	// loop counter

			// decrease by one to stop early to avoid averaging outside of array bounds
			if (targetwidth > sourcewidth)
				numpixels--;

			// the nested for loops to fit the colors  
			// from the old array into the new array 
			for (unsigned long y=0; y<CurrentHeight; y++)
			{
				// reset variables for each run through
				e = 0;
				x = 0;

				// for loop to run through length of new array
				for (unsigned long p=0; p<numpixels; p++)
				{
					// get pixel color from old array
					currentcolor = CurrentColors[y][x];

					// check error overflow variable for averaging values
					if ( e >= midval )
					{
						// get pixel color from neighbor pixel in old array
						nextcolor = CurrentColors[y][x+1];

						// parse out red, green and blue values separately
						red = GetRValue(currentcolor);
						green = GetGValue(currentcolor);
						blue = GetBValue(currentcolor);

						// for both pixels...
						red2 = GetRValue(nextcolor);
						green2 = GetGValue(nextcolor);
						blue2 = GetBValue(nextcolor);

						// average the colors of both pixels
						red = (red + red2) / 2;
						green = (green + green2) / 2;
						blue = (blue + blue2) / 2;

						// checkbox was checked, make it a green average
						if (Checked)
						{
							// make green by reducing red and blue values
							red = 10;
							blue = 10;
						}  //if (Checked)

						// recompile red, green and blue into colorref
						avgcolor = RGB(red, green, blue);

						// set averaged color back to currentcolor variable
						currentcolor = avgcolor;

						// another pixel has been averaged
						AveragedPixels++;

					}  //if ( e >= midval )

					// set pixel color to new array
					TempColors[y][p] = currentcolor;

					// another pixel has been placed
					TotalPixels++;

					// account for error overflow
					e = e + sourcewidth;

					// if error is high enough, move again
					while ( e >= targetwidth )
					{
						// reset error overflow counter
						e = e - targetwidth;
						x++;

					}  //while

				}  //for (numpixels)

				// copy last pixel from old array to new array
				if(targetwidth > sourcewidth)
				{
					// get and set pixel from old to new array
					TempColors[y][p] = CurrentColors[y][x];

					// another pixel has been placed
					TotalPixels++;

				}  //if (targetwidth > sourcewidth)

			}  //for (CurrentHeight)


			// the verticle stretch

			// initialize the variables
			targetwidth = SmoothHeight;		// new height
			sourcewidth = CurrentHeight;	// old height
			midval = targetwidth / 2;		// mid value - determines when to average
			e = 0;							// error overflow counter
			x = 0;							// position counter
			numpixels = targetwidth;		// loop counter

			// decrease by one to stop early to avoid averaging outside of array bounds
			if (targetwidth > sourcewidth)
				numpixels--;

			// the nested for loops to fit the colors  
			// from the old array into the new array 
			for (y=0; y<SmoothWidth; y++)
			{
				// reset variables for each run through
				e = 0;
				x = 0;

				// for loop to run through length of new array
				for (unsigned long p=0; p<numpixels; p++)
				{
					// get pixel color from old array
					currentcolor = TempColors[x][y];

					// check error overflow variable for averaging values
					if ( e >= midval )
					{
						// get pixel color from neighbor pixel in old array
						nextcolor = TempColors[x][y+1];

						// parse out red, green and blue values separately
						red = GetRValue(currentcolor);
						green = GetGValue(currentcolor);
						blue = GetBValue(currentcolor);

						// for both pixels...
						red2 = GetRValue(nextcolor);
						green2 = GetGValue(nextcolor);
						blue2 = GetBValue(nextcolor);

						// average the colors of both pixels
						red = (red + red2) / 2;
						green = (green + green2) / 2;
						blue = (blue + blue2) / 2;

						// checkbox was checked, make it a green average
						if (Checked)
						{
							// make green by reducing red and blue values
							red = 10;
							blue = 10;

						}  //if (Checked)

						// recompile red, green and blue into colorref
						avgcolor = RGB(red, green, blue);

						// set averaged color back to currentcolor variable
						currentcolor = avgcolor;

						// another pixel has been averaged
						AveragedPixels++;

					}  //if ( e >= midval )

					// set pixel color to new array
					SmoothColors[p][y] = currentcolor;
					
					// another pixel has been placed
					TotalPixels++;

					// account for error overflow
					e = e + sourcewidth;

					// if error is high enough, move again
					while ( e >= targetwidth )
					{
						// reset error overflow counter
						e = e - targetwidth;
						x++;

					}  //while

				}  //for (numpixels)

				// copy last pixel from old array to new array
				if(targetwidth > sourcewidth)
				{
					// get and set pixel from old to new array
					SmoothColors[p][y] = TempColors[x][y];
		
					// another pixel has been placed
					TotalPixels++;

				}  //if (targetwidty > sourcewidth)

			}  //for (SmoothWidth)

			// get the tick count to stop the timer
			finish = GetTickCount();

			// calculate time of algorithm
			duration = (double)(finish - start)/1000.0;
	
			// output the total number of pixels averaged
			char t[10];
			itoa(AveragedPixels,t,10);
			MessageBox(t,"Number of Averaged Pixels");

			// output the total number of pixels placed
			itoa(TotalPixels,t,10);
			MessageBox(t,"Number of Total Pixels");

			// delete old color array
			for (g=0; g < LastHeight; g++)
			{
				delete []LastColors[g];
			}

			delete []LastColors;

			// delete temp color array
			for (g=0; g < CurrentHeight; g++)
			{
				delete []TempColors[g];
			}

			delete []TempColors;

			// set up new last dimensions and color array
			LastWidth = CurrentWidth;
			LastHeight = CurrentHeight;
			LastColors = CurrentColors;
			
			// set up new current dimensions and color array
			CurrentWidth = SmoothWidth;
			CurrentHeight = SmoothHeight;
			CurrentColors = SmoothColors;

			// nested for loops to set pixels on SmoothMemDC
			for (x=0; x<SmoothWidth; x++)
			{

			   for (y=0; y<SmoothHeight; y++)
			   {
				   // set pixel in MemDC with color data from array
				   SmoothMemDC.SetPixel(x,y,SmoothColors[y][x]);

			   }  //for (SmoothHeight)

			}  //for (SmoothWidth)

			// deselect and delete bitmap object
			SmoothMemDC.SelectObject(&oldSmooth);
			SmoothBitmap.DeleteObject();

			// make bitmap of the specified size and select it...
			CurrentBitmap.CreateCompatibleBitmap( &dc, CurrentWidth, CurrentHeight);
			CBitmap * oldCurrent = CurrentMemDC.SelectObject(&CurrentBitmap);

			// copy BresenhamMemDC to CurrentMemDC to be displayed
			CurrentMemDC.BitBlt( 0, 0, CurrentWidth, CurrentHeight, &SmoothMemDC, 0, 0, SRCCOPY );

			// deselect and delete bitmap object
			CurrentMemDC.SelectObject(&oldCurrent);
			CurrentBitmap.DeleteObject();

			// the picture has been changed and not saved
			FileChanged = true;
			
			// force a call to OnPaint() to display picture
			Invalidate();

		}  //if (IDOK)

	}  //if (FileOpen)
	else
	{
		// a file hasn't been opened yet
		MessageBox("You must open a file first");

	}  //else (FileOpen)

}  //ImageScaleSmoothBresenham


/*****************************************************************/
/*  Author: Alex Slusarek                                        */
/*                                                               */
/*  Function:  scales the picture smaller by a facter of 1/2     */
/*             the algorithm takes 4 pixels and "converts" them  */
/*             into one pixel with a somewhat weighted average   */
/*                                                               */
/*  Input:  none, takes existing dimensions and halves them      */
/*                                                               */
/*  Output:  displays newly scaled picture on screen             */
/*****************************************************************/
afx_msg void CImageWin::ImageScaleCrudeSmaller()
{
	// check to make sure a file has actuall been opened
	// and a picture is available to scale
	if(FileOpen)
	{
		// variable used to count total number of new pixels placed
		unsigned long TotalPixels = 0;

		// create a dc to work with
		CClientDC dc( this );

		// new dimensions are 1/2 of old dimensions
		CrudeWidth = CurrentWidth / 2;
		CrudeHeight = CurrentHeight / 2;

		// make bitmap of the specified size and select it...
		CrudeBitmap.CreateCompatibleBitmap( &dc, CrudeWidth, CrudeHeight);
		CBitmap * oldCrude = CrudeMemDC.SelectObject(&CrudeBitmap);

		// set up the final dynamic array
		CrudeColors = new COLORREF * [CrudeHeight];

		for (unsigned long g=0; g < CrudeHeight; g++)
		{
			// make the array into two dimensions
			CrudeColors[g] = new COLORREF [CrudeWidth];
		}

		// all the variables necessary for my crude algorithm
		unsigned long w, h, x, y; 
		COLORREF newcolor, tempcolor;
		int red, green, blue, red2, green2, blue2, red3, green3, blue3, red4, green4, blue4;
		
		// initialize the variables
		w = 0;
		h = 0;
		
		// get the tick count to start the timer
		start = GetTickCount();

		// the nested for loops to fit the colors  
		// from the old array into the new array 
		for (y=0; y<CrudeHeight; y++)
		{
			// reset value for each run through
			w = 0;

			for (x=0; x<CrudeWidth; x++){
				
				// get pixel color from old array
				tempcolor = CurrentColors[h][w];

				// parse out red, green and blue values separately
				red = GetRValue(tempcolor);
				green = GetGValue(tempcolor);
				blue = GetBValue(tempcolor);

				// get pixel color from old array
				tempcolor = CurrentColors[h+1][w+1];

				// parse out red, green and blue values separately
				red2 = GetRValue(tempcolor);
				green2 = GetGValue(tempcolor);
				blue2 = GetBValue(tempcolor);

				// compare neighbor pixels to strengthen their values in the average
				if(( red >= (red2 + 10)) || ( red >= (red2 - 10)))  // changing the 10's will
					red = red2;										// cause the neighboring pixels
				if(( green >= (green2 + 10)) || ( green >= (green2 - 10)))  // to count more or less
					green = green2;									// as individual pixels in 
				if(( blue >= (blue2 + 10)) || ( blue >= (blue2 - 10)))  // computing the averages
					blue = blue2;

				// get pixel color from old array
				tempcolor = CurrentColors[h+1][w];

				// parse out red, green and blue values separately
				red3 = GetRValue(tempcolor);
				green3 = GetGValue(tempcolor);
				blue3 = GetBValue(tempcolor);
				
				// compare neighbor pixels to strengthen their values in the average
				if(( red2 >= (red3 + 10)) || ( red2 >= (red3 - 10)))
					red3 = red2;
				if(( green2 >= (green3 + 10)) || ( green2 >= (green3 - 10)))
					green3 = green2;
				if(( blue2 >= (blue3 + 10)) || ( blue2 >= (blue3 - 10)))
					blue3 = blue2;

				// get pixel color from old array
				tempcolor = CurrentColors[h][w+1];

				// parse out red, green and blue values separately
				red4 = GetRValue(tempcolor);
				green4 = GetGValue(tempcolor);
				blue4 = GetBValue(tempcolor);

				// compare neighbor pixels to strengthen their values in the average
				if(( red3 >= (red4 + 10)) || ( red3 >= (red4 - 10)))
					red4 = red3;
				if(( green3 >= (green4 + 10)) || ( green3 >= (green4 - 10)))
					green4 = green3;
				if(( blue3 >= (blue4 + 10)) || ( blue3 >= (blue4 - 10)))
					blue4 = blue3;

				// another way to compute the average - more straight forward
				//red = (red + red2 + red3 + red4) / 4;
				//green = (green + green2 + green3 + green4) / 4;
				//blue = (blue + blue2 + blue3 + blue4) / 4;

				// average the colors of the pixels
				red = (red + red2) / 2;
				green = (green + green2) / 2;
				blue = (blue + blue2) / 2;

				// recompile red, green and blue into colorref
				newcolor = RGB(red, green, blue);

				// move down to next group of pixels in row
				w = w + 2;

				// set pixel color to new array
				CrudeColors[y][x] = newcolor;

				// another pixel has been placed
				TotalPixels++;

			}

			// move down to next row of pixels
			h = h + 2;
		}

		// get the tick count to stop the timer
		finish = GetTickCount();

		// calculate time of algorithm
		duration = (double)(finish - start)/1000.0;

		// output the total number of pixels placed
		char t[10];
		itoa(TotalPixels,t,10);
		MessageBox(t,"Number of Total Pixels");

		// delete old color array
		for (g=0; g < LastHeight; g++)
		{
			delete []LastColors[g];
		}

		delete []LastColors;

		// set up new last dimensions and color array
		LastHeight = CurrentHeight;
		LastWidth = CurrentWidth;
		LastColors = CurrentColors;

		// set up new current dimensions and color array
		CurrentWidth = CrudeWidth;
		CurrentHeight = CrudeHeight;
		CurrentColors = CrudeColors;

		// nested for loops to set pixels on CrudeMemDC
		for (x=0; x<CrudeWidth; x++)
		{
		   for (y=0; y<CrudeHeight; y++)
		   {
			   // set pixel in MemDC with color data from array
			   CrudeMemDC.SetPixel(x,y,CrudeColors[y][x]);

		   }  //for (CrudeHeight)

		}  //for (CrudeWidth)

		// deselect and delete bitmap object
		CrudeMemDC.SelectObject(&oldCrude);
		CrudeBitmap.DeleteObject();

		// make bitmap of the specified size and select it...
		CurrentBitmap.CreateCompatibleBitmap( &dc, CurrentWidth, CurrentHeight);
		CBitmap * oldCurrent = CurrentMemDC.SelectObject(&CurrentBitmap);

		// copy CrudeMemDC to CurrentMemDC to be displayed
		CurrentMemDC.BitBlt( 0, 0, CurrentWidth, CurrentHeight, &CrudeMemDC, 0, 0, SRCCOPY );

		// deselect and delete bitmap object
		CurrentMemDC.SelectObject(&oldCurrent);
		CurrentBitmap.DeleteObject();

		// the picture has been changed and not saved
		FileChanged = true;
			
		// force a call to OnPaint() to display picture
		Invalidate();

	}  //if (FileOpen)
	else
	{
		// a file hasn't been opened yet
		MessageBox("You must open a file first");

	}  //else (FileOpen)

}  //ImageScaleCrudeSmaller


/*****************************************************************/
/*  Author: Alex Slusarek                                        */
/*                                                               */
/*  Function:  scales the picture bigger by a facter of 2        */
/*             the algorithm takes 1 pixel and expands it        */
/*             into four pixels with a straight copy of pixel    */
/*                                                               */
/*  Input:  none, takes existing dimensions and doubles them     */
/*                                                               */
/*  Output:  displays newly scaled picture on screen             */
/*****************************************************************/
afx_msg void CImageWin::ImageScaleCrudeBigger()
{
	// check to make sure a file has actuall been opened
	// and a picture is available to scale
	if(FileOpen)
	{
		// variable used to count total number of new pixels placed
		unsigned long TotalPixels = 0;

		// create a dc to work with
		CClientDC dc( this );

		// new dimensions are x2 old dimensions
		CrudeWidth = CurrentWidth * 2;
		CrudeHeight = CurrentHeight * 2;

		// make bitmap of the specified size and select it...
		CrudeBitmap.CreateCompatibleBitmap( &dc, CrudeWidth, CrudeHeight);
		CBitmap * oldCrude = CrudeMemDC.SelectObject(&CrudeBitmap);

		// set up the final dynamic array while we are at it
		CrudeColors = new COLORREF * [CrudeHeight];

		for (unsigned long g=0; g < CrudeHeight; g++)
		{
			// make the array into two dimensions
			CrudeColors[g] = new COLORREF [CrudeWidth];
		}

		// all the variables necessary for my crude algorithm
		unsigned long w, h, x, y; 
		COLORREF newcolor;
		
		// initialize the variables
		w = 0;
		h = 0;
		
		// get the tick count to start the timer
		start = GetTickCount();

		// the nested for loops to fit the colors  
		// from the old array into the new array 
		for (y=0; y<CurrentHeight; y++)
		{
			// reset value for each run through
			w = 0;

			for (x=0; x<CurrentWidth; x++)
			{
				// get pixel color from old array
				newcolor = CurrentColors[y][x];

				// set pixel color to new array
				CrudeColors[h][w] = newcolor;
				CrudeColors[h+1][w+1] = newcolor;
				CrudeColors[h+1][w] = newcolor;
				CrudeColors[h][w+1] = newcolor;

				// another four pixels have been placed
				TotalPixels = TotalPixels + 4;

				// move down to next group of pixels in row
				w = w + 2;

			}

			// move down to next row of pixels
			h = h + 2;
		}

		// get the tick count to stop the timer
		finish = GetTickCount();

		// calculate time of algorithm
		duration = (double)(finish - start)/1000.0;

		// output the total number of pixels placed
		char t[10];
		itoa(TotalPixels,t,10);
		MessageBox(t,"Number of Total Pixels");

		// delete old color array
		for (g=0; g < LastHeight; g++)
		{
			delete []LastColors[g];
		}

		delete []LastColors;

		// set up new last dimensions and color array
		LastHeight = CurrentHeight;
		LastWidth = CurrentWidth;
		LastColors = CurrentColors;

		// set up new last dimensions and color array
		CurrentWidth = CrudeWidth;
		CurrentHeight = CrudeHeight;
		CurrentColors = CrudeColors;

		// nested for loops to set pixels on CrudeMemDC
		for (x=0; x<CrudeWidth; x++)
		{
		   for (y=0; y<CrudeHeight; y++)
		   {
			   // set pixel in MemDC with color data from array
			   CrudeMemDC.SetPixel(x,y,CrudeColors[y][x]);

		   }  //for (CrudeHeight)

		}  //for (CrudeWidth)

		// deselect and delete bitmap object
		CrudeMemDC.SelectObject(&oldCrude);
		CrudeBitmap.DeleteObject();

		// make bitmap of the specified size and select it...
		CurrentBitmap.CreateCompatibleBitmap( &dc, CurrentWidth, CurrentHeight);
		CBitmap * oldCurrent = CurrentMemDC.SelectObject(&CurrentBitmap);

		// copy CrudeMemDC to CurrentMemDC to be displayed
		CurrentMemDC.BitBlt( 0, 0, CurrentWidth, CurrentHeight, &CrudeMemDC, 0, 0, SRCCOPY );

		// deselect and delete bitmap object
		CurrentMemDC.SelectObject(&oldCurrent);
		CurrentBitmap.DeleteObject();

		// the picture has been changed and not saved
		FileChanged = true;
			
		// force a call to OnPaint() to display picture
		Invalidate();

	}  //if (FileOpen)
	else
	{
		// a file hasn't been opened yet
		MessageBox("You must open a file first");

	}  //else (FileOpen)

}  //ImageScaleCrudeBigger


/*****************************************************************/
/*  Author: Alex Slusarek                                        */
/*                                                               */
/*  Function:  reverts the picture back to its original format   */
/*                                                               */
/*  Input:  none, takes existing dimensions and returns them to  */
/*          the original starting values                         */
/*                                                               */
/*  Output:  displays original picture on screen                 */
/*****************************************************************/
afx_msg void CImageWin::OriginalImage()
{
	// check to make sure a file has actuall been opened
	// and a picture is available to scale
	if(FileOpen)
	{
		// create a dc to work with
		CClientDC dc( this );

		// delete old color array
		for (unsigned long g=0; g < LastHeight; g++)
		{
			delete []LastColors[g];
		}

		delete []LastColors;

		// set up new last dimensions and color array
		LastHeight = CurrentHeight;
		LastWidth = CurrentWidth;
		LastColors = CurrentColors;

		// set up new current dimensions and color array
		CurrentWidth = OriginalWidth;
		CurrentHeight = OriginalHeight;

		// set up the current dynamic array while we are at it
		CurrentColors = new COLORREF * [CurrentHeight];

		for (g=0; g < CurrentHeight; g++)
		{
			// make the array into two dimensions
			CurrentColors[g] = new COLORREF [CurrentWidth];
		}

		// make bitmap of the specified size and select it...
		CurrentBitmap.CreateCompatibleBitmap( &dc, CurrentWidth, CurrentHeight);
		CBitmap * oldCurrent = CurrentMemDC.SelectObject(&CurrentBitmap);

		// the nested for loops to copy the colors  
		// from the original array into the new array 
		for (unsigned long x=0; x<CurrentWidth; x++)
		{
		   for (unsigned long y=0; y<CurrentHeight; y++)
		   {
			   // set pixel in MemDC with color data from array
			   CurrentMemDC.SetPixel(x,y,OriginalColors[y][x]);

			   // get and set pixel from original array to current array
			   CurrentColors[y][x] = OriginalColors[y][x];

		   }  //for (CurrentHeight)

		}  //for (CurrentWidth)

		// deselect and delete bitmap object
		CurrentMemDC.SelectObject(&oldCurrent);
		CurrentBitmap.DeleteObject();

		// the picture has not been changed and not saved
		FileChanged = false;
			
		// force a call to OnPaint() to display picture
		Invalidate();

	}  //if (FileOpen)
	else
	{
		// a file hasn't been opened yet
		MessageBox("You must open a file first");

	}  //else (FileOpen)

}  //OriginalImage


/******************************************************************/
/*  Author: Alex Slusarek                                         */
/*                                                                */
/*  Function:  reverts picture back to its last format            */
/*                                                                */
/*  Input:  none, takes existing dimensions and sets them to the  */
/*          last values previous                                  */
/*                                                                */
/*  Output:  displays last/previous picture on screen             */
/******************************************************************/
afx_msg void CImageWin::LastImage()
{
	// check to make sure a file has actuall been opened
	// and a picture is available to scale
	if (FileOpen)
	{
		// create a dc to work with
		CClientDC dc( this );

		unsigned long TempWidth = CurrentWidth;
		unsigned long TempHeight = CurrentHeight;
		COLORREF ** Temp = CurrentColors;

		// set up new current dimensions and color array
		CurrentWidth = LastWidth;
		CurrentHeight = LastHeight;
		CurrentColors = LastColors;

		// set up new last dimensions and color array
		LastWidth = TempWidth;
		LastHeight = TempHeight;
		LastColors = Temp;

		// make bitmap of the specified size and select it...
		CurrentBitmap.CreateCompatibleBitmap( &dc, CurrentWidth, CurrentHeight);
		CBitmap * oldCurrent = CurrentMemDC.SelectObject(&CurrentBitmap);

		// nested for loops to set pixels on CurrentMemDC
		for (unsigned long x=0; x<CurrentWidth; x++)
		{
		   for (unsigned long y=0; y<CurrentHeight; y++)
		   {
			   // set pixel in MemDC with color data from array
			   CurrentMemDC.SetPixel(x,y,CurrentColors[y][x]);

		   }  //for (CurrentHeight)

		}  //for (CurrentWidth)

		// deselect and delete bitmap object
		CurrentMemDC.SelectObject(&oldCurrent);
		CurrentBitmap.DeleteObject();

		// the picture has been changed and not saved
		FileChanged = true;
			
		// force a call to OnPaint() to display picture
		Invalidate();

	}  //if (FileOpen)
	else
	{
		// a file hasn't been opened yet
		MessageBox("You must open a file first");
	
	}  //else (FileOpen)

}  //LastImage


/******************************************************************/
/*  Author: Alex Slusarek                                         */
/*                                                                */
/*  Function:  takes the current picture, as it is viewed on the  */
/*             screen and saves it to file in .bmp format         */
/*                                                                */
/*  Input:  none, takes current picture and saves to file         */
/*                                                                */
/*  Output:  saves current picture to .bmp file                   */
/*           prompts user for new file name                       */
/******************************************************************/
afx_msg void CImageWin::OnFileSaveAs (){
	/*************************************************************
	** Saves the currently loaded image under a different filename
	*************************************************************/

	// check to make sure a file has actuall been opened
	// and a picture is available to scale
	if(FileOpen)
	{

		// create file dialog box --"Save As"
		CFileDialog FDlgBox (FALSE, _T ("bmp"), _T("*.bmp"), 
			 OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, 
			 "BITMAP files|*.bmp|");

		// user wants to save the picture / file
		if (FDlgBox.DoModal () == IDOK) {

			//Obtain filename from dialog box data
			strcpy(filename, FDlgBox.GetPathName () );

			// setup specific variables before saving to file
			image->BMPFileSetUp(CurrentWidth, CurrentHeight);
	
			// call Jake's function to save/write to a file
			image->BMPWrite(filename, &CurrentMemDC);
			
			// the picture has been saved
			FileChanged = false;

		}  //if (IDOK)

	}  //if (FileOpen)
	else
	{
		// a file hasn't been opened yet
		MessageBox("You must open a file first");
	
	}  //else (FileOpen)

}  //OnFileSaveAs


/*****************************************************************/
/*  Author: Alex Slusarek                                        */
/*                                                               */
/*  Function:  closes the program, checks to see if picture      */
/*             needs to be saved                                 */
/*                                                               */
/*  Input:  none, takes current picture if need to save          */
/*                                                               */
/*  Output:  closes program and saves file if necessary          */
/*           if saving, propmpts user for new file name          */
/*****************************************************************/
afx_msg void CImageWin::OnFileClose()
{
	//If image is altered and NOT saved, inquire user if file is to
	//be saved....
	if(FileChanged) 
	{
		// ask user if they would like to save current picture
		int reply = AfxMessageBox( "Save Changes?", MB_YESNOCANCEL, 0);
		
		// user wants to save the file
		if (reply == IDYES)
		{ 
			// call SaveAs function to do the job	
			OnFileSaveAs();
				
		}  //if (IDYES)
		else if(reply == IDCANCEL)
		{  
			// user cancelled operation
			// do nothing
			return;
		
		}  //elseif (IDCANCEL)	
	
	}  //if (FileChanged)

	// send a message to main window to tell it to close
	PostMessage (WM_CLOSE, 0, 0); 

}  //OnFileClose


/*****************************************************************/
/*  Author: Alex Slusarek                                        */
/*                                                               */
/*  Function:  refreshes the window as requested by the system   */
/*                                                               */
/*  Input:  none, takes CurrentMemDC as it sits currently        */
/*                                                               */
/*  Output:  displays current picture on screen                  */
/*****************************************************************/
afx_msg void CImageWin::OnPaint()
{
	// create a dc to work with
    CPaintDC dc( this );    

	// copy CurrentMemDC to DC (screen) to be displayed
	dc.BitBlt( 0, 0, CurrentWidth, CurrentHeight, &CurrentMemDC, 0, 0, SRCCOPY );

}  //OnPaint

// the message map to handle all of the main program's messages
BEGIN_MESSAGE_MAP( CImageWin, CFrameWnd )
   ON_WM_PAINT()
   ON_COMMAND(ID_ORIGINAL, OriginalImage)
   ON_COMMAND(ID_SAVE, OnFileSaveAs)
   ON_COMMAND(ID_BRESENHAM, ImageScaleBresenham)
   ON_COMMAND(ID_SMOOTHBRESENHAM, ImageScaleSmoothBresenham)
   ON_COMMAND(ID_LAST, LastImage)
   ON_COMMAND(ID_CRUDEUP, ImageScaleCrudeBigger)
   ON_COMMAND(ID_CRUDEDOWN, ImageScaleCrudeSmaller)
   ON_COMMAND(ID_OPEN, OnFileOpen)
   ON_COMMAND(ID_CLOSE, OnFileClose)
END_MESSAGE_MAP()


class CImageApp : public CWinApp {
public:

   BOOL InitInstance()
   {
      m_pMainWnd = new CImageWin;            // create window
      m_pMainWnd->ShowWindow( m_nCmdShow );  // make visible
      m_pMainWnd->UpdateWindow();            // force refresh

      return TRUE;
   }
} imageApp;


//  I left the disclaimer below as a safetly precaution becaue it was 
//  originally part of Dr. McVey's sample program which I used as a 
//  starting point
/**************************************************************************
 * (C) Copyright 1999 by Deitel & Associates, Inc. and Prentice Hall.     *
 * All Rights Reserved.                                                   *
 *                                                                        *
 * DISCLAIMER: The authors and publisher of this book have used their     *
 * best efforts in preparing the book. These efforts include the          *
 * development, research, and testing of the theories and programs        *
 * to determine their effectiveness. The authors and publisher make       *
 * no warranty of any kind, expressed or implied, with regard to these    *
 * programs or to the documentation contained in these books. The authors *
 * and publisher shall not be liable in any event for incidental or       *
 * consequential damages in connection with, or arising out of, the       *
 * furnishing, performance, or use of these programs.                     *
 *************************************************************************/
