我把它放在这里是因为执行此操作的算法比应该更难找到。希望谷歌能缓存这个。
问题是:你有一个位图和一个窗口。您希望在窗口内部绘制位图,填充窗口,保持纵横比,因为窗口会调整大小。
您可能还希望能够以其他方式适应它,以便您可以在窗口“上方”绘制图像,并且窗口中的所有区域都将被填充。这将剪掉一些图像。我在答案中提出了一个简单的算法。
答案 0 :(得分:1)
这是一个仅使用整数数学的实现。
该算法首先拉伸两个维度,保留纵横比。假设相应的其他维度占据整个空间,计算新的大小。在这些新尺寸中,超出可用区域的尺寸被设置为最大可能值,而另一个尺寸被缩小,保持纵横比。 (对于平移和扫描( bScale 设置为true
)模式,不会超出可用空间的维度将设置为占用整个范围内。)
(注意:如果 sizePicture 是一个空矩形,则此函数返回一个矩形,从原点或中心向左伸展一个像素,向上伸展一个像素。)
RECT size_rect( RECT& rcScreen,
RECT& sizePicture,
bool bCenter/*,
bool bScale*/ ) {
int clientWidth = rcScreen.right - rcScreen.left;
int clientHeight = rcScreen.bottom - rcScreen.top;
int picWidth = sizePicture.right - sizePicture.left;
int picHeight = sizePicture.bottom - sizePicture.top;
// Calculate new content size
int contentWidth = ::MulDiv( clientHeight, picWidth, picHeight );
int contentHeight = ::MulDiv( clientWidth, picHeight, picWidth );
// Adjust dimensions to fit inside client area
if ( contentWidth > clientWidth ) {
// To use the bScale parameter that allows the image to fill the entire
// client area, use the following if-clause instead.
//if ( ( bScale && ( contentWidth < clientWidth ) )
// || ( !bScale && ( contentWidth > clientWidth ) ) ) {
contentWidth = clientWidth;
contentHeight = ::MulDiv( contentWidth, picHeight, picWidth );
} else {
contentHeight = clientHeight;
contentWidth = ::MulDiv( contentHeight, picWidth, picHeight );
}
RECT rect = { 0 };
::SetRect( &rect, 0, 0, contentWidth, contentHeight );
if ( bCenter ) {
// Calculate offsets to center content
int offsetX = ( clientWidth - contentWidth ) / 2;
int offsetY = ( clientHeight - contentHeight ) / 2;
::OffsetRect( &rect, offsetX, offsetY );
}
return rect;
}
答案 1 :(得分:0)
制作两个RECT。一个是您希望适合的窗口(传递到rcScreen),另一个是图片的尺寸:
(pseudo-code)
RECT window;
GetClientRect(hwnd,&window)
RECT bitmap_rect;
BITMAP bitmap;
bitmap_rect.left = bitmap_rect.top = 0;
bitmap_rect.right = bitmap.bmWidth;
bitmap_rect.bottom = bitmap.bmHeight;
RECT draw_rect = size_rect(window,bitmap_rect,true,true);
然后StretchBlt it:
StretchBlt(toDC, draw_rect.left, draw_rect.top, draw_rect.right, draw_rect.bottom, fromDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
这是函数:(注意bCenter = false和Scale = true没有情况)。 ** bCenter是&#34;窗口中心图片的标志。&#34;标度为&#34;平移和扫描模式&#34;而不是&#34; letterbox,&#34;如果您使用图像作为要调整大小但不想拥有信箱的窗口背景,则非常有用。 **
RECT size_rect(RECT& rcScreen,
RECT& sizePicture,
bool bCenter,
bool Scale)
{
RECT rect = rcScreen;
double dWidth = rcScreen.right - rcScreen.left;
double dHeight = rcScreen.bottom - rcScreen.top;
double dAspectRatio = dWidth / dHeight;
double dPictureWidth = sizePicture.right - sizePicture.left;
double dPictureHeight = sizePicture.bottom - sizePicture.top;
double dPictureAspectRatio = dPictureWidth / dPictureHeight;
double nNewHeight = dHeight;
double nNewWidth = dWidth;
double nHeightCenteringFactor = 0;
double nWidthCenteringFactor = 0;
double xstart = rcScreen.left;
double ystart = rcScreen.top;
if (dPictureAspectRatio > dAspectRatio)
{
if (bCenter && Scale) {
nNewWidth = dPictureWidth*(1 / (dPictureHeight / dHeight));
xstart = rcScreen.left - ((nNewWidth / 2) - (dWidth / 2));
}
else {
nNewHeight = (int)(dWidth / dPictureWidth*dPictureHeight);
if (bCenter)
ystart = ((dHeight - nNewHeight) / 2) + rcScreen.top;
}
}
else if (dPictureAspectRatio < dAspectRatio)
{
if (bCenter && Scale) {
nNewHeight = dPictureHeight*(1 / (dPictureWidth / dWidth));
ystart = rcScreen.top - ((nNewHeight / 2) - (dHeight / 2));
}
else{
nNewWidth = (dHeight / dPictureHeight*dPictureWidth);
if (bCenter)
xstart = ((dWidth - nNewWidth) / 2) + rcScreen.left;
}
}
SetRect(&rect, xstart, ystart, nNewWidth, nNewHeight);
return rect;
}