/*
	tiff.c

	ＴＩＦＦ画像セーブ・ロード関数
	（２００ＫＢ程度のメモリが必要）
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <egb.h>
#include <wgb.h>
#include <msdos.cf>
#include <malloc.h>

#include <ryosuke.h>
#include <tifflib.h>
#include <msdos.cf>
#include <usrlib.h>

#define	DATABUF		(32*1024)
#define	IMAGEBUF	(16*1024)
#define	WORKBUF		_max(DECOMP_WORK_SIZE,COMP_WORK_SIZE)

static char *databuf = NULL;
static char *imagebuf = NULL;
static char *workbuf = NULL;
static int x,y;
static FILE *fp;
static	TIFFinfo	tiffinfo;


/*--------------------------------------------------------*/
/*                   作業用メモリの確保                   */
/*--------------------------------------------------------*/


int TIFFinitwork()
// 返値 0=正常終了  -1=メモリ不足
{
	if (databuf == NULL) {		// 作業用メモリ領域の確保
		if ((databuf = malloc(DATABUF+IMAGEBUF+WORKBUF)) == NULL)
			return -1;
		imagebuf = databuf + DATABUF;
		workbuf = imagebuf + IMAGEBUF;
	}
	return 0;
}

int TIFFinitworkGUI()
// 返値 0=正常終了  -1=メモリ不足
{
	if (databuf == NULL) {		// 作業用メモリ領域の確保
		if ((databuf = TL_calloc(1,DATABUF+IMAGEBUF+WORKBUF)) == NULL)
			return -1;
		imagebuf = databuf + DATABUF;
		workbuf = imagebuf + IMAGEBUF;
	}
	return 0;
}


/*--------------------------------------------------------*/
/*                 TIFF データの読み出し                  */
/*--------------------------------------------------------*/


static int load_x0, load_y0;


static int input_data(char *buf, int size)
{
	fread(buf,1,size,fp);
	return 0;
}


static int output_image(char *buf, int lofs, int lines)
{
	struct { char *buf;  short sel, sx,sy,ex,ey; } p;
	p.buf = buf;			p.sel = getds();
	p.sx = load_x0;			p.ex = load_x0 + x - 1;
	p.sy = load_y0 + lofs;	p.ey = load_y0 + lofs + lines - 1;
	EGB_putBlock( EGB_work, 0, (char*)&p );
	return 0;
	/*
		if (!(_wrtpage & 0x80)) {
			struct { char *buf;  short sel, sx,sy,ex,ey; } p;
			p.buf = buf;			p.sel = getds();
			p.sx = load_x0;			p.ex = load_x0 + x - 1;
			p.sy = load_y0 + lofs;	p.ey = load_y0 + lofs + lines - 1;
			EGB_putBlock(EGB_work, 0, (char*)&p);
			return 0;
		} else {
			gputblk(buf, load_x0, load_y0+lofs, x, lines, 0);
			return 0;
		}
	*/
}


static int (*putimagefunc)() = NOFNCint;


void TIFFload_putimagefunc(int (*func)())
{
	putimagefunc = func;
}


int TIFFload(char *fname, int x0, int y0)
// 返値  0=成功  -1=失敗
{
	if (TIFFinitwork() != 0)
		return -1;
	load_x0 = x0;
	load_y0 = y0;
	if ((fp = fopen(fname,"rb")) == NULL)
		return -1;
	fread(databuf,1,DATABUF,fp);		// ヘッダの読み出し
	if (TIFF_getHead(databuf,DATABUF) < 0)
		goto END;
	int pixelsize;
	int comp,fill;
	long strip,clut;
	if ((pixelsize = TIFF_checkMode(&x,&y,&comp,&fill,&strip,&clut)) < 0)
		goto END;
	if (pixelsize == 24)
		goto END;
	if (putimagefunc == NOFNCint)
		TIFF_setLoadFunc(output_image, input_data);
	else
		TIFF_setLoadFunc(putimagefunc, input_data);
	int img_xlen, img_ylen;
	img_xlen = (pixelsize==4 ? ((x+7) & 0xfffffff8) : x);
	img_ylen = IMAGEBUF / ((img_xlen*pixelsize+7)/8);
	if (clut!=0) {
		char plt[256*8+4];
		TIFF_getPal(plt);
		EGB_palette(EGB_work, 0, plt);
	}
	TIFF_loadImage(pixelsize,x,y,strip,fill,comp,
				   imagebuf,img_xlen,img_ylen,workbuf);
END:
	fclose(fp);
	// TIFF情報構造体の更新
	{
		tiffinfo.xlen = x;
		tiffinfo.ylen = y;
	}
	return 0;
}


/*--------------------------------------------------------*/
/*                 TIFF データの書き込み                  */
/*--------------------------------------------------------*/


static int save_x1, save_y1, save_xlen, save_ylen;


static int output_data(char *buf, long size)
{
	if (fwrite(buf,1,size,fp) < size)
		return -1;
	return 0;
}


static int input_image(char *buf,int lofs,int lines)
{
	struct { char *buf;  short sel, sx,sy,ex,ey; } p;
	p.buf = buf;	p.sel = getds();
	p.sx = save_x1;			p.ex = save_x1 + save_xlen - 1;
	p.sy = save_y1 + lofs;	p.ey = save_y1 + lofs + lines - 1;
	EGB_getBlock(EGB_work, (char*)&p);
	return 0;
}


#define	NOFNC	((int (*)())0)


static int (*getimagefunc)() = NOFNCint;


void TIFFsave_getimagefunc(int (*func)())
{
	getimagefunc = func;
}


int TIFFsave(char *fname, int x1,int y1,int xlen,int ylen, bool compress)
// 返値  0=成功  -1=画面モード/ファイル名の間違い
//				 -2=メモリ不足  -3=ディスク領域不足  -4=get関数エラー
{
	if (TIFFinitwork() != 0)
		return -2;
	save_x1 = x1;
	save_y1 = y1;
	save_xlen = xlen;
	save_ylen = ylen;
	int pixelsize,headsize;
	char _palet[256*8+4],*palet;
	palet = NULL;
	headsize = 512;

	int scrmod, wrtpage;
	wrtpage = EGB_getWritePage(EGB_work, getds());
	if ( wrtpage == 0 )
		scrmod = ( EGB_getResolution( NULL, NULL ) & 255 );
	else
		scrmod = ( (EGB_getResolution( NULL, NULL ) >> 8) & 255 );

	if (scrmod == 3 || scrmod == 4)
	{
		pixelsize = 4,  x = 640, y = 480;
		EGB_getPalette(wrtpage, _palet);
		palet = _palet;
	}
	else if (5 <= scrmod && scrmod <= 8)
		pixelsize = 16,	x = 256, y = 240;
	else if (9 <= scrmod && scrmod <= 11)
		pixelsize = 16, x = 320, y = 240;
	else if (12 <= scrmod && scrmod <= 14)
	{
		pixelsize = 8,  x = 640, y = 480;
		EGB_getPalette(wrtpage, _palet);
		palet = _palet;
		headsize = 2048;
	}
	else if (15 <= scrmod && scrmod <=18)
		pixelsize = 16,  x = 512, y = 480;
	else
		return -1;
	//
	// (1) ファイルをオープンし、ヘッダのサイズ分シークする。
	//     ヘッダサイズ : 256色モード=2048 bytes  その他モード=512 bytes
	if ((fp = fopen(fname,"wb")) == NULL)
		return -1;
	if (fwrite(databuf,1,headsize,fp) < headsize)
		{ fclose(fp);  return -3; }
	//
	// (2) 画面データの取り出しルーチンと、ファイルへ書き出すルーチンを登録
	if (getimagefunc == NOFNCint)
		TIFF_setSaveFunc(output_data,input_image);
	else
		TIFF_setSaveFunc(output_data,getimagefunc);
	//
	// (3) TIFF のセーブルーチンをコールする
	int img_xlen,img_ylen;
	img_xlen = (pixelsize==4 ? ((save_xlen+7) & 0xfffffff8) : save_xlen);
	img_ylen = IMAGEBUF / ((img_xlen*pixelsize+7)/8);
	int cmp_size;
	cmp_size = TIFF_saveImage(pixelsize, save_xlen, save_ylen, (compress? 5:1),
							  databuf, DATABUF, imagebuf, img_xlen, img_ylen,
							  workbuf);
	if (cmp_size == -1)
		{ fclose(fp);  return -4; }
	else if (cmp_size == -2)
		{ fclose(fp);  return -3; }
	//
	// (4) ヘッダ情報をつくる
	TIFF_setHead(databuf,pixelsize,save_xlen,save_ylen,
				 (compress? cmp_size: 0), palet);
	//
	// (5) ファイルを先頭にシークして、ヘッダを書き出し、クローズ
	fflush(fp);
	long nowfp;
	nowfp = ftell(fp);
	rewind(fp);
	if (fwrite(databuf,1,headsize,fp) < headsize)
		{ fclose(fp);  return -3; }
	fflush(fp);
	fseek(fp,nowfp,SEEK_SET);
	fclose(fp);
	// TIFF情報構造体の更新
	{
		tiffinfo.xlen = save_xlen;
		tiffinfo.ylen = save_ylen;
	}
	return 0;
}


/*--------------------------------------------------------*/
/*         TIFF データファイルに関する情報を得る          */
/*--------------------------------------------------------*/


int TIFFgetinfo(char *fname, TIFFinfo *info)
// 返値  0=正常終了
//      -1=ファイルが存在しない
//      -2=TIFF形式ではない
//      -3=メモリが足りない
{
	if (TIFFinitwork() != 0)
		return -3;
	if ((fp = fopen(fname,"rb")) == NULL)
		return -1;
	fread(databuf,1,DATABUF,fp);		// ヘッダの読み出し
	fclose(fp);
	if (TIFF_getHead(databuf,DATABUF) < 0)
		return -2;
	int xlen,ylen,pixelsize,comp,fill;  long strip,clut;
	if ((pixelsize = TIFF_checkMode(&xlen,&ylen,&comp,&fill,&strip,&clut)) < 0)
		return -2;
	info->xlen = xlen;
	info->ylen = ylen;
	info->compress = (comp == 1 ? NO : YES);
	info->pixelsize = pixelsize;
	return 0;
}

/* end of tiff.c */
