2009-07-09 13 views
34

एक आसान समस्या है, लेकिन किसी कारण से मैं इसे आज नहीं समझ सकता।बाध्यकारी बॉक्स में फिट करने के लिए छवि का आकार बदलें

मुझे छवि को अधिकतम संभव आकार में आकार बदलने की आवश्यकता है जो पहलू अनुपात को बनाए रखते हुए बाध्यकारी बॉक्स में फिट होगा।

मूल रूप से मैं कोड इस समारोह में भरने के लिए देख रहा हूँ:

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

कहाँ डब्ल्यू & ज मूल ऊंचाई और चौड़ाई (में) और नई ऊंचाई और चौड़ाई (नाबाद) और MaxWidth और कर रहे हैं मैक्सहेइट बाउंडिंग बॉक्स को परिभाषित करता है जिसमें छवि फिट होनी चाहिए।

+7

उस तरह कृपया दुरुपयोग नहीं refs कहते हैं। एक _immutable_ संरचना आयत बनाने के लिए काफी बेहतर है जिसमें चौड़ाई और ऊंचाई फ़ील्ड है, और फिर एक विधि लिखें ExpandToBound जो दो आयताकार लेता है और परिणामी आयताकार देता है। जब आप उन्हें _functions_ के रूप में कार्यान्वित करते हैं तो कार्यों के बारे में कारण बनाना बहुत आसान है। तर्क आते हैं, परिणाम आते हैं; कार्य राज्य को म्यूट नहीं करते हैं कि उनके पास स्वामित्व नहीं है। –

+0

@ एरिक लिपर्ट - सहमत, उदाहरण वास्तव में कार्यान्वित नहीं किया गया था, उदाहरण के लिए एक उबला हुआ संस्करण, आयताकार structs या अन्य चीजों के साथ समस्या को भ्रमित करने से बचने के लिए जो समस्या के मूल का हिस्सा नहीं हैं। –

उत्तर

74

लगाएं कि कौन से छोटा होता है: MaxWidth/w या MaxHeight/h फिर उस संख्या से w और h गुणा

स्पष्टीकरण:

आप स्केलिंग कारक जो छवि फिट बनाता है खोजने की जरूरत है।

स्केलिंग कारक, s ढूंढने के लिए, चौड़ाई के लिए है, तो इस तरह के s होना चाहिए कि: s * w = MaxWidth। इसलिए, स्केलिंग कारक MaxWidth/w है।

इसी प्रकार ऊंचाई के लिए।

जिसकी सबसे अधिक स्केलिंग की आवश्यकता होती है (छोटा s) वह कारक है जिसके द्वारा आपको पूरी छवि को स्केल करना होगा।

+0

यदि आप फ्लोट के साथ ऐसा करते हैं तो शायद आपको लगता है कि बाउंडिंग बॉक्स से मेल खाने वाला आयाम थोड़ा सा है (कभी-कभी, अप्रत्याशित तरीके से)। जब आप पहचानते हैं कि कौन सा आयाम मेल नहीं खाता है, तो शायद यह मानना ​​सबसे अच्छा होगा कि दूसरे को यह बिल्कुल सही होना चाहिए? –

+4

+1 तीन साल बाद मेरे Google परिणामों के शीर्ष पर बैठे। कोई उपद्रव कोई अव्यवस्था नहीं। धन्यवाद! – chaosTechnician

+1

जैसे आपकी प्रतिक्रिया सी में लिखी नहीं है, इसलिए मैं इसे पायथन –

0

मुझे इसी तरह की समस्या होगी और मुझे यह बहुत उपयोगी लगता है: article। जैसा कि मैंने सही ढंग से समझा है, आपको छवि का आकार बदलना होगा?

2

पायथन कोड, लेकिन शायद यह सही दिशा में बात करेंगे:

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

आपका कोड काम करता है अगर छवि को कम किया जाना चाहिए, न कि कंटेनर फिट करने के लिए इसे विस्तारित किया जाना चाहिए। मुझे लगता है कि आप इस तरह से अपने सशर्त, अद्यतन करना चाहिए: 'अगर new_width> box_width या new_height box_height या new_width

26

एरिक के सुझाव मैं इस तरह कुछ करना चाहते हैं के आधार पर:

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

मैं थोड़ा गया होगा कास्ट पर overboard, लेकिन मैं सिर्फ गणना में परिशुद्धता को संरक्षित करने की कोशिश कर रहा था।

+0

को 'वापसी परिणाम मत भूलना;' –

6

एक पहलू फिट के बजाय एक पहलू भरने के लिए, इसके बजाय बड़े अनुपात का उपयोग करें। यही है, मठ से मैट का कोड बदलें। मेरा गणित। मैक्स।

(एक पहलू भरने वाले बाउंड बॉक्स में से कोई भी खाली नहीं है, लेकिन सीमा के बाहर की कुछ छवियों को फिट कर सकता है, जबकि एक पहलू सीमा के बाहर की किसी भी छवि को छोड़ देता है लेकिन कुछ बाउंडिंग बॉक्स खाली छोड़ सकता है।)

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 किसी अन्य रूप में।

यहां मेरा (आधारित श्रीमान संस्करण है।वॉरेन कोड) विसंगति और एक मामूली refactor बिना:

// 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

पिछले जवाब के आधार पर, यहाँ एक जावास्क्रिप्ट समारोह है Über सरल। :) मुद्दा एक कारक ढूंढना है जिसके द्वारा आपको चौड़ाई और ऊंचाई गुणा करने की आवश्यकता है। समाधान एक का उपयोग करने का प्रयास करना है और यदि यह फिट नहीं है, तो दूसरे का उपयोग करें। तो ...

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)) 
      ); 
    } 
संबंधित मुद्दे