在對話框中顯示圖片,放大,縮小和移動

先上效果圖:

核心代碼:

void CShowInPicCtrlDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知處理程序代碼
	CString strFilePath = CMfcStrFile::OpenFile();

	if (m_pGDALShow)
	{
		delete m_pGDALShow;
		m_pGDALShow = nullptr;
	}

	//DC可能隨着窗口的改變而改變
	CRect rcPicture;
	GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(rcPicture);
	ScreenToClient(rcPicture);

	m_nDCWidth = rcPicture.Width();
	m_nDCHeight = rcPicture.Height();

	//寬度應爲4的整數倍
	m_nDCWidth = ((m_nDCWidth + 3) / 4) * 4;

	if (m_hBmp)
	{
		::DeleteObject(m_hBmp);
		m_hBmp = nullptr;
	}

	BITMAPINFO bmpInfo;
	bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmpInfo.bmiHeader.biWidth = m_nDCWidth;
	bmpInfo.bmiHeader.biHeight = m_nDCHeight;
	bmpInfo.bmiHeader.biPlanes = 1;
	bmpInfo.bmiHeader.biBitCount = 24;
	bmpInfo.bmiHeader.biCompression = BI_RGB;
	bmpInfo.bmiHeader.biSizeImage = 0;
	bmpInfo.bmiHeader.biXPelsPerMeter = 0;
	bmpInfo.bmiHeader.biYPelsPerMeter = 0;
	bmpInfo.bmiHeader.biClrUsed = 0;
	bmpInfo.bmiHeader.biClrImportant = 0;

	m_hBmp = CreateDIBSection(m_memDC.m_hDC, &bmpInfo, DIB_RGB_COLORS, (void **)&m_pFrontBuffer, NULL, 0);

	m_bmp.Detach();
	m_bmp.Attach(m_hBmp);

	if (strFilePath.GetLength())
	{
		std::string sFilePath = CStdStr::ws2s(CMfcStrFile::CString2string(strFilePath));
		m_pGDALShow = new CGDALShow(FromHandle(m_hWnd), sFilePath.c_str(), m_pFrontBuffer, m_nDCWidth, m_nDCHeight,
			TRUE, GetDlgItem(IDC_STATIC_PIC), &m_bmp, &m_memDC, &m_hBmp, &m_hOldBmp);
		m_pGDALShow->ShowImage(TRUE);
		m_pGDALShow->ThreadReadingData();
	}
}

相關的頭文件:

//[5/25/2018 autumoon]

#pragma once
#include "GdalUser.h"

//MEM_ALLOC_X、MEM_ALLOC_X必須是1或者3,爲1時節省內存,爲3時拖動體驗更好
#define	MEM_ALLOC_X			3
#define	MEM_ALLOC_Y			3
#define	MEM_ALLOC_NUM		(MEM_ALLOC_X * MEM_ALLOC_Y)
#define DC_OFFSET_NUM_X		((MEM_ALLOC_X - 1) >> 1)
#define DC_OFFSET_NUM_Y		((MEM_ALLOC_Y - 1) >> 1)

#define AU_MIN(x,y)	((x) < (y) ? (x) : (y))
#define AU_MAX(x,y)	((x) > (y) ? (x) : (y))

//必須使用外部雙緩存
class CGDALShow
{
public:
	//如果不是對話框,第二行參數全部取默認值即可
	CGDALShow(CWnd* pWnd, const char* imgPath, unsigned char* pFrontBuffer, int nDCWidth, int nDCHeight,
		BOOL bIsDlg = FALSE, CWnd* pCtrlWnd = nullptr, CBitmap* pbmp = nullptr, CDC* pmemDC = nullptr, HBITMAP* phBmp = nullptr, HBITMAP* phOldBmp = nullptr);
	~CGDALShow(void);
public:
	bool m_bIsLBtnDown;							//左鍵是否按下
	bool m_bIsMBtnDown;							//中鍵是否按下
	bool m_bUpdateScale;						//是否需要更新比例
	CBitmap* m_pbmp;							//外部顯示使用的變量,尺寸變化時內部可能更新
	CDC* m_pmemDC;
	CWnd* m_pCtrlWnd;
	HBITMAP* m_phBmp;
	HBITMAP* m_phOldBmp;
	int m_nDCWidth;								//顯示區域的寬度
	int m_nDCHeight;							//顯示區域的高度

	unsigned char* m_pFrontBuffer;				//內存buffer
	unsigned char* m_pFrontBufferDrag;			//DCbuffer備份,用於拖動的時候緩衝
	unsigned char* m_pFrontBufferDragThread;	//DCbuffer備份,用於線程讀取

	//根據控件座標,獲取信息
	bool GetPixValue(int nCtrlX, int nCtrlY, std::vector<int>& values, bool bGetRealValue = false);
	bool GetImgCoors(int nCtrlX, int nCtrlY, int& nImgX, int& nImgY, bool bYReverse = false);

	int ThreadReadingData(BOOL bThread = TRUE);
	void OnLButtonDown(POINT point);
	void OnLButtonUp(POINT point);
	void OnMButtonDown(POINT point);
	void OnMButtonUp(POINT point);
	void OnMouseMove(POINT point);
	void OnMouseWheel(short zDelta, CPoint pt);
	void ShowImage(BOOL bDirectDC = FALSE);

	static double m_dMaxScale;					//縮放最大比例
	static double m_dMinScale;					//縮放最小比例
	static double m_dScaleStep;					//縮放步進值
	static double m_dXoffset;					//顯示區域留白x
	static double m_dYoffset;					//顯示區域留白y
	static int m_nBgValue;						//背景值
	static int m_nButtonMove;					//使用鼠標按鈕移動 1代表左鍵 2代表中鍵
	
protected:
	bool m_bIsDlg;
	bool m_bDragDataReady;
	CGdalUser* m_pGu;
	double* m_pHist;					//直方圖統計
	double* m_plfCount;					//累計概率
	double m_dScale;					//當前比例
	double m_dScaleLast;				//上一次比例
	double m_dIniScale;					//金字塔比例
	unsigned char* m_pBufferPy;			//金字塔Buffer
	unsigned char* m_pClrLut;			//顏色查找表

	bool CreatePyramid();
	bool GetRealPixValue(int nCtrlX, int nCtrlY, std::vector<int>& vRealValues);
	int GetPointerForDlgShow(CWnd* pDlgWnd, CBitmap* pbmp, CDC* pmemDC, HBITMAP* phBmp, HBITMAP* phOldBmp);
	int ResampleArray(int nSrcBufWidth, int nSrcBufHeight, int nSrcLeft, int nSrcTop, int nSrcRight, int nSrcBottom, unsigned char* pSrc,
		int nDstBufWidth, int nDstBufHeight, int nDstLeft, int nDstTop, int nDstRight, int nDstBottom, unsigned char* pDst);
	int ResampleArray2BGR(int nSrcBufWidth, int nSrcBufHeight, int nSrcLeft, int nSrcTop, int nSrcRight, int nSrcBottom, unsigned char* pSrc, int nSrcBandNum,
		int nDstBufWidth, int nDstBufHeight, int nDstLeft, int nDstTop, int nDstRight, int nDstBottom, unsigned char* pDst, int nDstBandNum,
		int nSizeOfPointer = 1, int nSrcSkip = 0, int nDestSkip = 0);

	//用於線程讀取備用數據
	static bool PreReadFrontBufferDrag(LPVOID lpParameters);
	void ResetOffset();
	void ResetParameters();

private:
	CWnd* m_pWnd;
	double m_pXoffset;
	double m_pYoffset;
	double m_pXstart;
	double m_pYstart;

	int m_nImgWidth;
	int m_nImgHeight;
	int m_nIniWidth, m_nIniHeight, m_nBandNum, m_nBPB;
	int m_nX;
	int m_nY;
	int m_nShowWidth;
	int m_nShowHeight;

	POINT m_pMouDownPnt;
};

//對話框外部雙緩存
/************************************************************************
//Dlg中定義
CGDALShow* m_pGDALShow;
int m_nDCHeight;
int m_nDCWidth;
unsigned char* m_pFrontBuffer;

CBitmap m_bmp;
CDC m_memDC;
HBITMAP m_hBmp;
HBITMAP m_hOldBmp;

//構造函數中初始化
m_pGDALShow = nullptr;
m_nDCWidth = -1;
m_nDCHeight = -1;
m_pFrontBuffer = nullptr;

//析構函數中釋放
if (m_pGDALShow)
{
	delete m_pGDALShow;
	m_pGDALShow = nullptr;
}

//添加static控件或者picturectrl控件
//動作按鈕中添加如下內容
CString strFilePath = CMfcStrFile::OpenFile();

if (m_pGDALShow)
{
	delete m_pGDALShow;
	m_pGDALShow = nullptr;
}

//DC可能隨着窗口的改變而改變
CRect rcPicture;
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(rcPicture);
ScreenToClient(rcPicture);

m_nDCWidth = rcPicture.Width();
m_nDCHeight = rcPicture.Height();

//寬度應爲4的整數倍
m_nDCWidth = ((m_nDCWidth + 3) / 4) * 4;

if (m_hBmp)
{
	::DeleteObject(m_hBmp);
	m_hBmp = nullptr;
}

BITMAPINFO bmpInfo;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = m_nDCWidth;
bmpInfo.bmiHeader.biHeight = m_nDCHeight;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biSizeImage = 0;
bmpInfo.bmiHeader.biXPelsPerMeter = 0;
bmpInfo.bmiHeader.biYPelsPerMeter = 0;
bmpInfo.bmiHeader.biClrUsed = 0;
bmpInfo.bmiHeader.biClrImportant = 0;

m_hBmp = CreateDIBSection(m_memDC.m_hDC, &bmpInfo, DIB_RGB_COLORS, (void **)&m_pFrontBuffer, NULL, 0);

m_bmp.Detach();
m_bmp.Attach(m_hBmp);

if (strFilePath.GetLength())
{
	std::string sFilePath = CStdStr::ws2s(CMfcStrFile::CString2string(strFilePath));
	m_pGDALShow = new CGDALShow(FromHandle(m_hWnd), sFilePath.c_str(), m_pFrontBuffer, m_nDCWidth, m_nDCHeight,
		TRUE, GetDlgItem(IDC_STATIC_PIC), &m_bmp, &m_memDC, &m_hBmp, &m_hOldBmp);
	m_pGDALShow->ShowImage(TRUE);
	m_pGDALShow->ThreadReadingData();
}

//PreTranslateMessage(MSG* pMsg)
CRect rect;
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);

if (pMsg->message == WM_LBUTTONDOWN && m_pGDALShow && rect.PtInRect(pMsg->pt))
{
	m_pGDALShow->OnLButtonDown(pMsg->pt);
}

if (pMsg->message == WM_LBUTTONUP && m_pGDALShow && rect.PtInRect(pMsg->pt))
{
	m_pGDALShow->OnMButtonUp(pMsg->pt);
}

if (pMsg->message == WM_MBUTTONDOWN && m_pGDALShow && rect.PtInRect(pMsg->pt))
{
m_pGDALShow->OnMButtonDown(pMsg->pt);
}

if (pMsg->message == WM_MBUTTONUP && m_pGDALShow && rect.PtInRect(pMsg->pt))
{
m_pGDALShow->OnMButtonUp(pMsg->pt);
}

if (pMsg->message == WM_MOUSEMOVE && m_pGDALShow && rect.PtInRect(pMsg->pt))
{
	m_pGDALShow->OnMouseMove(pMsg->pt);
}

//OnMouseWheel()
if (m_pGDALShow)
{
	m_pGDALShow->OnMouseWheel(zDelta, pt);
}

//OnPaint()
CPaintDC dc(GetDlgItem(IDC_STATIC_PIC));
CRect rcclient;
GetDlgItem(IDC_STATIC_PIC)->GetClientRect(&rcclient);//獲取控件的屏幕座標
CWnd::DefWindowProc(WM_PAINT, (WPARAM)m_memDC.m_hDC, 0);

CBrush brush;
brush.CreatePatternBrush(&m_bmp);
dc.FillRect(rcclient, &brush);
dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &m_memDC, rcclient.left, rcclient.top, SRCPAINT);
brush.DeleteObject();

//OnSize()若對話框尺寸可能發生改變
if (cx < 1 || cy < 1)
{
	return;
}

CWnd* pWnd = GetDlgItem(IDC_STATIC_PIC);
if (pWnd)
{
	CRect rect;
	pWnd->GetClientRect(&rect);
	m_nDCHeight = rect.Height();
	m_nDCWidth = rect.Width();
	m_nDCWidth = ((m_nDCWidth + 3) / 4) * 4;
}

if (m_pGDALShow)
{
	m_pGDALShow->m_nDCWidth = m_nDCWidth;
	m_pGDALShow->m_nDCHeight = m_nDCHeight;
}

size_t nDCMemSize = m_nDCWidth * m_nDCHeight * 3;

BITMAPINFO bmpInfo;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = m_nDCWidth;
bmpInfo.bmiHeader.biHeight = m_nDCHeight;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biSizeImage = 0;
bmpInfo.bmiHeader.biXPelsPerMeter = 0;
bmpInfo.bmiHeader.biYPelsPerMeter = 0;
bmpInfo.bmiHeader.biClrUsed = 0;
bmpInfo.bmiHeader.biClrImportant = 0;

if (m_hBmp)
{
	SelectObject(m_memDC.m_hDC, m_hOldBmp);
	m_hOldBmp = NULL;
	DeleteObject(m_hBmp);
	m_hBmp = NULL;
}
m_hBmp = CreateDIBSection(m_memDC.m_hDC, &bmpInfo, DIB_RGB_COLORS, (void **)&m_pFrontBuffer, NULL, 0);
m_hOldBmp = (HBITMAP)::SelectObject(m_memDC.m_hDC, m_hBmp);

if (m_pGDALShow)
{
	//必須要更新這個buffer的指針
	m_pGDALShow->m_bUpdateScale = false;
	m_pGDALShow->m_pFrontBuffer = m_pFrontBuffer;
	m_pGDALShow->ThreadReadingData(FALSE);
	m_pGDALShow->ShowImage();
	m_pGDALShow->m_bUpdateScale = true;
}

/************************************************************************/

//視圖中外部雙緩存參考
/***********************************************************************
//View類中定義
CGDALShow* m_pGDALShow;
int m_nDCHeight;
int m_nDCWidth;
unsigned char* m_pFrontBuffer;

CBitmap m_bmp;
CDC m_memDC;
HBITMAP m_hBmp;
HBITMAP m_hOldBmp;

//構造函數中初始化
m_pGDALShow = nullptr;
m_nDCWidth = -1;
m_nDCHeight = -1;
m_pFrontBuffer = nullptr;

//析構函數中釋放
if (m_pGDALShow)
{
	delete m_pGDALShow;
	m_pGDALShow = nullptr;
}

//OnCreate()
CDC *pDC = GetDC();
m_memDC.CreateCompatibleDC(pDC);
ReleaseDC(pDC);

//OnSize()
if (cx < 1 || cy < 1)
{
return;
}

m_nDCHeight = cy;
m_nDCWidth = cx;
m_nDCWidth = ((m_nDCWidth + 3) / 4) * 4;
if (m_pGDALShow)
{
m_pGDALShow->m_nDCWidth = m_nDCWidth;
m_pGDALShow->m_nDCHeight = m_nDCHeight;
}

size_t nDCMemSize = m_nDCWidth * m_nDCHeight * 3;

BITMAPINFO bmpInfo;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = m_nDCWidth;
bmpInfo.bmiHeader.biHeight = m_nDCHeight;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biSizeImage = 0;
bmpInfo.bmiHeader.biXPelsPerMeter = 0;
bmpInfo.bmiHeader.biYPelsPerMeter = 0;
bmpInfo.bmiHeader.biClrUsed = 0;
bmpInfo.bmiHeader.biClrImportant = 0;

if (m_hBmp)
{
SelectObject(m_memDC.m_hDC, m_hOldBmp);
m_hOldBmp = NULL;
DeleteObject(m_hBmp);
m_hBmp = NULL;
}
m_hBmp = CreateDIBSection(m_memDC.m_hDC, &bmpInfo, DIB_RGB_COLORS, (void **)&m_pFrontBuffer, NULL, 0);
m_hOldBmp = (HBITMAP)::SelectObject(m_memDC.m_hDC, m_hBmp);

if (m_pGDALShow)
{
//必須要更新這個buffer的指針
m_pGDALShow->m_bUpdateScale = false;
m_pGDALShow->m_pFrontBuffer = m_pFrontBuffer;
m_pGDALShow->ThreadReadingData(FALSE);
m_pGDALShow->ShowImage();
m_pGDALShow->m_bUpdateScale = true;
}

//PreTranslateMessage(MSG* pMsg)
if (pMsg->message == WM_KEYDOWN && m_pGDALShow)
{
if (pMsg->wParam == VK_SPACE)
{
if (m_pGDALShow->m_nButtonMove == 2)
{
//切換移動圖像的鼠標按鍵爲左鍵
m_pGDALShow->m_nButtonMove = 1;
}
else
{	//恢復爲中鍵
m_pGDALShow->m_nButtonMove = 2;
}
}
}
else
{
if (pMsg->message == WM_LBUTTONDOWN && m_pGDALShow)
{
m_pGDALShow->OnLButtonDown(pMsg->pt);
}

if (pMsg->message == WM_LBUTTONUP && m_pGDALShow)
{
m_pGDALShow->OnLButtonUp(pMsg->pt);
}

if (pMsg->message == WM_MBUTTONDOWN && m_pGDALShow)
{
m_pGDALShow->OnMButtonDown(pMsg->pt);
}

if (pMsg->message == WM_MBUTTONUP && m_pGDALShow)
{
m_pGDALShow->OnMButtonUp(pMsg->pt);
}

if (pMsg->message == WM_MOUSEMOVE && m_pGDALShow)
{
m_pGDALShow->OnMouseMove(pMsg->pt);
}
}

//OnMouseWheel()
if (m_pGDALShow)
{
	m_pGDALShow->OnMouseWheel(zDelta, pt);
}

//OnDraw()
if (m_pGDALShow)
{
	BitBlt(pDC->m_hDC, 0, 0, m_nDCWidth, m_nDCHeight, m_memDC.m_hDC, 0, 0, SRCCOPY);
}

//動作函數中
if (m_pGDALShow)
{
delete m_pGDALShow;
m_pGDALShow = nullptr;
}
m_pGDALShow = new CGDALShow(FromHandle(m_hWnd), CStdStr::ws2s(strFilePath).c_str(), m_pFrontBuffer, m_nDCWidth, m_nDCHeight);
m_pGDALShow->ShowImage();
m_pGDALShow->ThreadReadingData();

/************************************************************************/

實現文件:

#include "..\StdAfx.h"
#include "GDALShow.h"
#include "afxdialogex.h"

//[6/26/2016 yufuxiang]
//[5/24/2018 autumoon]


CMutex mutexDrag;
CMutex mutexDragThread;


double CGDALShow::m_dMaxScale = 8.0;
double CGDALShow::m_dMinScale = 0.01;
double CGDALShow::m_dScaleStep = 120.0 / 0.125;
double CGDALShow::m_dXoffset = 0.0;
double CGDALShow::m_dYoffset = 0.0;
int CGDALShow::m_nBgValue = 240;
int CGDALShow::m_nButtonMove = 2;

CGDALShow::CGDALShow(CWnd* pWnd, const char* imgPath, unsigned char* pFrontBuffer, int nDCWidth, int nDCHeight,
	BOOL bIsDlg /*= FALSE*/, CWnd* pCtrlWnd /*= nullptr*/, CBitmap* pbmp /*= nullptr*/, CDC* pmemDC /*= nullptr*/, HBITMAP* phBmp /*= nullptr*/, HBITMAP* phOldBmp /*= nullptr*/)
{
	if (pWnd == nullptr || imgPath == nullptr)
	{
		return;
	}
	
	//復位所有參數
	ResetParameters();
	
	//獲取重要參數
	if (bIsDlg)
	{
		//對話框的時候每次顯示都會計算寬度與高度
		GetPointerForDlgShow(pCtrlWnd, pbmp, pmemDC, phBmp, phOldBmp);
	}
	else
	{
		if (pFrontBuffer == nullptr || nDCWidth < 1 || nDCHeight < 1)
		{
			return;
		}
	}
 	
	m_bIsDlg = bIsDlg == TRUE;
 	m_pWnd = pWnd;
 	m_pFrontBuffer = pFrontBuffer;
 
 	m_pGu = new CGdalUser();
 	if (!m_pGu->InitializeRead(imgPath))
 	{
 		return;
 	}
 	//先獲取這些數據是爲了計算偏移
 	m_nImgWidth = m_pGu->m_nImgWidth;
 	m_nImgHeight = m_pGu->m_nImgHeight;
 	m_nDCWidth = nDCWidth;
 	m_nDCHeight = nDCHeight;
 	
 	//居中顯示
 	ResetOffset();
 	//剩下的數據在這裏獲取
 	CreatePyramid();
}

CGDALShow::~CGDALShow(void)
{
	if (m_pGu)
	{
		delete m_pGu;
		m_pGu = nullptr;
	}

	if (m_pHist)
	{
		delete[] m_pHist;
		m_pHist = nullptr;
	}

	if (m_plfCount)
	{
		delete[] m_plfCount;
		m_plfCount = nullptr;
	}

	if (m_pBufferPy)
	{
		delete[] m_pBufferPy;
		m_pBufferPy = nullptr;
	}

	if (m_pClrLut)
	{
		delete[] m_pClrLut;
		m_pClrLut = nullptr;
	}

	if (m_pFrontBufferDrag)
	{
		delete[] m_pFrontBufferDrag;
		m_pFrontBufferDrag = nullptr;
	}

	if (m_pFrontBufferDragThread)
	{
		delete[] m_pFrontBufferDragThread;
		m_pFrontBufferDragThread = nullptr;
	}
}

void CGDALShow::OnLButtonDown(POINT point)
{
	if (m_nButtonMove == 1)
	{
		CRect rect;
		if (m_bIsDlg)
		{
			m_pCtrlWnd->GetWindowRect(&rect);
		}
		else
		{
			m_pWnd->GetWindowRect(&rect);
			SetCapture(m_pWnd->GetSafeHwnd());
		}

		if (rect.PtInRect(point))
		{
			m_bIsLBtnDown = true;
			m_bUpdateScale = false;
			m_pMouDownPnt = point;
		}
	}
}

void CGDALShow::OnLButtonUp(POINT point)
{
	if (m_nButtonMove == 1)
	{
		m_bIsLBtnDown = false;
		m_pMouDownPnt = point;

		m_pXstart += m_pXoffset;
		m_pYstart += m_pYoffset;
		m_dXoffset = m_pXoffset;
		m_dYoffset = m_pYoffset;
		m_pXoffset = 0.0;
		m_pYoffset = 0.0;

		if (!m_bIsDlg)
		{
			ReleaseCapture();
		}

		ThreadReadingData();
	}
}

void CGDALShow::OnMButtonDown(POINT point)
{
	if (m_nButtonMove == 2)
	{
		CRect rect;
		if (m_bIsDlg)
		{
			m_pCtrlWnd->GetWindowRect(&rect);
		}
		else
		{
			m_pWnd->GetWindowRect(&rect);
			SetCapture(m_pWnd->GetSafeHwnd());
		}

		if (rect.PtInRect(point))
		{
			m_bIsMBtnDown = true;
			m_bUpdateScale = false;
			m_pMouDownPnt = point;
		}
	}
}

void CGDALShow::OnMButtonUp(POINT point)
{
	if (m_nButtonMove == 2)
	{
		m_bIsMBtnDown = false;
		m_pMouDownPnt = point;

		m_pXstart += m_pXoffset;
		m_pYstart += m_pYoffset;
		m_dXoffset = m_pXoffset;
		m_dYoffset = m_pYoffset;
		m_pXoffset = 0.0;
		m_pYoffset = 0.0;

		if (!m_bIsDlg)
		{
			ReleaseCapture();
		}

		ThreadReadingData();
	}
}

void CGDALShow::OnMouseMove(POINT point)
{
	if (m_bIsLBtnDown  && m_bIsLBtnDown == 1|| m_bIsMBtnDown && m_nButtonMove == 2 )
	{
		CRect rect;
		if (m_bIsDlg)
		{
			m_pCtrlWnd->GetWindowRect(&rect);
		}
		else
		{
			m_pWnd->GetWindowRect(&rect);
		}
		if (rect.PtInRect(point) || !m_bIsDlg)
		{
			m_nX = int(m_pXstart + m_pXoffset + 0.5);
			m_nY = int(m_pYstart + m_pYoffset + 0.5);
			m_nShowWidth = int(m_nImgWidth*m_dScale + 0.5);
			m_nShowHeight = int(m_nImgHeight*m_dScale + 0.5);

			m_pXoffset = point.x - m_pMouDownPnt.x;
			m_pYoffset = m_pMouDownPnt.y - point.y;
			ShowImage();
		}
	}
}

void CGDALShow::OnMouseWheel(short zDelta, CPoint pt)
{
	if(zDelta>120)  zDelta=120;
	if(zDelta<-120) zDelta=-120;

	double tmpOffsetX=0;double tmpOffsetY=0;

	CRect rect;
	if (m_bIsDlg)
	{
		m_pCtrlWnd->GetWindowRect(&rect);
	}
	else
	{
		m_pWnd->GetWindowRect(&rect);
	}
	
	POINT point;
	point.x=pt.x;
	point.y=pt.y;

	if (rect.PtInRect(point))
	{
		if(m_dScale > m_dMinScale && zDelta < 0 || m_dScale < m_dMaxScale && zDelta > 0)
		{
			double tmpscale = zDelta/m_dScaleStep;
			tmpscale *= m_dScale;

			tmpOffsetX=m_nImgWidth*tmpscale*((double)(point.x-rect.left-m_pXstart)/(double)(m_nImgWidth*(m_dScale)));
			tmpOffsetY=m_nImgHeight*tmpscale*((double)(rect.bottom - point.y - m_pYstart)/(double)(m_nImgHeight*(m_dScale)));

			int nX = int(m_pXstart-tmpOffsetX + 0.5);
			int nY = int(m_pYstart-tmpOffsetY + 0.5);
			int nShowWidth = int(m_nImgWidth*(m_dScale+tmpscale) + 0.5);
			int nShowHeight = int(m_nImgHeight*(m_dScale+tmpscale) + 0.5);
			if (nShowWidth > 0 && nShowHeight > 0)
			{
				//這裏需要同步縮放drag中的數據
				int nBufferWidth = m_nDCWidth * MEM_ALLOC_X;
				int nBufferHeight = m_nDCHeight * MEM_ALLOC_Y;

				int nSrcLeft = m_nDCWidth * DC_OFFSET_NUM_X + m_nX;
				int nSrcTop = m_nDCHeight * DC_OFFSET_NUM_Y + m_nY;
				int nSrcRight = nSrcLeft + m_nShowWidth;
				int nSrcBottom = nSrcTop + m_nShowHeight;

				int nDstLeft = m_nDCWidth * DC_OFFSET_NUM_X + nX;
				int nDstTop = m_nDCHeight * DC_OFFSET_NUM_Y + nY;
				int nDstRight = nDstLeft + nShowWidth;
				int nDstBottom = nDstTop + nShowHeight;

				mutexDrag.Lock();
				ResampleArray(nBufferWidth, nBufferHeight, nSrcLeft, nSrcTop, nSrcRight, nSrcBottom, m_pFrontBufferDrag,
					nBufferWidth, nBufferHeight, nDstLeft, nDstTop, nDstRight, nDstBottom, m_pFrontBufferDrag);
				mutexDrag.Unlock();

				//採用此次縮放的結果
				m_nX = nX;
				m_nY = nY;
				m_nShowWidth = nShowWidth;
				m_nShowHeight = nShowHeight;
				ShowImage();
				m_dScale += tmpscale;
				m_pXstart -= tmpOffsetX;
				m_pYstart -= tmpOffsetY;
			}
		}
	}

	m_bUpdateScale = fabs(m_dScale - m_dScaleLast) > 0.00001;
	m_dScaleLast = m_dScale;

	ThreadReadingData();
}

bool CGDALShow::CreatePyramid()
{
	//顯示照片
	m_nBandNum = m_pGu->m_nBandNum;
	m_nBPB = m_pGu->m_nBPB;

	//金字塔buffer,用於顯示全局的時候讀取顯示
	const int nPyIniLength = 10000;

	double dWidthIniProp = (double)nPyIniLength / m_nImgWidth;
	double dHeightIniProp = (double)nPyIniLength / m_nImgHeight;
	m_dIniScale = dWidthIniProp < dHeightIniProp ? dWidthIniProp : dHeightIniProp;
	m_nIniWidth = int(m_pGu->m_nImgWidth * m_dIniScale + 0.5);
	m_nIniHeight = int(m_pGu->m_nImgHeight * m_dIniScale + 0.5);

	if (m_dIniScale >= 1.0)
	{
		//此時不需要縮放
		m_dIniScale = 1.0;
		m_nIniWidth = m_nImgWidth;
		m_nIniHeight = m_nImgHeight;
	}

	//分塊讀取更高效
	const int nBlock = 1024;
	BYTE* pBlockBuffer = new BYTE[m_nImgWidth * m_nBandNum * m_nBPB * nBlock];
	memset(pBlockBuffer, 0, sizeof(BYTE)* m_nImgWidth * m_nBandNum * m_nBPB * nBlock);
	int nBPP = m_nBPB * m_nBandNum;

	//用於顯示的金字塔
	m_pBufferPy = new BYTE[m_nIniWidth * m_nIniHeight * 3];
	memset(m_pBufferPy, 0, m_nIniWidth * m_nIniHeight * 3);
	int nRowBlockNum = (m_nImgHeight + nBlock - 1) / nBlock;
	
	if (m_nBPB == 2)
	{
		//16位影像需要讀取源數據,取得顏色查找表
		unsigned char* pBufferPyOri = new BYTE[m_nIniWidth * m_nIniHeight * m_nBandNum * m_nBPB];
		memset(pBufferPyOri, 0, m_nIniWidth * m_nIniHeight * m_nBandNum * m_nBPB);

		for (int j = 0; j < nRowBlockNum; ++j)
		{
			memset(pBlockBuffer, 0, sizeof(BYTE)* m_nImgWidth * m_nBandNum * m_nBPB * nBlock);
			m_pGu->ReadImg(0, j * nBlock, m_nImgWidth, j * nBlock + nBlock, pBlockBuffer,
				m_nImgWidth, nBlock, m_nBandNum, 0, 0, m_nImgWidth, nBlock, -1, 0);

			for (int m = 0; m < m_nIniHeight; m++)
			{
				int nSrcRows = int(m / m_dIniScale /*+ 0.5*/) - j * nBlock;
				if (nSrcRows >= nBlock || nSrcRows < 0)
				{
					continue;
				}
				BYTE *pBufferPyIndex = pBufferPyOri + m * m_nIniWidth * nBPP;
				BYTE *pBufferBlockIndex = pBlockBuffer + nSrcRows * m_nImgWidth * nBPP;
				for (int n = 0; n < m_nIniWidth; n++)
				{
					int nSrcCols = int(n / m_dIniScale /*+ 0.5*/);
					if (nSrcCols >= m_nImgWidth)
					{
						continue;
					}
					BYTE *pSubBufferPyIndex = pBufferPyIndex + n * nBPP;
					BYTE *pSubBufferBlockIndex = pBufferBlockIndex + nSrcCols * nBPP;
					memcpy(pSubBufferPyIndex, pSubBufferBlockIndex, nBPP);
				}
			}
		}
		//如果是16位影像
		if (m_pHist)
		{
			delete[] m_pHist;
			m_pHist = NULL;
		}
		m_pHist = new double[65536 * m_nBandNum];
		memset(m_pHist, 0, sizeof(double) * 65536 * m_nBandNum);

		for (int j = 0; j < m_nIniHeight; ++j)
		{
			unsigned short *pBufferIndex = (unsigned short*)pBufferPyOri + j * m_nIniWidth * m_nBandNum;
			for (int i = 0; i < m_nIniWidth; ++i)
			{
				unsigned short *pSubBufferIndex = pBufferIndex + i * m_nBandNum;
				for (int k = 0; k < m_nBandNum; ++k)
				{
					m_pHist[k * 65536 + pSubBufferIndex[k]] += 1.0;
				}
			}
		}

		if (m_pClrLut)
		{
			delete[] m_pClrLut;
			m_pClrLut = NULL;
		}

		m_pClrLut = new BYTE[m_nBandNum * 65536];
		memset(m_pClrLut, 0, sizeof(BYTE) * 65536 * m_nBandNum);

		if (m_plfCount)
		{
			delete[] m_plfCount;
			m_plfCount = NULL;
		}
		m_plfCount = new double[10];
		memset(m_plfCount, 0, sizeof(double) * 10);
		for (int i = 0; i < m_nBandNum; i++)
		{
			for (int j = 1; j < 65536; j++)
			{
				m_plfCount[i] += m_pHist[i * 65536 + j];
			}
		}

		double lfMinThreshold = 0.001, lfMaxThreshold = 0.001;

		for (int i = 0; i < m_nBandNum; i++)
		{
			double lfTmpCount = 0.0001;
			int nMinCut = 1, nMaxCut = 65535;
			for (int j = 1; j < 65536; j++)
			{
				lfTmpCount += m_pHist[i * 65536 + j];
				if (lfTmpCount / m_plfCount[i] > lfMinThreshold)
				{
					nMinCut = j;
					break;
				}
			}
			int nMinValue = 0, nMaxValue = 0;
			for (int j = 1; j < 65536; j++)
			{
				if (m_pHist[i * 65536 + j] > 1e-3)
				{
					nMinValue = j;
					break;
				}
			}
			for (int j = 65534; j > 0; j--)
			{
				if (m_pHist[i * 65536 + j] > 1e-3)
				{
					nMaxValue = j;
					break;
				}
			}

			lfTmpCount = 0.0001;
			for (int j = 65534; j > 0; j--)
			{
				lfTmpCount += m_pHist[i * 65536 + j];
				if (lfTmpCount / m_plfCount[i] > lfMaxThreshold)
				{
					nMaxCut = j;
					break;
				}
			}
			for (int j = 1; j < nMinCut; j++)
			{
				m_pClrLut[i * 65536 + j] = 1;
			}
			for (int j = nMinCut; j <= nMaxCut; j++)
			{
				m_pClrLut[i * 65536 + j] = max(1, min(253, (int)(251.0 * ((double)j - nMinCut) / ((double)nMaxCut - nMinCut) + 2)));
			}
			for (int j = nMaxCut + 1; j < 65536; j++)
			{
				m_pClrLut[i * 65536 + j] = 254;
			}
		}

		//刪除
		delete[] pBufferPyOri;
		pBufferPyOri = nullptr;
	}

	for (int j = 0; j < nRowBlockNum; ++j)
	{
		int nReadHeight = min(nBlock, m_nImgHeight - nBlock * j);
		memset(pBlockBuffer, 0, sizeof(BYTE)* m_nImgWidth * m_nBandNum * m_nBPB * nBlock);
		m_pGu->ReadImg(0, j * nBlock, m_nImgWidth, j * nBlock + nReadHeight, pBlockBuffer, m_nImgWidth, nReadHeight, m_nBandNum, 0, 0, m_nImgWidth, nReadHeight, -1, 0);

		//將當前讀取的塊,轉換爲RGB
		int nDstLeft = 0;
		int nDstTop = int(j * nBlock * m_dIniScale + 0.5);
		int nDstRight = m_nIniWidth;
		int nDstBottom = int((j * nBlock + nReadHeight) * m_dIniScale + 0.5);
		ResampleArray2BGR(m_nImgWidth, nReadHeight, 0, 0, m_nImgWidth, nReadHeight, pBlockBuffer, m_nBandNum,
			m_nIniWidth, m_nIniHeight, nDstLeft, nDstTop, nDstRight, nDstBottom, m_pBufferPy, 3);
	}

	delete[] pBlockBuffer;
	pBlockBuffer = nullptr;

	return 0;
}

bool CGDALShow::GetRealPixValue(int nCtrlX, int nCtrlY, std::vector<int>& vRealValues)
{
	int nImgX = 0, nImgY = 0;

	//用GDALUser讀取的時候,y是反的
	if (!GetImgCoors(nCtrlX, nCtrlY, nImgX, nImgY, true))
	{
		return false;
	}

	vRealValues.clear();
	//讀取當前行的數據,保留原始數據
	unsigned char* pData = new unsigned char[m_nBandNum * m_nBPB];
	m_pGu->ReadImage(nImgX, nImgY, 1, 1, pData);

	if (m_nBPB == 1)
	{
		for (int i = 0; i < m_nBandNum; ++i)
		{
			vRealValues.push_back(pData[i]);
		}
	}
	else if (m_nBPB == 2)
	{
		unsigned short* pSData = (unsigned short*)pData;
		for (int i = 0; i < m_nBandNum; ++i)
		{
			vRealValues.push_back(pSData[i]);
		}
	}

	//如果是單通道,則需要複製結果
	if (m_nBandNum < 3)
	{
		vRealValues.resize(3);
		vRealValues[1] = vRealValues[0];
		vRealValues[2] = vRealValues[0];
	}

	delete[] pData;
	pData = nullptr;

	return true;
}

bool CGDALShow::PreReadFrontBufferDrag(LPVOID lpParameters)
{
	mutexDragThread.Lock();
	CGDALShow* pGs = (CGDALShow*)lpParameters;

	//獲取參數
	CGdalUser* pGu = pGs->m_pGu;
	unsigned char** ppBufferPy = &pGs->m_pBufferPy;
	unsigned char** ppFrontBuffer = &pGs->m_pFrontBuffer;
	unsigned char** ppFrontBufferDrag = &pGs->m_pFrontBufferDrag;
	unsigned char** ppFrontBufferDragThread = &pGs->m_pFrontBufferDragThread;
	const double& dScale = pGs->m_dScale;
	const double& dXoffset = pGs->m_dXoffset;
	const double& dYoffset = pGs->m_dYoffset;
	const double& dIniScale = pGs->m_dIniScale;
	const int& nDCWidth = pGs->m_nDCWidth;
	const int& nDCHeight = pGs->m_nDCHeight;
	const int& nBPB = pGs->m_nBPB;
	const int& nBandNum = pGs->m_nBandNum;
	const int& nIniWidth = pGs->m_nIniWidth;
	const int& nIniHeight = pGs->m_nIniHeight;
	const int& nX = pGs->m_nX;
	const int& nY = pGs->m_nY;
	const int& nShowWidth = pGs->m_nShowWidth;
	const int& nShowHeight = pGs->m_nShowHeight;

	if (pGu == nullptr && ppBufferPy == nullptr)
	{
		return false;
	}

	//根據當前的比例和金字塔比例,決定從金字塔還是從影像直接讀取數據
	int nBufferWidth = nDCWidth * MEM_ALLOC_X;
	int nBufferHeight = nDCHeight * MEM_ALLOC_Y;
	const int nBufferSize = nBufferWidth * nBufferHeight * 3;

	if (*ppFrontBufferDragThread != nullptr)
	{
		delete[] *ppFrontBufferDragThread;
	}

	*ppFrontBufferDragThread = new unsigned char[nBufferSize];
	memset(*ppFrontBufferDragThread, m_nBgValue, nBufferSize);

	const int nBufferSizeOri = nBufferWidth * nBufferHeight * nBandNum * nBPB;
	BYTE* pFrontBufferDragOri = new BYTE[nBufferSizeOri];

	//將用於拖動的緩存刷成背景色
	memset(pFrontBufferDragOri, m_nBgValue, nBufferSizeOri);

	int nPosOffsetX = 0;
	int nPosOffsetY = 0;
	int nWidthOffset = 0;
	int nHeightOffset = 0;

	if (dIniScale < 1.0 && dScale > dIniScale)
	{
		//此時需要從影像直接讀取
		int nSrcLeft = 0;
		int nSrcTop = 0;
		int nSrcRight = pGs->m_nImgWidth;
		int nSrcBottom = pGs->m_nImgHeight;

		int nDstLeft = 0;
		int nDstTop = 0;
		int nDstRight = nShowWidth;
		int nDstBottom = nShowHeight;

		if (nShowWidth > nBufferWidth || nShowHeight > nBufferHeight)
		{
			//此時需要讀取的數據太多,用緩存讀取部分數據即可
			if (nDCWidth + nX < 0)
			{
				//此時讀取起點需要變更
				nSrcLeft = int(-(nDCWidth + nX) / dScale - 0.5);
				nPosOffsetX = -(nDCWidth + nX);
				nDstRight -= nPosOffsetX;
			}

			if (nDCHeight + nY < 0)
			{
				nSrcTop = int(-(nDCHeight + nY) / dScale - 0.5);
				nPosOffsetY = -(nDCHeight + nY);
				nDstBottom -= nPosOffsetY;
			}

			if (nDstRight > nBufferWidth)
			{
				nWidthOffset = nDstRight - nBufferWidth;
				nSrcRight = int(nSrcLeft + nBufferWidth / dScale /*+ 0.5*/);
				nDstRight = nBufferWidth;
			}

			if (nDstBottom > nBufferHeight)
			{
				nHeightOffset = nDstBottom - nBufferHeight;
				nSrcBottom = int(nSrcTop + nBufferHeight / dScale /*+ 0.5*/);
				nDstBottom = nBufferHeight;
			}
		}

		int nPosLeft = nDCWidth + nX + nPosOffsetX;
		int nPosTop = nDCHeight + nY + nPosOffsetY;
		int nPosRight = nPosLeft + nShowWidth - nPosOffsetX - nWidthOffset;
		int nPosBottom = nPosTop + nShowHeight - nPosOffsetY - nHeightOffset;

		//讀取9倍區域到drag緩存中
		HRESULT hRes = pGu->ReadImg(nSrcLeft, nSrcTop, nSrcRight, nSrcBottom, pFrontBufferDragOri,
			nBufferWidth, nBufferHeight, nBandNum, nDstLeft, nDstTop, nDstRight, nDstBottom, -1, 0);
		//偏移到指定的位置,可能越界(已經有越界處理)
		pGs->ResampleArray2BGR(nBufferWidth, nBufferHeight, 0, 0, nDstRight, nDstBottom, pFrontBufferDragOri, nBandNum,
			nBufferWidth, nBufferHeight, nPosLeft, nPosTop, nPosRight, nPosBottom, *ppFrontBufferDragThread, 3);
	}
	else
	{
		//金字塔直接處理
		int nPosLeft = nDCWidth + nX + nPosOffsetX;
		int nPosTop = nDCHeight + nY + nPosOffsetY;
		int nPosRight = nPosLeft + nShowWidth - nPosOffsetX - nWidthOffset;
		int nPosBottom = nPosTop + nShowHeight - nPosOffsetY - nHeightOffset;
		//偏移到指定的位置,可能越界(已經有越界處理)
		pGs->ResampleArray(nIniWidth, nIniHeight, 0, 0, nIniWidth, nIniHeight, *ppBufferPy,
			nBufferWidth, nBufferHeight, nPosLeft, nPosTop, nPosRight, nPosBottom, *ppFrontBufferDragThread);
	}

	mutexDrag.Lock();
	//這個量專門用於讀寫時候的拖拽
	if (*ppFrontBufferDrag != nullptr)
	{
		delete[] * ppFrontBufferDrag;
	}
	*ppFrontBufferDrag = new unsigned char[nBufferSize];
	memcpy(*ppFrontBufferDrag, *ppFrontBufferDragThread, nBufferSize);
	mutexDrag.Unlock();

	mutexDragThread.Unlock();
	pGs->m_bDragDataReady = true;

	delete[] pFrontBufferDragOri;
	pFrontBufferDragOri = nullptr;

	return true;
}

int CGDALShow::GetPointerForDlgShow(CWnd* pCtrlWnd, CBitmap* pbmp, CDC* pmemDC, HBITMAP* phBmp, HBITMAP* phOldBmp)
{
	//DC可能隨着窗口的改變而改變
	m_pCtrlWnd = pCtrlWnd;
	m_pbmp = pbmp;
	m_pmemDC = pmemDC;
	m_phBmp = phBmp;
	m_phOldBmp = phOldBmp;

	return 0;
}

int CGDALShow::ResampleArray(int nSrcBufWidth, int nSrcBufHeight, int nSrcLeft, int nSrcTop, int nSrcRight, int nSrcBottom, unsigned char* pSrc,
	int nDstBufWidth, int nDstBufHeight, int nDstLeft, int nDstTop, int nDstRight, int nDstBottom, unsigned char* pDst)
{
	if (pSrc == nullptr || pDst == nullptr)
	{
		return -1;
	}

	//左上爲小
	int nSrcWidth = nSrcRight - nSrcLeft;
	int nSrcHeight = nSrcBottom - nSrcTop;
	int nDstWidth = nDstRight - nDstLeft;
	int nDstHeight = nDstBottom - nDstTop;

	if (nSrcWidth < 0 || nSrcHeight < 0 || nDstWidth < 0 || nDstHeight < 0)
	{
		return -1;
	}

	double dWidthProp = (double)nDstWidth / nSrcWidth;
	double dHeightProp = (double)nDstHeight / nSrcHeight;

	//如果源地址和目標地址一樣
	unsigned char* pSrcBak(pSrc);
	if (pSrc == pDst)
	{
		int nSrcMemSize = nSrcBufWidth * nSrcBufHeight * 3;
		pSrcBak = new unsigned char[nSrcMemSize];
		memcpy(pSrcBak, pSrc, nSrcMemSize);
		memset(pSrc, m_nBgValue, nSrcMemSize);
	}

	//處理8位圖像
	for (int j = 0; j < nDstHeight; ++j)
	{
		int nyc = nDstTop + j;
		int nyp = nSrcTop + int(j / dHeightProp/* + 0.5*/);
		if (nyp >= AU_MAX(0, nSrcTop) && nyp < AU_MIN(nSrcBottom, nSrcBufHeight)
			&& nyc >= AU_MAX(0, nDstTop) && nyc < AU_MIN(nDstBottom, nDstBufHeight))
		{
			unsigned char* pBufferDst = pDst + (nyc * nDstBufWidth) * 3;
			unsigned char* pBufferSrc = pSrcBak + (nyp * nSrcBufWidth) * 3;
			for (int i = 0; i < nDstWidth; ++i)
			{
				int nxc = nDstLeft + i;
				int nxp = nSrcLeft + int(i / dWidthProp/* + 0.5*/);
				if (nxp >= AU_MAX(0, nSrcLeft) && nxp < AU_MIN(nSrcRight, nSrcBufWidth)
					&& nxc >= AU_MAX(0, nDstLeft) && nxc < AU_MIN(nDstRight, nDstBufWidth))
				{
					unsigned char* pSubBufferDst = pBufferDst + nxc * 3;
					unsigned char* pSubBufferSrc = pBufferSrc + nxp * 3;
					memcpy(pSubBufferDst, pSubBufferSrc, 3);
				}
			}
		}
	}

	if (pSrc == pDst && pSrcBak != nullptr)
	{
		delete[] pSrcBak;
		pSrcBak = nullptr;
	}

	return 0;
}

int CGDALShow::ResampleArray2BGR(int nSrcBufWidth, int nSrcBufHeight, int nSrcLeft, int nSrcTop, int nSrcRight, int nSrcBottom, unsigned char* pSrc, int nSrcBandNum,
	int nDstBufWidth, int nDstBufHeight, int nDstLeft, int nDstTop, int nDstRight, int nDstBottom, unsigned char* pDst, int nDstBandNum,
	int nSizeOfPointer /*= 1*/, int nSrcSkip /*= 0*/, int nDestSkip /*= 0*/)
{
	if (pSrc == nullptr || pDst == nullptr || nDstBandNum < 3)
	{
		//必須轉成BGR
		return -1;
	}

	//左上爲小
	int nSrcWidth = nSrcRight - nSrcLeft;
	int nSrcHeight = nSrcBottom - nSrcTop;
	int nDstWidth = nDstRight - nDstLeft;
	int nDstHeight = nDstBottom - nDstTop;

	if (nSrcWidth < 0 || nSrcHeight < 0 || nDstWidth < 0 || nDstHeight < 0)
	{
		return -1;
	}

	double dWidthProp = (double)nDstWidth / nSrcWidth;
	double dHeightProp = (double)nDstHeight / nSrcHeight;

	//如果源地址和目標地址一樣
	unsigned char* pSrcBak(pSrc);
	if (pSrc == pDst)
	{
		int nSrcMemSize = nSrcBufWidth * nSrcBufHeight * nSrcBandNum * nSizeOfPointer;
		pSrcBak = new unsigned char[nSrcMemSize];
		memcpy(pSrcBak, pSrc, nSrcMemSize);
		memset(pSrc, m_nBgValue, nSrcMemSize);
	}

	//採樣
	const int nBandNum = AU_MIN(nDstBandNum, nSrcBandNum);

	if (m_nBPB == 1)
	{
		//處理8位圖像
		for (int j = 0; j < nDstHeight; ++j)
		{
			int nyc = nDstTop + j;
			int nyp = nSrcTop + int(j / dHeightProp/* + 0.5*/);
			if (nyp >= AU_MAX(0, nSrcTop) && nyp < AU_MIN(nSrcBottom, nSrcBufHeight)
				&& nyc >= AU_MAX(0, nDstTop) && nyc < AU_MIN(nDstBottom, nDstBufHeight))
			{
				unsigned char* pBufferDst = pDst + (nyc * nDstBufWidth) * nDstBandNum * nSizeOfPointer + nSrcSkip;
				unsigned char* pBufferSrc = pSrcBak + (nyp * nSrcBufWidth) * nSrcBandNum * nSizeOfPointer + nDestSkip;
				for (int i = 0; i < nDstWidth; ++i)
				{
					int nxc = nDstLeft + i;
					int nxp = nSrcLeft + int(i / dWidthProp/* + 0.5*/);
					if (nxp >= AU_MAX(0, nSrcLeft) && nxp < AU_MIN(nSrcRight, nSrcBufWidth)
						&& nxc >= AU_MAX(0, nDstLeft) && nxc < AU_MIN(nDstRight, nDstBufWidth))
					{
						unsigned char* pSubBufferDst = pBufferDst + nxc * nDstBandNum * nSizeOfPointer;
						unsigned char* pSubBufferSrc = pBufferSrc + nxp * nSrcBandNum * nSizeOfPointer;
						if (nSrcBandNum == 1)
						{
							for (int k = 0; k < 3; ++k)
							{
								memcpy(pSubBufferDst + k, pSubBufferSrc, nSizeOfPointer);
							}
						}
						else if (nSrcBandNum >= 3)
						{
							for (int k = 0; k < 3; ++k)
							{
								//bmp爲BGR的順序
								memcpy(pSubBufferDst + k, pSubBufferSrc + 2 - k, nSizeOfPointer);
							}
						}
					}
				}
			}
		}
	}
	else
	{
		//處理16位圖像
		unsigned short* pBuffer = (unsigned short*)pSrcBak;
		for (int j = 0; j < nDstHeight; ++j)
		{
			int nyc = nDstTop + j;
			int nyp = nSrcTop + int(j / dHeightProp/* + 0.5*/);
			if (nyp >= AU_MAX(0, nSrcTop) && nyp < AU_MIN(nSrcBottom, nSrcBufHeight)
				&& nyc >= AU_MAX(0, nDstTop) && nyc < AU_MIN(nDstBottom, nDstBufHeight))
			{
				unsigned char* pBufferDst = pDst + (nyc * nDstBufWidth) * nDstBandNum + nSrcSkip;
				unsigned short* pBufferSrc = pBuffer + (nyp * nSrcBufWidth) * nSrcBandNum + nDestSkip;
				for (int i = 0; i < nDstWidth; ++i)
				{
					int nxc = nDstLeft + i;
					int nxp = nSrcLeft + int(i / dWidthProp/* + 0.5*/);
					if (nxp >= AU_MAX(0, nSrcLeft) && nxp < AU_MIN(nSrcRight, nSrcBufWidth)
						&& nxc >= AU_MAX(0, nDstLeft) && nxc < AU_MIN(nDstRight, nDstBufWidth))
					{
						unsigned char* pSubBufferDst = pBufferDst + nxc * nDstBandNum;
						unsigned short* pSubBufferSrc = pBufferSrc + nxp * nSrcBandNum;
						if (nSrcBandNum == 1)
						{
							for (int k = 0; k < 3; k++)
							{
								pSubBufferDst[k] = m_pClrLut[pSubBufferSrc[0]];
							}
						}
						else if (nSrcBandNum >= 3)
						{
							for (int k = 0; k < 3; k++)
							{
								//bmp爲BGR的順序
								pSubBufferDst[k] = m_pClrLut[(2 - k) * 65536 + pSubBufferSrc[2 - k]];
							}
						}
					}
				}
			}
		}
	}

	if (pSrc == pDst && pSrcBak != nullptr)
	{
		delete[] pSrcBak;
		pSrcBak = nullptr;
	}

	return 0;
}

int CGDALShow::ThreadReadingData(BOOL bThread /*= TRUE*/)
{
	m_bDragDataReady = false;

	if (bThread)
	{
		AfxBeginThread(AFX_THREADPROC(PreReadFrontBufferDrag), this);
	}
	else
	{
		PreReadFrontBufferDrag(this);
	}

	return 0;
}

//
void CGDALShow::ResetOffset()
{
	if (m_nDCWidth < 1 || m_nDCHeight < 1 || m_nImgWidth < 1 || m_nImgHeight < 1)
	{
		return;
	}

	CRect rect;
	if (m_bIsDlg)
	{
		m_pCtrlWnd->GetWindowRect(&rect);
	}
	else
	{
		m_pWnd->GetWindowRect(&rect);
	}

	//計算比例
	double dWidthProp = (double)m_nDCWidth / m_nImgWidth;
	double dHeightProp = (double)m_nDCHeight / m_nImgHeight;
	m_dScale = min(dWidthProp, dHeightProp);
	m_dScale = min(1.0, m_dScale);

	double dNeedWidth = m_nImgWidth * m_dScale;
	double dNeedHeight = m_nImgHeight * m_dScale;
	//計算可能需要的偏移
	if (dNeedWidth < m_nDCWidth)
	{
		//此時需要顯示的圖像比較小
		m_pXstart = (m_nDCWidth - dNeedWidth) / 2;
	}

	if (dNeedHeight < m_nDCHeight)
	{
		//此時需要顯示的圖像比較小
		m_pYstart = (m_nDCHeight - dNeedHeight) / 2;
	}

	m_nX = int(m_pXstart + 0.5);
	m_nY = int(m_pYstart + 0.5);
	m_nShowWidth = int(m_nImgWidth*m_dScale + 0.5);
	m_nShowHeight = int(m_nImgHeight*m_dScale + 0.5);
}

void CGDALShow::ResetParameters()
{
	m_bDragDataReady = false;
	m_bIsLBtnDown = false;
	m_bIsMBtnDown = false;
	m_bIsDlg = false;
	m_bUpdateScale = true;

	m_dIniScale = 1.0;
	m_dScaleLast = 1.0;

	m_nDCWidth = 0;
	m_nDCHeight = 0;
	
	m_pGu = nullptr;
	m_pHist = nullptr;
	m_plfCount = nullptr;
	m_pFrontBuffer = nullptr;
	m_pFrontBufferDrag = nullptr;
	m_pFrontBufferDragThread = nullptr;	
	m_pBufferPy = nullptr;
	m_pClrLut = nullptr;
	m_pWnd = nullptr;
	m_pMouDownPnt = POINT();

	m_dXoffset = 0.0;
	m_dYoffset = 0.0;
	m_pXoffset = 0.0;
	m_pYoffset = 0.0;
	m_pXstart = 0.0;
	m_pYstart = 0.0;

	m_nImgWidth = 0;
	m_nImgHeight = 0;
	m_nIniWidth = 0;
	m_nIniHeight = 0;
	m_nBandNum = 1;
	m_nBPB = 1;

	m_nX = 0;
	m_nY = 0;

	m_nShowWidth = 0;
	m_nShowHeight = 0;
	m_dScale = 1.0;

	m_pbmp = nullptr;
	m_pmemDC = nullptr;
	m_pCtrlWnd = nullptr;
	m_phBmp = nullptr;
	m_phOldBmp = nullptr;

	//static變量
	m_dMaxScale = 8.0;
	m_dMinScale = 0.01;
	m_dScaleStep = 120.0 / 0.125;
	m_dXoffset = 0.0;
	m_dYoffset = 0.0;
	m_nBgValue = 240;
}

void CGDALShow::ShowImage(BOOL bDirectDC /*= false*/)
{
	//如果是對話框,需要做以下操作
	if (m_bIsDlg && m_pCtrlWnd && m_phBmp && m_pbmp)
	{
		CRect rcPicture;
		m_pCtrlWnd->GetWindowRect(rcPicture);
		m_nDCWidth = rcPicture.Width();
		m_nDCHeight = rcPicture.Height();

		//寬度應爲4的整數倍
		m_nDCWidth = ((m_nDCWidth + 3) / 4) * 4;

		if (*m_phBmp)
		{
			::DeleteObject(*m_phBmp);
			*m_phBmp = nullptr;
		}

		BITMAPINFO bmpInfo;
		bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		bmpInfo.bmiHeader.biWidth = m_nDCWidth;
		bmpInfo.bmiHeader.biHeight = m_nDCHeight;
		bmpInfo.bmiHeader.biPlanes = 1;
		bmpInfo.bmiHeader.biBitCount = 24;
		bmpInfo.bmiHeader.biCompression = BI_RGB;
		bmpInfo.bmiHeader.biSizeImage = 0;
		bmpInfo.bmiHeader.biXPelsPerMeter = 0;
		bmpInfo.bmiHeader.biYPelsPerMeter = 0;
		bmpInfo.bmiHeader.biClrUsed = 0;
		bmpInfo.bmiHeader.biClrImportant = 0;

		*m_phBmp = CreateDIBSection(m_pmemDC->m_hDC, &bmpInfo, DIB_RGB_COLORS, (void **)&m_pFrontBuffer, NULL, 0);
		*m_phOldBmp = (HBITMAP)::SelectObject(m_pmemDC->m_hDC, *m_phBmp);

		m_pbmp->Detach();
		m_pbmp->Attach(*m_phBmp);
	}

	//必須使用外部雙緩存
	memset(m_pFrontBuffer, m_nBgValue, m_nDCWidth * m_nDCHeight * 3);
	if(m_bUpdateScale || !m_bDragDataReady)
	{
		//線程正在讀取數據的時候,讀取金字塔
		ResampleArray(m_nIniWidth, m_nIniHeight, 0, 0, m_nIniWidth, m_nIniHeight, m_pBufferPy, m_nDCWidth, m_nDCHeight,
			m_nX, m_nY, m_nX + m_nShowWidth, m_nY + m_nShowHeight, m_pFrontBuffer);
	}
	else if (m_pFrontBufferDragThread)
	{
		//顯示部分影像時,將m_pFrontBufferDrag中間部分的內容平移到當前DC當中
		int nBufferWidth = m_nDCWidth * MEM_ALLOC_X;
		int nBufferHeight = m_nDCHeight * MEM_ALLOC_Y;

		int nSrcLeft = int(m_nDCWidth - m_pXoffset - 0.5);
		int nSrcTop = int(m_nDCHeight - m_pYoffset - 0.5);
		int nSrcRight = nSrcLeft + m_nDCWidth;
		int nSrcBottom = nSrcTop + m_nDCHeight;

		int nDstLeft = 0;
		int nDstTop = 0;
		int nDstRight = m_nDCWidth;
		int nDstBottom = m_nDCHeight;

		mutexDrag.Lock();
		for (int j = 0; j < m_nDCHeight; ++j)
		{
			unsigned char* pBufferDst = m_pFrontBuffer + (j * m_nDCWidth) * 3;
			unsigned char* pBufferSrc = m_pFrontBufferDrag + ((nSrcTop + j) * nBufferWidth) * 3 + nSrcLeft * 3;
			if (nSrcTop + j >= 0 && nSrcTop + j < nBufferHeight)
			{
				int nCopyWidth = AU_MIN((nBufferWidth - nSrcLeft), m_nDCWidth);
				if (nCopyWidth > 0)
				{
					memcpy(pBufferDst, pBufferSrc, nCopyWidth * 3);
				}
			}
		}
		mutexDrag.Unlock();
	}

	m_pWnd->Invalidate(FALSE);
}

bool CGDALShow::GetPixValue(int nCtrlX, int nCtrlY, std::vector<int>& values, bool bGetRealValue /*= false*/)
{
	if (nCtrlX < 0 || nCtrlX >= m_nDCWidth || nCtrlY <= 0 || nCtrlY > m_nDCHeight)
	{
		return false;
	}

	if (bGetRealValue)
	{
		//獲取真實的像素值
		return GetRealPixValue(nCtrlX, nCtrlY, values);
	}

	//讀取當前屏幕像素值
	nCtrlY = m_nDCHeight - nCtrlY;
	values.clear();
	int x1 = *(m_pFrontBuffer + (nCtrlY * m_nDCWidth + nCtrlX) * 3 + 0);
	int x2 = *(m_pFrontBuffer + (nCtrlY * m_nDCWidth + nCtrlX) * 3 + 1);
	int x3 = *(m_pFrontBuffer + (nCtrlY * m_nDCWidth + nCtrlX) * 3 + 2);

	//輸出RGB
	values.push_back(x3);
	values.push_back(x2);
	values.push_back(x1);

	return true;
}

bool CGDALShow::GetImgCoors(int nCtrlX, int nCtrlY, int& nImgX, int& nImgY, bool bYReverse /*= false*/)
{
	nImgX = int((nCtrlX - m_nX) / m_dScale);
	nImgY = int((nCtrlY - (m_nDCHeight - m_nShowHeight - m_nY)) / m_dScale);

	if (bYReverse)
	{
		//從0開始到m_nImgHeight - 1
		nImgY = m_nImgHeight - 1 - nImgY;
	}

	return nImgX >= 0 && nImgX < m_nImgWidth && nImgY >= 0 && nImgY < m_nImgHeight;
}

歡迎交流與分享。

發佈了61 篇原創文章 · 獲贊 11 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章