/******************************************************************************
 * program:     rasimg library                                                *
 * function:    Module for PNG support                                        *
 * modul:       ras_png.cc                                                    *
 * licency:     GPL or LGPL                                                   *
 ******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "types.h"
#include "raster.h"

#include <png.h>
#ifndef png_infopp_NULL
 #define png_infopp_NULL	NULL
#endif


#if (PNG_LIBPNG_VER_MAJOR>1) || (PNG_LIBPNG_VER_MAJOR==1 && PNG_LIBPNG_VER_MINOR>=5)
 #define USE_PNG1_5
#endif



#define SupportPNG  2



#ifdef SupportPNG


#if SupportPNG>=4 || SupportPNG==2
Image LoadPicturePNG(const char *Name)
{
Image Img;
png_byte header[8];			// 8 is the maximum size that can be checked
Raster2DAbstract *Raster = NULL;
APalette *Palette = NULL;
FILE *f;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_colorp palette;
int num_palette;
png_byte color_type;
int number_of_passes;
int i;

  if((f=fopen(Name,"rb"))==NULL) return(Img);

  fread(header, 1, 8, f);
  if(png_sig_cmp(header, 0, 8)) goto FINISH;

	/* initialize stuff */
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	
  if(!png_ptr) return(Img);	// [read_png_file] png_create_read_struct failed

  info_ptr = png_create_info_struct(png_ptr);
  if(!info_ptr) return(Img);	// [read_png_file] png_create_info_struct failed

  if(setjmp(png_jmpbuf(png_ptr))) return(Img);	// [read_png_file] Error during init_io

  png_init_io(png_ptr, f);
  png_set_sig_bytes(png_ptr, 8);

  png_read_info(png_ptr, info_ptr);

  //color_type = info_ptr->color_type;
  color_type = png_get_color_type(png_ptr,info_ptr);

  number_of_passes = png_set_interlace_handling(png_ptr);
  png_read_update_info(png_ptr, info_ptr);

	/* read file */
  if(setjmp(png_jmpbuf(png_ptr))) goto FINISH;	  // [read_png_file] Error during read_image  

  switch(png_get_channels(png_ptr,info_ptr))
    {
    case 1: if(png_get_rowbytes(png_ptr,info_ptr) > (png_get_image_width(png_ptr,info_ptr)*png_get_bit_depth(png_ptr,info_ptr)+7)/8) goto FINISH;
	    Raster = CreateRaster2D(png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),png_get_bit_depth(png_ptr,info_ptr));

            png_get_PLTE(png_ptr,info_ptr, &palette, &num_palette);
            if(num_palette>0 && palette!=NULL)
              {
              Palette = BuildPalette(num_palette,8);
	      if(Palette)
                {
                for(i=0;i<num_palette;i++)
		  {
		  Palette->R(i,palette[i].red);
		  Palette->G(i,palette[i].green);
		  Palette->B(i,palette[i].blue);
                  }
		}
              }
	    break;
    case 3: if(png_get_rowbytes(png_ptr,info_ptr) > (3*png_get_image_width(png_ptr,info_ptr)*png_get_bit_depth(png_ptr,info_ptr))/8) goto FINISH;
	    Raster = CreateRaster2DRGB(png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),png_get_bit_depth(png_ptr,info_ptr));
	    break;
    case 4: if(png_get_rowbytes(png_ptr,info_ptr) > (4*png_get_image_width(png_ptr,info_ptr)*png_get_bit_depth(png_ptr,info_ptr))/8) goto FINISH;
	    Raster = CreateRaster2DRGBA(png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),png_get_bit_depth(png_ptr,info_ptr));
	    break;	    
    }
  if(Raster==NULL) goto FINISH;

  png_read_image(png_ptr, (png_byte **)Raster->Data2D);


FINISH:
  fclose(f);
	/* Clean up after the read, and free any memory allocated - REQUIRED */
  if(png_ptr)
    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);

  Img.AttachRaster(Raster);
  Img.AttachPalette(Palette);  

  return(Img);  /* And we're done! */
}
#endif


#if SupportPNG>=3

// !!! NOT FINISHED !!!
int SavePicturePNG(const char *Name,const Image &Img)
{


	/* create file */
	FILE *fp = fopen(file_name, "wb");
	if (!fp)
		abort_("[write_png_file] File %s could not be opened for writing", file_name);


	/* initialize stuff */
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	
	if (!png_ptr)
		abort_("[write_png_file] png_create_write_struct failed");

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		abort_("[write_png_file] png_create_info_struct failed");

	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during init_io");

	png_init_io(png_ptr, fp);


	/* write header */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during writing header");

	png_set_IHDR(png_ptr, info_ptr, width, height,
		     bit_depth, color_type, PNG_INTERLACE_NONE,
		     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	png_write_info(png_ptr, info_ptr);


	/* write bytes */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during writing bytes");

	png_write_image(png_ptr, row_pointers);


	/* end write */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during end of write");

	png_write_end(png_ptr, NULL);

        /* cleanup heap allocation */
	for (y=0; y<height; y++)
		free(row_pointers[y]);
	free(row_pointers);

        fclose(fp);

}
#endif


TImageFileHandler PNG_Supp(".PNG",
#if SupportPNG>=4 || SupportPNG==2
	LoadPicturePNG,
#else
	NULL,
#endif
#if SupportPNG>=3
	SavePicturePNG);
#else
	NULL);
#endif


#endif

