如何将一个矩形缩放到另一个矩形内的最大尺寸?

77

我有一个源矩形和目标矩形。我需要找到源可以缩放的最大比例,以适应目标矩形并 保持其原始纵横比

Google 找到了一种方法,但我不确定它是否在所有情况下都适用。这是我的自制解决方案:

  • 计算每个矩形的高度/宽度。这给出了对角线 msrcmdest 的斜率。
  • 如果 msrc < mdst,则将源 宽度 缩放以适应目标 宽度 (并按相同比例缩放高度)
  • 否则,将源 高度 缩放以适应目标 高度(并按相同比例缩放宽度)

寻找此问题的其他可能解决方案。我甚至不确定我的算法在所有情况下是否可行!

5个回答

155
scale = min(dst.width/src.width, dst.height/src.height)

这是您的方法,但更加简洁。

要使用此方法,缩放后的矩形将具有以下形状:

width = src.width * scale
height = src.height * scale

10
好的!一旦你有了比例尺,就可以使用以下公式得到最终的尺寸:宽度 = 源图宽度 × 比例尺高度 = 源图高度 × 比例尺 - fregante
9
如果你想覆盖整个目的地区域,将“min”和“max”互换。 - Glogo
18
同样的解决方案,但对我来说名称更清晰:scale = min(maxWidth/actualWidth, maxHeight/actualHeight)newWidth = actualWidth*scalenewHeight = actualHeight*scale - Peppe L-G

13

另一种选择可能是先按最大宽度缩放,然后检查缩放后的高度是否大于最大允许高度,如果是,则按高度缩放(或反之亦然):

scale = (dst.width / src.width);
if (src.height * scale > dst.height)
 scale = dst.height / src.height;

我认为这个解决方案既更短,更快,也更易于理解。


我觉得你在第三行的比例弄反了。 - tom10

2
  1. 计算destWidth / srcWidthdestHeight / srcHeight的较小值
  2. 按照该比例进行缩放

编辑 当然,这与您的方法相同,只是公式的各个部分移动了位置。我的观点是,从语义上讲,这更清晰,但这只是一个观点。


1
如果所有的维度都不为零,我会使用以下代码(基本上与您的代码相匹配)。
scaleFactor = (outerWidth / outerHeight > innerWidth / innerHeight) 
    ? outerHeight / innerHeight
    : outerWidth / innerWidth

如果需要,这也可以被修改以允许任何维度为零。


3
我认为长度为零的矩形被称为“线段”。 :P - MusiGenesis
1
这个解决方案在数学上与我的解决方案完全相同:将你的不等式乘以(innerHeight * outerHeight / innerWidth),就可以得到我的不等式。我的代码的优点是,如果不等式失败,则无需重新计算解决方案。 - Guss
三元运算符也只会评估条件一次。当然,所有的解决方案都应该是数学等价的...或错误的... - Daniel Brückner
三元运算符将只计算一次条件,但通过以不同格式格式化条件,条件的计算部分可以成为答案之一。请注意,在计算中始终有3个乘法运算。我的解决方案在最坏情况下有3个操作,在其他情况下只有2个,因为正确的计算已经在测试之前完成。因此,性能提高了1/6(假设值的分布是随机的)。 - Guss

0

其他答案存在一个风险,当源宽度或源高度变为零时会生成除以零的异常。为了防范这种情况,我们应该将比较重写为数学上等价的多个表达式。此外,还需要额外的边缘条件来捕获无限缩放的情况。

除了具有比例之外,我真的想要目标矩形的尺寸,因此在这里我将提供比例计算和目标矩形计算。

由于存在无限边缘条件,我认为目标矩形将更加健壮/有用:

    if (sourceWidth == 0 && sourceHeight == 0) {
        // scale = Infinity;
        outputWidth = 0;
        outputHeight = 0;
        outputX = destWidth / 2;
        outputY = destHeight / 2;
    } else if (destWidth * sourceHeight > destHeight * sourceWidth) {
        scale = destHeight / sourceHeight;
        outputWidth = sourceWidth * destHeight / sourceHeight;
        outputHeight = destHeight;
        outputX = (destWidth - outputWidth) / 2;
        outputY = 0;
    } else {
        scale = destWidth / sourceWidth;
        outputWidth = destWidth;
        outputHeight = sourceHeight * destWidth / sourceWidth;
        outputX = 0;
        outputY = (destHeight - outputHeight) / 2;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接