
#include "stdafx.h"
#include "bmp_control.h"
//#include <gdiplus.h>
#include <gdiplus.h>
#include <mbstring.h>

#define ALINEAMIENTO_DWORDEX(x) ((x+4)&~4)
#define ALINEAMIENTO_DWORD(x) ((x+3)&~3)
#define WIDTHBYTES(i)   ((i+31)/32*4)
//**************************************************************************************
Cbmp_control::Cbmp_control(int cx, int cy)
{
	ancho=cx; alto=cy;
	bmp_info=(BITMAPINFO*)new char[sizeof(BITMAPINFOHEADER)];
	bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
	bmp_info->bmiHeader.biWidth=cx;
	bmp_info->bmiHeader.biHeight=cy;
	bmp_info->bmiHeader.biPlanes=1;
	
	bmp_info->bmiHeader.biBitCount=16;
	bmp_info->bmiHeader.biCompression=0;
	bmp_info->bmiHeader.biSizeImage=0;
	bmp_info->bmiHeader.biXPelsPerMeter=0;
	bmp_info->bmiHeader.biYPelsPerMeter=0;
	bmp_info->bmiHeader.biClrUsed=0;
	bmp_info->bmiHeader.biClrImportant=0;

	bmp_info->bmiHeader.biCompression=BI_RGB;
bmp_info->bmiHeader.biBitCount=32;
	bits=NULL;
	m_cdc=NULL;

	crea();
}
//**************************************************************************************
Cbmp_control::~Cbmp_control()
{
	destruye();
	delete bmp_info;
}
//**************************************************************************************
void Cbmp_control::destruye()
{
	if (bits!=NULL)
	{
		::SelectObject(m_hdc, m_old_bitmap);
		::DeleteObject(m_bitmap);
		::DeleteDC(m_hdc);
		delete m_cdc;
		m_cdc=NULL;
		bits=NULL;
	};
}
//**************************************************************************************
void Cbmp_control::crea(BOOL limpiar, char ch)
{
	destruye();

	HDC sdc=::GetDC(NULL);
	m_hdc=::CreateCompatibleDC(sdc);
	::ReleaseDC(0,sdc);
	LPVOID lp;
	bmp_info->bmiHeader.biSizeImage = ((256 * (bmp_info->bmiHeader.biBitCount / 8) + 3) & -4) * 192;
	m_bitmap=::CreateDIBSection(m_hdc,bmp_info,DIB_PAL_COLORS,&lp,NULL,NULL);
	DWORD dw = GetLastError();
	bits=(BYTE*)lp;
	
	if (bits==NULL)
	{
		//ASSERT(FALSE);
	    //AfxMessageBox(TEXT("sin memoria!"));
		::DeleteDC(m_hdc);
		m_hdc = NULL;
		return;
	}
	m_old_bitmap=(HBITMAP)::SelectObject(m_hdc, m_bitmap);
	m_cdc=new CDC();
	m_cdc->Attach(m_hdc);
	if (limpiar) 
		rellena_bits(ch);
	m_iniciado=FALSE;
}
//**************************************************************************************
/*
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
	UINT  num = 0;          // number of image encoders
	UINT  size = 0;         // size of the image encoder array in bytes

	Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;

	Gdiplus::GetImageEncodersSize(&num, &size);
	if(size == 0)
		return -1;  // Failure

	pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
	if(pImageCodecInfo == NULL)
		return -1;  // Failure

	Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);

	for(UINT j = 0; j < num; ++j)
	{
		if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return j;  // Success
		}    
	}

	free(pImageCodecInfo);
	return -1;  // Failure
}

BOOL Cbmp_control::guardar_bmp(char *path)
{
	
	Gdiplus::Bitmap *gr=Gdiplus::Bitmap::FromHBITMAP(m_bitmap,NULL);

	// Save the altered image.
	CLSID pngClsid;
	GetEncoderClsid(L"image/bmp", &pngClsid);
	gr->Save(L"c:\\temp\\ola.bmp",&pngClsid,NULL);
	return TRUE;

};*/
//**************************************************************************************
void Cbmp_control::redimensiona(int cx, int cy, BOOL limpiar, char ch)
{
	if (cx!=ancho || cy!=alto)
	{
		ancho=cx; alto=cy;
		bmp_info->bmiHeader.biWidth=cx;
		bmp_info->bmiHeader.biHeight=cy;
		crea(limpiar, ch);
	} 
	else
	{
		if (limpiar) 
			rellena_bits(ch);
	};
}
//**************************************************************************************
void Cbmp_control::rellena_bits(char ch)
{
	int aaa=WIDTHBYTES(ancho*24);
	int fdf=ALINEAMIENTO_DWORD(ancho*4);
	if (bits!=NULL)
		memset(bits, ch, alto*fdf);
}
//**************************************************************************************
void Cbmp_control::pon_bits(LPVOID src, int count)
{
	/*ASSERT(count<=alto*ALINEAMIENTO_DWORD(ancho));
	LPVOID lp=(LPVOID)bits;
	count>>=2;
	_asm
	{
		push ds;
		pop  es;
		mov  edi, dword ptr [lp];
		mov  esi, dword ptr [src];
		cld;
		mov ecx, count;
		rep movsd;
	};
	/*
	 if (count>Height*DWordAlign(Width)) return;
	 memcpy((LPVOID)Dib, src, count);
	*/
}
//**************************************************************************************
HDC Cbmp_control::dame_hdc()
{
	if (bits!=NULL) return m_hdc; else return 0;
		return 0;
}
//**************************************************************************************
CDC* Cbmp_control::dame_cdc()
{
	if (bits!=NULL) 
		return m_cdc; 
	else 
		return NULL;
	return NULL;
}
//**************************************************************************************
void Cbmp_control::pinta_dib( HDC dc, CRect r )
{
	if (bits!=NULL)
	{
		SetDIBitsToDevice(dc,r.left,r.top,r.Width(),
		r.Height(),r.left,bmp_info->bmiHeader.biHeight-r.bottom ,0 ,bmp_info->bmiHeader.biHeight , bits,
		bmp_info,DIB_RGB_COLORS);
	}
}
//**************************************************************************************
void Cbmp_control::escribe_pixel(int x, int y, BYTE valor)
{
	if (bits==NULL) 
		return;
	if (x<0 || y<0 || x>=ancho || y>=alto) 
		return;

	//m_bits[(m_alto-y-1)*WIDTHBYTES((m_ancho)+x)]=valor;
	//m_bits[(m_alto-y-1)*WIDTHBYTES(ALINEAMIENTO_DWORD(m_ancho))+200]=valor;//WIDTHBYTES(4*((m_ancho)+(x)))]=valor;

	
	//m_bits[367+ALINEAMIENTO_DWORD(x)]=valor;//WIDTHBYTES(4*((m_ancho)+(x)))]=valor;
	int ff=ALINEAMIENTO_DWORD(ancho*4);
	int fff=WIDTHBYTES(ancho)*8;
	bits[(alto-y-1)*(ff)+x*4+0]=valor;
	bits[(alto-y-1)*(ff)+x*4+1]=valor;
	bits[(alto-y-1)*(ff)+x*4+2]=valor;
	bits[(alto-y-1)*(ff)+x*4+3]=255;
	//m_bits[sizeof(BITMAPINFOHEADER)+(m_alto-y-1)*(fff)+120]=valor;
	//m_bits[(m_alto-y-1)*(ALINEAMIENTO_DWORD(m_ancho))+200]=valor;//
	//m_bits[(m_alto-y-1)*(ALINEAMIENTO_DWORD(m_ancho))+200]=valor;//
	//m_bits[ (y * m_ancho * 4) + (x * 4) + 0 ]=valor;
}
//**************************************************************************************
void Cbmp_control::colorea_pixel(int x, int y, BYTE valor)
{
	int res=WIDTHBYTES(ancho*24);
	if (bits==NULL) 
		return;
	if (x<0 || y<0 || x>=ancho || y>=alto) 
		return;
	//int index=(m_alto-y-1)*ALINEAMIENTO_DWORD(m_ancho)+x;
	//int index=(m_alto-y-1)*(m_ancho)+x;
	bits[(alto-y-1) + 20]=valor;
	bits[(alto-y-1) + 21]=valor;
	//m_bits[(m_alto-y-1)*(ALINEAMIENTO_DWORD(m_ancho))+x+1]=valor+25;
	//m_bits[(m_alto-y-1)*(ALINEAMIENTO_DWORD(m_ancho))+x+2]=valor+180;
}
//**************************************************************************************
void Cbmp_control::pinta_cruz(int x, int y, int ancho, BYTE color)
{
	 if (bits==NULL) 
		 return;
	 int i;
	 for (i=y-ancho; i<=y+ancho; i++) 
		 escribe_pixel(x, i, color);
	 for (i=x-ancho; i<=x+ancho; i++) 
		 escribe_pixel(i, y, color);
}
//**************************************************************************************
void Cbmp_control::mueve_datos(int cx, int cy)
{
	if (bits==NULL) 
		return;
	LPVOID lp1, lp2;
	if (cx!=0)
	{ // mueve datos en x
		if (abs(cx)<ancho)
		{
			for (int i=0; i<alto; i++)
			{
				lp1=(LPVOID)((BYTE*)bits+i*ALINEAMIENTO_DWORD(ancho));
				lp2=(LPVOID)((BYTE*)bits+i*ALINEAMIENTO_DWORD(ancho)+abs(cx));
				if (cx<0) 
					memcpy(lp2, lp1, ancho-abs(cx));
				else 
					memcpy(lp1, lp2, ancho-abs(cx));
			}
		}
	}

	if (cy!=0)
	{ // mueve datos en y
		if (abs(cy)<alto)
		{
			if (cy<0)
			{ // mueve datos hacia abajo
				for (int i=0; i<alto-abs(cy); i++)
				{
					lp2=(LPVOID)((BYTE*)bits+i*ALINEAMIENTO_DWORD(ancho));
					lp1=(LPVOID)((BYTE*)bits+(i+abs(cy))*ALINEAMIENTO_DWORD(ancho));
					memcpy(lp2, lp1, ancho);
				};
			} 
			else
			{
				for (int i=0; i<alto-abs(cy); i++)
				{
					lp2=(LPVOID)((BYTE*)bits+(alto-i-1)*ALINEAMIENTO_DWORD(ancho));
					lp1=(LPVOID)((BYTE*)bits+(alto-i-abs(cy)-1)*ALINEAMIENTO_DWORD(ancho));
					memcpy(lp2, lp1, ancho);
				}
			}
		}
	}
}
//**************************************************************************************
BOOL Cbmp_control::w2dib( CWnd *w,  CRect *rec, DWORD flags)
{
	CRect r;
	if (bits==NULL) 
		return FALSE;
	if(!rec)
	{
		w->GetClientRect(&r);
		rec=&r;
	}
	redimensiona(rec->Width(),rec->Height());
	if(!::BitBlt(m_hdc, 0, 0, ancho, alto, w->GetDC()->m_hDC, rec->left, rec->top, SRCCOPY))
		return FALSE;	
	return TRUE;
}
//**************************************************************************************
BOOL Cbmp_control::dib2file( char *path )
{
	
	if (bits==NULL)
	{
		return FALSE;
	}
	
	BOOL result = FALSE;
	PICTDESC pd;

	pd.cbSizeofstruct   = sizeof(PICTDESC);
	pd.picType      = PICTYPE_BITMAP;
	pd.bmp.hbitmap  = m_bitmap;
	pd.bmp.hpal     = 0;

	LPPICTURE picture;
	HRESULT res = OleCreatePictureIndirect(&pd, IID_IPicture, false,
		reinterpret_cast<void**>(&picture));

	if (!SUCCEEDED(res))
		return FALSE;

	LPSTREAM stream;
	res = CreateStreamOnHGlobal(0, true, &stream);

	if (!SUCCEEDED(res))
	{
		picture->Release();
		return FALSE;
	}

	LONG bytes_streamed;
	res = picture->SaveAsFile(stream, true, &bytes_streamed);

	HANDLE file = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, 0,
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

	if (!SUCCEEDED(res) || !file)
	{
		stream->Release();
		picture->Release();
		return FALSE;
	}

	HGLOBAL mem = 0;
	GetHGlobalFromStream(stream, &mem);
	LPVOID data = GlobalLock(mem);

	DWORD bytes_written;

	result   = !!WriteFile(file, data, bytes_streamed, &bytes_written, 0);
	result  &= (bytes_written == static_cast<DWORD>(bytes_streamed));

	GlobalUnlock(mem);
	CloseHandle(file);

	stream->Release();
	picture->Release();

	return result;

	




	

	// Free memory.  
	




	/*BITMAPINFO bi; 
	ZeroMemory(&bi, sizeof(BITMAPINFO));
	bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bi.bmiHeader.biWidth = ancho;
	bi.bmiHeader.biHeight = alto;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 24;*/

	/*BITMAPFILEHEADER bh;
	ZeroMemory(&bh, sizeof(BITMAPFILEHEADER));
	bh.bfType = 0x4d42; //bitmap 
	bh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bh.bfSize = bh.bfOffBits + ((alto*ancho)*3);

	CFile file;
	if(!file.Open(path, CFile::modeCreate | CFile::modeWrite))
	{ 
		return FALSE;
	}
	file.Write(&bh, sizeof(BITMAPFILEHEADER));
	file.Write(&(bmp_info->bmiHeader), sizeof(BITMAPINFOHEADER));
	file.Write(bits, 3 * alto*ancho);
	file.Close();*/
	//return TRUE;
}
//**************************************************************************************
BOOL Cbmp_control::w2file(CWnd *w,char* path, CRect *rec)
{
	CRect r;
	if (!rec)
	{
		w->GetClientRect(&r);
		rec=&r;
	}
	
	Cbmp_control cnt(rec->Width(),rec->Height());
	cnt.pon_iniciado(TRUE);
	return cnt.w2dib(w,rec) && cnt.dib2file(path);
	
}
//**************************************************************************************
