2009-07-09 23 views
34

簡単な問題ですが、何らかの理由で今日これを理解できません。イメージをバウンディングボックスに合わせてサイズを変更する

画像を、アスペクト比を維持しながら境界ボックスに収まる最大限のサイズにリサイズする必要があります。

Basicly私はこの機能を記入するためのコードを探しています:&時間wが元の高さと幅(中)、新たな高さと幅(アウト)とMaxWidthのとある

void CalcNewDimensions(ref int w, ref int h, int MaxWidth, int MaxHeight); 

MaxHeightは、イメージが収まる必要がある境界ボックスを定義します。

+7

乱用しないでください、引用文献のように呼び出します。 widthとheightフィールドを持つ_immutable_ structのRectangleを作成し、2つのRectangleを取り、結果のRectangleを返すExpandToBoundメソッドを作成する方が良いでしょう。関数を_functions_として実装すると、関数の理由を考えるのがはるかに簡単です。引数が入り、結果が出ます。関数は所有していない状態を変更しません。 –

+0

@ Eric Lippert - 合意しました。この例は、私が実際に実装した関数ではなく、問題の中核ではないRectangle構造体やその他のものとの混乱を避けるために煮詰めたバージョンです。 –

答えて

74

検索:MaxWidth/wまたはMaxHeight/h そして、その数

説明でwhを掛け:

あなたは画像のフィットを作るスケーリング係数を見つける必要があります。

スケーリング係数sを幅として見つけるには、sは、 s * w = MaxWidthのようにする必要があります。 したがって、倍率はMaxWidth/wです。

同様に高さ。

最もスケーリングが必要なもの(小さいs)は、画像全体を拡大縮小する必要がある要因です。

+0

フロートでこれを行うと、バウンディングボックスと一致するディメンションがわずかにオフになることがあります(時には予測不可能な方法で)。どのディメンションが一致しないのかを特定したら、他のディメンションとまったく同じものであると仮定するのが最善でしょうか? –

+4

+1 3年後にGoogleの検索結果の上部に座っています。マッスルではない。ありがとう! – chaosTechnician

+1

あなたの応答がcで書かれていないように、私はそれをPythonに適用することができます –

0

私は同様の問題を抱えており、非常に役に立ちました:article私が正しく理解したように、イメージのサイズを変更する必要がありますか?小さい

2

Pythonのコードが、多分それは正しい方向にあなたをポイントします:私は少しを行っている可能性がある

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; 
} 

:エリックの提案に基づいて

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) 
+0

画像を縮小する必要がある場合はコードを使用し、コンテナに合わせて拡大する必要がある場合は使用しないでください。 ' –

26

を私はこのような何かをしたいですキャストの上に乗っていましたが、計算の精度を維持しようとしていました。

+0

が戻り結果 'することを忘れないでください: '場合new_width> box_widthまたはnew_height box_heightまたはnew_width

6

アスペクトフィールの代わりにアスペクトフィルを実行するには、より大きな比率を使用します。つまり、MattのコードをMath.MinからMath.Maxに変更します。

(アスペクトの塗りつぶしによって、境界ボックスのどれも空になることはありませんが、画像の一部が境界線の外に出る可能性がありますが、アスペクトフィッティングは境界線の外に画像を残さずに境界線を空にします)

6

ウォーレン氏のコードを試しましたが、信頼できる結果が得られませんでした。例えば

、あなたが見ることができる

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。

ここは私のものです(Mr.

// 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)); 
} 
+0

あなた;' – Thomas

4

次のコードを生成し、より正確な結果:不一致とわずかなリファクタリングなしウォーレンのコード)

/** 
* 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 
    }; 
} 
0

は、ここではJavascriptの機能ですシンプル。 :)問題は、幅と高さを掛ける必要がある要因を見つけることです。解決策は、1つを使用して試してみて、適合しない場合は、もう一方を使用してください。だから... ...

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) 
1

:以前の回答に基づいて

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)) 
      ); 
    } 
関連する問題