MFC中显示图像的放大、缩小、移动功能

StretchBlt函数直接对图片进行放大,缩小,显示位置变换。
这个函数有两种形态一种全局函数是这样的: 
BOOL StretchBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop);

一种是CDC的成员函数是这样的:

BOOL StretchBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop );

在实现时有两点要注意

  1. 显示模式,使用SetStretchBltMode来控制像素在拉伸,缩小时的像素运算。在拉伸位图时一般不需要修改,在压缩位图显示时,默认值会出现颜色失真,这时可以使用HALFTONE模式。
  2. 在StrectchBlt中xSrc,ySrc为拷贝设备的逻辑坐标,在拷贝位图后在边缘是有一个逻辑单位的空白的,这点在放大图片对xSrc,ySrc进行设置容易被忽略。

目的描述

  1. 显示位图,鼠标点击图片,以所点击图片的位置为中心按照一定比例系数对图片显示进行放大缩小操作。
  2. 移动位图显示窗口,按下鼠标右键可以拖动位图的显示位置,对位图的显示区进行移动操作。

思路

  通过WM_LBUTTONDOWN或WM_LBUTTONCLICK来获取鼠标的动作的坐标,通常是CClientDC的逻辑坐标,如果是采用文档模式则一般CClientDC和显示窗口是一致的。如果采用PictureControl在窗口应用程序当中显示时,可以先获得PictureControl区域的屏幕坐标再转换成CClientDC的坐标。经过PicturenControl左上角坐标的计算,就可以得到鼠标点击位置在PictureControl区域中的逻辑坐标。再通过该坐标计算出在原设备区中的逻辑坐标,通过该逻辑坐标就可以计算出鼠标所在点在位图上的坐标。知道该位图上坐标后,就可以对原设备区进行拉伸,缩小,移动的操作了。

实现

放大,缩小

CStatic m_sPreview;//PictureControl 控件
CPoint m_CurClientPoint;//当前鼠标位置所在客户区的逻辑坐标
int m_iMultiple;//图像缩放显示倍数
enum PreviewType{enlarge,narrow,restore,move};
PreviewType m_nPrevewType;//命令模式
CPoint m_OriginSrcPoint;//显示图像右上角坐标
unsigned int iWidth,iHeight;//iWidth与iHeight是图片的横纵像素的数目
...
ClientToPictureControl(&m_sPreview,&m_CurClientPoint);
PictureControlToBmp(m_nWidthDest,m_nHeightDest,m_nWidthSrc,m_nHeightSrc,&m_OriginSrcPoint,&m_CurClientPoint);
m_nWidthSrc=iWidth/m_iMultiple;
m_nHeightSrc=iHeight/m_iMultiple;
Mutiply(m_nPreviewType,&m_OriginSrcPoint,&m_CurClientPoint,m_nWidthSrc,m_nHeightSrc);        
m_nYOriginSrc=m_OriginSrcPoint.y;//
m_nXOriginSrc=m_OriginSrcPoint.x;//
函数ClientToPictureControl功能为得到该点再控件坐标系的。
void ClientToPictureControl(CStatic *picControl,CPoint *point)//得到picControl在客户区的逻辑位置
{
    CWnd *pWnd;
    pWnd=picControl;
    CRect tmp;
    pWnd->GetWindowRect(&tmp);//控件窗口位置
    ScreenToClient(&tmp);
    *point = *point - tmp.TopLeft();
}
函数PictureControlToBmp功能是为得到鼠标位置在图像坐标系下的像素坐标 
void PictureControlToBmp(int nWidthDest,int nHeightDest,int nWidthSrc,int nHeightSrc,
CPoint *Origin,CPoint *point)
{
  point->x = point->x * nWidthSrc / nWidthDest+ Origin->x;
  point->y= point->y * nHeightSrc / nHeightDest+ Origin->y;
}
函数Mutiply//是调整显示右上角坐标的。
void Mutiply(PreviewType type,CPoint *Origin,CPoint *point, int width,int height)
{
    switch (type)
    {
    case CAlphaDlg::enlarge:
        if(point->x-width/2>0)
        {
            if(m_pMyDevice->m_sFrInfo.iWidth > point->x+width/2){
                Origin->x=point->x-width/2;}
            else{
                Origin->x=m_pMyDevice->m_sFrInfo.iWidth-width;
            }
        }
        else
        {
            Origin->x=0;
        }
        if(point->y-height/2>0)
        {
            if(m_pMyDevice->m_sFrInfo.iHeight> point->y+height/2){
                Origin->y=point->y-height/2;}
            else{
                Origin->y=m_pMyDevice->m_sFrInfo.iHeight-height;
            }
        }
        else
        {
            Origin->y=0;
        }
        break;
    case CAlphaDlg::narrow:
        if(point->x-width/2>0)
        {
            if(m_pMyDevice->m_sFrInfo.iWidth > point->x+width/2){
                Origin->x=point->x-width/2;}
            else{
                Origin->x=m_pMyDevice->m_sFrInfo.iWidth-width;
            }
        }
        else
        {
            Origin->x=0;
        }
        if(point->y-height/2>0)
        {
            if(m_pMyDevice->m_sFrInfo.iHeight> point->y+height/2){
                Origin->y=point->y-height/2;}
            else{
                Origin->y=m_pMyDevice->m_sFrInfo.iHeight-height;
            }
        }
        else
        {
            Origin->y=0;
        }
        break;
    case CAlphaDlg::restore:
        Origin->x=0;
        Origin->y=0;
        break;
    case CAlphaDlg::move:        
        break;
    default:
        break;
    }
}

以上,是图像放大缩小的步骤。

如果移动图像和上面类似,直接响应WM_MOUSEMOVE消息

void OnMouseMove(UINT nFlags, CPoint point)
{
    if(m_bTool==TRUE&&m_nPreviewType==move)
    {SetCursor(LoadCursor(NULL,IDC_SIZEALL));   
        CRect rect;
switch (nFlags)
        {
        case MK_LBUTTON:
            if(m_CurClientPoint!=point)
            {
                if(m_nXOriginSrc+(-point.x+m_CurClientPoint.x)/m_iMultiple>0)
                {
                    if(m_nXOriginSrc+(-point.x+m_CurClientPoint.x)/m_iMultiple + m_nWidthSrc< m_pMyDevice->m_sFrInfo.iWidth)
                    m_nXOriginSrc=m_nXOriginSrc+(-point.x+m_CurClientPoint.x)/m_iMultiple;    
                }
                else
                {
                    m_nXOriginSrc=0;
                }
                if(m_nYOriginSrc+(-point.y+m_CurClientPoint.y)/m_iMultiple>0)
                {
                    if(m_nYOriginSrc+(-point.y+m_CurClientPoint.y)/m_iMultiple + m_nHeightSrc< m_pMyDevice->m_sFrInfo.iHeight)
                    m_nYOriginSrc=m_nYOriginSrc+(-point.y+m_CurClientPoint.y)/m_iMultiple;    
                }
                else
                {
                    m_nYOriginSrc=0;
                }
                m_CurClientPoint = point ;
            }            
            m_sPreview.GetClientRect(&rect);
            InvalidateRect(rect,1);
            break;
        default:
            break;
        }
    }
原文地址:https://www.cnblogs.com/fastcam/p/5007179.html