按:因为模型的原因,图像显示时限定了了显示的区域以及锁定了长宽比,在缩小状态下没有任何问题,但是放大显示,如果还是锁定长宽比,就有些怪异了。因此,在放大状态下,要岁放大比例逐渐增大显示区域,此时长宽比就要根据实际情况进行变化,为了使图像不失真,对图像的裁剪也要变化。
改变显示区域的算法推导
根据本软件显示的模型,显示区域的矩形边界及其坐标是要参与计算的,图形的裁剪也要符合必须的比例关系,因此扩展显示区域,这些关系不能改变。否则,显示出来的图像的比例和位置关系就会出现问题。如图:
截取的图像用中间深蓝色矩形表示,显示范围 A0,屏幕(扩大的显示区域)为A1,其宽度为Sw,我们利用距离和比例关系进行计算。
问题简化描述为:已知Sub Img 与View A1 的位置关系,求Sub Img 在 Canvas A1 中的位置关系,A0 和A1 几何中心一致。
根据上面的条件,只要求得Sub img 的左上角到A1的左边和右边的距离即可
我们令水平距离为 X
根据比例关系
X=Sx + (Cw-Vw)/2
同理可以求得垂直距离Y
Y=Sy+(Ch-Vh)/2
而Sub Img 长宽不变。
任意显示区域而图像比例不变的代码
if (!subImg.IsNull()) {
subImg.Destroy();
}
//subImg.Create(m_ImgRect.Width(), m_ImgRect.Height(), 24); // 原来sub img的大小定义
subImg.Create(canvasRect.Width(), canvasRect.Height(), 24);//区域改变后的大小
CBilinearZoomFilter bzFilter;
CImage tmpImg;
//m_Ratio2 *= R;
float ratioW, ratioH;
ratioW = (float)orgImg.GetWidth() / subImgW;
ratioH = (float)orgImg.GetHeight() / subImgH;
CDC* pSrcDC = CDC::FromHandle(orgImg.GetDC());
CDC* pDstDC = CDC::FromHandle(subImg.GetDC());
int ModeOld = SetStretchBltMode(pDstDC->m_hDC, COLORONCOLOR);//设置指定设备环境中的位图拉伸模式, looks like STRETCH_HALFTONE mode, 0.16 ms or 0.00 ms
float x, y, w, h;
w = viewRec.Width()*ratioW;
h = viewRec.Height()*ratioH;
//原显示区域左上坐标
x = (0 - subImgX) / subImgW*viewRec.Width() ;
y = (0 - subImgY) / subImgH*viewRec.Height();
//调整显示区域后的左上坐标
x += (canvasRect.Width() - viewRec.Width()) / 2.0 +0.5;
y += (canvasRect.Height() - viewRec.Height()) / 2.0 +0.5;
pDstDC->StretchBlt(x, y, w, h, pSrcDC, 0, 0, orgImg.GetWidth(), orgImg.GetHeight(), SRCCOPY);
SetStretchBltMode(pDstDC->m_hDC, ModeOld);
subImg.ReleaseDC();
orgImg.ReleaseDC();
说明:在计算中一定不要在中间过程采用整数,否则其舍入误差会影响显示效果,而且误差会累积。
2020-03-28 于泛五道口地区
ps:北京春日正好,明天去山里看杏花。