/**
@brief JPEG 2000グラフィックデータ定義 for C++  (with OpenJpeg-1.5)

現在は JPEG 2000の読み込みのみ．@n
何枚もの画像が含まれていたり，オフセットが指定されている場合には未対応．

@file     Jpeg2KTool.cpp
@version  0.9
@date	  2014 10/19 
@author   Fumi.Iseki (C)

@attention
this software is based on OpenJPEG. http://www.openjpeg.org/
*/


#include "Jpeg2KTool.h"


#ifdef ENABLE_OPENJPEG

#if OPENJPEG_VERSION == JP2K_VER_15



using namespace jbxl;


void  JPEG2KImage::init(void)
{
	xs 	  = 0;
	ys 	  = 0;
	col   = 0;
	cmode = GRAPH_COLOR_RGBA;
	state = 0;
	image = NULL;
}


bool  JPEG2KImage::isNull(void)
{
	if (image!=NULL && image->comps!=NULL) return false;
	return true;
}


void  JPEG2KImage::free(void)
{
	if (image!=NULL) {
		opj_image_destroy(image);
	}

	init();
}


void  JPEG2KImage::fill(int v)
{
	if (!isNull()) {
		for (int k=0; k<col; k++) {
			if (image->comps[k].data!=NULL) {	
				for (int i=0; i<xs*ys; i++) {
					image->comps[k].data[i] = v;
				}
			}
		}
	}
}


void  JPEG2KImage::setup_image(void)
{
	if (!isNull()) {
		//
		xs = image->x1;
		ys = image->y1;

		col = 0;
		if (image->color_space==CLRSPC_UNSPECIFIED) {
			col = (int)image->numcomps;
		}
		else if (image->color_space==CLRSPC_SRGB) {
			col = 3;
		}
		else if (image->color_space==CLRSPC_GRAY) {
			col = 1;
		}
/*
		else if (image->color_space==CLRSPC_SYCC) {
			color_sycc_to_rgb(image);
			col = 3;
		}
*/

		// 設定されないものについては，未対応
		cmode = GRAPH_COLOR_UNKNOWN;
		int depth = (int)image->comps->bpp;
		if (depth==0) {
			if      (col==3) cmode = GRAPH_COLOR_RGB;
			else if (col==4) cmode = GRAPH_COLOR_RGBA;
		}
		else if (depth==32) {
			if      (col==3) cmode = GRAPH_COLOR_RGB;
			else if (col==4) cmode = GRAPH_COLOR_RGBA;
		}
		else if (depth==24) {
			if      (col==3) cmode = GRAPH_COLOR_RGB;
		}
		else if (depth==16) {
			if      (col==1) cmode = GRAPH_COLOR_MONO16;
			else if (col==3) cmode = GRAPH_COLOR_RGB16;
			else if (col==4) cmode = GRAPH_COLOR_RGBA16;
		}
		else if (depth==8) {
			if      (col==1) cmode = GRAPH_COLOR_MONO;
		}
  
		//
		freeNull(image->icc_profile_buf);
		image->icc_profile_len = 0;

/*
		DEBUG_MODE {
			print_message("JPEG2KImage::setup_image: OFFSET  %d %d %d %d\n", image->x0, image->y0, image->x1, image->x1);
			print_message("JPEG2KImage::setup_image: NUMCOMP %d\n", image->numcomps);
			print_message("JPEG2KImage::setup_image: COLORSP %d\n", image->color_space);
			print_message("JPEG2KImage::setup_image: XS YS   %d %d\n", xs, ys);
			print_message("JPEG2KImage::setup_image: COLOR   %d\n", col);
			print_message("JPEG2KImage::setup_image: CMODE   %d\n", cmode);
			print_message("\n");
			for (int i=0; i<(int)image->numcomps; i++) {
				print_message("JPEG2KImage::setup_image: DX DY %d %d\n", image->comps[i].dx, image->comps[i].dy);
				print_message("JPEG2KImage::setup_image: W  H  %d %d\n", image->comps[i].w,  image->comps[i].h);
				print_message("JPEG2KImage::setup_image: X0 Y0 %d %d\n", image->comps[i].x0, image->comps[i].y0);
				print_message("JPEG2KImage::setup_image: PREC  %d\n", image->comps[i].prec);
				print_message("JPEG2KImage::setup_image: DEPTH %d\n", image->comps[i].bpp);
				print_message("JPEG2KImage::setup_image: SGND  %d\n", image->comps[i].sgnd);
				print_message("JPEG2KImage::setup_image: RESNO %d\n", image->comps[i].resno_decoded);
				print_message("JPEG2KImage::setup_image: FACT  %d\n", image->comps[i].factor);
				print_message("\n");
			}
		}
*/
	}
}
	
	
	


//////////////////////////////////////////////////////////////////////

JPEG2KImage  jbxl::readJPEG2KFile(const char* fname)
{
	JPEG2KImage jp;
	//
	if (fname==NULL) {
		jp.state = ERROR_GRAPH_IVDARG;
		return jp;
	}

	int len = (int)file_size(fname);

	FILE* fp = fopen(fname, "rb");
	if (fp==NULL) {
		jp.state = ERROR_GRAPH_OPFILE;
		return jp;
	}

	unsigned char* data = (unsigned char*)malloc(len);
	if (data==NULL) {
		fclose(fp);
		jp.state = ERROR_GRAPH_MEMORY;
		return jp;
	}

	Buffer buf = read_Buffer_data(fp, 12);
	fseek(fp, 0, 0);
	int format = isJPEG2KHeader(buf);
	if (format==JP2K_FMT_NONE) format = JP2K_FMT_JPT;
	free_Buffer(&buf);

	fread(data, len, 1, fp);
	fclose(fp);

	jp = readJPEG2KData(data, len, format);
	::free(data);

	return jp;
}



JPEG2KImage  jbxl::readJPEG2KData(unsigned char* data, int len, int format)
{
	JPEG2KImage jp;

	opj_dinfo_t* codec  = NULL;
	opj_cio_t*	 stream = NULL;

	opj_dparameters_t parameters;	
	opj_set_default_decoder_parameters(&parameters);

	if (format==JP2K_FMT_J2K) {			// JPEG 2000 codestream
		codec = opj_create_decompress(CODEC_J2K);
	}	
	else if (format==JP2K_FMT_JP2) {	// JPEG 2000 compressed image data
		codec = opj_create_decompress(CODEC_JP2);
	}
	else if (format==JP2K_FMT_JPT) {	// JPEG 2000 JPIP
		codec = opj_create_decompress(CODEC_JPT);
	}
	else {
		print_message("JBXL::readJPEG2KData: ERROR: unknown file format!\n");
		jp.state = ERROR_GRAPH_NODATA;
		return jp;
	}

	opj_setup_decoder(codec, &parameters);
	stream = opj_cio_open((opj_common_ptr)codec, data, len);
	jp.image = opj_decode(codec, stream);
	if (jp.image==NULL) {
		opj_cio_close(stream);
		opj_destroy_decompress(codec);
		jp.state = ERROR_GRAPH_IVDDATA;
		return jp;
	}

	jp.setup_image();

	opj_cio_close(stream);
	opj_destroy_decompress(codec);

	return jp;
}



/**
JPEG 2000のヘッダからファイルの種類を返す．@n
ただし，ヘッダから JP2K_FMT_JPTであることは判別できないので，注意する．

@param buf ヘッダ情報の入った Buffer変数．最低12Byte必要．
@return    ファイル種別 (JP2K_FMT_NONE, JP2K_FMT_JP2, JP2K_FMT_J2K)
*/
int	 jbxl::isJPEG2KHeader(Buffer buf)
{
	int format = JP2K_FMT_NONE;

	if (!memcmp(buf.buf, JP2K_MAGIC_RFC3745_JP2, 12) || !memcmp(buf.buf, JP2K_MAGIC_JP2, 4)) {
		format = JP2K_FMT_JP2;
	}
	else if (!memcmp(buf.buf, JP2K_MAGIC_J2K, 4)) {
		format = JP2K_FMT_J2K;
	}
	return format;
}





#endif  	// OPENJPEG_VERSION
#endif  	// ENABLE_OPENJPEG



 
