float WINAPI GetPixelRatioInArea(int Color, int StartX, int StartY, int EndX, int EndY)
{
	FileDebug("Started CountPixelsInArea");
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return -1;
	}
	if (StartX == -1)
	{
		StartX = 0;
		StartY = 0;
		EndX = CurScreenshot->GetWidth();
		EndY = CurScreenshot->GetHeight();
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	int ret = 0;
	for (int y = StartY; y < EndY; y += 1)
		for (int x = StartX; x < EndX; x += 1)
			if (CurScreenshot->Pixels[y * Width + x] == Color)
				ret++;
	float AreaSize = (float)((EndX - StartX)*(EndY - StartY));
	FileDebug("Finished CountPixelsInArea");
	return ret * 100.0f / AreaSize;
}
void WINAPI SetGradientToColorRegion(int Color, float MaxChange, int NewColor, int StartX, int StartY, int EndX, int EndY)
{
	FileDebug("Started SetGradientToColorRegion");
	int R1 = GetRValue(Color);
	int G1 = GetGValue(Color);
	int B1 = GetBValue(Color);
	float RG1 = (float)R1 / (float)G1;
	float GB1 = (float)G1 / (float)B1;
	// human eye can distinguesh about 3db noise ( signal / noise ). We define a gradient to be the same if the expected value / real value is within this margin
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	for (int y = StartY; y < EndY; y += 1)
		for (int x = StartX; x < EndX; x += 1)
		{
			int Color = CurScreenshot->Pixels[y * Width + x];
			float B2 = GetRValue(Color);
			float G2 = GetGValue(Color);
			float R2 = GetBValue(Color);
			float RG2 = (float)R2 / (float)G2;
			float GB2 = (float)G2 / (float)B2;
			if (abs(RG2 - RG1) <= MaxChange && abs(GB2 - GB1) <= MaxChange)
				CurScreenshot->Pixels[y * Width + x] = NewColor;
		}
	FileDebug("Finished SetGradientToColorRegion");
}
void KeepColorRangeAndGradient(int Color, int MaxChange, int RMin, int RMax, int GMin, int GMax, int BMin, int BMax)
{
	FileDebug("Started KeepColorRange");
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	int R1 = GetRValue(Color);
	int G1 = GetGValue(Color);
	int B1 = GetBValue(Color);
	float RG1 = (float)R1 / (float)G1;
	float GB1 = (float)G1 / (float)B1;
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	for (int y = 0; y < CurScreenshot->GetHeight(); y += 1)
		for (int x = 0; x < CurScreenshot->GetWidth(); x += 1)
		{
			int Color = CurScreenshot->Pixels[y * Width + x];
			float B = GetRValue(Color);
			float G = GetGValue(Color);
			float R = GetBValue(Color);
			if (R >= RMin && R <= RMax && G >= GMin && G <= GMax && B >= BMin && B <= BMax)
			{
				float RG2 = (float)R / (float)G;
				float GB2 = (float)G / (float)B;
				if (abs(RG2 - RG1) > MaxChange || abs(GB2 - GB1) > MaxChange)
					CurScreenshot->Pixels[y * Width + x] = TRANSPARENT_COLOR;
//				else
//					CurScreenshot->Pixels[y * Width + x] = 0;
			}
			else
				CurScreenshot->Pixels[y * Width + x] = TRANSPARENT_COLOR;
		}
	FileDebug("Finished KeepColorRange");
}
void WINAPI ErodeNotInLine(int StartX, int StartY, int EndX, int EndY)
{
	FileDebug("Started ErodeNotInLine");
	// human eye can distinguesh about 3db noise ( signal / noise ). We define a gradient to be the same if the expected value / real value is within this margin
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	int *TempBuff = (int*)malloc(Width * CurScreenshot->GetHeight() * sizeof(int));
	memcpy(TempBuff, CurScreenshot->Pixels, Width * CurScreenshot->GetHeight() * sizeof(int));
	for (int y = StartY; y < EndY; y += 1)
		for (int x = StartX; x < EndX; x += 1)
		{
			int MiddlePixel = TempBuff[(y - 0) * Width + x - 0];
			//vert
			if (IsInLine(TempBuff[(y - 1) * Width + x - 0], MiddlePixel, TempBuff[(y + 1) * Width + x - 0]))
				continue;
			//hor
			if (IsInLine(TempBuff[(y - 0) * Width + x - 1], MiddlePixel, TempBuff[(y + 1) * Width + x + 1]))
				continue;
			if (IsInLine(TempBuff[(y - 1) * Width + x - 1], MiddlePixel, TempBuff[(y + 1) * Width + x + 1]))
				continue;
			if (IsInLine(TempBuff[(y - 1) * Width + x + 1], MiddlePixel, TempBuff[(y + 1) * Width + x - 1]))
				continue;
			CurScreenshot->Pixels[(y - 0) * Width + x - 0] = 0;
		}
	free(TempBuff);
	FileDebug("Finished ErodeNotInLine");
}
void WINAPI BlurrImage( int HalfKernelSize )
{
	FileDebug( "Started bluring screenshot" );
	if( CurScreenshot->Pixels == NULL )
	{
		FileDebug( "WARNING:Screenshot buffer is null when trying to blur it!" );
		return;
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	int Height = CurScreenshot->Bottom - CurScreenshot->Top;
	LPCOLORREF new_Pixels = (COLORREF*)_aligned_malloc( Width * Height * sizeof( COLORREF ) + SSE_PADDING, SSE_ALIGNMENT );
	if( new_Pixels == NULL )
	{
		FileDebug( "Error:Could not allocate buffer for blur!" );
		return;
	}

	if( HalfKernelSize == 1 )
	{
		//37 fps
		for( int y = 1; y < Height-1; y +=1 )
			for( int x = 1; x < Width-1; x += 1 )
			{
				int SumOfValuesRB = 0;
				int SumOfValuesG8 = 0;
				LPCOLORREF BoxStart = &CurScreenshot->Pixels[ y * Width + x ];
				for(int ky=-1;ky<=1;ky++)
					for(int kx=-1;kx<=1;kx++)
					{
						SumOfValuesRB += ( BoxStart[ ky * Width + kx ] & 0x00FF00FF );	//remove G and sum RB
						SumOfValuesG8 += ( BoxStart[ ky * Width + kx ] & 0x0000FF00);
					}
				int SumOfValuesR = ( SumOfValuesRB >> 0 ) & 0x0000FFFF;
				int SumOfValuesG = ( SumOfValuesG8 >> 8 ) & 0x0000FFFF;
				int SumOfValuesB = ( SumOfValuesRB >> 16 ) & 0x0000FFFF;
				new_Pixels[ y * Width + x ] = RGB( SumOfValuesR / 9, SumOfValuesG / 9, SumOfValuesB / 9 );
			}
			/**/
		//32 fps
/*		int CharWidth = Width * 4;
		for( int y = 1; y < Height-1; y +=1 )
			for( int x = 1; x < Width-1; x += 1 )
			{
				unsigned char *RowStart = (unsigned char *)&CurScreenshot->Pixels[ ( y - 1 ) * Width + x - 1 ];
				int SumOfValuesR = 0;
				int SumOfValuesG = 0;
				int SumOfValuesB = 0;
				for(int ky=0;ky<=2;ky++)
					for(int kx=0;kx<=2*4;kx+=4)
					{
						SumOfValuesR += RowStart[ ky * CharWidth + kx + 0 ];
						SumOfValuesG += RowStart[ ky * CharWidth + kx + 1 ];
						SumOfValuesB += RowStart[ ky * CharWidth + kx + 2 ];
					}
				new_Pixels[ y * Width + x ] = RGB( SumOfValuesR / 9, SumOfValuesG / 9, SumOfValuesB / 9 );
			} */
	}
	else
	{
void HistorygramInArea(int StartX, int StartY, int EndX, int EndY)
{
	FileDebug("Started HistorygramInArea");
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	if (StartX == -1)
	{
		StartX = 0;
		StartY = 0;
		EndX = CurScreenshot->GetWidth();
		EndY = CurScreenshot->GetHeight();
	}
	//create historygram
	std::map<int, int> Colors;
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	for (int y = StartY; y < EndY; y += 1)
		for (int x = StartX; x < EndX; x += 1)
			Colors[CurScreenshot->Pixels[y * Width + x]]++;

	std::map<int, int> Colors2;
	for (std::map<int, int>::iterator itr = Colors.begin(); itr != Colors.end(); itr++)
	{
		//get a unique key
		int key = itr->second * 1000;
		while (Colors2.find(key) != Colors2.end())
			key++;
		Colors2[key] = itr->first;
	}

	//print hystorygram
	for (std::map<int, int>::iterator itr = Colors2.begin(); itr != Colors2.end(); itr++)
	{
		int Color = itr->second;
		int Count = itr->first/1000;
		int B = GetRValue(Color);
		int G = GetGValue(Color);
		int R = GetBValue(Color);
		float RG = (float)(R) / (float)(G);
		float GB = (float)(G) / (float)(B);
		float RB = (float)(R) / (float)(B);
		printf("0x%X 0x%X %d %f %f %f %d %d %d\n", Color, STATIC_BGR_RGB(Color), Count, RG, GB, RB, R, G, B);
	}
	FileDebug("Finished HistorygramInArea");
	return;
}
void WINAPI TakeScreenshot( int aLeft, int aTop, int aRight, int aBottom )
{
	char TBuff[2000];
	sprintf_s(TBuff, sizeof(TBuff), "Started taking the screenshot [%d,%d][%d,%d]", aLeft, aTop, aRight, aBottom);
	FileDebug(TBuff);

	CycleScreenshots();
	ReleaseScreenshot();
	TakeNewScreenshot( aLeft, aTop, aRight, aBottom );

	FileDebug( "\tFinished taking the screenshot" );
//	if( CurScreenshot->Pixels == NULL )
//		FileDebug( "WARNING:Screenshot buffer is null when taking the screenshot!" );

	return ;
}
void WINAPI KeepGradientRegionMinValue(int Color, float MaxChange, int StartX, int StartY, int EndX, int EndY)
{
	FileDebug("Started KeepGradient");
	int R1 = GetRValue(Color);
	int G1 = GetGValue(Color);
	int B1 = GetBValue(Color);
	float RG1 = (float)R1 / (float)G1;
	float GB1 = (float)G1 / (float)B1;
	// human eye can distinguesh about 3db noise ( signal / noise ). We define a gradient to be the same if the expected value / real value is within this margin
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	for (int y = StartY; y < EndY; y += 1)
		for (int x = StartX; x < EndX; x += 1)
		{
			int Color = CurScreenshot->Pixels[y * Width + x];
			int B2 = GetRValue(Color);
			if (B1 > B2)
			{
				CurScreenshot->Pixels[y * Width + x] = TRANSPARENT_COLOR;
				continue;
			}
			int G2 = GetGValue(Color);
			if (G1 > G2)
			{
				CurScreenshot->Pixels[y * Width + x] = TRANSPARENT_COLOR;
				continue;
			}
			int R2 = GetBValue(Color);
			if (R1 > R2)
			{
				CurScreenshot->Pixels[y * Width + x] = TRANSPARENT_COLOR;
				continue;
			}
			float RG2 = (float)R2 / (float)G2;
			float GB2 = (float)G2 / (float)B2;
			if (abs(RG2 - RG1) > MaxChange || abs(GB2 - GB1) > MaxChange)
				CurScreenshot->Pixels[y * Width + x] = TRANSPARENT_COLOR;
			else
				CurScreenshot->Pixels[y * Width + x] = 0;
		}
	FileDebug("Finished KeepGradient");
}
void WINAPI KeepGradient3(int Color1, float MaxChange1, int Color2, float MaxChange2, int Color3, float MaxChange3)
{
	FileDebug("Started KeepGradient2");
	int R1 = GetRValue(Color1);
	int G1 = GetGValue(Color1);
	int B1 = GetBValue(Color1);
	float RG1 = (float)R1 / (float)G1;
	float GB1 = (float)G1 / (float)B1;
	int R2 = GetRValue(Color2);
	int G2 = GetGValue(Color2);
	int B2 = GetBValue(Color2);
	float RG2 = (float)R2 / (float)G2;
	float GB2 = (float)G2 / (float)B2;
	int R3 = GetRValue(Color3);
	int G3 = GetGValue(Color3);
	int B3 = GetBValue(Color3);
	float RG3 = (float)R3 / (float)G3;
	float GB3 = (float)G3 / (float)B3;
	// human eye can distinguesh about 3db noise ( signal / noise ). We define a gradient to be the same if the expected value / real value is within this margin
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	int StartX = 0;
	int StartY = 0;
	int EndX = CurScreenshot->GetWidth();
	int EndY = CurScreenshot->GetHeight();
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	for (int y = StartY; y < EndY; y += 1)
		for (int x = StartX; x < EndX; x += 1)
		{
			int Color = CurScreenshot->Pixels[y * Width + x];
			float B2 = GetRValue(Color);
			float G2 = GetGValue(Color);
			float R2 = GetBValue(Color);
			float RG = (float)R2 / (float)G2;
			float GB = (float)G2 / (float)B2;
			if (!(abs(RG2 - RG) > MaxChange2 || abs(GB2 - GB) > MaxChange2) && !(abs(RG - RG1) > MaxChange1 || abs(GB - GB1) > MaxChange1) && !(abs(RG - RG3) > MaxChange3 || abs(GB - GB3) > MaxChange3))
				CurScreenshot->Pixels[y * Width + x] = 0;
			else
				CurScreenshot->Pixels[y * Width + x] = TRANSPARENT_COLOR;
		}
	FileDebug("Finished KeepGradient2");

}
void WINAPI KeepColor3SetBoth(int SetRest, int SetColors, int Color1, int Color2, int Color3)
{
	FileDebug("Started KeepColor3SetBoth");
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract color!");
		return;
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	int Height = CurScreenshot->Bottom - CurScreenshot->Top;
	for (int y = 0; y < Height; y += 1)
		for (int x = 0; x < Width; x += 1)
			if (CurScreenshot->Pixels[y * Width + x] == Color1 || CurScreenshot->Pixels[y * Width + x] == Color2 || CurScreenshot->Pixels[y * Width + x] == Color3)
				CurScreenshot->Pixels[y * Width + x] = SetColors;
			else
				CurScreenshot->Pixels[y * Width + x] = SetRest;

	FileDebug("Finished KeepColor3SetBoth");
}
CachedPicture *CachePicture( char *aFilespec )
{
	FileDebug( "Started caching image" );
	int ExistingCacheIndex = GetCacheIndex( aFilespec );
	if( ExistingCacheIndex != -1 )
	{
		FileDebug( "Skipped caching image as it's already cached" );
		return &PictureCache[ExistingCacheIndex];
	}

	if( NrPicturesCached >= MAX_PICTURE_CACHE_COUNT )
	{
		FileDebug( "Skipped caching image as no more cache slots available" );
		return NULL; 
	}

	HDC hdc = GetDC(NULL);
	if (!hdc)
	{
		FileDebug( "Skipped caching image as failed to lock DC" );
		return NULL; 
	}

	strcpy_s( PictureCache[NrPicturesCached].FileName, DEFAULT_STR_BUFFER_SIZE, aFilespec );
	PictureCache[NrPicturesCached].NameHash = GetStrHash( aFilespec );

	int ImgType;
	PictureCache[NrPicturesCached].LoadedPicture = LoadPicture( aFilespec, 0, 0, ImgType, 0, false );
	if( PictureCache[NrPicturesCached].LoadedPicture == NULL )
	{
		FileDebug( "Skipped caching image as it could not be loaded" );
		ReleaseDC(NULL, hdc);
		return NULL;
	}

	bool image_is_16bit;
	LONG image_width, image_height;
	PictureCache[NrPicturesCached].Pixels = getbits( PictureCache[NrPicturesCached].LoadedPicture, hdc, image_width, image_height, image_is_16bit );
	if( PictureCache[NrPicturesCached].Pixels == NULL )
	{
		FileDebug( "Skipped caching image as it could not be converted to pixel map" );
		ReleaseDC(NULL, hdc);
		return NULL;
	}

	PictureCache[NrPicturesCached].Width = image_width;
	PictureCache[NrPicturesCached].Height = image_height;

	PictureCache[NrPicturesCached].NeedsPSCache = true;
	PictureCache[NrPicturesCached].NeedsSSCache = true;

	NrPicturesCached++;
	ReleaseDC(NULL, hdc);

	FileDebug( "\tFinished caching image" );

	return &PictureCache[NrPicturesCached-1];
}
void WINAPI RemoveIfHasStrongerNeighbours(int MinNeighbours, int StartX, int StartY, int EndX, int EndY)
{
	FileDebug("Started RemoveIfHasStrongerNeighbours");
	// human eye can distinguesh about 3db noise ( signal / noise ). We define a gradient to be the same if the expected value / real value is within this margin
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	for (int y = StartY; y < EndY; y += 1)
		for (int x = StartX; x < EndX; x += 1)
		{
			int Color = CurScreenshot->Pixels[y * Width + x];
			int B = GetRValue(Color);
			int G = GetGValue(Color);
			int R = GetBValue(Color);
			//int Sum = R + G + B;
			//check if it has stronger neighbours
			int StrongNeighbours = 0;
			for (int y2 = y - 1; y2 <= y + 1; y2++)
				for (int x2 = x - 1; x2 <= x + 1; x2++)
				{
					int Color2 = CurScreenshot->Pixels[y2 * Width + x2];
					int B2 = GetRValue(Color2);
					int G2 = GetGValue(Color2);
					int R2 = GetBValue(Color2);
					//int Sum2 = R2 + G2 + B2;
					//if (Sum2 > Sum)
					if (R2 > R || G2 > G || B2 > B)
					{
						StrongNeighbours++;
						if (StrongNeighbours >= MinNeighbours)
						{
							CurScreenshot->Pixels[y * Width + x] = 0;
							goto ELIMINATED_WEAK_PIXEL;
						}
					}
				}
		ELIMINATED_WEAK_PIXEL:;
		}
	FileDebug("Finished RemoveIfHasStrongerNeighbours");
}
void WINAPI ErodeOnEdgeNeighbours(int EdgeStrength, int StartX, int StartY, int EndX, int EndY)
{
	FileDebug("Started ErodeOnEdgeNeighbours");
	// human eye can distinguesh about 3db noise ( signal / noise ). We define a gradient to be the same if the expected value / real value is within this margin
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	int *TempBuff = (int*)malloc(Width * CurScreenshot->GetHeight() * sizeof(int));
	memcpy(TempBuff, CurScreenshot->Pixels, Width * CurScreenshot->GetHeight() * sizeof(int));
	for (int y = StartY; y < EndY; y += 1)
		for (int x = StartX; x < EndX; x += 1)
		{
			int Color = TempBuff[y * Width + x];
			int B = GetRValue(Color);
			int G = GetGValue(Color);
			int R = GetBValue(Color);
			int Sum = R + G + B;
			//check if it has stronger neighbours
			int StrongNeighbours = 0;
			for (int y2 = y - 1; y2 <= y + 1; y2++)
				for (int x2 = x - 1; x2 <= x + 1; x2++)
				{
					int Color2 = TempBuff[y2 * Width + x2];
					int B2 = GetRValue(Color2);
					int G2 = GetGValue(Color2);
					int R2 = GetBValue(Color2);
					int Sum2 = R2 + G2 + B2;
					if (abs(Sum2 - Sum) > EdgeStrength )
					{
						CurScreenshot->Pixels[y * Width + x] = 0;
						goto ELIMINATED_WEAK_PIXEL;

					}
				}
		ELIMINATED_WEAK_PIXEL:;
		}
	free(TempBuff);
	FileDebug("Finished ErodeOnEdgeNeighbours");
}
char* WINAPI GetImageSize( char *aImageFile )
{
	CachedPicture *cache = CachePicture( aImageFile );
	if( cache == NULL )
	{
		FileDebug( "Skipping Image info as image could not be loaded" );
		return "0|0";
	}
	if( cache->Pixels == NULL )
	{
		FileDebug( "Skipping Image info as image pixels are missing" );
		return "0|0";
	}
	if( cache->LoadedPicture == NULL )
	{
		FileDebug( "Skipping Image info as image is missing" );
		return "0|0";
	}

	sprintf_s( ReturnBuff, DEFAULT_STR_BUFFER_SIZE*10, "%d|%d", cache->Width, cache->Height );

	return ReturnBuff;
}
void CheckPrepareToleranceMaps( CachedPicture *cache, int NewTolerance, int TransparentColor )
{
	if( cache == NULL )
		return;

	if( NewTolerance == cache->MinMaxMapTolerance && TransparentColor == cache->TransparentColor )
		return;

	FileDebug( "Generating tolerance map" );

	cache->MinMaxMapTolerance = NewTolerance;
	cache->TransparentColor = TransparentColor;

	if( cache->MinMap[0] == NULL )
	{
		for( int i = 0;i<3;i++)
		{
			cache->MinMap[i] = (unsigned char *)_aligned_malloc( cache->Width * cache->Height + SSE_PADDING, SSE_ALIGNMENT );
			cache->MaxMap[i] = (unsigned char *)_aligned_malloc( cache->Width * cache->Height + SSE_PADDING, SSE_ALIGNMENT );
		}
	}

	for( int y = 0; y < cache->Height; y +=1 )
		for( int x = 0; x < cache->Width; x += 1 )
		{
			if( ( cache->Pixels[ y * cache->Width + x ] & 0x00FFFFFF ) == TransparentColor )
			{
				for( int i=0;i<3;i++)
				{
					cache->MinMap[i][ y * cache->Width + x ] = 0;
					cache->MaxMap[i][ y * cache->Width + x ] = 255;
				}
			}
			else
			{
				for( int i=0;i<3;i++)
				{
					int col = ( ((int)cache->Pixels[ y * cache->Width + x ]) >> ( i * 8 ) ) & 0xFF;
					int min = (int)col - NewTolerance;
					int max = (int)col + NewTolerance;
					if( min < 0 )
						min = 0;
					if( max > 255 )
						max = 255;
					cache->MinMap[i][ y * cache->Width + x ] = min;
					cache->MaxMap[i][ y * cache->Width + x ] = max;
				}
			}
		}
}
void KeepColorRange(int RMin, int RMax, int GMin, int GMax, int BMin, int BMax)
{
	FileDebug("Started KeepColorRange");
	if (CurScreenshot->Pixels == NULL)
	{
		FileDebug("WARNING:Screenshot buffer is null when trying to extract gradient!");
		return;
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
	for (int y = 0; y < CurScreenshot->GetHeight(); y += 1)
		for (int x = 0; x < CurScreenshot->GetWidth(); x += 1)
		{
			int Color = CurScreenshot->Pixels[y * Width + x];
			float B = GetRValue(Color);
			float G = GetGValue(Color);
			float R = GetBValue(Color);
			if (R >= RMin && R <= RMax && G >= GMin && G <= GMax && B >= BMin && B <= BMax)
				CurScreenshot->Pixels[y * Width + x] = 0;
			else
				CurScreenshot->Pixels[y * Width + x] = TRANSPARENT_COLOR;
		}
	FileDebug("Finished KeepColorRange");
}
void WINAPI MoveScreenshotToCache( char *Name )
{
	if( CurScreenshot->Pixels == NULL )
	{
		FileDebug( "Can not move screenshot to cache because there are no screenshots" );
		return;
	}


	if( NrPicturesCached >= MAX_PICTURE_CACHE_COUNT )
	{
		FileDebug( "Skipped caching image as no more cache slots available" );
		return; 
	}

	FileDebug( "Started caching screenshot" );

	strcpy_s( PictureCache[NrPicturesCached].FileName, DEFAULT_STR_BUFFER_SIZE, Name );
	PictureCache[NrPicturesCached].NameHash = GetStrHash( Name );

	PictureCache[ NrPicturesCached ].LoadedPicture = NULL;

	int PixelsByteSize = CurScreenshot->GetWidth() * CurScreenshot->GetHeight() * sizeof( COLORREF );
	PictureCache[ NrPicturesCached ].Pixels = (LPCOLORREF) _aligned_malloc( PixelsByteSize, SSE_ALIGNMENT );
	memcpy(	PictureCache[ NrPicturesCached ].Pixels, CurScreenshot->Pixels, PixelsByteSize );

	PictureCache[ NrPicturesCached ].Width = CurScreenshot->GetWidth();
	PictureCache[ NrPicturesCached ].Height = CurScreenshot->GetHeight();

	PictureCache[NrPicturesCached].NeedsPSCache = true;
	PictureCache[NrPicturesCached].NeedsSSCache = true;

	NrPicturesCached++;

	FileDebug( "\tFinished caching screenshot" );
}
char* WINAPI IsAnythingChanced( int StartX, int StartY, int EndX, int EndY )
{
	FileDebug( "Started IsAnythingChanced" );
	ReturnBuffIAC[0] = 0;
	if( CurScreenshot->Pixels == NULL )
	{
		FileDebug( "Skipping change search as no screenshot is available" );
		return "0|0|0";
	}
	// probably too lazy to set cords, reuse from previous screenshot
	if (StartX == EndX || StartY == EndY)
	{
		// take the screenshot
		TakeScreenshot(CurScreenshot->Left, CurScreenshot->Top, CurScreenshot->Right, CurScreenshot->Bottom);
	}
	if (PrevScreenshot == NULL || PrevScreenshot->Pixels == NULL)
	{
		FileDebug( "Skipping change search as no secondary screenshot is available" );
		return "0|0|0";
	}
	if( CurScreenshot->Left != PrevScreenshot->Left || CurScreenshot->Right != PrevScreenshot->Right || CurScreenshot->Top != PrevScreenshot->Top || CurScreenshot->Bottom != PrevScreenshot->Bottom )
	{
		FileDebug( "Screenshots were not taken from same place. Can't compare" );
		return "0|0|0";
	}
	if( StartY > EndY || StartX > EndX )
	{
		FileDebug( "Third / Fourth parameter does not seem to be width / height" );
		return "0|0|0";
	}
	int Width = CurScreenshot->Right - CurScreenshot->Left;
//	int Height = CurScreenshot->Bottom - CurScreenshot->Top;
	for( int y = StartY; y < EndY; y++ )
		for( int x = StartX; x < EndX; x++ )
			if( CurScreenshot->Pixels[ y * Width + x ] != PrevScreenshot->Pixels[ y * Width + x ] )
			{
				sprintf_s( ReturnBuffIAC, DEFAULT_STR_BUFFER_SIZE*10, "1|%d|%d", x, y );
				FileDebug( ReturnBuffIAC );
				return ReturnBuffIAC;
			}
	FileDebug( "\tEnd IsAnythingChanced" );
	return "0|0|0";
}
void TakeNewScreenshot( int aLeft, int aTop, int aRight, int aBottom )
{
	if( CurScreenshot->Pixels != NULL )
	{
		FileDebug( "Can not take screenshot as older one was not yet released." );
		return;
	}
	CurScreenshot->Left = aLeft;
	CurScreenshot->Top = aTop;
	CurScreenshot->Right = aRight;
	CurScreenshot->Bottom = aBottom;
	CurScreenshot->NeedsSSCache = true;
	CurScreenshot->NeedsPSCache = true;
	CurScreenshot->NeedsAlphaRemoved = true;
	CurScreenshot->NeedsSplitChannelCache = true;
	CurScreenshot->BytesPerPixel = 4;

	HDC sdc = NULL;
	HBITMAP hbitmap_screen = NULL;
	HGDIOBJ sdc_orig_select = NULL;
	COLORREF trans_color = CLR_NONE; // The default must be a value that can't occur naturally in an image.
    
	// Create an empty bitmap to hold all the pixels currently visible on the screen that lie within the search area:
	int search_width = aRight - aLeft;
	int search_height = aBottom - aTop;

	int MaxWidth, MaxHeight;
	GetMaxDesktopResolution( &MaxWidth, &MaxHeight );
	if( aLeft + search_width > MaxWidth )
		search_width = MaxWidth - aLeft;
	if( aTop + search_height > MaxHeight )
		search_height = MaxHeight - aTop;

	//make sure we did not capture more than we could. Avoid illegal memory read errors on bad screenshot params
	if( CurScreenshot->Right - CurScreenshot->Left > search_width )
		CurScreenshot->Right = CurScreenshot->Left + search_width;
	if( CurScreenshot->Bottom - CurScreenshot->Top > search_height )
		CurScreenshot->Bottom = CurScreenshot->Top + search_height;

	HDC hdc = GetDC(NULL);
	if( !hdc )
	{
		return;
	}

	sdc = CreateCompatibleDC(hdc);
	if( !sdc )
		goto end;

	hbitmap_screen = CreateCompatibleBitmap(hdc, search_width, search_height);
	if( !hbitmap_screen )
		goto end;

	sdc_orig_select = SelectObject(sdc, hbitmap_screen);
	if( !sdc_orig_select )
		goto end;

	// Copy the pixels in the search-area of the screen into the DC to be searched:
	if( !(BitBlt(sdc, 0, 0, search_width, search_height, hdc, aLeft, aTop, SRCCOPY)) )
		goto end;

	LONG screen_width, screen_height;
	bool screen_is_16bit;
	CurScreenshot->Pixels = getbits(hbitmap_screen, sdc, screen_width, screen_height, screen_is_16bit);
	if( !CurScreenshot->Pixels )
		goto end;

	LONG Pixels_count = screen_width * screen_height;

	// If either is 16-bit, convert *both* to the 16-bit-compatible 32-bit format:
	if( screen_is_16bit )
	{
		if (trans_color != CLR_NONE)
			trans_color &= 0x00F8F8F8; // Convert indicated trans-color to be compatible with the conversion below.
		for (int i = 0; i < Pixels_count; ++i)
			CurScreenshot->Pixels[i] &= 0x00F8F8F8; // Highest order byte must be masked to zero for consistency with use of 0x00FFFFFF below.
	}

end:
	// If found==false when execution reaches here, ErrorLevel is already set to the right value, so just
	// clean up then return.
	ReleaseDC(NULL, hdc);
	if (sdc)
	{
		if (sdc_orig_select) // i.e. the original call to SelectObject() didn't fail.
			SelectObject(sdc, sdc_orig_select); // Probably necessary to prevent memory leak.
		DeleteDC(sdc);
	}
	if (hbitmap_screen)
		DeleteObject(hbitmap_screen);
}
void WINAPI KeepGradient(int Color, float MaxChange)
{
	FileDebug("Started KeepGradient");
	KeepGradientRegion(Color, MaxChange, 0, 0, CurScreenshot->GetWidth(), CurScreenshot->GetHeight());
	FileDebug("Finished KeepGradient");
}
void WINAPI SetGradientToColor(int Color, float MaxChange, int NewColor)
{
	FileDebug("Started SetGradientToColor");
	SetGradientToColorRegion(Color, MaxChange, NewColor, 0, 0, CurScreenshot->GetWidth(), CurScreenshot->GetHeight());
	FileDebug("Finished SetGradientToColor");
}