#include <windows.h>
#include "ijl.h"//add ijl15.lib to Project -Settings -Link
#include <stdio.h>//for sprintf
#include "resource.h"
#define FULL 0
#define HALF 1
#define QUARTER 2

int CmdLineLen, Next;
char CmdLine[9000];
char Start[3];
BOOL gotsize = FALSE;

int x, y, Files = 0, ptr, FilenameStart = 0, Width, Height, padBytes, Resolution, Response, Quality = 90;
int FilenamePtr[100];
DWORD fileSize, OutFileSize, dwBytesRead, dwBytesWritten;
char Filename[MAX_PATH];
char ShortFilename[MAX_PATH];
char OutFile[MAX_PATH];
char ShortOutFile[MAX_PATH];
char JFile[1000];
char Directory[MAX_PATH];
char ErrorMsg[200];
BYTE *Buf, *pixel_buf;
HWND hwnd, hDlgModeless = NULL, hwndDlg;
HINSTANCE hInst;
HANDLE hFile, hFile2;
HCURSOR hCursor, hWaitingCursor;
OPENFILENAME ofn;
HDC hdcMem, hdc;
HBITMAP hBitmap;
PAINTSTRUCT ps;
RECT rect;
HGDIOBJ hObject;
BITMAPINFO bmi, *pbmi = &bmi;
BITMAPINFOHEADER bmih, *pbmih = &bmih;
JPEG_CORE_PROPERTIES jcprops;
IJLERR jerr;
WIN32_FIND_DATA fd;

char Version[] = "Version 1.3 by Doug Cox Dec 29, 2006";

int CALLBACK SizeProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
int CALLBACK QualityProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	MSG          msg;
	WNDCLASS     wndclass;
	char szAppName[] = "ReducePhotoSize";
	hInst = hInstance;

	wndclass.style         = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc   = WndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass (&wndclass))
		return 0;

	if (szCmdLine[0] != 0)
	{
		for (x = 0, CmdLineLen = 0; szCmdLine[x] != 0; x++)
			if (szCmdLine[x] != '"')
				CmdLine[CmdLineLen++] = szCmdLine[x];
		CmdLine[CmdLineLen] = 0;
	}

	hwnd = CreateWindow (szAppName, szAppName,
		WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
//		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
//		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		0,0,0,0,
		NULL, NULL, hInstance, NULL);

	ShowWindow (hwnd, iCmdShow);
	UpdateWindow (hwnd);

	while (GetMessage (&msg, NULL, 0, 0))
	{
//		if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))
		{
			TranslateMessage (&msg);
			DispatchMessage (&msg);
		}
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_CREATE:
		Start[0] = CmdLine[0];
		Start[1] = CmdLine[1];
		Start[2] = CmdLine[2];
		ptr = 0;

		if (CmdLineLen == 0)
		{
			ofn.lpstrFile         = JFile;
			ofn.lStructSize       = sizeof(OPENFILENAME);
			ofn.hwndOwner         = hwnd;
			ofn.hInstance         = hInst;
			ofn.lpstrFilter       = "*.jpg\x0*.jpg\x0\x0";
			ofn.lpstrCustomFilter = NULL;
			ofn.nMaxCustFilter    = 0;
			ofn.nFilterIndex      = 0;
			ofn.nMaxFile          = 1000;
			ofn.lpstrFileTitle    = ShortFilename;
			ofn.nMaxFileTitle     = MAX_PATH;
			ofn.lpstrInitialDir   = Directory;
			ofn.lpstrTitle        = "Select file[s]";
			ofn.Flags             = OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_ALLOWMULTISELECT|OFN_EXPLORER;
			ofn.nFileOffset       = 0;
			ofn.nFileExtension    = 0;
			ofn.lpstrDefExt       = "jpg";
			ofn.lCustData         = 0;
			ofn.lpfnHook          = NULL;
			ofn.lpTemplateName    = NULL;
			ofn.lpstrDefExt       =".jpg";

			if (0 == GetOpenFileName(&ofn))
			{
				SendMessage(hwnd, WM_DESTROY, 0, 0);
				return 0;
			}
			
			for (x = 0; (JFile[x] != 0) || (JFile[x+1] != 0); x++)
			{
				if (Files == 0)
					Filename[x] = JFile[x];
				if (JFile[x] == 0)
				{
					if (Files == 0)
						FilenameStart = x;
					FilenamePtr[Files] = x+1;
					Files++;
				}
			}
			if (Files == 0)
				Files = 1;
			for (ptr = 0 ; Files > 0; Files--, ptr++)
			{
				if (FilenameStart != 0)
				{
					y = FilenameStart;
					Filename[y++] = '\\';
					for (x = FilenamePtr[ptr]; JFile[x] != 0; x++, y++)
						Filename[y] = JFile[x];
					Filename[y] = 0;
				}
				hFile = CreateFile(Filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
				if (hFile != INVALID_HANDLE_VALUE)
					fileSize = GetFileSize(hFile, NULL);
				else
				{
					FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ErrorMsg, 200, NULL);
					MessageBox(hwnd, ErrorMsg, ERROR, MB_OK);
					return 0;
				}
				if (fileSize == 0)
				{
					MessageBox(hwnd, "File is empty", NULL, MB_OK);
					SendMessage(hwnd, WM_DESTROY, 0, 0);
					return 0;
				}
				else
				{
					Buf = (BYTE*)VirtualAlloc(NULL, fileSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
					ReadFile(hFile, Buf, fileSize, &dwBytesRead, NULL) ;
					if ((Buf[0] != 0xFF) || (Buf[1] != 0xD8) || (Buf[2] != 0xFF))
					{//if not a jpeg file
						VirtualFree(Buf, 0, MEM_RELEASE);
						MessageBox(hwnd, "That's not a jpeg file.", ERROR, MB_OK);
						DestroyWindow(hwnd);
						return 0;
					}

					if (FALSE == DialogBox(hInst, "SIZE", NULL, SizeProc))
					{
						VirtualFree(Buf, 0, MEM_RELEASE);
						ijlFree(&jcprops);
						DestroyWindow(hwnd);
						return 0;
					}
				}
				CloseHandle(hFile);

				for (x = 0, y = 0; (Filename[x] != '.') && (Filename[x] != 0); x++, y++)
					OutFile[y] = Filename[x];
				OutFile[y++] = 'X';
				for ( ; Filename[x] != 0; x++, y++)
					OutFile[y] = Filename[x];
				OutFile[y] = 0;

				for (x = 0, y = 0; ShortFilename[x] != '.'; x++, y++)
					ShortOutFile[y] = ShortFilename[x];
				ShortOutFile[y++] = 'X';
				for ( ; ShortFilename[x] != 0; x++, y++)
					ShortOutFile[y] = ShortFilename[x];
				ShortOutFile[y] = 0;
				Buf = (BYTE*)VirtualAlloc(NULL, (Width + padBytes) * Height * 3, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
retry:
				Response = DialogBox(hInst, "QUALITY", hwnd, QualityProc);
				if (Response == 96)
					goto retry;
				if (Response != 69)
				{
					if (Response)
					{
						hFile = CreateFile(OutFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
						if (hFile != INVALID_HANDLE_VALUE)
						{
							WriteFile(hFile, Buf, OutFileSize, &dwBytesWritten, NULL);
							SetFileTime(hFile, NULL, NULL, &fd.ftLastWriteTime);
						}
						CloseHandle(hFile);
					}
					else
						goto retry;
				}
				VirtualFree(Buf, 0, MEM_RELEASE);
				VirtualFree(pixel_buf, 0, MEM_RELEASE);
			}
		}
		else
		while (ptr < CmdLineLen)
		{
			for (Next = ptr+1; Next < CmdLineLen; Next++)
			{
				if ((CmdLine[Next] == Start[0]) && (CmdLine[Next+1] == Start[1]) && (CmdLine[Next+2] == Start[2]))
				{
					CmdLine[Next-1] = 0;//end of that filename
					break;
				}
			}
			hFile = CreateFile(&CmdLine[ptr], GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
			fileSize = GetFileSize(hFile, NULL);
			if (fileSize)
			{
				Buf = (BYTE*)VirtualAlloc(NULL, fileSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
				ReadFile(hFile, Buf, fileSize, &dwBytesRead, NULL) ;
				if ((Buf[0] != 0xFF) || (Buf[1] != 0xD8) || (Buf[2] != 0xFF))
				{//if not a jpeg file
					VirtualFree(Buf, 0, MEM_RELEASE);
					CloseHandle(hFile);
					MessageBox(hwnd, "That's not a jpeg file.", ERROR, MB_OK);
					DestroyWindow(hwnd);
					return 0;
				}
//				hDlgModeless = CreateDialog(hInst, "SIZE", hwnd, SizeProc);

				if (FALSE == DialogBox(hInst, "SIZE", NULL, SizeProc))
				{
					CloseHandle(hFile);
					VirtualFree(Buf, 0, MEM_RELEASE);
					ijlFree(&jcprops);
					DestroyWindow(hwnd);
					return 0;
				}
			}
			else
			{
				ptr = Next;
				CloseHandle(hFile);
				continue;
			}
			CloseHandle(hFile);

			for (x = ptr, y = 0; (CmdLine[x] != '.') && (CmdLine[x] != 0); x++, y++)
				OutFile[y] = CmdLine[x];
			OutFile[y++] = 'X';
			for ( ; CmdLine[x] != 0; x++, y++)
				OutFile[y] = CmdLine[x];
			OutFile[y] = 0;

			for ( ; (OutFile[y] != '\\') && (y); y--)
				;
			if (y)
				y++;
			for (x = 0; (OutFile[y] != '.') && (OutFile[y] != 0); x++, y++)
				ShortOutFile[x] = OutFile[y];
			ShortOutFile[x++] = 'X';
			for ( ; OutFile[y] != 0; x++, y++)
				ShortOutFile[x] = OutFile[y];
			ShortOutFile[x] = 0;

			Buf = (BYTE*)VirtualAlloc(NULL, (Width + padBytes) * Height * 3, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
retry2:
			Response = DialogBox(hInst, "QUALITY", hwnd, QualityProc);
			if (Response == 96)
				goto retry2;
			if (Response != 69)
			{
				if (Response)
				{
					hFile = CreateFile(OutFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
					if (hFile != INVALID_HANDLE_VALUE)
					{
						WriteFile(hFile, Buf, OutFileSize, &dwBytesWritten, NULL);
						SetFileTime(hFile, NULL, NULL, &fd.ftLastWriteTime);
					}
					CloseHandle(hFile);
				}
				else
					goto retry2;
			}
			VirtualFree(Buf, 0, MEM_RELEASE);
			VirtualFree(pixel_buf, 0, MEM_RELEASE);
			ptr = Next;
		}//end of while (TRUE)
		DestroyWindow(hwnd);
		return 0;

	case WM_DESTROY:
//		DestroyWindow(hwndDlg);
//		hDlgModeless = NULL;
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc (hwnd, message, wParam, lParam);
}

int CALLBACK SizeProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	char Res[50];
	static HWND hwndFull, hwndHalf, hwndQuarter;

	switch (message)
	{
	case WM_INITDIALOG:
		hWaitingCursor = LoadCursor(NULL, IDC_WAIT);
		jerr = ijlInit (&jcprops);//use Intel's ijl15.dll to convert JPEG files
		jcprops.JPGBytes = Buf;//source
		jcprops.JPGSizeBytes = fileSize;
		jcprops.JPGFile = NULL;
		jerr = ijlRead(&jcprops, IJL_JBUFF_READPARAMS);
		Width = jcprops.JPGWidth;
		Height = jcprops.JPGHeight;

		hwndFull = GetDlgItem(hwndDlg, IDC_RADIO1);
		hwndHalf = GetDlgItem(hwndDlg, IDC_RADIO2);
		hwndQuarter = GetDlgItem(hwndDlg, IDC_RADIO3);
		sprintf(Res, "%d by %d", Width, Height);
		SetWindowText(hwndFull, Res);
		sprintf(Res, "%d by %d", Width/2, Height/2);
		SetWindowText(hwndHalf, Res);
		sprintf(Res, "%d by %d", Width/4, Height/4);
		SetWindowText(hwndQuarter, Res);
		if (Resolution == FULL)
			CheckRadioButton(hwndDlg, IDC_RADIO1, IDC_RADIO3, IDC_RADIO1);
		else if (Resolution == HALF)
			CheckRadioButton(hwndDlg, IDC_RADIO1, IDC_RADIO3, IDC_RADIO2);
		else if (Resolution == QUARTER)
			CheckRadioButton(hwndDlg, IDC_RADIO1, IDC_RADIO3, IDC_RADIO3);
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDC_RADIO1:
			Resolution = FULL;
			break;
		case IDC_RADIO2:
			Resolution = HALF;
			break;
		case IDC_RADIO3:
			Resolution = QUARTER;
			break;
		case IDOK:
			if (Resolution == HALF)
			{
				Width /= 2;
				Height /= 2;
			}
			else if (Resolution == QUARTER)
			{
				Width /= 4;
				Height /= 4;
			}

			SetCursor(hWaitingCursor);
			jcprops.DIBWidth = Width;
			jcprops.DIBHeight = Height;
			padBytes = IJL_DIB_PAD_BYTES(Width, 3);
			jcprops.DIBPadBytes = padBytes;
			pixel_buf = (BYTE*)VirtualAlloc(NULL, (Width + jcprops.DIBPadBytes) * Height * 3, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
			jcprops.DIBBytes = pixel_buf;//destination
			jcprops.DIBChannels = 3;
			jcprops.DIBColor = IJL_BGR;
			if (Resolution == FULL)
				jerr = ijlRead (&jcprops, IJL_JBUFF_READWHOLEIMAGE);
			else if (Resolution == HALF)
				jerr = ijlRead (&jcprops, IJL_JBUFF_READONEHALF);
			else
				jerr = ijlRead (&jcprops, IJL_JBUFF_READONEQUARTER);
			ijlFree(&jcprops);
			VirtualFree(Buf, 0, MEM_RELEASE);

			bmih.biSize = sizeof(BITMAPINFOHEADER);
			bmih.biWidth = Width;
			bmih.biHeight = -(Height);// - for right-side-up picture
			bmih.biPlanes = 1;
			bmih.biBitCount = 24;
			bmih.biCompression = BI_RGB;
			bmih.biSizeImage = 0;
			bmih.biXPelsPerMeter = 0;
			bmih.biYPelsPerMeter = 0;
			bmih.biClrUsed = 0;
			bmih.biClrImportant = 0;
			bmi.bmiHeader = *pbmih;
			SetCursor(hCursor);

			EndDialog (hwndDlg, TRUE);
			return TRUE;
			break;
		case IDCANCEL:
			EndDialog (hwndDlg, FALSE);
			return FALSE;
		}
	}
	return FALSE;
}

int CALLBACK QualityProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	int x;
	char asdf[10];
	char fdsa[15];
	static HWND hwndQuality, hwndInputSize, hwndOutputSize;

	switch (message)
	{
	case WM_INITDIALOG:
		SetCursor(hWaitingCursor);
		jerr = ijlInit (&jcprops);//use Intel's ijl15.dll to convert JPEG files
		jcprops.DIBWidth = Width;
		jcprops.DIBHeight = Height;
		jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(Width, 3);
		jcprops.DIBChannels = 3;
		jcprops.DIBColor = IJL_BGR;
		jcprops.DIBBytes = pixel_buf;//input buffer
		jcprops.JPGColor = IJL_YCBCR;
		jcprops.JPGWidth = Width;
		jcprops.JPGHeight = Height;
		jcprops.jquality = Quality;
		jcprops.JPGSubsampling = IJL_422; // 4:2:2 subsampling.
		jcprops.JPGBytes = Buf;//output buffer
		jcprops.JPGSizeBytes = (Width + padBytes) * Height * 3;//estimate
		jcprops.JPGFile = NULL;
		jerr = ijlWrite(&jcprops,IJL_JBUFF_WRITEWHOLEIMAGE);
		OutFileSize = jcprops.JPGSizeBytes;//re-computed by ijl15.dll
		ijlFree(&jcprops);
		SetCursor(hCursor);

		sprintf(fdsa, "%i by %i", Width, Height);
		SetWindowText(GetDlgItem(hwndDlg, IDC_EDIT4), fdsa);
		hwndQuality = GetDlgItem(hwndDlg, IDC_EDIT1);
		hwndInputSize = GetDlgItem(hwndDlg, IDC_EDIT2);
		hwndOutputSize = GetDlgItem(hwndDlg, IDC_EDIT3);
		_itoa(Quality, asdf, 10);
		SetWindowText(hwndQuality, asdf);
		_itoa(fileSize/1024, asdf, 10);
		for (x = 0; asdf[x] != 0; x++)
			;
		asdf[x++] = ' ';
		asdf[x++] = 'K';
		asdf[x++] = 'B';
		asdf[x++] = 0;
		SetWindowText(hwndInputSize, asdf);
		_itoa(OutFileSize/1024, asdf, 10);
		for (x = 0; asdf[x] != 0; x++)
			;
		asdf[x++] = ' ';
		asdf[x++] = 'K';
		asdf[x++] = 'B';
		asdf[x++] = 0;
		SetWindowText(hwndOutputSize, asdf);
		SetWindowText(GetDlgItem(hwndDlg, IDC_EDIT5), ShortOutFile);
		SetFocus(hwndQuality);
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK://Continue
			GetWindowText(hwndQuality, asdf, 10);
			x = atoi(asdf);
			if (x != Quality)
			{
				Quality = x;
				x = 96;
			}
			else
				x = TRUE;
			EndDialog (hwndDlg, x);
			return TRUE;

		case IDC_BUTTON1://Retry with new JPEG quality
			GetWindowText(hwndQuality, asdf, 10);
			Quality = atoi(asdf);
			EndDialog (hwndDlg, FALSE);
			return FALSE;

		case IDCANCEL:
			EndDialog (hwndDlg, 69);
			return 69;
		}
	}
	return FALSE;
}
