一个简单的问题,但由于某种原因,我今天无法弄清楚这一点。调整图像以适合边框
我需要将图像调整到最大可能大小,将适合在边界框,同时保持高宽比。
Basicly我正在寻找的代码填写此功能:
void CalcNewDimensions(ref int w, ref int h, int MaxWidth, int MaxHeight);
其中,w & h为原来的高度和宽度(以)和新的高度和宽度(出)和MaxWidth和。MaxHeight定义图像必须适合边框
一个简单的问题,但由于某种原因,我今天无法弄清楚这一点。调整图像以适合边框
我需要将图像调整到最大可能大小,将适合在边界框,同时保持高宽比。
Basicly我正在寻找的代码填写此功能:
void CalcNewDimensions(ref int w, ref int h, int MaxWidth, int MaxHeight);
其中,w & h为原来的高度和宽度(以)和新的高度和宽度(出)和MaxWidth和。MaxHeight定义图像必须适合边框
查找哪一个较小:MaxWidth/w
或MaxHeight/h
然后由数乘以w
和h
说明:
你需要找到的缩放因子使图像配合。
要查找比例因子s
,则为宽度,那么s
必须为: s * w = MaxWidth
。 因此,缩放因子是MaxWidth/w
。
类似的高度。
,需要最缩放的一个(小s
)是你必须调整整个图像的因素。
如果你用float来做这件事,你可能会发现与边界框相匹配的尺寸略微偏离(有时候,以不可预知的方式)。当你确定哪个维度不匹配时,最好简单地假设另一个维度应该是什么? – 2009-08-19 23:02:55
+1三年后,我坐在Google结果的顶部。没有麻烦,没有大惊小怪。谢谢! – chaosTechnician 2012-06-04 16:21:46
就像你的回复没有写在c中一样,所以我可以将它应用到python – 2015-06-28 23:18:18
我倒是类似的问题,我发现非常有用:article。正如我理解正确,你需要调整图像的大小?
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)
基于埃里克的建议,我会做这样的事情:
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;
}
我可能去了一下在演职员表上过度工作,但我只是想在计算中保持精确度。
要执行方面填充而不是方面拟合,请改用较大的比例。也就是说,将Matt的代码从Math.Min更改为Math.Max。
(纵横填充不会将边界框留空,但可能会将某些图像放在边界外,而纵横比不会超出边界的图像,但可能会使边界框的某些部分为空。)
试用了沃伦先生的代码,但没有产生可靠的结果。
例如,
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。
这是我的(基于先生的版本先生。沃伦的代码)没有差异和轻微的重构:
// 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));
}
下面的代码生成更加准确的结果:
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))
);
}
根据前面的答案,这里是一个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
};
}
非常简单。 :)问题是要找到一个因素,你需要乘以宽度和高度。解决方法是尝试使用一个,如果不适合,请使用另一个。所以......
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)
像请不要滥用裁判。最好制作一个带有宽度和高度字段的_immutable_结构Rectangle,然后编写一个方法ExpandToBound,该方法需要两个Rectangle并返回生成的Rectangle。当你将它们作为_functions_实现时,推理功能要容易得多。争论进入,结果出来;函数不会改变它们不拥有的状态。 – 2009-07-09 20:55:40
@Eric Lippert - 同意,这个例子不是我实际实现的函数,只是一个简化版本,以避免与Rectangle结构或其他不属于问题核心的问题混淆。 – 2009-12-22 15:02:26