Search Unity

Code Snippet: Size RawImage to Parent, keep aspect ratio.

Discussion in 'UGUI & TextMesh Pro' started by shawnblais, Jan 24, 2016.

  1. shawnblais

    shawnblais

    Joined:
    Oct 11, 2012
    Posts:
    324
    Here's a handy little script I came up with, so you can tell any RawImage to fill it's parent's Rect, while maintaining the aspect ratio of the src texture. It also supports %-based padding, and images that have been rotated by 90 degree increments.
    Code (csharp):
    1.  
    2. static class CanvasExtensions {
    3.     public static Vector2 SizeToParent(this RawImage image, float padding = 0) {
    4.         var parent = image.transform.parent.GetComponent<RectTransform>();
    5.         var imageTransform = image.GetComponent<RectTransform>();
    6.         if (!parent) { return imageTransform.sizeDelta; } //if we don't have a parent, just return our current width;
    7.         padding = 1 - padding;
    8.         float w = 0, h = 0;
    9.         float ratio = image.texture.width / (float)image.texture.height;
    10.         var bounds = new Rect(0, 0, parent.rect.width, parent.rect.height);
    11.         if (Mathf.RoundToInt(imageTransform.eulerAngles.z) % 180 == 90) {
    12.               //Invert the bounds if the image is rotated
    13.               bounds.size = new Vector2(bounds.height, bounds.width);
    14.         }
    15.         //Size by height first
    16.         h = bounds.height * padding;
    17.         w = h * ratio;
    18.         if (w > bounds.width * padding) { //If it doesn't fit, fallback to width;
    19.             w = bounds.width * padding;
    20.             h = w / ratio;
    21.         }
    22.         imageTransform.sizeDelta = new Vector2(w, h);
    23.         return imageTransform.sizeDelta;
    24.     }
    25. }
    26.  
    Usage:
    Code (csharp):
    1. rawImage.SizeToParent();
    This is mostly useful for when you're loading a bunch of external images into a container, w/ random aspect ratios, and want them to fill the available space, without losing aspect ratio. The Image control is has a similar API, but requires you create a new Sprite() everytime you swap textures, which is a major performance drain.
     
    Last edited: Jun 20, 2019
    Tsigaro, tokar_dev, ROBYER1 and 13 others like this.
  2. Freezy

    Freezy

    Joined:
    Jul 15, 2012
    Posts:
    234
    Thank you for sharing, this saved me some time ;-)
    I did make some adjustments, enjoy !


    Code (CSharp):
    1.    
    2. public static Vector2 SizeToParent(this RawImage image, float padding = 0) {
    3.         float w = 0, h = 0;
    4.         var parent = image.GetComponentInParent<RectTransform>();
    5.         var imageTransform = image.GetComponent<RectTransform>();
    6.  
    7.         // check if there is something to do
    8.         if (image.texture != null) {
    9.             if (!parent) { return imageTransform.sizeDelta; } //if we don't have a parent, just return our current width;
    10.             padding = 1 - padding;
    11.             float ratio = image.texture.width / (float)image.texture.height;
    12.             var bounds = new Rect(0, 0, parent.rect.width, parent.rect.height);
    13.             if (Mathf.RoundToInt(imageTransform.eulerAngles.z) % 180 == 90) {
    14.                 //Invert the bounds if the image is rotated
    15.                 bounds.size = new Vector2(bounds.height, bounds.width);
    16.             }
    17.             //Size by height first
    18.             h = bounds.height * padding;
    19.             w = h * ratio;
    20.             if (w > bounds.width * padding) { //If it doesn't fit, fallback to width;
    21.                 w = bounds.width * padding;
    22.                 h = w / ratio;
    23.             }
    24.         }
    25.         imageTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, w);
    26.         imageTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, h);
    27.         return imageTransform.sizeDelta;
    28.     }
    29.  
     
    tokar_dev, MilenaRocha, Oli_C and 5 others like this.
  3. elpuerco63

    elpuerco63

    Joined:
    Jun 26, 2014
    Posts:
    271
    Have tried this in various ways but I keep getting null reference on line: 4?
     
    tokar_dev likes this.
  4. Freezy

    Freezy

    Joined:
    Jul 15, 2012
    Posts:
    234
    var parent = image.transform.parent.GetComponentInParent<RectTransform>();

    Is the raw Image parented to an object with a recttransform?
     
    elpuerco63 likes this.
  5. elpuerco63

    elpuerco63

    Joined:
    Jun 26, 2014
    Posts:
    271
    DOH!!!! had script attached to wrong GO....!
     
    Freezy likes this.
  6. NorthStar79

    NorthStar79

    Joined:
    May 8, 2015
    Posts:
    88
    works like a charm, Thanks!
     
  7. lumoconnor

    lumoconnor

    Joined:
    Jan 17, 2016
    Posts:
    27
    Hey, thanks for this code. Its very useful, however, I think I found a bug.

    GetComponentInParent() returns a component on this game object or its parents. So, in my case it was returning the RectTransform of the image itself instead of the parent rect. Super annoying. Here's the documentation:
    https://docs.unity3d.com/ScriptReference/GameObject.GetComponentInParent.html

    A fix - change line 3 to...
    Code (CSharp):
    1. var parent = image.transform.parent.GetComponent<RectTransform>();
     
  8. BreynartStudios

    BreynartStudios

    Joined:
    Feb 3, 2018
    Posts:
    7
    I really appreciate it!!! Works flawlessly :)
     
  9. shawnblais

    shawnblais

    Joined:
    Oct 11, 2012
    Posts:
    324
    Fixed. Better late than never :)
     
  10. schreibtischkrieger2019

    schreibtischkrieger2019

    Joined:
    Jul 12, 2019
    Posts:
    13
    make sure ur RawImage RectTransform is not Stretched in the Editor.
     
  11. ROBYER1

    ROBYER1

    Joined:
    Oct 9, 2015
    Posts:
    1,454
    This was so helpful thankyou!
     
  12. cyoz89

    cyoz89

    Joined:
    Feb 3, 2015
    Posts:
    1
    I attached the component "Aspect Ratio Fitter" to the "Raw Image", and set "Width Controls Height" or "Height controls Width" according to the aspect ratio you want (depending if the raw image is expected to stretch horizontally or vertically). Worked for me, its definitely easier, though I dont know if more efficient. Just in case it might help someone, or to maybe look into it.
     
  13. shacharoz

    shacharoz

    Joined:
    Jul 11, 2013
    Posts:
    98
    didn't work for video.
    but maybe for images it should work