#include "stdafx.h"


const BYTE BMP[2] = {0x42, 0x4D};
const BYTE JPG[3]=  {0xFF, 0xD8, 0xFF}; //, 0xE0 4A 46 49 46 00 app.
const BYTE PNG[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
const BYTE TIF[4] = {0x4D, 0x4D, 0x00, 0x2A};
const BYTE GIF[6] = {0x47, 0x49, 0x46, 0x38}; //, 0x37, 0x61}; app.


ImageFileFormat imageFileFormat(const LPBYTE image)
{
	if (memcmp(image, BMP, 2) == 0)
	{
		return Image_File_Format_BMP;
	}
	if (memcmp(image, JPG, 3) == 0)
	{
		return Image_File_Format_JPG;
	}
	if (memcmp(image, PNG, 8) == 0)
	{
		return Image_File_Format_PNG;
	}

	if (memcmp(image, TIF, 4) == 0)
	{
		return Image_File_Format_TIF;
	}
	if (memcmp(image, GIF, 6) == 0)
	{
		return Image_File_Format_GIF;
	}
	return Image_File_Format_UNKNOWN;
}


int imageProcess(LPBYTE imagePtr, DWORD imageSize, int maxHeight, int thumbSize,
		int& imageWidth, int& imageHeight, int& stretchedWidth, int& stretchedHeight, 
		LPBYTE& thumbPtr,
		LPBYTE& stretchedPtr, DWORD& thumbDataSize, DWORD& stretchedSize)
{
	ImageFileFormat imageFormat = Image_File_Format_JPG;
	int result = JPEG_FAILURE;
	PBITMAPINFO pbi = NULL;
	BITMAPINFO bi;
	PBITMAPFILEHEADER pbhi = NULL;
	LPBYTE pbits = NULL, bmpInputPtr = NULL, thumbInputPtr = NULL;

	memset(&bi, 0, sizeof(BITMAPINFO));

 	imageFormat = imageFileFormat(imagePtr);

	switch (imageFormat)
	{
	case Image_File_Format_BMP:		
		
		pbhi = (PBITMAPFILEHEADER) imagePtr;  		
		
		pbi =  (PBITMAPINFO)(imagePtr + sizeof(BITMAPFILEHEADER));
		
		if (pbi->bmiHeader.biBitCount != 24)
		{
			result = JPEG_ERROR_UNSUPPORT_FORMAT;
		}
		else		
		{
			pbits = imagePtr + pbhi->bfOffBits;				 
			imageWidth  = pbi->bmiHeader.biWidth;
			imageHeight = pbi->bmiHeader.biHeight;

			memcpy(&bi, pbi, sizeof(BITMAPINFO));
		
			if (pbi->bmiHeader.biHeight>maxHeight)
			{
				stretchedHeight = maxHeight;
				stretchedWidth = pbi->bmiHeader.biWidth*maxHeight/pbi->bmiHeader.biHeight;
			}
			else
			{
				stretchedWidth  = pbi->bmiHeader.biWidth;
				stretchedHeight = pbi->bmiHeader.biHeight;
			}

			if ((result = scaleBmp(&bi, pbits, bmpInputPtr, stretchedWidth, stretchedHeight))
					== JPEG_SUCCESS)
			{
				if ((result = readBmpBuffer(&bi, stretchedPtr, stretchedSize, bmpInputPtr))
					== 	JPEG_SUCCESS)
				{
					if ((result = scaleBmp(&bi, bmpInputPtr, thumbInputPtr, thumbSize, thumbSize)) 
						== JPEG_SUCCESS)
					{
						result = readBmpBuffer(&bi, thumbPtr, thumbDataSize, thumbInputPtr);
						free(thumbInputPtr);
					}
					if (result != JPEG_SUCCESS)
					{
						free(stretchedPtr);
					}
				}
				free(bmpInputPtr);
			}
		}
		break;
	case Image_File_Format_JPG:	  		
		if ((result = scaleTo(imagePtr, imageSize, thumbSize, thumbSize,  
			imageWidth, imageHeight, thumbPtr, thumbDataSize)) == JPEG_SUCCESS)
		{
			if ((result = scaleLessThan(imagePtr, imageSize, maxHeight, stretchedPtr, 
				stretchedWidth, stretchedHeight, stretchedSize)) != JPEG_SUCCESS)
			{
				free(thumbPtr);
			}
		}
		break;
	default:
		result = JPEG_ERROR_UNSUPPORT_FORMAT;
		break;
	}
	return result;
}
				

			
int scaleLessThan(const LPBYTE jpgPtr, DWORD jpgSize, int maxHeight, LPBYTE& pbits,
		int& stretchedWidth, int& stretchedHeight, DWORD& stretchedSize)
{
	int result      = JPEG_FAILURE;
	PBITMAPINFO pbi = NULL;
	LPBYTE imagePtr = NULL;

	if ((result = readJpgBuffer(jpgPtr, jpgSize, pbi)) == JPEG_SUCCESS)
	{
		if (pbi->bmiHeader.biHeight > maxHeight)
		{
			stretchedHeight = maxHeight;
			stretchedWidth  = pbi->bmiHeader.biWidth * maxHeight / pbi->bmiHeader.biHeight;
		}
		else
		{
			stretchedWidth  = pbi->bmiHeader.biWidth;
			stretchedHeight = pbi->bmiHeader.biHeight;
		} 
		if ((result = scaleBmp(pbi, stretchedWidth, stretchedHeight)) == JPEG_SUCCESS)
		{				
			if ((result = readBmpBuffer(pbi, pbits, stretchedSize)) == JPEG_SUCCESS)
			{
				result = JPEG_SUCCESS;			
			}  			
		}
		free(pbi);
	}
	return result;
}  

int scaleTo(const LPBYTE jpgPtr, DWORD jpgSize, int thumbWidth, int thumbHeight, 
			int& imageWidth, int& imageHeight, LPBYTE& pbits, DWORD& stretchedSize)
{
	int result      = JPEG_FAILURE;
	PBITMAPINFO pbi = NULL;

	if ((result     = readJpgBuffer(jpgPtr, jpgSize, pbi)) == JPEG_SUCCESS)
	{
		imageWidth  = pbi->bmiHeader.biWidth;
		imageHeight = pbi->bmiHeader.biHeight;
		if ((result = scaleBmp(pbi, thumbWidth, thumbHeight)) == JPEG_SUCCESS)
		{
			if ((result = readBmpBuffer(pbi, pbits, stretchedSize)) == JPEG_SUCCESS)
			{
				result = JPEG_SUCCESS;			
			}  			
		}
		free(pbi);
	}
	return result;
}  

int readBmpBuffer(PBITMAPINFO pbi, LPBYTE& dest, DWORD& size, LPBYTE imagePtr)
{
	JPEG_CORE_PROPERTIES jcprops;
	IJLERR jerr;
	PBITMAPINFOHEADER pbhi = NULL;
	int    colorNumber = 0;
	int    widthBytes  = 0;
	int    bufferSize  = 0;
	LPBYTE  buffer = NULL;
	LPBYTE  startPtr = NULL, endPtr = NULL;
	LPBYTE  pbits = NULL;

	 
	if (pbi == NULL)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}  

	if ((jerr = ijlInit( &jcprops)) != IJL_OK)
	{
		return JPEG_ERROR_IJL_INIT;
	}

	pbhi = &pbi->bmiHeader;
	jcprops.DIBWidth    = pbhi->biWidth;
	jcprops.DIBHeight   = pbhi->biHeight;
	jcprops.DIBChannels = 3;
	jcprops.DIBColor    = IJL_BGR;
	jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(pbhi->biWidth, 3);

	jcprops.JPGWidth  = jcprops.DIBWidth;
	jcprops.JPGHeight = jcprops.DIBHeight;
	jcprops.jquality  = 80;
	jcprops.JPGChannels = 3;   	

	if (imagePtr == NULL)
	{
		pbits = 	(LPBYTE)pbi + pbhi->biSize + colorNumber * sizeof(RGBQUAD);
	}
	else
	{
		pbits = imagePtr;
	}

	widthBytes = ((pbhi->biWidth*pbhi->biBitCount+31) & (~31)) / 8;


	switch (pbhi->biBitCount)
	{  
	case 24: 
		colorNumber = 0;
		break;
		//ijl doesn't support other than 24 color
	default:
		ijlFree(&jcprops);
		return JPEG_ERROR_UNSUPPORT_FORMAT;
	}
		/*
	case 1:
	case 4:
	case 8:
		jcprops.UseJPEGPROPERTIES = 1;
		if (pbhi->biClrUsed == 0)
		{
			colorNumber = (1 << pbhi->biBitCount);
		}
		else
		{
			colorNumber = pbhi->biClrUsed;
		}
		break;

	case 16:
	case 32: 
		jcprops.UseJPEGPROPERTIES = 1;
		jcprops.jprops.DIBLineBytes = widthBytes;
		colorNumber = 0;
		break;	
		
	} 
	*/
	bufferSize =pbhi->biHeight * widthBytes; 

	if ((buffer = (LPBYTE)malloc(bufferSize)) == NULL)
	{
		ijlFree(&jcprops);
		return JPEG_ERROR_MEMORY_ALLOC;
	}

	for (int i = 0; i < pbhi->biHeight; i ++)
	{
		startPtr = 	buffer + i * widthBytes;
		endPtr = pbits + (pbhi->biHeight - i - 1) * widthBytes;
		
		memcpy(startPtr, endPtr, widthBytes);
	}
	jcprops.DIBBytes    = buffer;

	

	if ((dest = (LPBYTE)malloc(bufferSize)) == NULL)
	{
		ijlFree(&jcprops);
		free(buffer);
		return JPEG_ERROR_MEMORY_ALLOC;
	}  
	jcprops.JPGBytes     = dest;
	jcprops.JPGSizeBytes = bufferSize;

	if ((jerr = ijlWrite(&jcprops, IJL_JBUFF_WRITEWHOLEIMAGE))  != IJL_OK)
	{
		ijlFree(&jcprops);
		free(dest);
		free(buffer);	 
		return JPEG_ERROR_IJL_READ_PARAM;
	}
	free(buffer);
	size = jcprops.JPGSizeBytes;

	ijlFree(&jcprops);
	
	return JPEG_SUCCESS;
}




int saveJpgFile(const TCHAR* fileName, const LPBYTE dest, DWORD size)
{
	HANDLE fileHandle = NULL;
	DWORD tempSize = 0;
	int result = JPEG_FAILURE; 
	if (dest == NULL)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}
	if ((fileHandle = CreateFile(fileName, GENERIC_WRITE|STANDARD_RIGHTS_ALL, FILE_SHARE_READ, 
		 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
	{
		return JPEG_ERROR_CREATE_FILE;
	}
	if (WriteFile(fileHandle, dest, size, &tempSize, NULL))
	{
		result = JPEG_SUCCESS;
	}
	CloseHandle(fileHandle);
	return result;
}

int readJpgFile(const char* src, PBITMAPINFO& pbi)
{
	JPEG_CORE_PROPERTIES jcprops;
	IJLERR jerr;
	PBITMAPINFOHEADER pbhi;
	int imageSize  = 0;;
	int bufferSize = 0;
	int widthBytes = 0;
	LPBYTE  pbits  = NULL;
	int result = JPEG_FAILURE;

	if (src == NULL)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}

	if ((jerr = ijlInit( &jcprops)) != IJL_OK)
	{
		return JPEG_ERROR_IJL_INIT;
	}

	jcprops.JPGFile    = src;

	//Read JPEG parameters from the file
	if ((jerr = ijlRead(&jcprops, IJL_JFILE_READPARAMS)) == IJL_OK)
	{  
		widthBytes = (jcprops.JPGWidth*3 + 31) & (~31);
		imageSize = widthBytes * jcprops.JPGHeight;

		bufferSize = sizeof(BITMAPINFOHEADER) + imageSize;
		
		if ((pbi = (PBITMAPINFO)malloc(bufferSize)) == NULL)
		{	
			pbhi = (PBITMAPINFOHEADER) pbi;

			pbhi->biSize         = sizeof(BITMAPINFOHEADER);
			pbhi->biPlanes       = 1;
			pbhi->biClrUsed      = 0;
			pbhi->biWidth        = jcprops.JPGWidth;
			pbhi->biHeight       = jcprops.JPGHeight;
			pbhi->biCompression  = BI_RGB;
			pbhi->biClrImportant = 0;
			pbhi->biBitCount     = 24;
			pbhi->biXPelsPerMeter= 0;
			pbhi->biYPelsPerMeter= 0;
			pbhi->biSizeImage    = imageSize;
			pbits = (LPBYTE)pbi + pbhi->biSize;	  

			//Set up the DIB specification for the JPEG decoder
			jcprops.DIBWidth    = jcprops.JPGWidth;
			jcprops.DIBHeight   = -jcprops.JPGHeight; //Implies a bottom-up DIB.
			jcprops.DIBChannels = 3; //jcprops.JPGChannels;	 //3????
			jcprops.DIBColor    = IJL_BGR;
			jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.JPGWidth, 3);
			jcprops.DIBBytes    = reinterpret_cast<BYTE*>(pbits); 			
			//jcprops.JPGSizeBytes = imageSize;

			if ((jerr = ijlRead(&jcprops, IJL_JFILE_READWHOLEIMAGE)) == IJL_OK)
			{			 
				result = JPEG_SUCCESS;
			}
			else
			{
				free(pbi);
			}
		}
	}
	ijlFree(&jcprops);
	return result;
}

int readJpgBuffer(const LPBYTE src, DWORD size, PBITMAPINFO& pbi)
{
	JPEG_CORE_PROPERTIES jcprops;
	IJLERR jerr;
	int result = JPEG_FAILURE;
	PBITMAPINFOHEADER pbhi;
	int imageSize  = 0;;
	int bufferSize = 0;
	int widthBytes = 0;
	LPBYTE  pbits  = NULL;

	if (src == NULL || size <= 0)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}

	if ((jerr = ijlInit( &jcprops)) != IJL_OK)
	{
		return JPEG_ERROR_IJL_INIT;
	}

	jcprops.JPGBytes     = src;
	jcprops.JPGSizeBytes = size;

	//Read JPEG parameters from the file
	if ((jerr = ijlRead(&jcprops, IJL_JBUFF_READPARAMS))  == IJL_OK)
	{  
		widthBytes = (jcprops.JPGWidth * 3 + 31) & (~31);
		imageSize = widthBytes * jcprops.JPGHeight;

		bufferSize = sizeof(BITMAPINFOHEADER) + imageSize; 	

		if ((pbi = (PBITMAPINFO)malloc(bufferSize)) != NULL)
		{	
			pbhi = (PBITMAPINFOHEADER) pbi;	 
			pbhi->biSize         = sizeof(BITMAPINFOHEADER);
			pbhi->biPlanes       = 1;
			pbhi->biClrUsed      = 0;
			pbhi->biWidth        = jcprops.JPGWidth;
			pbhi->biHeight       = jcprops.JPGHeight;
			pbhi->biCompression  = BI_RGB;
			pbhi->biClrImportant = 0;
			pbhi->biBitCount     = 24;
			pbhi->biXPelsPerMeter= 0;
			pbhi->biYPelsPerMeter= 0;
			pbhi->biSizeImage    = imageSize;
			pbits = (LPBYTE)pbi + pbhi->biSize;	 
			//Set up the DIB specification for the JPEG decoder
			jcprops.DIBWidth    = jcprops.JPGWidth;
			jcprops.DIBHeight   = - jcprops.JPGHeight; //Implies a bottom-up DIB.
			jcprops.DIBChannels = 3; //jcprops.JPGChannels;	 //3????
			jcprops.DIBColor    = IJL_BGR;
			jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.JPGWidth, 3);
			jcprops.DIBBytes    = reinterpret_cast<BYTE*>(pbits);

			jcprops.JPGSizeBytes = imageSize;
			jcprops.jquality   = 100;

			if ((jerr = ijlRead(&jcprops, IJL_JBUFF_READWHOLEIMAGE)) == IJL_OK)
			{
				result = JPEG_SUCCESS;
			}
			else
			{  
				free(pbi);
			}
		}
	}  
	jerr=ijlFree(&jcprops);
	return result;
}

int scaleBmp(PBITMAPINFO pbi, LPBYTE pbits, LPBYTE& lpNewBits, int width, int height)
{
	HDC hdc, srcDC=NULL, destDC=NULL;
	int result = JPEG_FAILURE;
	int srcWidthBytes =0, destWidthBytes = 0;
	HBITMAP hSrcBmp        = NULL, hDestBmp = NULL;
	PBITMAPINFOHEADER pbhi = NULL;
 	
	if (pbi == NULL  || width < 0 || height < 0)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}
	pbhi  = (PBITMAPINFOHEADER) pbi;

	if ((hdc = CreateDC(_T("DISPLAY"), NULL, NULL, NULL)) != NULL)
	{
		if ((srcDC  = CreateCompatibleDC(hdc)) != NULL && 
			(destDC = CreateCompatibleDC(hdc)) != NULL)
		{							
			srcWidthBytes = ((pbhi->biWidth * pbhi->biBitCount + 31) & (~31)) / 8;

			if ((hSrcBmp = CreateCompatibleBitmap(hdc, pbhi->biWidth, pbhi->biHeight))!= NULL)
			{	
				SelectObject(srcDC, hSrcBmp);
				if (SetDIBits(srcDC, hSrcBmp, 0, pbhi->biHeight, pbits, pbi, DIB_RGB_COLORS))
				{ 							
					destWidthBytes = ((width * pbhi->biBitCount + 31) & (~31)) / 8;

					if ((hDestBmp = CreateCompatibleBitmap(hdc, width, height))!= NULL)
					{
						SelectObject(destDC, hDestBmp);	 						
						if (SetStretchBltMode(srcDC, HALFTONE)&&SetStretchBltMode(destDC, HALFTONE)
							&&SetBrushOrgEx(srcDC, 0, 0, NULL)&&SetBrushOrgEx(destDC, 0, 0, NULL))
						{ 	
							if (StretchBlt(destDC, 0, 0, width, height, srcDC, 0, 0, 
								pbhi->biWidth, pbhi->biHeight, SRCCOPY))
							{												 
								if ((lpNewBits = (LPBYTE)malloc(destWidthBytes * height))!= NULL)
								{	 								
									pbhi->biWidth  = width;
									pbhi->biHeight = height;
									pbhi->biSizeImage = destWidthBytes * height; 
									if (GetDIBits(destDC, hDestBmp, 0, height, lpNewBits, pbi, DIB_RGB_COLORS))
									{
										result = JPEG_SUCCESS;
									}
								}
								else
								{
									result = JPEG_ERROR_MEMORY_ALLOC;
								}								
							} 
						}
						DeleteObject(hDestBmp);						
					}  
				}
				DeleteObject(hSrcBmp);				
			}
			DeleteDC(srcDC);
			DeleteDC(destDC); 						
		}
	    DeleteDC(hdc);		
	}
	return result;	
}




int scaleBmp(PBITMAPINFO pbi,  LPBYTE& lpNewBits, int width, int height)
{
	HDC hdc, srcDC=NULL, destDC=NULL;
	int result = JPEG_FAILURE;
	int srcWidthBytes =0, destWidthBytes = 0;
	HBITMAP hSrcBmp        = NULL, hDestBmp = NULL;
	PBITMAPINFOHEADER pbhi = NULL;
	LPBYTE pbits           =    NULL;
	int mode ;
 	
	if (pbi == NULL  || width < 0 || height < 0)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}
	pbhi  = (PBITMAPINFOHEADER) pbi;
	pbits = (LPBYTE)pbi + sizeof(BITMAPINFOHEADER); 

	if ((hdc = CreateDC(_T("DISPLAY"), NULL, NULL, NULL)) != NULL)
	{
		if ((srcDC  = CreateCompatibleDC(hdc)) != NULL && 
			(destDC = CreateCompatibleDC(hdc)) != NULL)
		{							
			srcWidthBytes = ((pbhi->biWidth * pbhi->biBitCount + 31) & (~31)) / 8;

			if ((hSrcBmp = CreateCompatibleBitmap(hdc, pbhi->biWidth, pbhi->biHeight))!= NULL)
			{	
				SelectObject(srcDC, hSrcBmp);
				if (SetDIBits(srcDC, hSrcBmp, 0, pbhi->biHeight, pbits, pbi, DIB_RGB_COLORS))
				{ 							
					destWidthBytes = ((width * pbhi->biBitCount + 31) & (~31)) / 8;

					if ((hDestBmp = CreateCompatibleBitmap(hdc, width, height))!= NULL)
					{
						SelectObject(destDC, hDestBmp);
						mode = GetStretchBltMode(srcDC);
						if (SetStretchBltMode(srcDC, HALFTONE))
						{ 							
							if (StretchBlt(destDC, 0, 0, width, height, srcDC, 0, 0, 
								pbhi->biWidth, pbhi->biHeight, SRCCOPY))
							{												 
								if ((lpNewBits = (LPBYTE)malloc(destWidthBytes * height))!= NULL)
								{	 								
									pbi->bmiHeader.biWidth  = width;
									pbi->bmiHeader.biHeight = height;
									pbi->bmiHeader.biSizeImage = destWidthBytes * height; 
									if (GetDIBits(destDC, hDestBmp, 0, height, lpNewBits, pbi, DIB_RGB_COLORS))
									{
										result = JPEG_SUCCESS;
									}
								}
								else
								{
									result = JPEG_ERROR_MEMORY_ALLOC;
								}								
							} 
						}
						DeleteObject(hDestBmp);						
					}  
				}
				DeleteObject(hSrcBmp);				
			}
			DeleteDC(srcDC);
			DeleteDC(destDC); 						
		}
	    DeleteDC(hdc);		
	}
	return result;	
}


int scaleBmp(PBITMAPINFO pbi, int width, int height)
{
	HDC hdc = NULL, srcDC  = NULL, destDC=NULL;
	int result             = JPEG_FAILURE;
	int srcWidthBytes      = 0, destWidthBytes = 0;
	int srcImageSize       = 0, destImageSize  = 0;
	HBITMAP hSrcBmp        = NULL, hDestBmp = NULL;
	PBITMAPINFOHEADER pbhi = NULL;
	LPBYTE pbits           = NULL;
	LPBYTE lpNewBits       = NULL;
	int mode = 0;

	if (pbi == NULL  || width < 0 || height < 0)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}
	pbhi           = (PBITMAPINFOHEADER) pbi;  

	srcWidthBytes  = ((pbhi->biWidth * pbhi->biBitCount + 31) & (~31)) / 8;
	destWidthBytes = ((width         * pbhi->biBitCount + 31) & (~31)) / 8;	
	srcImageSize   = pbhi->biHeight  * srcWidthBytes;
	destImageSize  = height          * destWidthBytes;

	if (destImageSize > srcImageSize)
	{
		if ((lpNewBits = (LPBYTE) realloc(pbi, sizeof(BITMAPINFOHEADER) + destImageSize)) == NULL)
		{
			return 	JPEG_ERROR_MEMORY_ALLOC;
		}
		else
		{
			pbi  = (PBITMAPINFO)lpNewBits;
			pbhi = (PBITMAPINFOHEADER) pbi;
		}
	} 

	pbits = (LPBYTE)pbi + sizeof(BITMAPINFOHEADER);

	if ((hdc = CreateDC(_T("DISPLAY"), NULL, NULL, NULL)) != NULL)
	{
		if ((srcDC  = CreateCompatibleDC(hdc)) != NULL && 
			(destDC = CreateCompatibleDC(hdc)) != NULL)
		{ 			
			mode = SetStretchBltMode(srcDC, HALFTONE);
			mode = SetStretchBltMode(destDC, HALFTONE);

			if ((hSrcBmp = CreateCompatibleBitmap(hdc, pbhi->biWidth, pbhi->biHeight))!= NULL)
			{	
				SelectObject(srcDC, hSrcBmp);
				if (SetDIBits(srcDC, hSrcBmp, 0, pbhi->biHeight, pbits, pbi, DIB_RGB_COLORS))
				{ 	
					if ((hDestBmp = CreateCompatibleBitmap(hdc, width, height))!= NULL)
					{
						SelectObject(destDC, hDestBmp);
						if (StretchBlt(destDC, 0, 0, width, height, srcDC, 0, 0, 
							pbhi->biWidth, pbhi->biHeight, SRCCOPY))
						{												
							pbi->bmiHeader.biWidth  = width;
							pbi->bmiHeader.biHeight = height;
							pbi->bmiHeader.biSizeImage = destImageSize; 
							if ((result = GetDIBits(destDC, hDestBmp, 0, 
								height, pbits, pbi, DIB_RGB_COLORS)) != 0)
							{
								result = JPEG_SUCCESS;
							}						
							else
							{
								result = JPEG_ERROR_READ_BITS;
							}								
						}
						DeleteObject(hDestBmp);	 
					}  
				}
				DeleteObject(hSrcBmp);				
			}
			DeleteDC(srcDC);
			DeleteDC(destDC); 						
		}
	    DeleteDC(hdc);		
	}
	return result;	
}


int createBmpInfoStruct(const BITMAP& bmp, PBITMAPINFO& pbmi)
{ 
	WORD    cClrBits; 
	int     result       = 0;
	int     colorNumber  = 0;
	int     bufferSize   = 0;
	int     imageSize    = 0;
     
    // Convert the color format to a count of bits. 
	imageSize = bmp.bmWidthBytes * bmp.bmHeight;
	cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);	  
    switch (cClrBits)
    {
    case 1:
	case 2:
    case 4:
    case 8:
		colorNumber = 1<< cClrBits;	 
		bufferSize  = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * colorNumber + imageSize;        
       break;
    case 16:       
    case 24:
    case 32:
       bufferSize   = sizeof(BITMAPINFOHEADER) + imageSize;         
       break;
    default:
        return JPEG_ERROR_INVALID_FORMAT; //failed ! this means we don't support "jpg" or "png" which has "0" here
    }
    
    if (pbmi == NULL)
	{
       return JPEG_ERROR_MEMORY_ALLOC;
    }  

    // 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 the bitmap is not compressed, set the BI_RGB flag. 
    pbmi->bmiHeader.biCompression = BI_RGB; 
    pbmi->bmiHeader.biClrUsed     = 0;
    

	pbmi = (PBITMAPINFO) malloc(sizeof(BITMAPINFOHEADER) + 
			sizeof(RGBQUAD) * colorNumber); 

    // Compute the number of bytes in the array of color 
    // indices and store the result in biSizeImage. 
    // For Windows NT/2000, the width must be DWORD aligned unless 
    // the bitmap is RLE compressed. This example shows this. 
    // For Windows 95/98, 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 JPEG_SUCCESS; 
} 


int createBmpFile(const TCHAR* pszFile, PBITMAPINFO pbi, LPBYTE lpBits) 
{ 
HANDLE              hf                = NULL;                  // file handle 
BITMAPFILEHEADER    hdr;       // bitmap file-header 
PBITMAPINFOHEADER   pbih;     // bitmap info-header 
DWORD               dwTmp; 
int                 colorNumber = 0;
int					result      = JPEG_ERROR_FILE_WRITE;

	if (pszFile == NULL || pbi == NULL || lpBits == NULL)
	{
		return 	JPEG_ERROR_INVALID_PARAM;
	}

    memset(&hdr, 0, sizeof(BITMAPFILEHEADER));
    pbih   = (PBITMAPINFOHEADER) pbi; 
     
    colorNumber = pbi->bmiHeader.biClrUsed;
    if (pbi->bmiHeader.biBitCount < 16 && pbi->bmiHeader.biClrUsed == 0) 
	{
       colorNumber = (1 << pbi->bmiHeader.biBitCount);
    }            

    hf  = CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, (DWORD) 0, NULL, CREATE_ALWAYS, 
		 FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); 
    if(hf == INVALID_HANDLE_VALUE)
	{	   
       return JPEG_ERROR_FILE_CREATE;
	}

    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M" 
    // Compute the size of the entire file. 
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + colorNumber * 
		sizeof(RGBQUAD) + pbih->biSizeImage); 
    
    // Compute the offset to the array of color indices. 
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize + 
		colorNumber * sizeof (RGBQUAD); 
    // Copy the BITMAPFILEHEADER into the .BMP file. 

    if(WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp,  NULL))
	{      
		if(WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER), (LPDWORD) &dwTmp, ( NULL)))
		{
			if(WriteFile(hf, (LPVOID) pbi->bmiColors, colorNumber * sizeof (RGBQUAD), 
				(LPDWORD) &dwTmp, ( NULL)))
			{
				if(WriteFile(hf, (LPSTR) lpBits, pbih->biSizeImage, (LPDWORD) &dwTmp,NULL))
				{
					result =  JPEG_SUCCESS;
				}
			}
		}
	}
	CloseHandle(hf);
    return result;
}

int createBmpFile(const TCHAR* pszFile, PBITMAPINFO pbi) 
{ 
	PBITMAPINFOHEADER   pbih;     // bitmap info-header 
	int                 colorNumber = 0;
	LPBYTE              lpBits      = NULL;

	if (pszFile == NULL || pbi == NULL)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}

    pbih   = (PBITMAPINFOHEADER) pbi; 
     
    colorNumber = pbi->bmiHeader.biClrUsed;
    if (pbi->bmiHeader.biBitCount < 16 && pbi->bmiHeader.biClrUsed == 0) 
	{
       colorNumber = (1 << pbi->bmiHeader.biBitCount);
    }    
	
	lpBits = (LPBYTE)pbi + pbih->biSize + colorNumber * sizeof(RGBQUAD);

	return createBmpFile(pszFile, pbi, lpBits);

}


void calculateMD5(const unsigned char *data, int nbytes, unsigned char digest[16])
{
	md5_state_t state;
	md5_init(&state);
	md5_append(&state, data, nbytes);
	md5_finish(&state, digest);
}

void saveToFile(TCHAR* fileName)
{
	LPBYTE imagePtr;
	DWORD imageSize;
	int imageWidth;
	int imageHeight;
	int stretchedWidth;
	int stretchedHeight;
	LPBYTE thumbPtr;
	LPBYTE stretchedPtr;
	DWORD thumbDataSize;
	DWORD stretchedSize; 

	if (!mapFile(fileName, imagePtr, imageSize))
	{
		_tprintf(_T("fileMapping error %d fileName=%s\n"), GetLastError(), fileName);		
		return;
	}

	if (imageProcess(imagePtr, imageSize, DefaultMaxHeight, DefaultThumbnailSize,
		imageWidth, imageHeight, stretchedWidth, stretchedHeight, thumbPtr, 
		stretchedPtr, thumbDataSize, stretchedSize) == JPEG_SUCCESS)
	{ 
		saveJpgFile(_T("original.jpg"), imagePtr, imageSize);
		saveJpgFile(_T("stretched.jpg"), stretchedPtr, stretchedSize);
		saveJpgFile(_T("thumbnail.jpg"), thumbPtr, thumbDataSize);	
		free(thumbPtr);
		free(stretchedPtr);
	}  		
	unmapFile(imagePtr); 
}
	 


/*
int readJpgBuffer(const LPBYTE src, PBITMAPINFO& pbi)
{
	JPEG_CORE_PROPERTIES jcprops;
	IJLERR jerr;
	PBITMAPINFOHEADER pbhi;
	int imageSize  = 0;;
	int bufferSize = 0;
	int widthBytes = 0;
	LPBYTE  pbits  = NULL;

	if (src == NULL)
	{
		return JPEG_ERROR_INVALID_PARAM;
	}

	if ((jerr = ijlInit( &jcprops)) != IJL_OK)
	{
		return JPEG_ERROR_IJL_INIT;
	}

	jcprops.JPGBytes     = src;
	jcprops.JPGSizeBytes = 400;

	//Read JPEG parameters from the file
	if ((jerr = ijlRead(&jcprops, IJL_JBUFF_READPARAMS))  != IJL_OK)
	{
		ijlFree(&jcprops);
		return JPEG_ERROR_IJL_READ_PARAM;
	}	 	

	widthBytes = IJL_DIB_AWIDTH(jcprops.JPGWidth, jcprops.JPGChannels);
	imageSize = widthBytes * jcprops.JPGHeight;

	bufferSize = sizeof(BITMAPINFOHEADER) + imageSize;
	if ((pbi = (PBITMAPINFO)malloc(bufferSize)) == NULL)
	{
		ijlFree(&jcprops);
		return JPEG_ERROR_MEMORY_ALLOC;
	}

	pbhi = (PBITMAPINFOHEADER) pbi;

	pbhi->biSize         = sizeof(BITMAPINFOHEADER);
	pbhi->biPlanes       = 1;
	pbhi->biClrUsed      = 0;
	pbhi->biWidth        = jcprops.JPGWidth;
	pbhi->biHeight       = jcprops.JPGHeight;
	pbhi->biCompression  = BI_RGB;
	pbhi->biClrImportant = 0;
	pbhi->biBitCount     = 24;
	pbhi->biXPelsPerMeter= 0;
	pbhi->biYPelsPerMeter= 0;
	pbhi->biSizeImage    = imageSize;
	pbits = (LPBYTE)pbi + pbhi->biSize;


	//Set up the DIB specification for the JPEG decoder
	jcprops.DIBWidth    = jcprops.JPGWidth;
	jcprops.DIBHeight   = - jcprops.JPGHeight; //Implies a bottom-up DIB.
	jcprops.DIBChannels = 3; //jcprops.JPGChannels;	 //3????
	jcprops.DIBColor    = IJL_BGR;
	jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.JPGWidth, 3);
	jcprops.DIBBytes    = reinterpret_cast<BYTE*>(pbits);

	//Set the JPG color space ... this will always be somewhat of an
	//educated guess at best because JPEG is "color blind" (i.e.,
	//nothing in the bit stream tells you what color space the data was
	//encoded from. However, in this example we assume that we are
	//reading JFIF files which means that 3 channel images are in the
	//YCbCr color space and 1 channel images are in the Y color space.
	

    
	//jcprops.JPGColor = IJL_OTHER;
	jcprops.JPGSizeBytes = imageSize;
	jcprops.jquality   = 100;

	jerr = ijlRead(&jcprops, IJL_JBUFF_READWHOLEIMAGE);

  
	//Make sure the read was successful
	if (jerr != IJL_OK)
	{	
		return JPEG_ERROR_IJL_READ_DATA;
	}
	jerr=ijlFree(&jcprops);

	if (jerr != IJL_OK)
	{			
		return JPEG_ERROR_IJL_FREE;
	}
	return JPEG_SUCCESS;
}
#endif
*/


