/*
Copyright (c) 2000-2010, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/


/**	@file	dkbifi.h	dkbif internal functions.
*/
#ifndef DKBIFI_H_INCLUDED

/**	Avoid multiple inclusions. */
#define DKBIFI_H_INCLUDED

#include "dk.h"

#if DK_HAVE_STRING_H
#include <string.h>
#else
#if DK_HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#include <stdio.h>
#if DK_HAVE_SETJMP_H
#if !DK_HAVE_PNG_H
#include <setjmp.h>
#endif
#endif
#if DK_HAVE_MATH_H
#include <math.h>
#endif

#if DK_HAVE_ZLIB_H
#include <zlib.h>
#if DK_HAVE_PNG_H
#include <png.h>
#endif
/* if DK_HAVE_PNG_H */
#endif
/* if DK_HAVE_ZLIB_H */
#if DK_HAVE_JPEGLIB_H
#include <jpeglib.h>
#endif
#if DK_HAVE_PNM_H
#include <pnm.h>
#else
#if DK_HAVE_NETPBM_PNM_H
#include <netpbm/pnm.h>
#endif
#endif
#if DK_HAVE_TIFF_H
#include <tiff.h>
#include <tiffio.h>
#endif

#include "dksf.h"
#include "dkerror.h"
#include "dkmem.h"
#include "dksto.h"
#include "dkma.h"
#include "dkstream.h"

#include "dkbif.h"



#if DK_HAVE_JPEGLIB_H

/**	JPEGLIB error management.
*/
struct _dkbif_jpg_error_mgr_ {
  struct jpeg_error_mgr pub;	/**< Error manager. */
#if DK_HAVE_SETJMP_H
  jmp_buf setjmp_buffer;	/**< Buffer for setjmp address. */
#endif
};

/**	JPEGLIB error management structure. */
typedef struct _dkbif_jpg_error_mgr_  dkbif_jpg_error_mgr;

/**	JPEGLIB error management pointer. */
typedef struct _dkbif_jpg_error_mgr_ *dkbif_jpg_error_ptr;

#endif


/**	JFIF analysis result: OK. */
#define JFIF_RESULT_OK			0

/**	JFIF analysis result: Probably OK (don't know exactly). */
#define JFIF_RESULT_PROBLEMATIC		1

/**	JFIF analysis result: Definitely failed. */
#define JFIF_RESULT_UNUSABLE		2


/**	Image frame.
 */
typedef struct {
  unsigned long		 n;	/**< Number of frame in file. */
  unsigned long		 w;	/**< Width in pixels. */
  unsigned long		 h;	/**< Height in pixels. */
  int			 ch;	/**< Number of channels, 1=gray...4=rgb+alpha.*/
  unsigned short	 bpc;	/**< Bits per component. */
  unsigned short	 vmask;	/**< Same as vmax, but unsigned short. */
  double		 vmax;	/**< Maximum value for bits per pixel. */
  double		 xdpi;	/**< X resolution, <0 if not specified. */
  double		 ydpi;	/**< Y resolution, <0 if not specified. */
  double		 mr;	/**< Mix background red. */
  double		 mg;	/**< Mix background green. */
  double		 mb;	/**< Mix background blue. */
  union {
    int dummy;			/**< Dummy entry if no bitmap library at all. */
#if DK_HAVE_ZLIB_H	&& DK_HAVE_PNG_H
    struct {
      /* data retrieved from png_get_IHDR() */
      unsigned long	 wi;	/**< Width. */
      unsigned long	 he;	/**< Height. */
      unsigned short	 vmask;	/**< Mask matching bit-depth bd. */
      int		 bd;	/**< Bit depth  from png_get_IHDR(). */
      int		 ct;	/**< Color type. */
      int		 it;	/**< Interlace type. */
      int		 zt;	/**< Compression type. */
      int		 ft;	/**< Filter type. */
      int		 ch;	/**< Number of channels. */
      png_color_16	 bg;	/**< Background from background chunk. */
      png_color_16p	 bgp;	/**< Pointer to bg. */
      png_uint_32	 ppm;	/**< Pixel per meter (general). */
      png_uint_32	 xppm;	/**< Pixel per meter (x). */
      png_uint_32	 yppm;	/**< Pixel per meter (y). */
      int		 have_kgd;	/**< Flag: Have background chunk. */
      png_bytep		*rows;	/**< Frame data. */
      unsigned long	 rowbytes;	/**< Number of bytes in one row. */
      png_colorp	 palp;	/* color palette */
      int		 paln;	/* elements in palette */
    } png;		/**< PNG frame. */
#endif
#if DK_HAVE_JPEGLIB_H
    struct {
      JSAMPLE			**rowbuffer;	/**< Frame data. */
    } jpg;		/**< JPEG frame. */	
#endif
#if DK_HAVE_PNM_H || DK_HAVE_NETPBM_PNM_H
    struct {
      int rows;		/**< Number of lines. */
      int cols;		/**< Number of columns. */
      int format;	/**< Format sub type. */
      xel **array;	/**< Frame pixel data. */
      xelval maxxelval;	/**< Maximum pixel data value. */
      double maxxeldbl;	/**< Maximum pixel data value converted to double. */
    } pnm;		/**< NetPBM frame. */
#endif
#if DK_HAVE_TIFF_H
    struct {
      uint32	w;	/**< Frame width. */
      uint32	h;	/**< Frame height. */
      uint16	bpc;	/**< Bits per component. */
      uint16	spp;	/**< Samples per pixel = ch. */
      uint32	*raster;	/**< Frame data. */
      double	xres;	/**< X resolution. */
      double	yres;	/**< Y resolution. */
      unsigned char rescm;	/**< Flag: resolution in TIFF in cm. */
    } tif;		/**< TIFF frame. */
#endif
    /* ---- Add additional file type here. */
  } d;			/**<	Data. */
} dk_bif_frame_t;



/**	Bif image.
 */
typedef struct {
  int			 t;	/**< Type:  DKBIF_TYPE_xxx. */
  int			 ec;	/**< Error code of last error occured. */
  unsigned long		 nof;	/**< Number of frames in file. */
  dk_storage_t		*f;	/**< Frames storage. */
  dk_storage_iterator_t	*fi;	/**< Frames storage iterator. */
  unsigned long		 w_all;	/**< Maximum width (width of widest frame). */
  unsigned long		 h_all;	/**< Maximum height (height of highest frame).*/
  dk_bif_frame_t	*cf;	/**< Current frame. */
  double		 mtl;	/**< Mask creation trigger level. */
  double		 vmax;	/**< Maximum value for bits per pixel. */
  unsigned short	 obpc;	/**< Output bits per pixel. */
  int			 m;	/**< Flag: mix against background. */
  double		 mr;	/**< Mixing background red. */
  double		 mg;	/**< Mixing background green. */
  double		 mb;	/**< Mixing background blue. */
  unsigned char		 fntsc;	/**< Flag: allow fast rgb to gray conversion. */
  unsigned char		 whs;	/**< Flag:  width and height sufficient. */
  union {
    int dummy;			/**< Dummy entry if no library available. */
    /* ----- additional file types require modifications here ----- */
#if DK_HAVE_ZLIB_H	&& DK_HAVE_PNG_H
    struct {
      png_structp	 pp;	/**< Pointer to image data. */
      png_infop		 pi;	/**< Pointer to image info. */
    } png;			/**< PNG image data. */
#endif
#if DK_HAVE_JPEGLIB_H
    struct {
      /*
        0 ... no initialization yet
	1 ... decrompress structure initialized
	2 ... + input source defined
	3 ... + header was read
	4 ... + decompression was started
	5 ... + decompression was finished
      254 ... error occured, cleanup already done
      255 ... cinfo + all data (except rowbuffer) released
      */
      int state;		/**< Current state of reading. */
      struct jpeg_decompress_struct cinfo;	/**< Decompression structure. */
      dkbif_jpg_error_mgr	emgr;		/**< Error manager. */
      dk_bif_jfif_analyze_t	jpgana;		/**< JFIF analysis manager. */
    } jpg;			/**< JPEG data. */
#endif
#if DK_HAVE_PNM_H || DK_HAVE_NETPBM_PNM_H
#endif
#if DK_HAVE_TIFF_H
    struct {
      TIFF *tiff;		/**< TIFF image data. */
    } tif;			/**< TIFF data. */
#endif
  } d;				/**< Data. */
  char *tmpfilename;		/**< Name for a temporary file .*/
} dk_bif_t;



/*
	Internal library functions
*/

/* dkbif */
#if defined(EXTERN)
#undef EXTERN
#endif
#if DKBIF_C
#define EXTERN /* nix */
#else
#if DK_HAVE_PROTOTYPES
#define EXTERN /* nix */
#else
#define EXTERN extern
#endif
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/**	Create new frame in image.
 * 	@param	b	Image.
 * 	@param	n	Frame index.
 * 	@return	Pointer on success, NULL on error.
 */
EXTERN dk_bif_frame_t *
dkbif_frame_new DK_PR((dk_bif_t *b, unsigned long n));

/**	Find maximum value for bits per component.
 * 	@param	b	Bits per component.
 * 	@return	Maximum pixel value for bit depth.
 */
EXTERN unsigned short
dkbif_max_for_bpc DK_PR((unsigned short b));
#if defined(__cplusplus)
}
#endif

/* dkbifpng */
#if DK_HAVE_ZLIB_H	&& DK_HAVE_PNG_H
#if defined(EXTERN)
#undef EXTERN
#endif
#if DKBIFPNG_C
#define EXTERN /* nix */
#else
#if DK_HAVE_PROTOTYPES
#define EXTERN /* nix */
#else
#define EXTERN extern
#endif
#endif
#if defined(__cplusplus)
extern "C" {
#endif

/**	Read PNG header for image.
 * 	@param	p	Image.
 * 	@param	f	File to read.
 * 	@return Success flag.
 */
EXTERN int
dkbifpng_header DK_PR((dk_bif_t *p, FILE *f));

/**	Read PNG data for image.
 * 	@param	p	Image.
 * 	@param	f	File to read.
 * 	@return	Success flag.
 */
EXTERN int
dkbifpng_data DK_PR((dk_bif_t *p, FILE *f));

/**	Get red component of pixel.
 * 	@param	p	Image
 * 	@param	x	Column index of pixel.
 * 	@param	y	Row index of pixel.
 * 	@return	Red component converted to output bit depth.
 */
EXTERN unsigned short
dkbifpng_red DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));

/**	Get green component of pixel.
 * 	@param	p	Image
 * 	@param	x	Column index of pixel.
 * 	@param	y	Row index of pixel.
 * 	@return	Green component converted to output bit depth.
 */
EXTERN unsigned short
dkbifpng_green DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));

/**	Get blue component of pixel.
 * 	@param	p	Image
 * 	@param	x	Column index of pixel.
 * 	@param	y	Row index of pixel.
 * 	@return	Blue component converted to output bit depth.
 */
EXTERN unsigned short
dkbifpng_blue DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));

/**	Get gray component of pixel.
 * 	@param	p	Image
 * 	@param	x	Column index of pixel.
 * 	@param	y	Row index of pixel.
 * 	@return	Gray component converted to output bit depth.
 */
EXTERN unsigned short
dkbifpng_gray DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));

/**	Get alpha component of pixel.
 * 	@param	p	Image
 * 	@param	x	Column index of pixel.
 * 	@param	y	Row index of pixel.
 * 	@return	Alpha component converted to output bit depth.
 */
EXTERN unsigned short
dkbifpng_alpha DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));

/**	Release PNG specific data of image.
 * 	This function is called when the image is released.
 * 	@param	p	Image.
 */
EXTERN void
dkbifpng_release DK_PR((dk_bif_t *p));

/**	Release data for one frame.
 * 	@param	p	Image.
 * 	@param	f	Frame to release.
 */
EXTERN void
dkbifpng_frame_release DK_PR((dk_bif_t *p, dk_bif_frame_t *f));
#if defined(__cplusplus)
}
#endif
#endif

/* dkbifjpg */
#if DK_HAVE_JPEGLIB_H
#if defined(EXTERN)
#undef EXTERN
#endif
#if DKBIFJPG_C
#define EXTERN /* nix */
#else
#if DK_HAVE_PROTOTYPES
#define EXTERN /* nix */
#else
#define EXTERN extern
#endif
#endif
#if defined(__cplusplus)
extern "C" {
#endif
EXTERN int
dkbifjpg_header DK_PR((dk_bif_t *p, FILE *f));
EXTERN int
dkbifjpg_data DK_PR((dk_bif_t *p, FILE *f));
EXTERN unsigned short
dkbifjpg_red DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbifjpg_green DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbifjpg_blue DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbifjpg_gray DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbifjpg_alpha DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN void
dkbifjpg_release DK_PR((dk_bif_t *p));
EXTERN void
dkbifjpg_frame_release DK_PR((dk_bif_t *p, dk_bif_frame_t *f));
#if defined(__cplusplus)
}
#endif
#endif

/* dkbifpbm */
#if DK_HAVE_JPEGLIB_H
#if defined(EXTERN)
#undef EXTERN
#endif
#if DKBIFPBM_C
#define EXTERN /* nix */
#else
#if DK_HAVE_PROTOTYPES
#define EXTERN /* nix */
#else
#define EXTERN extern
#endif
#endif
#if defined(__cplusplus)
extern "C" {
#endif
EXTERN int
dkbifpbm_header DK_PR((dk_bif_t *p, FILE *f));
EXTERN int
dkbifpbm_data DK_PR((dk_bif_t *p, FILE *f));
EXTERN unsigned short
dkbifpbm_red DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbifpbm_green DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbifpbm_blue DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbifpbm_gray DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbifpbm_alpha DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN void
dkbifpbm_release DK_PR((dk_bif_t *p));
EXTERN void
dkbifpbm_frame_release DK_PR((dk_bif_t *p, dk_bif_frame_t *f));
#if defined(__cplusplus)
}
#endif
#endif

/* dkbiftif */
#if DK_HAVE_TIFF_H
#if defined(EXTERN)
#undef EXTERN
#endif
#if DKBIFTIF_C
#define EXTERN /* nix */
#else
#if DK_HAVE_PROTOTYPES
#define EXTERN /* nix */
#else
#define EXTERN extern
#endif
#endif
#if defined(__cplusplus)
extern "C" {
#endif
EXTERN int
dkbiftif_header DK_PR((dk_bif_t *p, FILE *f));
EXTERN int
dkbiftif_data DK_PR((dk_bif_t *p, FILE *f));
EXTERN unsigned short
dkbiftif_red DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbiftif_green DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbiftif_blue DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbiftif_gray DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN unsigned short
dkbiftif_alpha DK_PR((dk_bif_t *p, unsigned long x, unsigned long y));
EXTERN void
dkbiftif_release DK_PR((dk_bif_t *p));
EXTERN void
dkbiftif_frame_release DK_PR((dk_bif_t *p, dk_bif_frame_t *f));
#if defined(__cplusplus)
}
#endif
#endif

/**	ERROR: Failed to process input.
*/
#define DKBIF_ERR_FAILED_TO_PROCESS_INPUT		-1

/**	ERROR: Failed to create a temporary file.
*/
#define DKBIF_ERR_FAILED_TO_CREATE_TEMPORARY_FILE	-2

/**	DPI difference to ignore.
*/
#define DPI_EPSILON					0.00001

#endif

