/*
								+---------------------------------+
								|                                 |
								|  ***   Tiny jpeg decoder   ***  |
								|                                 |
								|  Copyright  © -tHE SWINe- 2006  |
								|                                 |
								|             Jpeg.h              |
								|                                 |
								+---------------------------------+
*/

#pragma once
#ifndef __TINY_JPEG_INCLUDED
#define __TINY_JPEG_INCLUDED

/**
 *	@file Jpeg.h
 *	@author -tHE SWINe-
 *	@date 2006
 *	@brief tiny jpeg decoder (compiles to cca 3kB with MSVC)
 *
 *	@date 2006-08-30
 *
 *	todo - write code for __JPEG_DEC_ALLOW_SUBSAMPLED_IMAGES code path (not really necessary).
 *	todo - write code to support 12-bit extended DCT images.
 *	todo - refine code for lossless compression to eliminate rounding error when decompressing > 8bit
 *	lossless images (alloc just two int16 scanlines to remember predictor values).
 *
 *	@date 2007-09-27
 *
 *	fixed error with restart interval being set to 0 in some jpeg files (value 0 means restart
 *	is disabled, which is rather strange, it would be better not to mention it at all).
 *
 *	@date 2007-11-12
 *
 *	reformat (added line breaks where lines were longer than 100 characters).
 *
 *	@date 2007-12-24
 *
 *	improved linux compatibility by adding posix integer types.
 *
 *	@date 2008-02-25
 *
 *	added function for loading jpegs from memory.
 *
 *	@date 2008-03-04
 *
 *	using Integer.h header, using CallStack.h instead of crtdbg.h.
 *	renamed CTinyJpegDecoder::CFileBuffer to CTinyJpegDecoder::CBufferredFile.
 *	changed size of zigZag table back to 64 and it's type to int (speed / obfuscation purposes).
 *
 *	@date 2008-03-11
 *
 *	fixed error on line 1281 where macroblock index overrun check was "less than 63",
 *	it should've been 64 (error carried-in on 2008-03-04 update).
 *
 *	@date 2008-07-25
 *
 *	added ability to load image "thumbnails" using DC values only. while this is very
 *	fast, it works for lossy compression only. loading thumbnail of lossless image would
 *	result in access violation right now. but this is low priority, nobody uses lossless
 *	jpeg today.
 *
 *	@date 2008-09-11
 *
 *	added ability to get image information without having to decode it trough overloaded
 *	function CTinyJpegDecoder::t_JPEG_Info().
 *
 *	@date 2009-05-04
 *
 *	fixed mixed windows / linux line endings.
 *
 *	@date 2012-02-16
 *
 *	Clarified that CTinyJpegDecoder::TimageInfo::n_bit_width is number of bits per pixel component
 *	rather than the number of bits per pixel (e.g. for RGB8 image, this value is 8 (not 24)).
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 *	@date 2012-07-20
 *
 *	Added convenience functions CTinyJpegDecoder::p_Load_Jpeg() and CTinyJpegDecoder::t_Jpeg_Info().
 *
 */

#include "Bitmap.h"
#include <stdio.h>
#include "DCT.h"

/*
 *		=== config section ===
 */

/**
 *	@def __JPEG_DEC_MAX_COMPONENT_NUM
 *
 *	@brief maximal number of color components
 *
 *	Decoding routines are written to support arbitrary number of components,
 *		colorspace conversion routines support 1 - 4 components. Almost all
 *		jpeg implementatinos use 4. Maximum possible component count in jpeg is 255.
 */
#define __JPEG_DEC_MAX_COMPONENT_NUM 4

/**
 *	@def __JPEG_DEC_VERBOSE
 *
 *	@brief If defined, prints tables, header info, ... (to stdout).
 */
//#define __JPEG_DEC_VERBOSE

/**
 *	@def __JPEG_DEC_READ_VERBOSE
 *
 *	@brief If defined, prints some debug info about file input (to stdout).
 */
//#define __JPEG_DEC_READ_VERBOSE

/**
 *	@def __JPEG_DEC_DECODE_VERBOSE
 *
 *	@brief If defined, prints decoding progress (i.e. Huffman codes, DCT coeffs (to stdout).
 */
//#define __JPEG_DEC_DECODE_VERBOSE

/**
 *	@def __JPEG_DEC_ALLOW_SUBSAMPLED_GRAYSCALE
 *
 *	Jpeg specs allow grayscale images with sampling 1x1 only. If defined, decoder is able to
 *		render grayscale images with other sampling factors as well (do not affect rendering of
 *		color images).
 *
 *	@note Resulting code is larger when enabled.
 */
//#define __JPEG_DEC_ALLOW_SUBSAMPLED_GRAYSCALE

/**
 *	@def __JPEG_DEC_SUPPORT_LOSSLESS
 *
 *	@brief If defined, decoder can handle lossless jpeg images as well.
 */
//#define __JPEG_DEC_SUPPORT_LOSSLESS

/**
 *	@def __JPEG_DEC_USE_LOSSLESS_NONSTD_RLE
 *
 *	@brief Do @c NOT use!
 *
 *	If defined, jpeg lossless algorithm is further enhanced by RLE compression. <tt>This is non-standard
 *		extension, which requires all images to be written by encoder, supporting this extension!</tt>
 *		Never use in programs where your jpeg files are available in standalone-file form so they could
 *		be potentialy copied away! Do not breed nor allow anyone to breed non-standard jpegs away from
 *		your app (note there is no record in image file header wheter this extension was used or not).
 *
 *	@note It is more appropriate to use PNG format instead, this may be used only if code size
 *		is constraint.
 */
//#define __JPEG_DEC_USE_LOSSLESS_NONSTD_RLE

/**
 *	@def __JPEG_DEC_SUPPORT_RG
 *
 *	@brief Enable branch that can unpack two-channel Jpeg images (RG).
 *
 *	It is possible to use RG images for uv-maps for effects like water distortion, etc).
 *		It is of course possible to use regular RGB as well, setting blue channel to zero.
 */
//#define __JPEG_DEC_SUPPORT_RG

/**
 *	@def __JPEG_DEC_SUPPORT_YCCK
 *
 *	@brief Enables branch that can unpack YCCK images.
 */
//#define __JPEG_DEC_SUPPORT_YCCK

#ifndef __JPEG_DEC_SUPPORT_YCCK
/**
 *	@def __JPEG_DEC_SUPPORT_CMYK
 *
 *	@brief enables branch that can unpack CMYK images
 *
 *	Enable branch that can unpack CMYK images (jpeg does contain component number only,
 *		not component meaning so it's possible to handle 4-component jpegs either
 *		as YCCK (common), or as CMYK (possible, but not widely used)).
 *
 *	@note This can be only used if __JPEG_DEC_SUPPORT_YCCK is not defined (this has
 *		lower priority).
 */
//#define __JPEG_DEC_SUPPORT_CMYK
#endif

/**
 *	@def __JPEG_DEC_INTEGER_IDCT
 *
 *	@brief enables use of fast integer IDCT
 *
 *	If defined, uses faster integer IDCT, otherwise usea precise, slower float IDCT.
 *
 *	@note In MSVC, it's faster only if compiling with optimize speed. With optimize size,
 *		it's a little bit slower.
 */
#define __JPEG_DEC_INTEGER_IDCT

#if defined(__JPEG_DEC_INTEGER_IDCT) && defined(DCT_ENABLE_MMX) && !defined(_DEBUG)
/**
 *	@def __JPEG_DEC_USE_MMX
 *
 *	@brief if defined, faster MMX integer IDCT path is used
 *
 *	@note This is only used if __JPEG_DEC_INTEGER_IDCT is defined.
 *	@note MMX IDCT note code is a bit larger (~500 bytes) than integer IDCT code.
 */
#define __JPEG_DEC_USE_MMX
#endif

//#define __JPEG_DEC_STRIP_ERROR_CHECKS
// if defined, all error checks aparts from alloc success tests are removed - saves a few code bytes
// (arround 1 kB; use with precaution - errors during decoding process may make your program crash)

/**
 *	@def __JPEG_DEC_RGB
 *
 *	@brief if defined, swaps R and B during colorspace transformation, making the
 *		colorspace RGBX (the default UberLame colorspace is BGRA)
 *
 *	@note It is possible to swap R and B later, but it is redundant operation. This doesn't
 *		actually swap R and B, but calculates it swapped instead (with zero cost).
 */
//#define __JPEG_DEC_RGB

/*
 *		=== ~config section ===
 */

/**
 *	@brief Tiny jpeg decoder (compiles to ~3kB)
 *
 *	This is tiny (and not very fast) jpeg decoder. Can decode baseline jpeg images
 *		with 1, 2, 3 or 4 color components. Doesn't support progressive jpeg, but
 *		does support lossless jpeg (if __JPEG_DEC_SUPPORT_LOSSLESS defined).
 */
class CTinyJpegDecoder {
public:
	/**
	 *	@brief information about jpeg image
	 *
	 *	Holds information about an image, namely width and height in pixels,
	 *		number of color components and number of bits per component.
	 */
	struct TImageInfo {
		int n_width, /**< image width, in pixels */
			n_height; /**< image height, in pixels */
		int n_component_num, /**< number of image color components (usually 1 or 3) */
			n_bit_width; /**< number of bits per component (usually 8) @note This was not tested with 12bpp jpegs. */
	};

private:
	static int p_zig_indices[64]; // actualy inverse zig sequence

	class CBufferredFile { // class for fast buffered file input (also assures byte-order reversion)
	protected:
		unsigned char _m_p_buffer_[16384], *m_p_buffer;
		static const size_t m_n_buffer_size;
		size_t m_n_buffer_used;
		const unsigned char *m_p_buffer_ptr;
		FILE *m_p_fr;

	public:
		CBufferredFile(FILE *p_fr);
		CBufferredFile(const unsigned char *p_data, size_t n_size);
		bool Read_Byte(uint8_t &r_n_byte);
		bool Read_Short(int16_t &r_n_short);
		bool inline Read_Short(uint16_t &r_n_short) { return Read_Short((int16_t&)r_n_short); }
		bool Read_Marker(uint16_t &r_n_marker_code);
		bool Skip_Bytes(size_t n_byte_num);
	};

	class CBitReader { // class for reading bit-by-bit, used in huffman decoder
	protected:
		uint8_t m_n_cur_byte; // current byte, it's shifted as we eat bits
		bool m_b_0xff_byte; // set to true if last byte read was 0xff
		uint8_t m_n_bit_num; // number of valid bits in byte
		bool m_b_error_flag;

	public:
		CBitReader();
		bool inline b_Error() { return m_b_error_flag; }
		uint8_t n_GetBit(CBufferredFile *p_file_buffer);
		int16_t n_GetNumber(int n_bit_num, CBufferredFile *p_file_buffer);
		void Restart();
	};

	struct TBlockAction { // table for block actions
		uint16_t n_id;
		bool (*p_function)(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	};
	static const TBlockAction m_p_action_table[];

	struct TQuantTable { // quantization table
		bool b_16_bit; // otherwise 8-bit
#ifdef __JPEG_DEC_INTEGER_IDCT
		int p_value[64]; // 16:16 fixed-point (short would be enough for 8-bit quant tables, but not for 16 bit)
#else
		float p_value[64]; // hack! - should be unsigned short, but i pre-multiplied it and can use faster IDCT function
#endif
	} m_p_quant_table[4];
	// quantization tables (can be separate one for each component)

	struct THuffmanTable {
		bool b_valid; // did we read it from the file? in case we didn't, it could make our program crash, (unlikely if quantization tables are missing, image just looks scrambled but it can never make program crash)
		uint8_t p_code_num[16]; // number of codes for all possible 16 lengths
		uint8_t *p_code[16]; // 16 pointers into p_code_table where the actual data are
		uint16_t p_min_code_value[16]; // min and max code value; n+1 bit code must be >= p_min_code_value[n] && < p_max_code_value[n] (thus in case p_code_num[n] == 0 then also p_min_code_value[n] == p_max_code_value[n])
		//uint16_t p_max_code_value[16]; // don't store this, it's equal to p_min_code_value[n] + p_code_num[n]
		uint8_t p_code_table[256]; // table for all huffman codes
	} m_p_huffman_table[4][2]; // 0 = AC, 1 = DC
	// huffman tables (can be separate one for each component)

	struct TComponentInfo {
		uint8_t n_component_id; // 1 = Y, 2 = Cb, 3 = Cr (JFIF standard)
		uint8_t n_sampling_horiz;
		uint8_t n_sampling_vert; // component sampling (1, 2, or 4 usually)
		uint8_t n_scale_horiz;
		uint8_t n_scale_vert;
		uint8_t n_quant_table_index; // used quantization table
	};
	// outside TImageHeader because of scope issues (needed visibility for TScanHeader::TComponentInfo)

	struct TImageHeader {
		uint16_t n_frame_start_marker; // marker_SOF0_HuffBaseline_DCT supported for now only
		uint8_t n_sample_precision; // 8 (8 or 12 for extended baseline or progressive)
		int16_t n_height;
		int16_t n_width;
		int n_macro_block_num, n_macro_block_x_num; // number of macro-blocks
		uint8_t n_component_num; // should be 1-4 (1 = gray, 3 = YCbCr, 4 = CMYK)
		TComponentInfo p_component_info[__JPEG_DEC_MAX_COMPONENT_NUM];
	} m_t_image_header;
	// image header

	struct TRestartInterval {
		bool b_enabled;
		uint16_t n_interval;
	} m_t_restart;
	// restart interval definition

	struct TScanHeader {
		uint8_t n_component_num; // should match TImageHeader::n_component_num

		struct TComponentInfo2 {
			uint8_t n_component_id; // should match TImageHeader::TComponentInfo::n_component_id
			TComponentInfo *p_component; // points to image header component
			uint8_t n_DC_entropy_table;
			uint8_t n_AC_entropy_table; // table indices <0, 3>
			THuffmanTable *p_DC_table, *p_AC_table;
		} p_component_info[__JPEG_DEC_MAX_COMPONENT_NUM];

		uint8_t n_spectrum_first; // index (in zig-zag order) of first coded coefficient
		uint8_t n_spectrum_last; // index (in zig-zag order) of last coded coefficient (should be set to 63 for sequential DCT)
		uint8_t n_sucessive_approximation; // two nibbles, point transform, should be zero (not used in marker_SOF0_HuffBaseline_DCT)
	};

	struct TImageData {
		bool b_read_image_header;
		bool b_want_image; // do we want to decode image?
		bool b_want_thumbnail; // do we want to decode thumbnails?
#ifdef __JPEG_DEC_SUPPORT_LOSSLESS
		bool b_lossless; // set to true in case marker_SOF3_HuffLossless was read; valid only if b_read_image_header == true
#endif
		uint8_t *p_framebuffer[__JPEG_DEC_MAX_COMPONENT_NUM]; // frame-buffers, as big as image size / component sampling
		uint16_t p_framebuffer_width[__JPEG_DEC_MAX_COMPONENT_NUM];
		uint16_t p_framebuffer_height[__JPEG_DEC_MAX_COMPONENT_NUM];
		int16_t p_dc_value[__JPEG_DEC_MAX_COMPONENT_NUM]; // dc accumulators
	} m_t_image_data; // cleared always when starting decoding jpeg

	template <const int n_component_num, class TColorConversion>
	class CImageRenderer;
	// template body in Jpeg.cpp (don't want to put it here as it's pretty useless)

public:
	/**
	 *	@copydoc p_Decode_JPEG
	 */
	static inline TBmp *p_Load_Jpeg(const char *p_s_filename, bool b_thumbnail = false)
	{
		TBmp *p_image;
		CTinyJpegDecoder dec;
		FILE *p_fr;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
		if(fopen_s(&p_fr, p_s_filename, "rb"))
#else //_MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		if(!(p_fr = fopen(p_s_filename, "rb")))
#endif //_MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
			return 0;
		if(!(p_image = dec.p_Decode_JPEG(p_fr, b_thumbnail))) {
			fclose(p_fr);
			return 0;
		}
		fclose(p_fr);
		return p_image;
	}

	/**
	 *	@copydoc t_JPEG_Info
	 */
	static inline TImageInfo t_Jpeg_Info(const char *p_s_filename, bool b_thumbnail = false)
	{
		TImageInfo t_info = {0};
		CTinyJpegDecoder dec;
		FILE *p_fr;
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER >= 1400
		if(fopen_s(&p_fr, p_s_filename, "rb"))
#else //_MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
		if(!(p_fr = fopen(p_s_filename, "rb")))
#endif //_MSC_VER && !__MWERKS__ && _MSC_VER >= 1400
			return t_info;
		t_info = dec.t_JPEG_Info(p_fr, b_thumbnail);
		fclose(p_fr);
		return t_info;
	}

	/**
	 *	@brief loads image from a file
	 *
	 *	@param[in] p_fr is opened file, containing jpeg image (may contain more, decoding
	 *		will stop at image end marker)
	 *	@param[in] b_thumbnail is thumbnail flag; if set, only DC values are used to load
	 *		the image, resulting in faster loading times, but also 8 times smaller resolution
	 *
	 *	@return Returns pointer to bitmap on success, null pointer on failure.
	 *
	 *	@note Output format of color images may be either RGB, or BGR. Refer to
	 *		__JPEG_DEC_RGB macro documentation for more details.
	 */
	TBmp *p_Decode_JPEG(FILE *p_fr, bool b_thumbnail = false);

	/**
	 *	@brief loads image from a file
	 *
	 *	@param[in] p_data is pointer to memory, containing jpeg data
	 *	@param[in] n_size is size of jpeg in memory
	 *	@param[in] b_thumbnail is thumbnail flag; if set, only DC values are used to load
	 *		the image, resulting in faster loading times, but also 8 times smaller resolution
	 *
	 *	@return Returns pointer to bitmap on success, null pointer on failure.
	 *
	 *	@note Output format of colorf images may be either RGB, or BGR. Refer to
	 *		__JPEG_DEC_RGB macro documentation for more details.
	 */
	TBmp *p_Decode_JPEG(const void *p_data,
		unsigned int n_size, bool b_thumbnail = false);

	/**
	 *	@brief gets information about image in a file
	 *
	 *	@param[in] p_fr is opened file, containing jpeg image (may contain more, decoding
	 *		will stop at image end marker)
	 *	@param[in] b_thumbnail is thumbnail flag; if set, only DC values are used to load
	 *		the image, resulting in faster loading times, but also 8 times smaller resolution
	 *
	 *	@return Returns TImageInfo with information about given jpeg file on success,
	 *		or TImageInfo with all fields set to null on failure (file is not readable
	 *		/ not jpeg).
	 */
	TImageInfo t_JPEG_Info(FILE *p_fr, bool b_thumbnail = false);

	/**
	 *	@brief gets information about image in a file
	 *
	 *	@param[in] p_data is pointer to memory, containing jpeg data
	 *	@param[in] n_size is size of jpeg in memory
	 *	@param[in] b_thumbnail is thumbnail flag; if set, only DC values are used to load
	 *		the image, resulting in faster loading times, but also 8 times smaller resolution
	 *
	 *	@return Returns TImageInfo with information about given jpeg file on success,
	 *		or TImageInfo with all fields set to null on failure (file is not readable
	 *		/ not jpeg).
	 */
	TImageInfo t_JPEG_Info(const void *p_data,
		unsigned int n_size, bool b_thumbnail = false);

	/**
	 *	@brief supplies quantization tables before decoding
	 *
	 *	In Jpeg, it's possible to supply quantization tables before decoding image.
	 *	Iimage is decoded anyway, even if it doesn't contain quantization tables, and
	 *	it is possible to save some space if all images use the same quantization
	 *	tables.
	 *
	 *	@param[in] n_index is zero-based quant table index, has to be in range 0 - 3
	 *	@param[in] p_table points to table data (if b_16_bit == false, then it's array
	 *		of 64 unsigned chars, if b_16_bit == true then it's array of 64
	 *		unsigned shorts)
	 *	@param[in] b_16_bit chooses between 16-bit data in p_table (true), or 8-bit
	 *		data (false).
	 */
	bool Supply_QuantTable(int n_index, const void *p_table, bool b_16_bit);

private:
	bool Read_Blocks(CBufferredFile &file_buffer, bool b_thumbnail, bool b_image);
	TBmp *_p_Decode_JPEG(CBufferredFile &file_buffer, bool b_thumbnail);
	TImageInfo _t_JPEG_Info(CBufferredFile &file_buffer, bool b_thumbnail);
	static bool Read_SkipMarker(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	static bool Read_Unsupported(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	static bool Read_Skip(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	static bool Read_JFIF_Header(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	static bool Read_RestartInterval(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	static bool Read_QuantTables(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	static bool Read_HuffmanTables(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	static bool Read_FrameHeader(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	static bool Read_StartScan(uint16_t n_block_id, CTinyJpegDecoder *p_this, CBufferredFile *p_file_buffer);
	bool Decode_Baseline_MacroBlock(int n_macro_block_index, const TScanHeader *p_scan_head,
		CBitReader &r_bit_reader, CBufferredFile *p_file_buffer);
	bool Decode_Baseline_MacroBlock_DCOnly(int n_macro_block_index, const TScanHeader *p_scan_head,
		CBitReader &r_bit_reader, CBufferredFile *p_file_buffer);
#ifdef __JPEG_DEC_SUPPORT_LOSSLESS
	bool Decode_Lossless_Image(const TScanHeader *p_scan_head,
		CBitReader &r_bit_reader, CBufferredFile *p_file_buffer);
#endif
};

#endif // !__TINY_JPEG_INCLUDED
