#include"image.h"
#include<string.h>
#include<GameOs\PNG\png.h>

int Image::IsPng(Stuff::FileStream *stream)
{

	int i;
	BYTE hdr[8],chdr[8];

	bool ret;
	
	chdr[0]=0x89;
	chdr[1]=0x50;
	chdr[2]=0x4E;
	chdr[3]=0x47;
	chdr[4]=0x0D;
	chdr[5]=0x0A;
	chdr[6]=0x1A;
	chdr[7]=0x0A;

	stream->ReadBytes(hdr,8);
ret=true;
	for(i=0;i<8;i++)
	{
	if(hdr[i]!=chdr[i]) ret=false;
	}

stream->Rewind();
return ret;

}

FILE		*imgpngfl=NULL;
Stuff::FileStream *imgpngstream=NULL;

void imlibPngReadCallback(png_structp png, png_bytep pbtData, png_size_t nLength)
{
	Verify((imgpngstream!=NULL && imgpngfl==NULL) || (imgpngstream==NULL && imgpngfl!=NULL));

	if(imgpngfl)
		fread((LPVOID)pbtData,nLength,1,imgpngfl);
	else
		imgpngstream->ReadBytes(pbtData,nLength);
}

void imlibPngWriteCallback(png_structp png, png_bytep pbtData, png_size_t nLength)
{
	Verify((imgpngstream!=NULL && imgpngfl==NULL) || (imgpngstream==NULL && imgpngfl!=NULL));

	if(imgpngfl)
		fwrite(pbtData,nLength,1,imgpngfl);
	else
		imgpngstream->WriteBytes(pbtData,nLength);
}


void Image::InternalLoadPng()
{
png_structp	m_png;					// Our PNG ADT
png_infop	m_pPngInfo;				// Info retrieved from the PNG data up to IDAT chunk

int			m_nColorType;
int			m_nInterlaceType;
int			m_nBitDepth;


//
// Reading PNG files
//
	m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	m_pPngInfo = png_create_info_struct(m_png);
	if( m_pPngInfo == NULL )
		STOP(( "Error Reading file '%s'",fname ));

	#pragma warning( disable: 4611 )
	setjmp(m_png->jmpbuf);
	#pragma warning( default: 4611 )

		
	png_set_read_fn( m_png, 0, imlibPngReadCallback );

	png_read_info(m_png, m_pPngInfo);

	png_uint_32	nDummy;
	int	nCompressionType, nFilterType;
	png_get_IHDR(m_png, m_pPngInfo, &nDummy, &nDummy, &m_nBitDepth, &m_nColorType, &m_nInterlaceType, &nCompressionType, &nFilterType);

/*
	if (m_nColorType == PNG_COLOR_TYPE_PALETTE)
		png_set_expand(m_png);

	if (m_nColorType == PNG_COLOR_TYPE_GRAY && m_nBitDepth < 8)
		png_set_expand(m_png);

	if (m_nColorType == PNG_COLOR_TYPE_GRAY)
		png_set_gray_to_rgb(m_png);

	if (png_get_valid(m_png, m_pPngInfo, PNG_INFO_tRNS))
		png_set_expand(m_png);

		png_set_bgr(m_png);
		png_set_filler(m_png, 0xff, PNG_FILLER_AFTER);
*/
	xpos=ypos=0;
	vxlen=xlen=m_pPngInfo->width;
	vylen=ylen=m_pPngInfo->height; 
	Bpp=m_pPngInfo->pixel_depth;
		
		itype=ITYPE_RGB;

	if (m_nColorType == PNG_COLOR_TYPE_PALETTE)
		itype=ITYPE_INDEXED;

	if (m_nColorType == PNG_COLOR_TYPE_GRAY && m_nBitDepth < 8)
		itype=ITYPE_INDEXED;

	if (m_nColorType == PNG_COLOR_TYPE_GRAY)
		itype=ITYPE_INDEXED;

	if(itype==ITYPE_INDEXED) MakeGrayscalePalette();
	IAlloc();
	BYTE *dat=(BYTE *)Lock();
	
	for( int y=0; y<ylen; y++ )
	{
		png_read_row(m_png, (BYTE*)dat+Pitch*y, NULL);
	}
//
// Clean up PNG reading
//
	UnLock();
	png_read_end(m_png, m_pPngInfo);
	png_destroy_read_struct(&m_png, (png_infopp)(m_pPngInfo ? &m_pPngInfo : NULL), (png_infopp)NULL );

	if(itype!=ITYPE_INDEXED)	
	{
		if(Bpp==24)
			Mask.Set(0x0000ff,0x00ff00,0xff0000); 
		else
			if(Bpp==32)
				Mask.Set(0x000000ff,0x0000ff00,0x00ff0000,0xff000000); 
	}



}

void Image::LoadPng(Stuff::FileStream *stream)
{
	imgpngfl=NULL;
	imgpngstream=stream;	
	InternalLoadPng();
}

void Image::LoadPng(FILE *fl)
{
	imgpngfl=fl;
	imgpngstream=NULL;	
	InternalLoadPng();
}


void Image::InternalSavePng()
{
	png_structp	m_png;					// Our PNG ADT
png_infop	m_pPngInfo;				// Info retrieved from the PNG data up to IDAT chunk

	m_png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	m_pPngInfo = png_create_info_struct(m_png);

	#pragma warning( disable: 4611 )
	setjmp(m_png->jmpbuf);
	#pragma warning( default: 4611 )
	
	png_set_write_fn( m_png, 0, imlibPngWriteCallback ,NULL);

	if(itype!=ITYPE_INDEXED)	
	{
		if(Bpp==24)
			MaskTo(RGBMask(0x0000ff,0x00ff00,0xff0000)); 
		else
			if(Bpp==32)
				MaskTo(RGBMask(0x000000ff,0x0000ff00,0x00ff0000,0xff000000)); 
	}


if(itype==ITYPE_RGB)
{
if(GetBpp()==32)
	png_set_IHDR(m_png, m_pPngInfo, xlen, ylen, 8, PNG_COLOR_TYPE_RGB_ALPHA,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
else
	png_set_IHDR(m_png, m_pPngInfo, xlen, ylen, 8, PNG_COLOR_TYPE_RGB,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
else
{
	png_set_IHDR(m_png, m_pPngInfo, xlen, ylen, 8, PNG_COLOR_TYPE_GRAY,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}



  png_write_info(m_png, m_pPngInfo);

  BYTE *dat=(BYTE *)Lock();

	for( int y=0; y<ylen; y++ )
	{
		png_write_row(m_png, (BYTE*)dat+Pitch*y);
	}
UnLock();
	png_write_end(m_png, m_pPngInfo);
	png_destroy_write_struct(&m_png, (png_infopp)(m_pPngInfo ? &m_pPngInfo : NULL));


}


void Image::SavePng(Stuff::FileStream *stream)
{
	imgpngfl=NULL;
	imgpngstream=stream;	
	InternalSavePng();
}

void Image::SavePng(FILE *fl)
{
	imgpngfl=fl;
	imgpngstream=NULL;	
	InternalSavePng();
}

void Image::GetPngInfo(Stuff::FileStream *stream)
{
	int i;
	BYTE hdr[8],chdr[8];

	unsigned int cnkhdr=0,chunksize,chunktag;
	
	chdr[0]=0x89;
	chdr[1]=0x50;
	chdr[2]=0x4E;
	chdr[3]=0x47;
	chdr[4]=0x0D;
	chdr[5]=0x0A;
	chdr[6]=0x1A;
	chdr[7]=0x0A;

	stream->ReadBytes(hdr,8);
	for(i=0;i<8;i++)
	{
	if(hdr[i]!=chdr[i]) GENFERR("Not a png file");
	}
	

	stream->ReadBytes(&chunksize,4);
	stream->ReadBytes(&chunktag,4);
	
	stream->ReadBytes(&xlen,4);
	stream->ReadBytes(&ylen,4);
	stream->ReadBytes(&ylen,4);
	
	Bpp=0;
	stream->ReadBytes(&Bpp,1);

	BYTE tbt;
	stream->ReadBytes(&tbt,1);

	if(tbt==3)
		itype=ITYPE_INDEXED;
	else
		itype=ITYPE_RGB;

		if(itype!=ITYPE_INDEXED)	
	{
		if(Bpp==24)
			Mask.Set(0x0000ff,0x00ff00,0xff0000); 
		else
			if(Bpp==32)
				Mask.Set(0x0000ff00,0x00ff0000,0xff000000,0x000000ff); 
	}

}

int Image::IsPng()
{
	char *spos;
	spos=NULL;
	int i,slen=strlen(fname);
	for(i=slen-1;i>=0 && fname[i]!='.';i--);
	if(i<0) return 0;
	if(fname[i]=='.') spos=fname+i+1;
	return !strcmpi("png",spos);
}

int Image::IsPng(FILE *fl)
{
if(!fl)  GENNFERR("Invalid File");

	int i;
	BYTE hdr[8],chdr[8];
	int fpos=ftell(fl);

	bool ret;
	
	chdr[0]=0x89;
	chdr[1]=0x50;
	chdr[2]=0x4E;
	chdr[3]=0x47;
	chdr[4]=0x0D;
	chdr[5]=0x0A;
	chdr[6]=0x1A;
	chdr[7]=0x0A;

	fread(hdr,8,1,fl);
ret=true;
	for(i=0;i<8;i++)
	{
	if(hdr[i]!=chdr[i]) ret=false;
	}

fseek(fl,fpos,SEEK_SET);
return ret;
}

void Image::LoadPng(char *str)
{
	Stuff::FileStream stream;
	stream.Open(str,Stuff::FileStream::ReadOnly);
	LoadPng(&stream);
	strcpy(fname,str);
}

void Image::GetPngInfo(FILE *fl)
{
	int i,pos;
	BYTE hdr[8],chdr[8];
	pos=ftell(fl);

	unsigned int cnkhdr=0,chunksize,chunktag;
	
	chdr[0]=0x89;
	chdr[1]=0x50;
	chdr[2]=0x4E;
	chdr[3]=0x47;
	chdr[4]=0x0D;
	chdr[5]=0x0A;
	chdr[6]=0x1A;
	chdr[7]=0x0A;

	fread(hdr,8,1,fl);
	for(i=0;i<8;i++)
	{
	if(hdr[i]!=chdr[i]) GENFERR("Not a png file");
	}
	

	fread(&chunksize,4,0,fl);
	fread(&chunktag,4,0,fl);
	
	fread(&xlen,4,0,fl);
	fread(&ylen,4,0,fl);

	fread(&ylen,4,0,fl);
	
	Bpp=(int)getc(fl);

	if(getc(fl)==3)
		itype=ITYPE_INDEXED;
	else
		itype=ITYPE_RGB;

		if(itype!=ITYPE_INDEXED)	
	{
		if(Bpp==24)
			Mask.Set(0x0000ff,0x00ff00,0xff0000); 
		else
			if(Bpp==32)
				Mask.Set(0x0000ff00,0x00ff0000,0xff000000,0x000000ff); 
	}

}

void Image::GetPngInfo(char *str)
{
	Stuff::FileStream stream;
	stream.Open(str,Stuff::FileStream::ReadOnly);
	GetPngInfo(&stream);
	strcpy(fname,str);
}





void Image::SavePng(char *str)
{
	Stuff::FileStream stream;
	stream.Open(str,Stuff::FileStream::WriteOnly);
	SavePng(&stream);
	strcpy(fname,str);
}


