#include "image.h"
#include<stdio.h>
#include<math.h>
#include<string.h>


#define Round(x) floor((x)+.5f);

// >>>>>>>>>>>>>>>>>>>> Histogram Members 

Histogram::Histogram()
{
}

void Histogram::Clear()
{
for(int i=0;i<256;i++) Data[i]=0;
Peak=0;
}

Histogram::Histogram(Image &img,RMETHOD rmet)
{
Histogram();
img.FillHistogram(this,rmet);
}
	
int Histogram::GetBottom(float per)
{
int lowcut=(int)(per*.01*Peak);
int i;
for(i=0;i<256;i++) if (Data[i]>lowcut) return i;
STOP(("Invalid Histogram"));
return 0;
}

int Histogram::GetTop(float per)
{
int lowcut=(int)(per*.01*Peak);
for(int i=255;i>=0;i--) if (Data[i]>lowcut) return i;
STOP(("Invalid Histogram"));
return 255;
}

Histogram::~Histogram()
{
}



RGBHistogram::RGBHistogram(Image &img)
{
img.FillHistogram(this);
}

void RGBHistogram::Clear()
{
RHist.Clear();
GHist.Clear();
BHist.Clear();
}

ImgRGBColor RGBHistogram::GetBottom(float per)
{
ImgRGBColor col;
col.r=RHist.GetBottom(per);
col.g=GHist.GetBottom(per);
col.b=BHist.GetBottom(per);
col.a=0;
return col;
}

ImgRGBColor RGBHistogram::GetTop(float per)
{
ImgRGBColor col;
col.r=RHist.GetTop(per);
col.g=GHist.GetTop(per);
col.b=BHist.GetTop(per);
col.a=255;
return col;
}

// >>>>>>>>>>>>>>>>>>>> Image Members 


Image::Image(char *Str)
{
	Init();
	Load(Str);
}

Image::Image(Image &img)
{
	Init();
	*this=img;
}

void Image::Init()
{
	strcpy(fname,"");
	Data=NULL;
	xpos=ypos=vxlen=vylen=LockStack=Pitch=Bpp=xlen=ylen=0;
	itype=ITYPE_RGB;
	pal=NULL;
	Mask.Set(0x00ff0000,0x0000ff00,0x000000ff,0) ;
}  

Image::Image() { Init(); }

Image::Image(int xl,int yl)
{
	Init();
	CreateBlank(xl,yl);
}

Image::Image(int xl,int yl,ImgRGBColor col)
{
	Init();
	CreateSolid(xl,yl,col);
}

Image::~Image() { Delete(); }

ImgRGBColor Image::GetColor(Point &p)
{
	if(p.x>=xlen || p.y>=ylen) return ImgRGBColor(0,0,0);
	ImgRGBColor trgb;
	RGBPixel *tptr;
	BYTE *bp=Lock();
	tptr=(RGBPixel *)(bp+ ((p.x+p.y*xlen)*(Bpp>>3)));
	trgb.Set(*tptr,Mask);
	UnLock();
	return trgb;
}

// >>>>>>>>>>>>>>>>>>>>>>>> Internals
void Image::IAlloc()
{
	if(IsData()) IFree();
	Pitch=xlen*(Bpp>>3);
	BYTE *dt=new BYTE[ylen*Pitch+4];
	if(dt==NULL)
	  GENFERR("Not Enough Memory to Create Image");
		
	Data=dt;
	Flag|=IMG_ISDATA;
}

void Image::SetData(BYTE *dt)
{
	int y,axl=xlen*(Bpp>>3);
	int yval1,yval2;
	if(!IsData()) IAlloc();
	BYTE *dat=Lock();
	
	for(yval1=yval2=y=0;y<ylen;y++,yval1+=Pitch,yval2+=axl)
		memcpy(dat+yval1,dt+yval2,axl);
	// for(x=0;x<axl;x++)   dat[x+yval1]=dt[x+yval2]; //Revised for Performance
	
	UnLock();
}

void Image::IFree()
{
	if(IsData()) delete Data;
	Mask(Flag,IMG_ISDATA);
	Data=0; 
}


void Image::Delete()
{
	IFree();
	fname[0]=0;
	xpos=ypos=vxlen=vylen=Bpp=xlen=ylen=0;
	itype=ITYPE_RGB;
	if(pal) delete pal;
//	for(int i=0;i<256;i++) pal[i].r=pal[i].g=pal[i].b=0;
}

int Image::IsData()	  {return Flag&IMG_ISDATA;} 

BYTE *Image::Lock()
{
	if(Flag&IMG_LOCKED) UnLock();
	Flag|=IMG_LOCKED;
	return Data;
}

void Image::UnLock() { if(Flag&IMG_LOCKED)  Mask(Flag,IMG_LOCKED); }

//>>>>>>>>>>>>>>>>>> Palletteing
void Image::RealizePalette() //here for overloading
{ }

void Image::SetPaletteEntry(int idx,int r,int g ,int b)
{ 
	AllocPal();
	SetPaletteEntry(idx,ImgRGBColor(r,g,b));  
}

void Image::SetPaletteEntry(int idx,float r,float g,float b) 
{ 
	AllocPal();
	SetPaletteEntry(idx,ImgRGBColor(r,g,b));  
}

void Image::SetPaletteEntry(int idx,const ImgRGBColor &rgb) 
{
	AllocPal();
	if (idx>255 ||idx <0) return;
	pal[idx]=rgb;
	RealizePalette();
}

void Image::MakeGrayscalePalette()
{
	AllocPal();
	int i;
	
	for(i=0;i<256;i++)
	{
		pal[i]=i;
	}

	RealizePalette();
}

ImgRGBColor Image::GetPaletteEntry(int idx)
{ return pal[idx]; } 

//>>>>>>>>>>>>>>>>>> Loading Helpers

void Image::Load(char *str)
{
	FILE *fl=fopen(str,"rb"); 
	
	if(!fl) 
	{
		char tfn[MAX_PATH*2];
		strcpy(tfn,"Cannot open file for reading:");
		strcat(tfn,str);
		GENNFERR(tfn);
	}
	
	strcpy(fname,str);
	Load(fl);
	fclose(fl);
}

void Image::Load(FILE *fl)
{
	if(IsTiff(fl)) 
		LoadTiff(fl);
	else
	if(IsGif(fl))  
		LoadGif(fl);
	else
	if(IsPng(fl))  
		LoadPng(fl);
	else
	if(IsTga())  
		LoadTga(fl);
	else
	STOP(("Unknown format for General Load"));
	//	if(IsTga())    LoadTga(fl);
//	if(IsPng())  LoadPng(fl);
}

void Image::Load()
{
	Load(fname);
}

void Image::Blt(Image &img,FRect dst)
{
	dst.left*=vxlen; dst.right*=vxlen;
	dst.top*=vylen;  dst.bottom*=vylen;
	Blt(img,(RECT)TRect(dst));
}

void Image::Blt(Image &img,FRect dst,FRect src)
{
	dst.left*=vxlen; dst.right*=vxlen;
	dst.top*=vylen;  dst.bottom*=vylen;
	src.left*=img.vxlen; src.right*=img.vxlen;
	src.top*=img.vylen;  src.bottom*=img.vylen;
	Blt(img,TRect(dst),TRect(src));
}

void Image::Blt(Image &img,int x,int y,FRect src)
{
	src.left*=img.vxlen; src.right*=img.vxlen;
	src.top*=img.vylen;  src.bottom*=img.vylen;
	Blt(img,x,y,TRect(src));
}

void Image::Blt(Image &img,RECT &dst)
{ 
	Blt(img,dst,TRect(0,0,img.vxlen,img.vylen));
}

void Image::Blt(Image &img,int x,int y)
{
	Blt(img,x,y,TRect(0,0,img.vxlen,img.vylen));
}

/*
void Image::Blt(Image &img,RECT dst,RECT &src)
{
int dr,db;
int xd,yd;
int ddx,ddy;

  float MyFact;
  MyFact=((float)(src.right-src.left))/(dst.right-dst.left);
  
	src.top+=(int)(MyFact/2);
	src.bottom+=(int)(MyFact/2);
	src.left+=(int)(MyFact/2);
	src.right+=(int)(MyFact/2);
	
	  ddx=dst.right-dst.left;
	  ddy=dst.bottom-dst.top;
	  xd=src.right-src.left;
	  yd=src.bottom-src.top;
	  
		dst.right-=xpos;
		dst.left-=xpos;
		dst.bottom-=ypos;
		dst.top-=ypos;
		
		  
			if(src.left>=(img.xpos+img.xlen) || src.top>=(img.ypos+img.ylen) ||
			src.right<=img.xpos || src.bottom<img.ypos ) return;
			
			  
				//left clip
				if(src.left<=img.xpos) //fix source move dest.
				{ dst.left+=(img.xpos-src.left)*ddx/xd; src.left=0;}
				else			   //fix destination move source
				src.left-=img.xpos;
				
				  if(src.top<=img.ypos) //fix source move dest.
				  { dst.top+=(img.ypos-src.top)*ddy/yd; src.top=0; }
				  else			   //fix destination move source
				  src.top-=img.ypos;
				  
					//right clip
					
					  if(src.right>(img.xpos+img.xlen)) 
					  {
					  dst.right-=(src.right-(img.xpos+img.xlen))*ddx/xd;
					  src.right=img.xlen;	
					  }
					  else
					  src.right=img.xlen-((img.xlen+img.xpos)-src.right);	
					  
						if(src.bottom>(img.ypos+img.ylen)) 
						{
						dst.bottom-=(src.bottom-(img.ypos+img.ylen))*ddy/yd;
						src.bottom=img.ylen;	
						}
						else
						src.bottom=img.ylen-((img.ylen+img.ypos)-src.bottom);	
						
						  
							if(dst.left<0)  { src.left-=dst.left*img.xlen/ddx; dst.left=0; }
							if(dst.top<0)   { src.top-=dst.top*img.ylen/ddy;   dst.top=0;  }
							
							  
								if(dst.right>xlen) { src.right=src.left+(xlen-dst.left)*xd/ddx; dr=xlen;}
								else {dr=dst.right; }
								
								  if(dst.bottom>ylen){ src.bottom=src.top+(ylen-dst.top)*yd/ddy; db=ylen; }
								  else {db=dst.bottom; }
								  
									dst.right=dr;
									dst.bottom=db;
									
									  
										if(src.right<=0 || src.bottom<=0 || 
										src.left>=img.xlen || src.top>=img.ylen) return;
										
										  //ret=Surface->Blt(&dst,img.Surface,&src,flag,&bfx); 
										  
											BYTE *dptS=img.Lock(),*dptD=Lock();
											
											  if((dst.right-dst.left)<=(src.right-src.left)) //Downsample X
											  {
											  if((dst.bottom-dst.top)<=(src.bottom-src.top)) //Downsample Y
											  {
											  int psizeS=(img.Bpp>>3),psizeD=(Bpp>>3);
											  int x,y;
											  float prx=(float)(src.right-src.left)/(2*(dst.right-dst.left));
											  float pry=(float)(src.bottom-src.top)/(2*(dst.bottom-dst.top));
											  float csx,csy;
											  ImgRGBColor col,colsum;
											  RGBPixel *tptr;
											  
												ImageOperator Opt;
												
												  Opt.CreateGaussian((int)(pry*2),(int)(prx*2));
												  int r,c,cpx,cpy,idx;
												  float fr,fg,fb,fa,sum,w;
												  BYTE *tdp;
												  int rs,re,cs,ce;
												  re=Opt.GetRows()>>1;
												  rs=-re;
												  ce=Opt.GetCols()>>1;
												  cs=-ce;
												  
													
													  
														for(csy=(float)src.top,y=dst.top;y<dst.bottom;y++,csy+=pry*2)
														for(csx=(float)src.left,x=dst.left;x<dst.right;x++,csx+=prx*2)
														{
														
														  cpx=(int)Round(csx+cs);
														  cpy=(int)Round(csy+rs);
														  tdp=dptS+(cpx+cpy*img.xlen)*psizeS;
														  fr=fg=fb=fa=sum=0.0f;
														  for(r=rs;r<=re;r++,tdp+=img.Pitch)	
														  for(idx=0,c=cs;c<=ce;c++,idx+=psizeS)	
														  {
														  
															cpx=(int)(csx+c); cpy=(int)(csy+r);
															if(cpx>=0 && cpy>=0 && cpx<img.xlen && cpy<img.ylen)
															{
															tptr=(RGBPixel *)(tdp+idx);
															col.Set(*tptr,img.Mask);
															w=Opt.GetWeight(r+re,c+ce);
															fr+=col.r*w;
															fg+=col.g*w;
															fb+=col.b*w;
															fa+=col.a*w;
															sum+=w;
															}
															}	
															fr/=sum; fg/=sum; fb/=sum; fa/=sum;
															colsum.r=(int)floor(fr+0.05f); 
															colsum.g=(int)floor(fg+0.05f);  
															colsum.b=(int)floor(fb+0.05f); 
															colsum.a=(int)floor(fa+0.05f);
															
															  tptr=(RGBPixel *)(dptD+((int)x+((int)y)*xlen)*psizeD);
															  tptr->Set(colsum,Mask);
															  }
															  
																}
																else											//UpSample Y
																{
																GENFERR("Upsampling not supported(yet)");
																}
																
																  }
																  else											//UpSample X
																  {
																  if((dst.bottom-dst.top)<=(src.bottom-src.top)) //Downsample Y
																  {
																  GENFERR("Upsampling not supported(yet)");
																  }
																  else											//UpSample Y
																  {
																  GENFERR("Upsampling not supported(yet)");
																  }
																  }
																  
																	UnLock();
																	img.UnLock();
																	
																	  
																		}
*/


void Image::Blt(Image &img,RECT dst,RECT &src)
{
	int dr,db;
	int xd,yd;
	int ddx,ddy;
	ddx=dst.right-dst.left;
	ddy=dst.bottom-dst.top;
	xd=src.right-src.left;
	yd=src.bottom-src.top;
	
	dst.right-=xpos;
	dst.left-=xpos;
	dst.bottom-=ypos;
	dst.top-=ypos;
	
	
	if(src.left>=(img.xpos+img.xlen) || src.top>=(img.ypos+img.ylen) ||
		src.right<=img.xpos || src.bottom<img.ypos ) return;
	
	
	//left clip
	if(src.left<=img.xpos) //fix source move dest.
	{ dst.left+=(img.xpos-src.left)*ddx/xd; src.left=0;}
	else			   //fix destination move source
		src.left-=img.xpos;
	
	if(src.top<=img.ypos) //fix source move dest.
	{ dst.top+=(img.ypos-src.top)*ddy/yd; src.top=0; }
	else			   //fix destination move source
		src.top-=img.ypos;
	
	//right clip
	
	if(src.right>(img.xpos+img.xlen)) 
	{
		dst.right-=(src.right-(img.xpos+img.xlen))*ddx/xd;
		src.right=img.xlen;	
	}
	else
		src.right=img.xlen-((img.xlen+img.xpos)-src.right);	
	
	if(src.bottom>(img.ypos+img.ylen)) 
	{
		dst.bottom-=(src.bottom-(img.ypos+img.ylen))*ddy/yd;
		src.bottom=img.ylen;	
	}
	else
		src.bottom=img.ylen-((img.ylen+img.ypos)-src.bottom);	
	
	
	if(dst.left<0)  { src.left-=dst.left*img.xlen/ddx; dst.left=0; }
	if(dst.top<0)   { src.top-=dst.top*img.ylen/ddy;   dst.top=0;  }
	
	
	if(dst.right>xlen) { src.right=src.left+(xlen-dst.left)*xd/ddx; dr=xlen;}
	else {dr=dst.right; }
	
	if(dst.bottom>ylen){ src.bottom=src.top+(ylen-dst.top)*yd/ddy; db=ylen; }
	else {db=dst.bottom; }
	
	dst.right=dr;
	dst.bottom=db;
	
	
	if(src.right<=0 || src.bottom<=0 || 
		src.left>=img.xlen || src.top>=img.ylen) return;
	
	//ret=Surface->Blt(&dst,img.Surface,&src,flag,&bfx); 
	
	
	enum STYPE {ST_DOWN,ST_UP,ST_COPY};
	STYPE xdec,ydec;
	
	if((dst.right-dst.left)==(src.right-src.left)) 
		xdec=ST_COPY;
	else
		if((dst.right-dst.left)<(src.right-src.left)) 
			xdec=ST_DOWN;
		else
			xdec=ST_UP;
		
		if((dst.bottom-dst.top)==(src.bottom-src.top)) 
			ydec=ST_COPY;
		else
			if((dst.bottom-dst.top)<(src.bottom-src.top)) 
				ydec=ST_DOWN;
			else
				ydec=ST_UP;
			
			BYTE *dptS=img.Lock(),*dptD=Lock();
			bool fastcopy;
			
			if(Bpp==img.Bpp && Mask==img.Mask) fastcopy=true; else fastcopy=false;			
			
			if(xdec==ST_COPY && ydec==ST_COPY)
			{//Pure Copy
				int psizeS=(img.Bpp>>3),psizeD=(Bpp>>3);
				int sp=img.GetPitch()-(src.right-src.left)*psizeS,dp=GetPitch()-(dst.right-dst.left)*psizeD;
				int x,y;
				ImgRGBColor col;
				RGBPixel *tptr;
				BYTE *tdptS=dptS+(src.left+src.top*img.GetWidth())*psizeS,*tdptD=dptD+(dst.left+dst.top*GetWidth())*psizeD;
				

				if(fastcopy)
				{
					int scanllen=(dst.right-dst.left)*psizeD;
					for(y=dst.top;y<dst.bottom;y++,tdptS+=img.GetPitch(), tdptD+=GetPitch())
						CopyMemory(tdptD,tdptS,scanllen);
				}
				else


				{
					for(y=dst.top;y<dst.bottom;y++,tdptS+=sp,tdptD+=dp)
						for(x=dst.left;x<dst.right;x++,tdptS+=psizeS,tdptD+=psizeD)
						{
							tptr=(RGBPixel *)(tdptS);
							col.Set(*tptr,img.Mask);
							tptr=(RGBPixel *)(tdptD);
							tptr->Set(col,Mask);
						}
				}		
			}
			
			if((xdec==ST_DOWN && ydec==ST_DOWN) ||  
				(xdec==ST_DOWN && ydec==ST_COPY) ||
				(xdec==ST_COPY && ydec==ST_DOWN))
			{
				int psizeS=(img.Bpp>>3),psizeD=(Bpp>>3);
				int x,y;
				float prx=(float)(src.right-src.left)/(2*(dst.right-dst.left));
				float pry=(float)(src.bottom-src.top)/(2*(dst.bottom-dst.top));
				float csx,csy,xslp,yslp;
				int coldiv;
				ImgRGBColor col,colsum;
				RGBPixel *tptr;
				int ixslp,iyslp;

				for(csy=(float)src.top+pry,y=dst.top;y<dst.bottom;y++,csy+=pry*2)
					for(csx=(float)src.left+prx,x=dst.left;x<dst.right;x++,csx+=prx*2)
					{
						colsum.r=colsum.g=colsum.b=colsum.a=0;
						coldiv=0;
						for(yslp=csy-pry;yslp<csy+pry;yslp+=1.0f)
							for(xslp=csx-prx;xslp<csx+prx;xslp+=1.0f)
							{
							ixslp=(int)xslp;
							iyslp=(int)yslp;
								if(ixslp>=0 && iyslp>=0 && ixslp<img.xlen && iyslp<img.ylen)
								{
									tptr=(RGBPixel *)(dptS+(ixslp+iyslp*img.xlen)*psizeS);
									col.Set(*tptr,img.Mask);
									colsum.r+=col.r;
									colsum.g+=col.g;
									colsum.b+=col.b;
									colsum.a+=col.a;
									coldiv++;
								}
							}
							
								if(coldiv==0) coldiv=1;
								colsum.r/=coldiv;	
								colsum.g/=coldiv;	
								colsum.b/=coldiv;	
								colsum.a/=coldiv;	
								tptr=(RGBPixel *)(dptD+((int)x+((int)y)*xlen)*psizeD);
								tptr->Set(colsum,Mask);
					}
			}
			
			if((xdec==ST_UP && ydec==ST_UP) ||  
				(xdec==ST_UP && ydec==ST_COPY) ||
				(xdec==ST_COPY && ydec==ST_UP))
			{
				int psizeS=(img.Bpp>>3),psizeD=(Bpp>>3);
				int x,y;
				float prx=(float)(src.right-src.left)/(dst.right-dst.left);
				float pry=(float)(src.bottom-src.top)/(dst.bottom-dst.top);
				float yacc,xacc;
				ImgRGBColor lhcol,nhcol,lvcol,nvcol,col;
				RGBPixel *tptr;
				int ixacc,iyacc;
				yacc=0.0f;
				for(y=dst.top;y<dst.bottom;y++)
				{
					xacc=0.0f;
					iyacc=(int)yacc;
					for(x=dst.left;x<dst.right;x++)
					{
						ixacc=(int)xacc;
						tptr=(RGBPixel *)(dptS+(ixacc+iyacc*img.xlen)*psizeS);
						col.Set(*tptr,img.Mask);
						
						tptr=(RGBPixel *)(dptD+(x+y*xlen)*psizeD);
						tptr->Set(col,Mask);
						
						xacc+=prx;
					}
					yacc+=pry;
				}
				
			}
			
			if((xdec==ST_DOWN && ydec==ST_UP) || 
				(xdec==ST_UP && ydec==ST_DOWN) )
			{
				Image tmpim;
				RECT tmpdrct;
				tmpdrct.left=tmpdrct.top=0;
				tmpdrct.right=dst.right-dst.left;
				tmpdrct.bottom=src.bottom-src.top;
				tmpim.CreateBlank(tmpdrct.right,tmpdrct.bottom,itype,Bpp);
				tmpim.Blt(img,tmpdrct,src);
				Blt(tmpim,dst,tmpdrct);
			}
			
			UnLock();
			img.UnLock();
			
			
	}
	
	
	void Image::Blt(Image &img,int x,int y,RECT &src)
	{
		
		int xd,yd;
		xd=src.right-src.left;
		yd=src.bottom-src.top;
		
		x+=img.xpos-xpos;
		y+=img.ypos-ypos;
		
		if((x+xd)>xlen) src.right-=(x+xd)-xlen; 
		if((y+yd)>ylen) src.bottom-=(y+yd)-ylen; 
		
		if(x<0) {src.left-=x; x=0;} 
		if(y<0) {src.top-=y; y=0;}  
		
		if(src.right<=0 || src.bottom<=0 || 
			src.left>=img.xlen || src.top>=img.ylen) return;
		
		
		RECT dst={x,y,x+img.xlen,y+img.ylen};
		
		if(dst.bottom>ylen) dst.bottom=ylen;
		if(dst.right>xlen) dst.right=xlen;
		
		//ret=Surface->Blt(&dst,img.Surface,NULL,flag,&bfx); 
		
		int psizeS=(img.Bpp>>3),psizeD=(Bpp>>3);
		int xc,yc,axlS=img.Pitch,axlD=Pitch;
		RGBPixel *tptr;
		ImgRGBColor col;	
		
		BYTE *dptS=img.Lock(),*dptD=Lock();
		int SVoff,DVoff;
		int SHoff,DHoff;
		
		for(SVoff=src.top*axlS,DVoff=dst.top*axlD,yc=dst.top;
		yc<dst.bottom;
		yc++,SVoff+=axlS,DVoff+=axlD)
			for(SHoff=src.left*psizeS,DHoff=dst.left*psizeD,xc=dst.left;
			xc<dst.right;
			xc++,SHoff+=psizeS,DHoff+=psizeD)
			{
				tptr=(RGBPixel *)(dptS+SHoff+SVoff);
				col.Set(*tptr,Mask);
				tptr=(RGBPixel *)(dptD+DHoff+DVoff);
				tptr->Set(col,img.Mask);
			}
			
			UnLock();
			img.UnLock();
			
	}
	
	void Image::MeanBlur(int xs,int ys)
	{
		ImageOperator Fil;
		Fil.CreateMean(xs,ys);	
		ApplyOperator(Fil);
	}
	
	void Image::GaussianBlur(float pix)
	{
		ImageOperator Fil;
		Fil.CreateGaussian(pix);	
		ApplyOperator(Fil);
	}
	
	void Image::ApplyOperator(ImageOperator &Opt)
	{
		if(itype!=ITYPE_RGB)
			GENNFERR("(ApplyOperator)Image is not RGB");
		
		Image tmpimg;
		tmpimg.CreateBlank(xlen,ylen,itype,Bpp);
		tmpimg.Mask=Mask;
		
		int x,y,r,c,cpx,cpy;
		float fr,fg,fb,fa,sum,w;
		int rs,re,cs,ce,psize=Bpp>>3;
		re=Opt.GetRows()>>1;
		rs=-re;
		ce=Opt.GetCols()>>1;
		cs=-ce;
		
		BYTE *dpt=Lock();
		BYTE *dd=tmpimg.Lock();
		
		
		RGBPixel *tptr;
		ImgRGBColor col;
		
		int idx;
		
		BYTE *tdp;
		
		for(y=0;y<ylen;y++)
			for(x=0;x<xlen;x++)
			{
				tdp=(BYTE *)(dpt+((x+cs)+(y+rs)*xlen)*psize);
				sum=fr=fg=fb=fa=0.0f;				//Zero out Accumulators
				BYTE *tdp=(BYTE *)(dpt+((x+cs)+(y+rs)*xlen)*psize);
				
				if( (x+cs)<0 || (x+ce)>=xlen ||
					(y+rs)<0 || (y+re)>=ylen ) //This is an edge
				{
					
					for(r=rs;r<=re;r++,tdp+=Pitch)	
						for(idx=0,c=cs;c<=ce;c++,idx+=psize)	
						{
							cpx=x+c; cpy=y+r;
							if(cpx>=0 && cpy>=0 && cpx<xlen && cpy<ylen)
							{
								tptr=(RGBPixel *)(tdp+idx);
								col.Set(*tptr,Mask);
								w=Opt.GetWeight(r+re,c+ce);
								fr+=col.r*w;
								fg+=col.g*w;
								fb+=col.b*w;
								fa+=col.a*w;
								sum+=w;
							}
						}	
						
				}
				else
				{
					
					for(r=rs;r<=re;r++,tdp+=Pitch)	
						for(idx=0,c=cs;c<=ce;c++,idx+=psize)	
						{
							tptr=(RGBPixel *)(tdp+idx);
							col.Set(*tptr,Mask);
							w=Opt.GetWeight(r+re,c+ce);
							fr+=col.r*w;
							fg+=col.g*w;
							fb+=col.b*w;
							fa+=col.a*w;
						}	
						sum=Opt.GetTotal();
				}
				
				fr/=sum; fg/=sum; fb/=sum; fa/=sum;
				col.r=(int)floor(fr+0.5f);
				col.g=(int)floor(fg+0.5f);
				col.b=(int)floor(fb+0.5f); 
				col.a=(int)floor(fa+0.5f);
				tptr=(RGBPixel *)(dd);
				tptr->Set(col,tmpimg.Mask);
				dd+=psize;
			}
			
			tmpimg.UnLock();
			UnLock();
			*this=tmpimg;
	}
	
	void Image::BltBlend(Image &img,float efact,RECT &src,float tfact,float rfact,float bfact,float lfact)
	{
		RECT dst;
		dst.top=dst.left=0;
		dst.right=GetWidth();
		dst.bottom=GetHeight();
		
		
		float MyFact;
		MyFact=((float)(src.right-src.left))/(dst.right-dst.left);
		if(tfact<MyFact) tfact=MyFact;
		if(bfact<MyFact) bfact=MyFact;
		if(rfact<MyFact) rfact=MyFact;
		if(lfact<MyFact) lfact=MyFact;
		
		src.top+=(int)(MyFact/2);
		src.bottom+=(int)(MyFact/2);
		src.left+=(int)(MyFact/2);
		src.right+=(int)(MyFact/2);
		
		/*
		int dr,db;
		int xd,yd;
		int ddx,ddy;
		ddx=dst.right-dst.left;
		ddy=dst.bottom-dst.top;
		xd=src.right-src.left;
		yd=src.bottom-src.top;
		
		  dst.right-=xpos;
		  dst.left-=xpos;
		  dst.bottom-=ypos;
		  dst.top-=ypos;
		  
			
			  
				if(src.left>=(img.xpos+img.xlen) || src.top>=(img.ypos+img.ylen) ||
				src.right<=img.xpos || src.bottom<img.ypos ) return;
				
				  
					//left clip
					if(src.left<=img.xpos) //fix source move dest.
					{ dst.left+=(img.xpos-src.left)*ddx/xd; src.left=0;}
					else			   //fix destination move source
					src.left-=img.xpos;
					
					  if(src.top<=img.ypos) //fix source move dest.
					  { dst.top+=(img.ypos-src.top)*ddy/yd; src.top=0; }
					  else			   //fix destination move source
					  src.top-=img.ypos;
					  
						//right clip
						
						  if(src.right>(img.xpos+img.xlen+1)) 
						  {
						  dst.right-=(src.right-(img.xpos+img.xlen))*ddx/xd;
						  src.right=img.xlen;	
						  }
						  else
						  src.right=img.xlen-((img.xlen+img.xpos)-src.right);	
						  
							if(src.bottom>(img.ypos+img.ylen+1)) 
							{
							dst.bottom-=(src.bottom-(img.ypos+img.ylen))*ddy/yd;
							src.bottom=img.ylen;	
							}
							else
							src.bottom=img.ylen-((img.ylen+img.ypos)-src.bottom);	
							
							  
								if(dst.left<0)  { src.left-=dst.left*img.xlen/ddx; dst.left=0; }
								if(dst.top<0)   { src.top-=dst.top*img.ylen/ddy;   dst.top=0;  }
								
								  
									if(dst.right>xlen) { src.right=src.left+(xlen-dst.left)*xd/ddx; dr=xlen;}
									else {dr=dst.right; }
									
									  if(dst.bottom>ylen){ src.bottom=src.top+(ylen-dst.top)*yd/ddy; db=ylen; }
									  else {db=dst.bottom; }
									  
										dst.right=dr;
										dst.bottom=db;
										
										  
											if(src.right<=0 || src.bottom<=0 || 
											src.left>=img.xlen || src.top>=img.ylen) return;
											
											  //ret=Surface->Blt(&dst,img.Surface,&src,flag,&bfx); 
		*/
		
		BYTE *dptS=img.Lock(),*dptD=Lock();
		
		if((dst.right-dst.left)<=(src.right-src.left)) //Downsample X
		{
			if((dst.bottom-dst.top)<=(src.bottom-src.top)) //Downsample Y
			{
				int psizeS=(img.Bpp>>3),psizeD=(Bpp>>3);
				int x,y;
				float prx=(float)(src.right-src.left)/(2*(dst.right-dst.left));
				float pry=(float)(src.bottom-src.top)/(2*(dst.bottom-dst.top));
				float csx,csy;
				ImgRGBColor col,colsum;
				RGBPixel *tptr;
				
				ImageOperator Opt;
				
				int r,c,cpx,cpy,idx;
				float fr,fg,fb,fa,sum,w;
				float CurFact;
				BYTE *tdp;
				
				int rs,re,cs,ce;
				
				Opt.CreateGaussian((int)MyFact,(int)MyFact);
				re=Opt.GetRows()>>1;
				rs=-re;
				ce=Opt.GetCols()>>1;
				cs=-ce;
				
				float tr,br,lr,rr,mr;
				float invefact=1/efact;
				
				for(csy=(float)src.top,y=dst.top;y<dst.bottom;y++,csy+=pry*2)
					for(csx=(float)src.left,x=dst.left;x<dst.right;x++,csx+=prx*2)
					{
						
						tr=1.0f-((float)(y*invefact)/(ylen));
						if(tr<0) tr=0.0f;
						br=((float)(( (y+1) - (ylen-(ylen*efact)) )*invefact)/(ylen));
						if(br<0) br=0.0f;
						lr=1.0f-((float)(x*invefact)/(xlen));
						if(lr<0) lr=0.0f;
						rr=((float)(( (x+1) - (xlen-(xlen*efact)) )*invefact)/(xlen));
						if(rr<0) rr=0.0f;
						mr=1.0f-(tr+br+lr+rr);
						if(mr<0) mr=0.0f;
						
						CurFact=MyFact;
						CurFact=(tfact*tr)>CurFact?tfact*tr:CurFact;
						CurFact=(bfact*br)>CurFact?bfact*br:CurFact;
						CurFact=(lfact*lr)>CurFact?lfact*lr:CurFact;
						CurFact=(rfact*rr)>CurFact?rfact*rr:CurFact;
						
						/*				
						CurFact=
						(MyFact*mr+
						tfact*tr+
						bfact*br+
						lfact*lr+
						rfact*rr)/( tr+br+lr+rr+mr );
						*/				
						CurFact=(float)floor(CurFact+0.5f);
						
						Opt.CreateGaussian((int)CurFact,(int)CurFact);
						re=Opt.GetRows()>>1;
						rs=-re;
						ce=Opt.GetCols()>>1;
						cs=-ce;
						
						cpx=(int)Round(csx+cs);
						cpy=(int)Round(csy+rs);
						tdp=dptS+(cpx+cpy*img.xlen)*psizeS;
						fr=fg=fb=fa=sum=0.0f;
						for(r=rs;r<=re;r++,tdp+=img.Pitch)	
							for(idx=0,c=cs;c<=ce;c++,idx+=psizeS)	
							{
								cpx=(int)(csx+c); cpy=(int)(csy+r);
								//					cpx=(int)Round(csx+c); cpy=(int)Round(csy+r);
								if(cpx>=0 && cpy>=0 && cpx<img.xlen && cpy<img.ylen)
								{
									tptr=(RGBPixel *)(tdp+idx);
									col.Set(*tptr,img.Mask);
									w=Opt.GetWeight(r+re,c+ce);
									fr+=col.r*w;
									fg+=col.g*w;
									fb+=col.b*w;
									fa+=col.a*w;
									sum+=w;
								}
							}	
							fr/=sum; fg/=sum; fb/=sum; fa/=sum;
							colsum.r=(int)Round(fr); 
							colsum.g=(int)Round(fg);  
							colsum.b=(int)Round(fb); 
							colsum.a=(int)Round(fa);
							
							tptr=(RGBPixel *)(dptD+(x+y*xlen)*psizeD);
							tptr->Set(colsum,Mask);
					}
					
			}
			else											//UpSample Y
			{
				GENFERR("Upsampling not supported(yet)");
			}
}
else											//UpSample X
{
	if((dst.bottom-dst.top)<=(src.bottom-src.top)) //Downsample Y
	{
		GENFERR("Upsampling not supported(yet)");
	}
	else											//UpSample Y
	{
		GENFERR("Upsampling not supported(yet)");
	}
}

UnLock();
img.UnLock();



}

//
// Added by SMJ on 6/4/99
//
void Image::Rotate180()
{
	int		pixelSize = Bpp / 8;
	int		dataSize = Pitch * ylen;
	BYTE*	back = Data + dataSize - pixelSize;
	BYTE*	newData = new BYTE [dataSize];
	BYTE*	front = newData;
	
	while (back > Data)
	{
		memcpy(front,back,pixelSize);
		
		front += pixelSize;
		back -= pixelSize;
	}
	
	delete Data;
	Data = newData;
}

void Image::BltDominantColor(Image &img,RECT dst,RECT &src)
{
	int dr,db;
	int xd,yd;
	int ddx,ddy;
	ddx=dst.right-dst.left;
	ddy=dst.bottom-dst.top;
	xd=src.right-src.left;
	yd=src.bottom-src.top;
	
	dst.right-=xpos;
	dst.left-=xpos;
	dst.bottom-=ypos;
	dst.top-=ypos;
	
	
	if(src.left>=(img.xpos+img.xlen) || src.top>=(img.ypos+img.ylen) ||
		src.right<=img.xpos || src.bottom<img.ypos ) return;
	
	
	//left clip
	if(src.left<=img.xpos) //fix source move dest.
	{ dst.left+=(img.xpos-src.left)*ddx/xd; src.left=0;}
	else			   //fix destination move source
		src.left-=img.xpos;
	
	if(src.top<=img.ypos) //fix source move dest.
	{ dst.top+=(img.ypos-src.top)*ddy/yd; src.top=0; }
	else			   //fix destination move source
		src.top-=img.ypos;
	
	//right clip
	
	if(src.right>(img.xpos+img.xlen)) 
	{
		dst.right-=(src.right-(img.xpos+img.xlen))*ddx/xd;
		src.right=img.xlen;	
	}
	else
		src.right=img.xlen-((img.xlen+img.xpos)-src.right);	
	
	if(src.bottom>(img.ypos+img.ylen)) 
	{
		dst.bottom-=(src.bottom-(img.ypos+img.ylen))*ddy/yd;
		src.bottom=img.ylen;	
	}
	else
		src.bottom=img.ylen-((img.ylen+img.ypos)-src.bottom);	
	
	
	if(dst.left<0)  { src.left-=dst.left*img.xlen/ddx; dst.left=0; }
	if(dst.top<0)   { src.top-=dst.top*img.ylen/ddy;   dst.top=0;  }
	
	
	if(dst.right>xlen) { src.right=src.left+(xlen-dst.left)*xd/ddx; dr=xlen;}
	else {dr=dst.right; }
	
	if(dst.bottom>ylen){ src.bottom=src.top+(ylen-dst.top)*yd/ddy; db=ylen; }
	else {db=dst.bottom; }
	
	dst.right=dr;
	dst.bottom=db;
	
	
	if(src.right<=0 || src.bottom<=0 || 
		src.left>=img.xlen || src.top>=img.ylen) return;
	
	//ret=Surface->Blt(&dst,img.Surface,&src,flag,&bfx); 
	
	
	enum STYPE {ST_DOWN,ST_UP,ST_COPY};
	STYPE xdec,ydec;
	
	if((dst.right-dst.left)==(src.right-src.left)) 
		xdec=ST_COPY;
	else
		if((dst.right-dst.left)<(src.right-src.left)) 
			xdec=ST_DOWN;
		else
			xdec=ST_UP;
		
		if((dst.bottom-dst.top)==(src.bottom-src.top)) 
			ydec=ST_COPY;
		else
			if((dst.bottom-dst.top)<(src.bottom-src.top)) 
				ydec=ST_DOWN;
			else
				ydec=ST_UP;

if(ydec==ST_UP || xdec==ST_UP )
STOP(("Upsampling Not Supported"));			

			BYTE *dptS=img.Lock(),*dptD=Lock();
			bool fastcopy;
			
			if(Bpp==img.Bpp && Mask==img.Mask) fastcopy=true; else fastcopy=false;			
			
			if(xdec==ST_COPY && ydec==ST_COPY)
			{//Pure Copy
				int psizeS=(img.Bpp>>3),psizeD=(Bpp>>3);
				int sp=img.GetPitch()-(src.right-src.left)*psizeS,dp=GetPitch()-(dst.right-dst.left)*psizeD;
				int x,y;
				ImgRGBColor col;
				RGBPixel *tptr;
				BYTE *tdptS=dptS+(src.left+src.top*img.GetWidth())*psizeS,*tdptD=dptD+(dst.left+dst.top*GetWidth())*psizeD;
				

				if(fastcopy)
				{
					int scanllen=(dst.right-dst.left)*psizeD;
					for(y=dst.top;y<dst.bottom;y++,tdptS+=img.GetPitch(), tdptD+=GetPitch())
						CopyMemory(tdptD,tdptS,scanllen);
				}
				else


				{
					for(y=dst.top;y<dst.bottom;y++,tdptS+=sp,tdptD+=dp)
						for(x=dst.left;x<dst.right;x++,tdptS+=psizeS,tdptD+=psizeD)
						{
							tptr=(RGBPixel *)(tdptS);
							col.Set(*tptr,img.Mask);
							tptr=(RGBPixel *)(tdptD);
							tptr->Set(col,Mask);
						}
				}		
			}
			
			if((xdec==ST_DOWN && ydec==ST_DOWN) ||  
				(xdec==ST_DOWN && ydec==ST_COPY) ||
				(xdec==ST_COPY && ydec==ST_DOWN))
			{
				int psizeS=(img.Bpp>>3),psizeD=(Bpp>>3);
				int x,y;
				float prx=(float)(src.right-src.left)/(2*(dst.right-dst.left));
				float pry=(float)(src.bottom-src.top)/(2*(dst.bottom-dst.top));
				float csx,csy,xslp,yslp;
				int colmax,idx;
				ImgRGBColor col;
				RGBPixel *tptr;
				colmax=(int)ceil(prx*2)*(int)ceil(pry*2);
				int *ColorCount=new int[colmax];
				ImgRGBColor *ColorList=new ImgRGBColor[colmax];
				int colortotal;
				
				for(csy=(float)src.top+pry,y=dst.top;y<dst.bottom;y++,csy+=pry*2)
					for(csx=(float)src.left+prx,x=dst.left;x<dst.right;x++,csx+=prx*2)
					{
						colortotal=0;

						for(yslp=csy-pry;yslp<csy+pry;yslp+=1.0f)
							for(xslp=csx-prx;xslp<csx+prx;xslp+=1.0f)
								if(((int)xslp)>=0 && ((int)yslp)>=0 && ((int)xslp)<img.xlen && ((int)yslp)<img.ylen)
								{
									tptr=(RGBPixel *)(dptS+((int)xslp+((int)yslp)*img.xlen)*psizeS);
									col.Set(*tptr,img.Mask);
									for(idx=0;idx<colortotal && ColorList[idx]!=col;idx++);
									
									if(idx<colortotal)
									{
									 ColorCount[idx]++;
									}
									else
									{
									 ColorCount[colortotal]=1;
									 ColorList[colortotal]=col;
									 colortotal++;
									}
									
								}
								
								int maxnum,maxval;
								
								maxval=0;
								
								for(idx=0;idx<colortotal;idx++)
								{
								if(ColorCount[idx]>maxval) 
									{
									maxnum=idx;
									maxval=ColorCount[idx];
									}
								}

								
								tptr=(RGBPixel *)(dptD+((int)x+((int)y)*xlen)*psizeD);
								tptr->Set(ColorList[maxnum],Mask);
					}
				
				delete ColorCount;
				delete ColorList;
			
			}
			
			
			UnLock();
			img.UnLock();
}

// Image Operator

void ImageOperator::Create(int sr,int sc)
{
	Destroy();
	
	
	Rows=sr;
	Cols=sc;
	
	Rows|=1; Cols|=1; //Always make odd No even filters have unpredicatable results
	
	dat=new float *[Rows];
	int i,j;
	for(i=0;i<Rows;i++)
	{
		dat[i]=new float[Cols];
		for(j=0;j<Cols;j++)
			dat[i][j]=0.0f;
	}
	
	Sum=0.0f;
}

void ImageOperator::Destroy()
{
	int i;
	for(i=0;i<Rows;i++)
		delete dat[i];
	
	delete dat;
	
}

void ImageOperator::CreateGaussian(float pix)
{
	//Implement This
	//Create a Square Gaussian Matrix Based on a pixel radius
	CreateMean((int)pix,(int)pix);
	
}

void ImageOperator::CreateGaussian(int sx,int sy)
{
	Create(sx,sy);
	
	
	Sum=0.0f;
	
	int i,j;
	for(i=0;i<Rows;i++)
		for(j=0;j<Cols;j++)
		{
			dat[i][j]=(float)(exp((float)-(j*j/sx*sx))*exp((float)-(i*i/sy*sy)));
			Sum+=dat[i][j];
		}
		
}

void ImageOperator::CreateMean(int sx,int sy)
{
	Create(sx,sy);
	
	int i,j;
	for(i=0;i<Rows;i++)
		for(j=0;j<Cols;j++)
		{
			dat[i][j]=1.0f;
		}
		
		Sum=(float)Rows*Cols;
}

void ImageOperator::CalculateSum()
{
	
	Sum=0.0f;
	
	int i,j;
	for(i=0;i<Rows;i++)
		for(j=0;j<Cols;j++)
		{
			Sum+=dat[i][j];
		}
		
		
		
}

