#include "MSurface.h"
#include <stdio.h>
#include "jpeg/jpeglib.h"


/*
  Interface entre clase MSurface y libreria JPEG.
*/

// Nombre      : MSurface::LoadJPG()
// Parametros  : char* pcFileName
// Retorno     : 0: OK ; -1: ERROR
// Descripcion : Carga un JPG desde el fichero pasado como parametro
int MSurface::LoadJPG(char* pcFileName)
{
  MVFSFILE* f;

  f=MVFS::fopen(pcFileName,"rb");
  if (!f)
  {
    return (-1);
  }

  if (LoadJPG(f)!=0)
  {
    return (-1);
  }

  MVFS::fclose(f);

  return (0);
}

// Nombre      : MSurface::SaveJPG()
// Parametros  : char* pcFileName, int iQuality
// Retorno     : 0:OK ; -1: ERROR
// Descripcion : Graba la superficie en un JPG. iQuality va de 0 a 100 y define la calidad de la imagen
int MSurface::SaveJPG(char* pcFileName, int iQuality)
{
  MVFSFILE* f;

  f=MVFS::fopen(pcFileName,"wb");
  if (!f)
  {
    return (-1);
  }

  if (SaveJPG(f, iQuality)!=0)
  {
    return (-1);
  }

  MVFS::fclose(f);

  return (0);
}

// Nombre      : MSurface::LoadJPG()
// Parametros  : MVFSFILE* f
// Retorno     : 0: OK ; -1: ERROR
// Descripcion : Carga un fichero desde el handle pasado como parametro
int MSurface::LoadJPG(MVFSFILE* f)
{
  int iReturn;
  unsigned i;
  unsigned char** pImage;
  struct jpeg_decompress_struct cinfo;  
  struct jpeg_error_mgr jerr;
  
  // Error
  cinfo.err = jpeg_std_error(&jerr);  

  // inicializamos objetos de descompresion
  jpeg_create_decompress(&cinfo);
  
  // asignamos stream de entrada
  jpeg_stdio_src(&cinfo, f);
  
  // Leemos cabecera de jpg
  jpeg_read_header(&cinfo, TRUE);

  if (cinfo.num_components!=3 || cinfo.out_color_space!=JCS_RGB)
  {
    // solo soportamos 24 bits rgb.    
    iReturn=-1;
    goto JPEGDECEND;
  }

  // Descompresion
  jpeg_start_decompress(&cinfo);


  // Inicializamos memoria
  MSurfaceDescriptor sd;
  sd.m_uiWidth=cinfo.output_width;
  sd.m_uiHeight=cinfo.output_height;
  sd.m_pfPixelFormat=CommonPixelDescriptors[E__RGB24__888];

  if (Init(sd, NULL, NULL, "")!=0)
  {
    iReturn=-1;
    goto JPEGDECEND;
  }


  pImage=new unsigned char*[cinfo.output_height];
  if (!pImage)
  {
    iReturn=-1;
    goto JPEGDECEND;
  }

  for (i=0 ; i<cinfo.output_height ; i++)
  {
    pImage[i]=(unsigned char*)GetSurfacePointer(0,i);
  }

  while (cinfo.output_scanline < cinfo.output_height) 
  {
    jpeg_read_scanlines(&cinfo, pImage+cinfo.output_scanline, cinfo.output_height);
  }

  delete[] pImage;

  jpeg_finish_decompress(&cinfo);

  iReturn=0;
  
JPEGDECEND:
  // chapamos objeto de descompresion
  jpeg_destroy_decompress(&cinfo);

  
  return (iReturn);
}

// Nombre      : MSurface::SaveJPG()
// Parametros  : MVFSFILE* f, int iQuality
// Retorno     : 0: OK ; -1: ERROR
// Descripcion : Graba la superficie al handle pasado como parametro.
//               iQuality va de 0 a 100.
int MSurface::SaveJPG(MVFSFILE* f, int iQuality)
{
  int iReturn;
  unsigned i;
  unsigned char** pImage;  
  MSurface s;
  struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;


  // Inicializamos cosillas
  cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);

  // Convertimos de imagen fuente a 24 bit RGB
  MSurfaceDescriptor sd;
  sd.m_uiWidth=this->GetPSurfaceDescriptor()->m_uiWidth;
  sd.m_uiHeight=this->GetPSurfaceDescriptor()->m_uiHeight;
  sd.m_pfPixelFormat=CommonPixelDescriptors[E__RGB24__888];
  
  if (s.Init(sd, NULL, NULL)!=0)
  {
    iReturn=-1;
    goto JPEGCOMPEND;
  }

  s.ConvertFrom(*this);
  
  // Marcamos fichero de salida
  jpeg_stdio_dest(&cinfo, f);

  cinfo.image_width       =s.GetSurfaceDescriptor().m_uiWidth;
  cinfo.image_height      =s.GetSurfaceDescriptor().m_uiHeight;
  cinfo.input_components  =3; // RGB 24 bits
  cinfo.in_color_space    =JCS_RGB;

  // Parametros de compresion por defecto
  jpeg_set_defaults(&cinfo);

  // Ajustamos calidad
  jpeg_set_quality(&cinfo, iQuality, TRUE);

  // Alocamos punteros
  pImage=new unsigned char*[s.GetSurfaceDescriptor().m_uiHeight];
  if (!pImage)
  {
    iReturn=-1;
    goto JPEGCOMPEND;
  }

  for (i=0 ; i<s.GetSurfaceDescriptor().m_uiHeight ; i++)
  {
    pImage[i]=(unsigned char*)s.GetSurfacePointer(0,i);
  }

  // empezamos compresion
  jpeg_start_compress(&cinfo, TRUE);

  // Comprimimos
  while (cinfo.next_scanline < cinfo.image_height) 
  {	    
	    jpeg_write_scanlines(&cinfo, pImage+cinfo.next_scanline, cinfo.image_height);
	}

  // Acabamos compresion
  jpeg_finish_compress(&cinfo);

  delete[] pImage;

  iReturn=0;

JPEGCOMPEND:

  jpeg_destroy_compress(&cinfo);

  return (iReturn);
}

