一个简单的问题,但由于某种原因,我今天无法解决这个问题。
我需要将图像调整到适合边框的最大可能尺寸,同时保持纵横比。
基本上我正在寻找填写此功能的代码:
void CalcNewDimensions(ref int w, ref int h, int MaxWidth, int MaxHeight);
w& h是原始高度和宽度(in)以及新的高度和宽度(out),MaxWidth和MaxHeight定义图像必须适合的边界框。
答案 0 :(得分:79)
查找哪个更小:MaxWidth / w
或MaxHeight / h
然后将w
和h
乘以该数字
<强>解释强>
您需要找到使图像适合的缩放系数。
要查找宽度的缩放系数s
,则s
必须为:
s * w = MaxWidth
。
因此,缩放因子为MaxWidth / w
。
同样适用于身高。
需要最大缩放(较小s
)的那个是您必须缩放整个图像的因素。
答案 1 :(得分:26)
根据Eric的建议,我会做这样的事情:
private static Size ExpandToBound(Size image, Size boundingBox)
{
double widthScale = 0, heightScale = 0;
if (image.Width != 0)
widthScale = (double)boundingBox.Width / (double)image.Width;
if (image.Height != 0)
heightScale = (double)boundingBox.Height / (double)image.Height;
double scale = Math.Min(widthScale, heightScale);
Size result = new Size((int)(image.Width * scale),
(int)(image.Height * scale));
return result;
}
我可能在演员阵容上有点过分,但我只是想在计算中保持精确度。
答案 2 :(得分:7)
试过沃伦先生的代码,但它没有产生可靠的结果。
例如,
ExpandToBound(new Size(640,480), new Size(66, 999)).Dump();
// {Width=66, Height=49}
ExpandToBound(new Size(640,480), new Size(999,50)).Dump();
// {Width=66, Height=50}
你可以看到,身高= 49,身高= 50。
这是我的(Warren先生代码的基础版本)没有差异和轻微的重构:
// Passing null for either maxWidth or maxHeight maintains aspect ratio while
// the other non-null parameter is guaranteed to be constrained to
// its maximum value.
//
// Example: maxHeight = 50, maxWidth = null
// Constrain the height to a maximum value of 50, respecting the aspect
// ratio, to any width.
//
// Example: maxHeight = 100, maxWidth = 90
// Constrain the height to a maximum of 100 and width to a maximum of 90
// whichever comes first.
//
private static Size ScaleSize( Size from, int? maxWidth, int? maxHeight )
{
if ( !maxWidth.HasValue && !maxHeight.HasValue ) throw new ArgumentException( "At least one scale factor (toWidth or toHeight) must not be null." );
if ( from.Height == 0 || from.Width == 0 ) throw new ArgumentException( "Cannot scale size from zero." );
double? widthScale = null;
double? heightScale = null;
if ( maxWidth.HasValue )
{
widthScale = maxWidth.Value / (double)from.Width;
}
if ( maxHeight.HasValue )
{
heightScale = maxHeight.Value / (double)from.Height;
}
double scale = Math.Min( (double)(widthScale ?? heightScale),
(double)(heightScale ?? widthScale) );
return new Size( (int)Math.Floor( from.Width * scale ), (int)Math.Ceiling( from.Height * scale ) );
}
答案 3 :(得分:6)
要执行宽高比填充而不是宽高比,请使用较大的比例。也就是说,将Matt的代码从Math.Min更改为Math.Max。
(方面填充不会使边界框空,但可能会将某些图像放在边界之外,而方面适合不会使边界之外的任何图像留下,但可能会使某些边界框留空。)
答案 4 :(得分:5)
以下代码可以产生更准确的结果:
public static Size CalculateResizeToFit(Size imageSize, Size boxSize)
{
// TODO: Check for arguments (for null and <=0)
var widthScale = boxSize.Width / (double)imageSize.Width;
var heightScale = boxSize.Height / (double)imageSize.Height;
var scale = Math.Min(widthScale, heightScale);
return new Size(
(int)Math.Round((imageSize.Width * scale)),
(int)Math.Round((imageSize.Height * scale))
);
}
答案 5 :(得分:3)
简单。 :)问题是找到一个需要乘以宽度和高度的因子。解决方案是尝试使用一个,如果不适合,请使用另一个。所以......
private float ScaleFactor(Rectangle outer, Rectangle inner)
{
float factor = (float)outer.Height / (float)inner.Height;
if ((float)inner.Width * factor > outer.Width) // Switch!
factor = (float)outer.Width / (float)inner.Width;
return factor;
}
将图片(pctRect)拟合到窗口(wndRect)这样的调用
float factor=ScaleFactor(wndRect, pctRect); // Outer, inner
RectangleF resultRect=new RectangleF(0,0,pctRect.Width*factor,pctRect.Height*Factor)
答案 6 :(得分:2)
Python代码,但它可能会指向正确的方向:
def fit_within_box(box_width, box_height, width, height):
"""
Returns a tuple (new_width, new_height) which has the property
that it fits within box_width and box_height and has (close to)
the same aspect ratio as the original size
"""
new_width, new_height = width, height
aspect_ratio = float(width) / float(height)
if new_width > box_width:
new_width = box_width
new_height = int(new_width / aspect_ratio)
if new_height > box_height:
new_height = box_height
new_width = int(new_height * aspect_ratio)
return (new_width, new_height)
答案 7 :(得分:1)
根据之前的答案,这是一个Javascript函数:
/**
* fitInBox
* Constrains a box (width x height) to fit in a containing box (maxWidth x maxHeight), preserving the aspect ratio
* @param width width of the box to be resized
* @param height height of the box to be resized
* @param maxWidth width of the containing box
* @param maxHeight height of the containing box
* @param expandable (Bool) if output size is bigger than input size, output is left unchanged (false) or expanded (true)
* @return {width, height} of the resized box
*/
function fitInBox(width, height, maxWidth, maxHeight, expandable) {
"use strict";
var aspect = width / height,
initWidth = width,
initHeight = height;
if (width > maxWidth || height < maxHeight) {
width = maxWidth;
height = Math.floor(width / aspect);
}
if (height > maxHeight || width < maxWidth) {
height = maxHeight;
width = Math.floor(height * aspect);
}
if (!!expandable === false && (width >= initWidth || height >= initHeight)) {
width = initWidth;
height = initHeight;
}
return {
width: width,
height: height
};
}
答案 8 :(得分:0)
我遇到了类似的问题,我发现它非常有用:article。据我所知,你需要调整图像大小?
答案 9 :(得分:0)
用于此任务的Python代码基于Jason的答案,并针对通过img.shape传递的常规参数进行了升级和参数重排。
def fit_within_box(box_height, box_width, height, width):
"""
Returns a tuple (new_width, new_height) which has the property
that it fits within box_width and box_height and has (close to)
the same aspect ratio as the original size
"""
new_width, new_height = width, height
aspect_ratio = float(width) / float(height)
if new_width > box_width or new_height < box_height:
new_width = box_width
new_height = int(new_width / aspect_ratio)
if new_height > box_height or new_width < box_width:
new_height = box_height
new_width = int(new_height * aspect_ratio)
return new_height, new_width