一個簡單的問題,但由於某種原因,我今天無法弄清楚這一點。調整圖像以適合邊框
我需要將圖像調整到最大可能大小,將適合在邊界框,同時保持高寬比。
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