先上效果圖:
核心代碼:
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;
}
歡迎交流與分享。