#include "Image.h"
#include <gdiplus.h>



WCHAR * ImageManip :: ToUnicodeFR ( const char * szStr ) {
	int len = strlen(szStr) + 1;
	WCHAR * ret = new WCHAR[len];
	for(int i=0;i<len;i++)
		ret[i] = szStr[i];
	return ret;
}

int * ImageManip :: GetPixelData(char * szImgName,int& width,int& height) {
	WCHAR * unicode = ToUnicodeFR(szImgName);
	Bitmap * b = new Bitmap(unicode);
	delete unicode;

	width = b->GetWidth();
	height = b->GetHeight();

	return Bitmap2PixelData(b);
}

inline int ImageManip :: ARGB2Pixel(int alpha, int r, int g, int b) {
	if ( alpha > 255 )
		alpha = 255;
	else if ( alpha < 0 )
		alpha = 0;
	if ( r > 255 )
		r = 255;
	else if ( r < 0 )
		r = 0;
	if ( g > 255 )
		g = 255;
	else if ( g < 0 )
		g = 0;
	if ( b > 255 )
		b = 255;
	else if ( b < 0 )
		b = 0;
	// shift r and g to encode
	r = (r << 16); 
	g = (g << 8 ); 
	// return ( ((alpha << 24 )&0xff000000)  | r | g| b );
	// Ignore the alpha channel : we dont need it
	return ( r | g| b );
}

// Given a Bitmap - get an integer encoded data of the pixels
int * ImageManip :: Bitmap2PixelData(Bitmap *b) {
  // get width and height of Bitmap
  int width = b->GetWidth();
  int height = b->GetHeight();
  // make sure these are valid
  if ( width *height <= 0 )
    return NULL;
  // allocate memory for pixel data
  int *pixelData_ARGB = new int[width*height];
  if ( pixelData_ARGB == NULL )
    return NULL;
  // get the pixel values from the bitmap and encode
  // into the array allocated above.
  BitmapData bmData;
  Rect rect(0, 0, width, height);
  b->LockBits(rect,
    ImageLockModeRead,
    PixelFormat32bppARGB,
    &bmData);
  int stride = bmData.Stride;
  BYTE *p = (BYTE *)((void *)bmData.Scan0);
  int nOffset = stride - width*4;    // bytes to skip at end of
                                     // each row
  for(int y=0; y < height;y++) {
    for(int x=0; x < width; ++x ) {
      // GDI lies about RGB - internally it's BGR
      pixelData_ARGB[y*width+x] =  ARGB2Pixel(p[3], p[2], p[1],
                                              p[0]);
      p += 4;
    }
    p += nOffset;
  }
  b->UnlockBits(&bmData);
  //return the pixel data array
  return (pixelData_ARGB);
}

Bitmap * ImageManip :: PixelData2BitMap(int width, int height,
                          int *pixData_ARGB) {
  // create a temporary Bitmap
  Bitmap bit(width, height, PixelFormat32bppARGB);
  // create its clone for returning
  Bitmap *b = bit.Clone(0, 0, bit.GetWidth(), bit.GetHeight(),
              PixelFormat32bppARGB);
  BitmapData bmData;
  Rect rect(0, 0, b->GetWidth(), b->GetHeight());
  b->LockBits(rect,
    ImageLockModeRead | ImageLockModeWrite,
    PixelFormat32bppARGB,
    &bmData);
  int stride = bmData.Stride;
  BYTE *p = (BYTE *)((void *)bmData.Scan0);
  int nOffset = stride - width*4;   // bytes to skip at end of
                                    // each row
  int pixel;
  for(int y=0; y < height;y++) {
    for(int x=0; x < width; ++x ) {
      // GDI lies about RGB - internally it's BGR
      pixel = pixData_ARGB[y*width+x];
      p[3] = (BYTE) ((pixel >> 24) & 0xff);    // alpha
      p[2] = (BYTE) ((pixel >> 16) & 0xff);    // pixel red
      p[1] = (BYTE) ((pixel >> 8 ) & 0xff);    // pixel green
      p[0] = (BYTE) ((pixel      ) & 0xff);    // pixel blue
      p += 4;
    }
    p += nOffset;
  }
  b->UnlockBits(&bmData);
  return (b);
}

int ImageManip :: GetCodecClsid(const char * _format, CLSID* pClsid)
{
	UnicodeDestroyer ud;
	ud.Str = ToUnicodeFR(_format);

	UINT num = 0;  // number of image encoders
	UINT size = 0; // size of the image encoder array in bytes
	ImageCodecInfo* pImageCodecInfo = NULL;
	GetImageEncodersSize(&num, &size);
	if(size == 0)
		return -1; // Failure
	pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
	if(pImageCodecInfo == NULL)
		return -1; // Failure
    
	GetImageEncoders(num, size, pImageCodecInfo);
	for(UINT j = 0; j < num; ++j)
	{
		if( wcscmp(pImageCodecInfo[j].MimeType, ud.Str) == 0 )
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			return j; // Success
		}
	} // for
	return -1; // Failure
} // GetCodecClsid


Bitmap * ImageManip :: GetEdge(Bitmap * b)
{
//	Bitmap b(Nam);
	Bitmap* b2;

	INT iWidth = b -> GetWidth();
	INT iHeight = b -> GetHeight();

	Rect rect(0,0,iWidth,iHeight);
	b2 = b -> Clone(rect,PixelFormat24bppRGB); 

  
	BitmapData bmData;
	BitmapData bmData2;

	b -> LockBits(rect,ImageLockModeRead | ImageLockModeWrite,PixelFormat24bppRGB,&bmData);
	b2->LockBits(rect,ImageLockModeRead |ImageLockModeWrite,PixelFormat24bppRGB,&bmData2);
   
	int stride = bmData.Stride;

	unsigned char * p2 = (unsigned char *)bmData.Scan0;
	unsigned char * p = (unsigned char *)bmData2.Scan0;
   
   
	int nOffset = stride - iWidth*3; 
	int nWidth = iWidth * 3;

	int nPixel = 0, nPixelMax = 0;

	p += stride;
	p2 += stride;
	int nThreshold = 0;
	for(int y=1;y<iHeight-1;++y)
    {
		p += 3;
		p2 += 3;

		for(int x=3; x < nWidth-3; ++x )
		{       
			nPixelMax = abs((p2 - stride + 3)[0] - (p2+stride-3)[0]);
			nPixel = abs((p2 + stride + 3)[0] - (p2 - stride - 3)[0]);
			if (nPixel>nPixelMax) nPixelMax = nPixel;
			nPixel = abs((p2 - stride)[0] - (p2 + stride)[0]);
            if (nPixel>nPixelMax) nPixelMax = nPixel;
			nPixel = abs((p2+3)[0] - (p2 - 3)[0]);
            if (nPixel>nPixelMax) nPixelMax = nPixel;
			if (nPixelMax < nThreshold) 
				nPixelMax = 0;
			
			int i = 40;
			if(nPixelMax > nThreshold && nPixelMax < i)
				nPixelMax = 0;
			
			if(nPixelMax > i)
				nPixelMax = 255;
			
			p[0] = (byte) nPixelMax;
			++ p;
			++ p2;
		}

        p += 3 + nOffset;
        p2 += 3 + nOffset;
	}
	b -> UnlockBits(&bmData);
	b2->UnlockBits(&bmData2);
	//b2->LockBits(rect,ImageLockModeRead |ImageLockModeWrite,PixelFormat24bppRGB,&bmData2);
	return b2;//bmData2;
}

int * ImageManip :: GetEdgeData(int * P,int W,int H)
{
	int * Q;
	Bitmap * b = PixelData2BitMap(W,H,P);
	if(P != NULL)
		delete [] P;
	Bitmap * b1 = GetEdge(b);
	delete []b;
	Q = Bitmap2PixelData(b1);
	delete []b1;
	for(int i = 0;i < W * H;i ++)
	{
		int r,g,b;
		r = Q[i] & (0x00ff0000);
		r = r >> 16;
		g = Q[i] & (0x0000ff00);
		g = g >> 8;
		b = Q[i] & (0x000000ff);
		if(r == 255 || g == 255 || b == 255)
		{
			Q[i] = 1;
		}
		else
		{
			Q[i] = 0;
		}
	}
	return Q;
}


void GDIP :: Init()
{
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
}

void GDIP :: ShutDown()
{
	GdiplusShutdown(gdiplusToken);
}

