/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
------------------------------------------------------------------------------*/


		#include "pict_io_jpeglib/pict_jpeglib_codec.h"
		#include "picture/pict.h"
		#include "container/narray.h"

		using namespace GS;


#if 1

extern "C"
{
	int		JpgLoad_ansic(void *buf, int len, char **output, unsigned int *width, unsigned int *height);
	int		JpgSave_ansic(char *dst, int dst_len, int *size, int qual, char *buf, unsigned int w, unsigned int h);
	void	JpgFree_ansic(char **p);
};

//------------------------------------------------------------------------------
void		FetchHCoef(char *bf, int w, int /*h*/, int x, int y, float *cf)
{
	bf += y * w * 3;
	for	( int p = (x - 2); p < (x + 2); p++ )
	{
		int		op = p;
				if	( op < 0 )	op = 0;
		else	if	( op >= w )	op = w - 1;
		*cf++ = (float)((unsigned char)bf[op * 3]);
	}
}
float		Spline4Inter(float t, float *cf)
{
	float	v = cf[1]+0.5f*t*(cf[2]-cf[0]+t*(cf[2]+cf[1]*(-2.0f)+cf[0]+t*((cf[2]-cf[1])*9.0f+(cf[0]-cf[3])*3.f+t*((cf[1]-cf[2])*15.f+(cf[3]-cf[0])*5.f+t*((cf[2]-cf[1])*6.f+(cf[0]-cf[3])*2.f)))));
			if	( v < 0.f )
			v = 0.f;
	else	if	( v > 255.f )
			v = 255.f;
	return	v;
}
char		*RgbResize(char *rgb, int ow, int oh, int w, int h)
{
	char	*nr = new char[w * h * 3], *pr;
	int		x, y, c, v;
	float	hc[4], vc[4];
	float	px, py, dx, dy;

	dx = (float)ow / (float)w;
	dy = (float)oh / (float)h;

	py = 0.f;
	pr = nr;
	for	( y = 0; y < h; y++ )
	{
		px = 0.f;
		for	( x = 0; x < w; x++ )
		{
			for	( c = 0; c < 3; c++ )
			{
				float *pvc = vc;
				for	( v = -2; v < 2; v++ )
				{
					int	sy = v + (int)py;
					if ( sy < 0 ) sy = 0;
					if ( sy >= oh ) sy = oh - 1;
					FetchHCoef(rgb + c, ow, oh, (int)px, sy, hc);
					*pvc++ = Spline4Inter(px - ((int)px), hc);
				}
				*pr++ = (unsigned char)Spline4Inter(py - ((int)py), vc);
			}
			px += dx;
		}
		py += dy;
	}
	return	nr;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void	JpeglibCppInterfaceFree(char **p)
{	JpgFree_ansic(p);	}
int		JpeglibCppInterfaceLoad(void *f, int l, char **o, unsigned int *w, unsigned int *h)
{	return	JpgLoad_ansic(f, l, o, w, h);	}
int		JpeglibCppInterfaceSave(char *dst, int dst_len, int *size, int q, char *b, unsigned int w, unsigned int h)
{	return	JpgSave_ansic(dst, dst_len, size, q, b, w, h);	}
//------------------------------------------------------------------------------

#endif

//------------------------------------------------------------------------------
bool				PictureJpeglibCodec::Load(IO::Handle &handle, Picture &picture)
{
	uchar header[2];
	handle.Rewind();
	if	(handle.Read(header, 2) != 2)
		return false;
	if	((header[0] != 0xff) || (header[1] != 0xd8))
		return false;

	// SOI marker found, good to go.
	size_t	size = handle.GetSize();
	Array <void *> buffer((uint)size);
	if	(!buffer)
		return false;

	handle.Rewind();
	handle.Read(buffer, size);

	uint width, height;
	char *c_data = NULL;

	if	(JpeglibCppInterfaceLoad(buffer, (int)size, &c_data, &width, &height))
	{
		// Transfer C data to a C++ allocation.
		picture.AllocAs(width, height);
		if	(uchar *data = picture.GetData())
		{
			uchar *j_data = (uchar *)c_data;
			for	(uint h = 0; h < height; ++h)
				for	(uint w = 0; w < width; ++w)
				{
					data[0] = j_data[2];
					data[1] = j_data[1];
					data[2] = j_data[0];
					data[3] = j_data[3];
					j_data += 4;
					data += 4;
				}
		}

		// Drop C data.
		JpeglibCppInterfaceFree(&c_data);
	}
	return asbool(picture.GetData());
}
bool				PictureJpeglibCodec::Save(IO::Handle &handle, const Picture &picture)
{
	// FIXME this is stupid.
	Array <char> dst(5000000);
	if	(!dst)
		return false;

	int size = 0;
	if	(!JpeglibCppInterfaceSave(&dst[0], (uint)dst.GetSize(), &size, 100, (char *)picture.GetData(), picture.GetWidth(), picture.GetHeight()))
		return false;

	return handle.Write(dst, size) == (size_t)size;
}
//------------------------------------------------------------------------------
