/*------------------------------------------------------------------------------*
 * File Name: matdata_utils.c 													*
 * Creation: 2006-12-11															*
 * Purpose: matrix data functions, ROI tec										*
 * Copyright (c) OriginLab Corp. 2006											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * EJP 2007-09-05 v8.0697 QA70-10337 ACCESS_MATOBJ_PAL							*
 *	Hong 07/16/09 QA80-13532 NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP			*
 *------------------------------------------------------------------------------*/

#include <Origin.h>

#include <image_utils.h>
#include <oErrMsg.h> 

#include <ReportTree.h>
//#include <..\Originlab\grobj_utils.h> 
#include <..\Originlab\matdata_utils.h>

/// Hong 07/16/09 QA80-13532 NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
class BitmapHandlePtr
{
public:
	BitmapHandlePtr(BOOL bOwner = TRUE);
	~BitmapHandlePtr();
	
	pBITMAPHANDLE Get();
	BOOL SetAsOwner(BOOL bIsOwner);
private:
	BOOL			m_bIsOwner;
	pBITMAPHANDLE	m_pbh;
};

BitmapHandlePtr::BitmapHandlePtr(BOOL bOwner/* = TRUE*/)
{
	m_pbh = ol_new_bitmap();
	m_bIsOwner = TRUE;
}

BitmapHandlePtr::~BitmapHandlePtr()
{
	if ( m_pbh && m_bIsOwner )
		ol_delete_bitmap(m_pbh);
}

pBITMAPHANDLE BitmapHandlePtr::Get()
{
	return m_pbh;
}
BOOL BitmapHandlePtr::SetAsOwner(BOOL bIsOwner)
{
	BOOL	bOldVal = m_bIsOwner;
	m_bIsOwner = bIsOwner;
	return bOldVal;
}
/// end NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP

///Sandy 2006-12-19 MOVE_TO_IMAGE_LPROFLIE_DATA
/*
///---Sim 12-11-2006 GET_IMAGE_LINE_PROFILE
bool get_matrix_line_profile(GraphObject& go, MatrixObject& mo, vector& vxPoints, vector& vyPoints, vector& vIntensity)
{
	if ( !go.IsValid() || !mo.IsValid() )
		return false;
	
	int nPType = PROJECTION_NONE;
	int nWidth = get_thick_line_width(go);
	int nDir = get_thick_line_dir(go);
	
	matrix& mat = mo.GetDataObject();
	int nCols = mat.GetNumCols();
	int nRows = mat.GetNumRows();
	
	//convert xy to mat index
	vector vx(2), vy(2);
	if(nDir == LN_HORIZONTAL)
	{
		vx[0] = 0;
		vx[1] = nCols;
		vy[0] = go.Y + ( (double)nWidth/2 );
		vy[1] = go.Y + ( (double)nWidth/2 );
		
	}
	else if(nDir == LN_VERTICAL)
	{
		vy[0] = 0;
		vy[1] = nRows;
		vx[0] = go.X + ( (double)nWidth/2 );
		vx[1] = go.X + ( (double)nWidth/2 );		
	}
	else
	{
		return false;//temp
	}
	
	double dPts;

	switch(nPType)
	{
	case PROJECTION_HOR:
		vector vxDiff;
		vx.Difference(vxDiff);
		vxDiff.Sum(dPts);
		break;
	case PROJECTION_VER:
		vector vyDiff;
		vy.Difference(vyDiff);
		vyDiff.Sum(dPts);
		break;
	case PROJECTION_NONE:
		vector vxDiff;
		vx.Difference(vxDiff);
		vector vyDiff;
		vy.Difference(vyDiff);
		for (int ii = 0; ii < vxDiff.GetSize(); ii++)
		{
			double nx = floor(vxDiff[ii] + 0.5);
			double ny = floor(vyDiff[ii] + 0.5);
			dPts += sqrt(nx*nx + ny*ny);
		}
		break;
	}
	int nPts = floor(dPts + 0.5);
	nPts++;
		
	vxPoints.SetSize(nPts);
	vyPoints.SetSize(nPts);
	vector vError(nPts);
	
	vIntensity.SetSize(nPts);

	int nRet = ocmath_image_lines_profile(nRows, nCols, mat,
		vx.GetSize(), vx, vy,
		nPts, vxPoints, vyPoints, vIntensity, vError,
		nWidth, INTERP2_NEAREST, nPType);
		
 	return true;
}
///---END GET_IMAGE_LINE_PROFILE
*/


///Sandy 2006-12-19 MOVE_FROM_IMAGE_UTILS 
//---- CPY 12/7/06 DATA_TO_IMAGE_MAT
//Sandy 2006-12-9 PALLETE_NEED_WHEN_8BITS
//int image_convert_from_data(const MatrixObject& moSource, MatrixObject& moLBitmap, double dMin, double dMax, int nBits)


int image_convert_from_data(const MatrixObject& moSource, MatrixObject& moLBitmap, 
						double dMin, double dMax, int nBits, const HPALETTE hPalette)
{
	///Sandy 2007-5-29 move to set_image_data()
	/*
	pBITMAPHANDLE pLBmp = ol_new_bitmap();
	if(NULL == pLBmp)
		return -1;
	//if(dMin == dMax)
		//return -2;
	int nMin = 0, nMax;
	
	
	if(nBits == 16)
		nMax = 0x0000FFFF;
	else if(nBits == 12)
		nMax = 0x00000FFF;
	else
		nMax = 0x000000FF;

	
	matrix m1(moSource);
	int nErr = ocmath_linear_transform(m1, 0, m1.GetNumCols()*m1.GetNumRows(), nMin, nMax, dMin, dMax);
	

	///Sandy 2007-5-23 ADD Bits=12 support
	//if(nBits == 16)
	if(nBits == 16 || nBits == 12)
	{	
		matrix<ushort> m2;
		m2 = m1;
		int nRet = ol_create_bitmap_from_matrix(pLBmp, m2, m2.GetNumCols(), m2.GetNumRows());
		if( nRet != SUCCESS )
			return -10;
	}
	else //if(nBits == 8)
	{

		///add by Sandy 2006-12-9
		int nRet;
		if(hPalette!=NULL)
		{
			nRet = L_SetBitmapPalette(pLBmp, hPalette);
			if( nRet != SUCCESS )
				return nRet;
		}
		//end
		//
		matrix<byte> m2;
		m2 = m1;
		

		
		nRet = ol_create_bitmap_from_byte_matrix(pLBmp, m2, m2.GetNumCols(), m2.GetNumRows());
		if( nRet != SUCCESS )
			return -10;

	}

	
	moLBitmap.SetLeadBitmap(pLBmp, false, true);
	*/
	matrix mData(moSource);
	return set_image_data(mData, moLBitmap, dMin, dMax, nBits, hPalette );
}
//------


int image_to_gray(MatrixObject& mo, int nbits)
{
	if(!mo.IsValid())
		return XFERR_INVALID_IMAGE;
	
	Image img(mo);
	if(!img.IsValid())
		return XFERR_INVALID_IMAGE;
	
	BITMAPHANDLE* pLBmp = img.GetLBmp();
	
	return image_to_gray(pLBmp, nbits);
	
}

int image_to_gray(BITMAPHANDLE* pLBmp, int nbits)
{
	
	if(nbits != 8 && nbits != 12 && nbits != 16)
		return INTOPTN_OUT_OF_RANGE;
	
	return L_GrayScaleBitmap(pLBmp, nbits);

}


bool is_image_grayscale(MatrixObject& mo)
{
	if(!mo.IsValid())
		return false;
	
	Image img(mo);
	if(!img.IsValid())
		return false;
	
	BITMAPHANDLE* pLBmp = img.GetLBmp();
	
	return is_image_grayscale(pLBmp);

}

bool is_image_grayscale(BITMAPHANDLE* pLBmp)
{
	if(GRAY_NO == L_IsGrayScaleBitmap(pLBmp))
		return false;
	
	return true;
}
///end

int image_split_rgb(const MatrixObject& moSource, MatrixObject& moRed, MatrixObject& moGreen, MatrixObject& moBlue, BOOL bRenameAccordingToChannel)
{
	int nRet = FAILURE;
	if( moSource )
	{
		pBITMAPHANDLE pLBmpSrc = (pBITMAPHANDLE)moSource.GetLeadBitmap();
		if( pLBmpSrc )
		{
			pBITMAPHANDLE pbhR, pbhG, pbhB;
			/// Hong 07/16/09 QA80-13532 NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
			//pbhR = ol_new_bitmap();
			//pbhG = ol_new_bitmap();
			//pbhB = ol_new_bitmap();
			BitmapHandlePtr	bhptrR, bhptrG, bhptrB;
			pbhR = bhptrR.Get();
			pbhG = bhptrG.Get();
			pbhB = bhptrB.Get();
			/// end NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
			nRet = ol_color_separate_bitmap(pLBmpSrc, COLORSEP_RGB, pbhB, pbhG, pbhR);
			if( SUCCESS == nRet )
			{
				moRed.SetLeadBitmap(pbhR, false, true);
				moGreen.SetLeadBitmap(pbhG, false, true);
				moBlue.SetLeadBitmap(pbhB, false, true);
				/// Hong 07/16/09 QA80-13532 NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
				bhptrR.SetAsOwner(false);
				bhptrG.SetAsOwner(false);
				bhptrB.SetAsOwner(false);
				/// end NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
			}
		}
	}
	return nRet;
}

int image_merge_rgb(MatrixObject& moTarget, const MatrixObject& moRed, const MatrixObject& moGreen, const MatrixObject& moBlue)
{
	// Check all matrix objects.
	if( !moTarget || !moRed || !moGreen || !moBlue )
		return FAILURE;

	// Get and check LeadBitmaps from source matrix objects.
	pBITMAPHANDLE pbhR, pbhG, pbhB;
	pbhR = (pBITMAPHANDLE)moRed.GetLeadBitmap();
	pbhG = (pBITMAPHANDLE)moGreen.GetLeadBitmap();
	pbhB = (pBITMAPHANDLE)moBlue.GetLeadBitmap();
	if( NULL == pbhR || NULL == pbhG || NULL == pbhB )
		return FAILURE;

	// Get LeadBitmap from target matrix object.
	bool bNew = false;
	pBITMAPHANDLE pbhDst = (pBITMAPHANDLE)moTarget.GetLeadBitmap();
	
	// If target matrix object does not have LeadBitmap then create new one for it.
	if( NULL == pbhDst )
	{
		pbhDst = ol_new_bitmap();
		if( NULL == pbhDst )
			return FAILURE;
		bNew = true;
	}
	int nRet = ol_color_merge_bitmap(pbhDst, COLORSEP_RGB, pbhB, pbhG, pbhR);
	/// Hong 07/16/09 QA80-13532 NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
	/*
	if( SUCCESS == nRet )
		moTarget.SetLeadBitmap(pbhDst, true, true);
	else if( bNew )
		L_FreeBitmap(pbhDst);
	*/
	if( SUCCESS == nRet )
		moTarget.SetLeadBitmap(pbhDst, !bNew, true);
	else if( bNew )
		ol_delete_bitmap(pbhDst);
	/// end NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP

	return nRet;
}

/// YuI 08/30/06 QA70-8944 IMAGE_TYPE_XVARIABLE
/**
*/
int image_split_rgb(const Image& imgSource, Image& imgRed, Image& imgGreen, Image& imgBlue)
{
	BITMAPHANDLE bhR, bhG, bhB;
	
	int nRet = ol_color_separate_bitmap(imgSource.GetLBmp(), COLORSEP_RGB, &bhB, &bhG, &bhR);
	if( SUCCESS == nRet )
	{
		imgRed.SetLBmp(&bhR);
		imgGreen.SetLBmp(&bhG);
		imgBlue.SetLBmp(&bhB);
	}
	L_FreeBitmap(&bhR);
	L_FreeBitmap(&bhG);
	L_FreeBitmap(&bhB);
	return nRet;
}

int image_merge_rgb(Image& imgTarget, const Image& imgRed, const Image& imgGreen, const Image& imgBlue)
{
	pBITMAPHANDLE pbhR = imgRed.GetLBmp();
	pBITMAPHANDLE pbhG = imgGreen.GetLBmp();
	pBITMAPHANDLE pbhB = imgBlue.GetLBmp();
	
	if( NULL == pbhR || NULL == pbhG || NULL == pbhB )
		return FAILURE;

	// Get LeadBitmap from target matrix object.
	bool bNew = false;
	pBITMAPHANDLE pbhDst = imgTarget.GetLBmp();
	if( NULL == pbhDst )
	{
		pbhDst = ol_new_bitmap(); 
		if( NULL == pbhDst )
			return FAILURE;
		bNew = true;
	}
	int nRet = ol_color_merge_bitmap(pbhDst, COLORSEP_RGB, pbhB, pbhG, pbhR);
	/// Hong 07/16/09 QA80-13532 NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
	/*
	if( SUCCESS == nRet )
		imgTarget.SetLBmp(pbhDst, true);
	else if( bNew )
		L_FreeBitmap(pbhDst);
	*/
	if( SUCCESS == nRet )
		imgTarget.SetLBmp(pbhDst, !bNew);
	else if( bNew )
		ol_delete_bitmap(pbhDst);
	/// end NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP

	return nRet;
}

//------ CPY 9/7/05 ROTATE_FOR_8_BITS_MATRIX
/*
int image_rotate(MatrixObject& moTarget, double dAngle)
{
	if( FSI_USHORT != moTarget.GetInternalData() )
		return FAILURE; // unsupported matrix type

	string strDatasetName = moTarget.GetDatasetName();
	
	Matrix<USHORT> mat(strDatasetName);

	UINT nNumCols = mat.GetNumCols();
	UINT nNumRows = mat.GetNumRows();
	
	BITMAPHANDLE LBmp;
	int nRet = ol_create_bitmap_from_matrix(&LBmp, mat, nNumCols, nNumRows);
	if( nRet != SUCCESS )
		return nRet;

	dAngle *= 100;
	int nAngle = dAngle;
	nRet = L_RotateBitmap(&LBmp, nAngle, ROTATE_RESIZE, 0); // let caller specify last two args?
	if( nRet != SUCCESS )
		return nRet;

	mat.SetSize(LBmp.Height, LBmp.Width);

	nRet = ol_set_matrix_from_bitmap(mat, &LBmp);
	if( nRet != SUCCESS )
		return nRet;
	
	L_FreeBitmap(&LBmp);
	return SUCCESS;
}
*/
///CPY we dont need this anymore, with MatrixObjLeadBitmap class, can easily call Lead function directly
/*	
int image_rotate(MatrixObject& moTarget, double dAngle)
{
	MatrixObjLeadBitmap	lbmp(moTarget);
	if(lbmp.IsValid())
	{
		dAngle *= 100;
		int nAngle = dAngle;
		return L_RotateBitmap(&lbmp.m_LBmp, nAngle, ROTATE_RESIZE, 0); // let caller specify last two args?
	}
	return FAILURE;
}
*/
//---------
//------Sandy 10/9/2005, for get image data range from color bit
//no support ROMM order(will return 0)
int get_image_data_max_val(pBITMAPHANDLE BmpHdl)
{
	int nMaxVal=0;
	int nChannelNum=0;


	/// YuI 11/09/05 QA70-8279 REPORT_TREE_AND_REPORT_DATA_XVARIABLES
	// I do not know why it is here but it prevents imgHistogram from working properly
	// will send e-mail to Sandy to look
	/*
	if(BmpHdl.Order==ORDER_ROMM)//8bits and less or 24bit and 48bit ROMM order
	{
		return 0;
	}
	*/
	/// end REPORT_TREE_AND_REPORT_DATA_XVARIABLES
	
	if(L_IsGrayScaleBitmap(BmpHdl)==GRAY_NO)
		nChannelNum=3;
	else
		nChannelNum=1;


	switch(BmpHdl->BitsPerPixel)
	{
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
	case 6:
	case 7:
	case 8:
		nMaxVal=255;
		break;
	case 12://only GrayScale
		if(nChannelNum!=1)
			return 0;
		nMaxVal=4095;
		break;
	case 16://only GrayScale
		nMaxVal=65535;
		break;
	case 24://3 channels
		nMaxVal=255;
		break;
	case 32://4 channels
		nMaxVal=255;
		break;
	case 48://3 channels
		nMaxVal=65535;
		break;
	case 64://4 channels
		nMaxVal=65535;
		break;
		
	default:
		nMaxVal=0;
		
	}
	return nMaxVal;
}

///Sandy 2006-12-9 add
int image_duplicate_palette(const MatrixObject& mo, HPALETTE& hPalette)
{
	if(!mo.IsValid()||mo.HasData(false))
		return XFERR_INVALID_IMAGE;
	Image img(mo);
	pBITMAPHANDLE pLBmp = img.GetLBmp();
	
	hPalette = L_DupBitmapPalette(pLBmp);
	
	return 0;
	
}


int gray_image_subtract_background(MatrixObject& moImg, MatrixObject& moSrcImg, UINT uChannel, bool bIsHiBG)
{

	Image imgSrc(moSrcImg);
	Image img(moImg);
	
	if(!imgSrc.IsValid()||!img.IsValid())
		return XFERR_INVALID_IMAGE;

	BITMAPHANDLE* pLBmp = img.GetLBmp();
	BITMAPHANDLE* pSrcLBmp = imgSrc.GetLBmp();
	
	return gray_image_subtract_background(pLBmp, pSrcLBmp, uChannel, bIsHiBG);
	
}


///Sandy 2006-12-4 move from XF for reuse
int adjust_image_brightness(BITMAPHANDLE* pLBmp, int a )
{
	a *= 10;
	
	if(a < -1000 || a > 1000)
		return INTOPTN_OUT_OF_RANGE;
	
	return L_ChangeBitmapIntensity(pLBmp, a);
	
}

int adjust_image_brightness(MatrixObject& mo, int a )
{
	if(!mo.IsValid())
		return false;
	
	Image img(mo);
	if(!img.IsValid())
		return false;
	
	BITMAPHANDLE* pLBmp = img.GetLBmp();
	return adjust_image_brightness(pLBmp, a );
}
///end

///Sandy 2006-12-19 move from XF: pTargetLBmp uses to input background and output the result, pSrcLBmp is the source image to subtract background
int gray_image_subtract_background(BITMAPHANDLE* pTargetLBmp, BITMAPHANDLE* pSrcLBmp, UINT uChannel, bool bIsHiBG)
{

	///Sandy 2006-12-9 make sure two bitmap has same palette when it is 8 bits
	if(!is_image_grayscale(pSrcLBmp))
		image_to_gray(pSrcLBmp, 8);
	
	L_CopyBitmapPalette(pTargetLBmp, pSrcLBmp);
	//end
	
	int nOperation;
	if(bIsHiBG)  
	{
	 	L_InvertBitmap(pTargetLBmp);
	 	nOperation = CB_OP_ADD;
	 	//L_InvertBitmap(pSrcLBmp);
	}
	else
	{
		nOperation = CB_OP_SUBDST;
	}

						   
	vector<int> vnSrcChannel = {CB_SRC_MASTER,CB_SRC_RED,CB_SRC_GREEN,CB_SRC_BLUE};
	vector<int> vnDstChannel = {CB_DST_MASTER,CB_DST_RED,CB_DST_GREEN,CB_DST_BLUE};
	vector<int> vnResChannel = {CB_RES_MASTER,CB_RES_RED,CB_RES_GREEN,CB_RES_BLUE};
	

	if(uChannel < 0 || uChannel >= vnSrcChannel.GetSize())
		return INTOPTN_OUT_OF_RANGE;
	
	UINT uFlag =nOperation|vnSrcChannel[uChannel]|vnDstChannel[uChannel]|vnResChannel[uChannel];
 
	int nXDst, nYDst, nXSize, nYSize,nXSrc, nYSrc;
	nXDst=nYDst=nXSrc=nYSrc=0;
	nXSize=pTargetLBmp->Width;
	nYSize=pTargetLBmp->Height;
	
	int nRet = L_CombineBitmapExt(pTargetLBmp,nXDst, nYDst, nXSize, nYSize,
    					pSrcLBmp, nXSrc, nYSrc, uFlag);

	if(bIsHiBG)  
	{
	 	L_InvertBitmap(pTargetLBmp);
	 	//L_InvertBitmap(pSrcLBmp);
	}		
					
	return nRet;    					
}



	




//sandy 2006-12-7 delete since no permission to use at present.
/*
///Sandy 2006-12-4 add
int image_morphlogical_filter(BITMAPHANDLE* pLBmp,UINT uFltDim, UINT uOperation)
{
	int nRet;
	
	switch(uOperation)
	{
	case IMG_MORPH_DILATION:
		nRet =  L_MaxFilterBitmap( pLBmp,uFltDim);
		break;
	case IMG_MORPH_EROSION:
		nRet =  L_MinFilterBitmap( pLBmp,uFltDim);
		break;
	case IMG_MORPH_OPEN:
	{
		nRet = L_MaxFilterBitmap( pLBmp,uFltDim);
		if(nRet != SUCCESS)
			break;
		nRet =  L_MinFilterBitmap( pLBmp,uFltDim);
		break;
	}
	
	case IMG_MORPH_CLOSE:
	{
		
		nRet = L_MinFilterBitmap( pLBmp,uFltDim);
		if(nRet != SUCCESS)
			break;
		nRet = L_MaxFilterBitmap( pLBmp,uFltDim);		
		break;
	}
	
	default:
		nRet = XFERR_INTOPTN_OUT_OF_RANGE;
		break;
		
	}

	return nRet;
}*/

int auto_level_image(MatrixObject& mo, uint uOptions, LVLCLR* pCL)
{
	if(!mo.IsValid())
		return false;
	
	Image img(mo);
	if(!img.IsValid())
		return false;
	
	BITMAPHANDLE* pLBmp = img.GetLBmp();
	return auto_level_image(pLBmp, uOptions, pCL);
}


int auto_level_image(BITMAPHANDLE* pLBmp, uint uOptions,  LVLCLR* pCL)
{
	vector<uint> vnFlags = {AUTO_LEVEL, AUTO_CONTRAST, AUTO_INTENSITY};
	
	if(uOptions < 0 || uOptions >= vnFlags.GetSize())
		return XFERR_INTOPTN_OUT_OF_RANGE;
	

	if(pCL!=NULL)
		return L_AutoColorLevelBitmap(pLBmp, pCL, 50, 50, vnFlags[uOptions]);
	else
		return L_AutoColorLevelBitmap(pLBmp, NULL, 50, 50, vnFlags[uOptions]);
}





/// end IMAGE_TYPE_XVARIABLE






int apply_pal_to_image(Image& img, string strPalFile)
{
	pBITMAPHANDLE pLBmp = img.GetLBmp();
	return  apply_pal_to_LT_bmp(pLBmp,strPalFile );

}


int apply_pal_to_LT_bmp(pBITMAPHANDLE pLBmp, string strPalFile)
{
	int nRet;
	short nColors;
	vector<byte> vR, vG, vB;
	
	//if(type == PAL_GRAYSCALE)
		//nRet = read_color_map_binary(PAL_FILE_NAME_GRAYSCALE, nColors, vR, vG, vB);
	//else if(type == PAL_RAINBOW)
		//nRet = read_color_map_binary(PAL_FILE_NAME_RAINBOW, nColors, vR, vG, vB);
	//else if(type == PAL_RWB)
		//nRet = read_color_map_binary(PAL_FILE_NAME_REDWHITEBLUE, nColors, vR, vG, vB);
	//else
		//return INTOPTN_OUT_OF_RANGE;
		
	nRet = read_color_map_binary(strPalFile, nColors, vR, vG, vB);
	
	if(nRet != OE_NOERROR)
		return nRet;
	
	int nMaxVal = get_image_data_max_val(pLBmp);
	/// EJP 2007-09-05 v8.0697 QA70-10337 ACCESS_MATOBJ_PAL
	///if(nMaxVal > 256)
	if( nMaxVal > 255 )
	/// end ACCESS_MATOBJ_PAL
		return XFERR_NOT_SUPPORT_MORE_THAN_255;
	

	LPRGBQUAD pPalette; 
	pPalette = (LPRGBQUAD)malloc(4*(nMaxVal+1) * sizeof(RGBQUAD));
	/// EJP 2007-09-05 v8.0697 QA70-10337 ACCESS_MATOBJ_PAL
	///nRet = L_GetBitmapColors(pLBmp, 0, nMaxVal, pPalette);
	nRet = L_GetBitmapColors(pLBmp, 0, nMaxVal + 1, pPalette);
	/// end ACCESS_MATOBJ_PAL
	if(nRet !=  SUCCESS)
	{
		free(pPalette);
		return nRet;
	}
	
	/// EJP 2007-09-05 v8.0697 QA70-10337 ACCESS_MATOBJ_PAL
	///for (int ii=0; ii < nMaxVal; ii++)
	for( int ii = 0; ii <= nMaxVal; ii++ )
	/// end ACCESS_MATOBJ_PAL
    {
       pPalette[ii].rgbBlue = (BYTE) vB[ii];
       pPalette[ii].rgbGreen = (BYTE) vG[ii];
       pPalette[ii].rgbRed = (BYTE) vR[ii];
       //pPalette[ii].rgbReserved = 0;
    }

	/// EJP 2007-09-05 v8.0697 QA70-10337 ACCESS_MATOBJ_PAL
	///nRet =  L_PutBitmapColors(pLBmp, 0, nMaxVal, pPalette);
	nRet =  L_PutBitmapColors(pLBmp, 0, nMaxVal + 1, pPalette);
	/// end ACCESS_MATOBJ_PAL
	if(nRet !=  SUCCESS)
	{
		free(pPalette);
		return nRet;
	}
	
	free(pPalette);	
	return nRet;
}



///Sandy 2006-11-29 Add for reuse histogram in other XF besides imghistogram
int histogram_image(BITMAPHANDLE* pLBmp, int* pHist,UINT uLen, UINT uChannel)
{
	
	vector<int> vnFlags = {CHANNEL_MASTER, CHANNEL_RED, CHANNEL_GREEN,CHANNEL_BLUE};
	if(uChannel < 0 || uChannel >= vnFlags.GetSize())
	{
		return CER_INPUT_OPTION_OUT_OF_RANGE;
	}


	int nFlag=vnFlags[uChannel];

	return  L_GetBitmapHistogram( pLBmp, pHist, uLen, nFlag );

}
//end

void color_level_initialize(int nMaxV, LVLCLR& lc)
{
	vector vcl(5);  
	vcl[0] = 0 ;
	vcl[1] = nMaxV;
	vcl[2] = 0;
	vcl[3] = nMaxV;
	vcl[4] = 1;
	
	lc.uStructSize = sizeof(LVLCLR);

	SET_COLOR_LEVEL(master, vcl, lc);
	SET_COLOR_LEVEL(red, vcl, lc);
	SET_COLOR_LEVEL(green, vcl, lc);
	SET_COLOR_LEVEL(blue, vcl, lc);
	
}

int set_color_level_to_LVLCLR(int nMaxLevel, int nChannel, double dBlack, double dWhite, double dGamma, LVLCLR& lc)
{
	
	vector vcl(5);
	vcl[0] = nMaxLevel * dBlack/100;
	//vcl[1] = nMaxLevel * (1-dWhite/100);
	vcl[1] = nMaxLevel * dWhite/100;
	
	if(vcl[1]<vcl[0]+2)
		return XFERR_LEVEL_CLIP_INVALID;
	vcl[2] = 0;
	vcl[3] = nMaxLevel;
	vcl[4] = dGamma;
	
	switch(nChannel)
	{
	case 0:
		SET_COLOR_LEVEL(master, vcl, lc);
		break;
	case 1:
		SET_COLOR_LEVEL(red, vcl, lc);
		break;
	case 2:
		SET_COLOR_LEVEL(green, vcl, lc);
		break;
	case 3:
		SET_COLOR_LEVEL(blue, vcl, lc);
		break;
	default:
		break;
	}
	
	return CER_NO_ERROR;
									  
}

void get_color_level_from_LVLCLR(int nMaxLevel, int nChannel, LVLCLR& lc, double& dBlack, double& dWhite, double& dGamma)
{
	vector vcl(5);
	switch(nChannel)
	{
	case 0:
		GET_COLOR_LEVEL(master, vcl, lc);
		break;
	case 1:
		GET_COLOR_LEVEL(red, vcl, lc);
		break;
	case 2:
		GET_COLOR_LEVEL(green, vcl, lc);
		break;
	case 3:
		GET_COLOR_LEVEL(blue, vcl, lc);
		break;
	default:
		break;
		
	}
	
	//dWhite = round((1 - vcl[1]/nMaxLevel) * 100, 0);
	dWhite = round(vcl[1]/nMaxLevel * 100, 0);
	dBlack = round(vcl[0]/nMaxLevel * 100, 0);
	dGamma = round(vcl[4], 2);	
		
}


///Sandy 2006-7-26 show LVLCLR info to a report
void show_color_level_info(ReportData& outData, LVLCLR& lc)
{
	int nDataTableID = 100;
	int nIDx = IDST_FIT_X;
	int nIDy = IDST_FIT_Y;
	outData.ID = IDST_RESULT_CURVES;

	ReportTable rt;
	rt = outData.CreateTable("cl", "Color_Level", nDataTableID);
	
	vector<string> vstr = {"Min Input", "Max Input", "Min Output", "Max Output", "Gamma"};
    rt.AddColumn(vstr, "level", nIDx, "Level", OKDATAOBJ_DESIGNATION_X);
	
    vector vcl(5);  
    GET_COLOR_LEVEL(master, vcl, lc);
	rt.AddColumn(vcl, "master", nIDy++, "Master", OKDATAOBJ_DESIGNATION_Y);
	
	GET_COLOR_LEVEL(red, vcl, lc);
	rt.AddColumn(vcl, "red", nIDy++, "Red", OKDATAOBJ_DESIGNATION_Y);

	GET_COLOR_LEVEL(green, vcl, lc);
	rt.AddColumn(vcl, "green", nIDy++, "Green", OKDATAOBJ_DESIGNATION_Y);
	
	GET_COLOR_LEVEL(blue, vcl, lc);
	rt.AddColumn(vcl, "blue", nIDy, "Blue", OKDATAOBJ_DESIGNATION_Y);
}



///end

///Sandy add 2006-12-22
int get_matrix_upright_line_profile(MatrixObject& mo,  double dLeft, double dTop, double dRight, double dBottom,
						 vector& vxPoints, vector& vyPoints, vector& vIntensity)
{
	
	vector vx(2), vy(2);
	int nWidth;
	vector vDiff;
	double dPts;
	
	if((dRight-dLeft)>(dBottom-dTop))
	{
		nWidth = dBottom-dTop;
		vx[0] = dLeft;
		vx[1] = dRight;
		vy[0] = dTop + nWidth/2;
		vy[1] = dBottom - nWidth/2;
		
		vx.Difference(vDiff);
		vDiff.Sum(dPts);		
		
	}
	else
	{
		nWidth = dRight-dLeft;
		vx[0] = dLeft + nWidth/2;
		vx[1] = dRight - nWidth/2;
		vy[0] = dTop;
		vy[1] = dBottom;

		vy.Difference(vDiff);
		vDiff.Sum(dPts);		
	}


	int nPts = floor(dPts + 0.5);
	nPts++;
		
	vxPoints.SetSize(nPts);
	vyPoints.SetSize(nPts);
	vector vError(nPts);
	
	vIntensity.SetSize(nPts);
	
	matrix& mat = mo.GetDataObject();
	int nCols = mat.GetNumCols();
	int nRows = mat.GetNumRows();	

	int nRet = ocmath_image_lines_profile(nRows, nCols, mat,
		vx.GetSize(), vx, vy,
		nPts, vxPoints, vyPoints, vIntensity, vError,
		nWidth, INTERP2_NEAREST, PROJECTION_NONE);	
	return nRet;
}
//end


int set_image_data(matrixbase& mbData, MatrixObject& moLBitmap, 
						double dMin, double dMax, int nBits, const HPALETTE hPalette)
{
	/// Hong 07/16/09 QA80-13532 NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
	//pBITMAPHANDLE pLBmp = ol_new_bitmap();
	BitmapHandlePtr	bhptr;
	pBITMAPHANDLE pLBmp = bhptr.Get();
	/// end NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
	if(NULL == pLBmp)
		return -1;
	//if(dMin == dMax)
		//return -2;
	int nMin = 0, nMax;
	
	
	if(nBits == 16)
		nMax = 0x0000FFFF;
	else if(nBits == 12)
		nMax = 0x00000FFF;
	else
		nMax = 0x000000FF;

	matrix m1 = mbData;
	int nErr = ocmath_linear_transform(m1, 0, m1.GetNumCols()*m1.GetNumRows(), nMin, nMax, dMin, dMax);
	

	if(nBits == 16 || nBits == 12)
	{	
		matrix<ushort> m2;
		m2 = m1;
		int nRet = ol_create_bitmap_from_matrix(pLBmp, m2, m2.GetNumCols(), m2.GetNumRows());
		if( nRet != SUCCESS )
			return -10;
	}
	else //if(nBits == 8)
	{

		///add by Sandy 2006-12-9
		int nRet;
		if(hPalette!=NULL)
		{
			nRet = L_SetBitmapPalette(pLBmp, hPalette);
			if( nRet != SUCCESS )
				return nRet;
		}
		//end
		//
		matrix<byte> m2;
		m2 = m1;
		

		
		nRet = ol_create_bitmap_from_byte_matrix(pLBmp, m2, m2.GetNumCols(), m2.GetNumRows());
		if( nRet != SUCCESS )
			return -10;

	}

	bhptr.SetAsOwner(false); /// Hong 07/16/09 QA80-13532 NEED_OL_DELETE_BITMAP_FOR_OL_NEW_BITMAP
	moLBitmap.SetLeadBitmap(pLBmp, false, true);

	return 0;
}