如何在UIImageView中使用Aspect Fit后获取图像的大小

74

我正在以“Aspect Fit”模式将图像加载到图像视图中。 我需要知道我的图像被缩放到的大小。 请帮忙。

20个回答

147

23
这正是所需之物——[imageView setFrame:AVMakeRectWithAspectRatioInsideRect(image.size, imageView.frame)] - greg
1
良好且干净的选择。这里是文档链接http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVFoundation_Functions/Reference/reference.html - Popara
不想使用AVFoundation框架?我会在另一个回答中发布两个替代AVMakeRectWithAspectRatioInsideRect()的实用函数。 - Timo
1
这应该是被接受的答案。上面被接受的答案不正确,也不能在不同情况下工作。 - jjpp
太棒了。优秀的。 - Akshit Zaveri
1
对于Swift开发者:导入AVFoundation库,然后使用AVMakeRectWithAspectRatioInsideRect((image?.size)!, imageView.frame).height获取图像的高度。 - Ben Sullivan

56

我想在不包含AVFoundation框架的情况下使用AVMakeRectWithAspectRatioInsideRect()

因此,我实现了以下两个工具函数:

CGSize CGSizeAspectFit(CGSize aspectRatio, CGSize boundingSize)
{
    float mW = boundingSize.width / aspectRatio.width;
    float mH = boundingSize.height / aspectRatio.height;
    if( mH < mW )
        boundingSize.width = boundingSize.height / aspectRatio.height * aspectRatio.width;
    else if( mW < mH )
        boundingSize.height = boundingSize.width / aspectRatio.width * aspectRatio.height;
    return boundingSize;
}

CGSize CGSizeAspectFill(CGSize aspectRatio, CGSize minimumSize)
{
    float mW = minimumSize.width / aspectRatio.width;
    float mH = minimumSize.height / aspectRatio.height;
    if( mH > mW )
        minimumSize.width = minimumSize.height / aspectRatio.height * aspectRatio.width;
    else if( mW > mH )
        minimumSize.height = minimumSize.width / aspectRatio.width * aspectRatio.height;
    return minimumSize;
}

编辑:通过删除重复的除法进行了优化。

CGSize CGSizeAspectFit(const CGSize aspectRatio, const CGSize boundingSize)
{
    CGSize aspectFitSize = CGSizeMake(boundingSize.width, boundingSize.height);
    float mW = boundingSize.width / aspectRatio.width;
    float mH = boundingSize.height / aspectRatio.height;
    if( mH < mW )
        aspectFitSize.width = mH * aspectRatio.width;
    else if( mW < mH )
        aspectFitSize.height = mW * aspectRatio.height;
    return aspectFitSize;
}

CGSize CGSizeAspectFill(const CGSize aspectRatio, const CGSize minimumSize)
{
    CGSize aspectFillSize = CGSizeMake(minimumSize.width, minimumSize.height);
    float mW = minimumSize.width / aspectRatio.width;
    float mH = minimumSize.height / aspectRatio.height;
    if( mH > mW )
        aspectFillSize.width = mH * aspectRatio.width;
    else if( mW > mH )
        aspectFillSize.height = mW * aspectRatio.height;
    return aspectFillSize;
}

编辑结束

这个函数接受一个给定的大小(第一个参数),并保持其宽高比。然后尽可能填充给定的边界(第二个参数),而不违反宽高比。

使用此函数来回答原始问题:

// Using aspect fit, scale the image (size) to the image view's size.
CGSize sizeBeingScaledTo = CGSizeAspectFit(theImage.size, theImageView.frame.size);
请注意图像决定了宽高比,而图像视图则决定要填充的大小。非常欢迎反馈。

2
如果你喜欢这种类型的东西,可以将其调整为使用“CGFloats”。 - Timo
2
非常好的答案。您还可以将其调整为以某个视图为中心,以获取UIImageView中AspectFit图像的实际CGRect。我做了这样的事情: <code> CGSize imageSize = CGSizeAspectFit(imageView.image.size,imageView.frame.size); CGRect actualImageRect = CGRectMake(0,0,imageSize.width,imageSize.height); actualImageRect.origin.x = imageView.center.x - imageSize.width / 2; actualImageRect.origin.y = imageView.center.y - imageSize.height / 2; </code> - LilDwarf
谢谢,这是一个很棒的实用函数。 - EralpB
我已经包含了一个优化版本,它去除了重复的除法。现在,一个无分支等效版本可能是一个有趣的挑战。 :) - Timo

31

请查看@Paul-de-Lange的答案,而不是这个


我在容易访问的变量中找不到任何内容,因此这里是一种蛮力方法:

- (CGSize) aspectScaledImageSizeForImageView:(UIImageView *)iv image:(UIImage *)im {

float x,y;
float a,b;
x = iv.frame.size.width;
y = iv.frame.size.height;
a = im.size.width;
b = im.size.height;

if ( x == a && y == b ) {           // image fits exactly, no scaling required
    // return iv.frame.size;
}
else if ( x > a && y > b ) {         // image fits completely within the imageview frame
    if ( x-a > y-b ) {              // image height is limiting factor, scale by height
        a = y/b * a;
        b = y;
    } else {
        b = x/a * b;                // image width is limiting factor, scale by width
        a = x;
    }
} 
else if ( x < a && y < b ) {        // image is wider and taller than image view
    if ( a - x > b - y ) {          // height is limiting factor, scale by height
        a = y/b * a;
        b = y;
    } else {                        // width is limiting factor, scale by width
        b = x/a * b;
        a = x;
    }
}
else if ( x < a && y > b ) {        // image is wider than view, scale by width
    b = x/a * b;
    a = x;
}
else if ( x > a && y < b ) {        // image is taller than view, scale by height
    a = y/b * a;
    b = y;
}
else if ( x == a ) {
    a = y/b * a;
    b = y;
} else if ( y == b ) {
    b = x/a * b;
    a = x;
}
return CGSizeMake(a,b);

}

这段代码不准确。它不能处理所有情况。例如,如果您有一张2048 x 1536的图像,并尝试将其适配到514 x 402中,它会返回缩放后的高度402,而实际上应该按照宽度进行缩放。我将 if ( a - x > b - y ) { 改为 if ( a - x > b - y && (y/b * a) < x) { 来修复它。其他语句也应该被检查。 - renaun
您好,先生。我发现这个答案很有帮助,但是您能否帮助我解决我的问题:https://dev59.com/mH7aa4cB1Zd3GeqPmSX8 - Mrug

18

这个简单的函数将计算纵横比适应后的图像尺寸:

Swift 5.1

extension UIImageView {

    var imageSizeAfterAspectFit: CGSize {
        var newWidth: CGFloat
        var newHeight: CGFloat

        guard let image = image else { return frame.size }

        if image.size.height >= image.size.width {
            newHeight = frame.size.height
            newWidth = ((image.size.width / (image.size.height)) * newHeight)

            if CGFloat(newWidth) > (frame.size.width) {
                let diff = (frame.size.width) - newWidth
                newHeight = newHeight + CGFloat(diff) / newHeight * newHeight
                newWidth = frame.size.width
            }
        } else {
            newWidth = frame.size.width
            newHeight = (image.size.height / image.size.width) * newWidth

            if newHeight > frame.size.height {
                let diff = Float((frame.size.height) - newHeight)
                newWidth = newWidth + CGFloat(diff) / newWidth * newWidth
                newHeight = frame.size.height
            }
        }
        return .init(width: newWidth, height: newHeight)
    }
}

Objective C:

 -(CGSize)imageSizeAfterAspectFit:(UIImageView*)imgview{


    float newwidth;
    float newheight;

    UIImage *image=imgview.image;

    if (image.size.height>=image.size.width){
        newheight=imgview.frame.size.height;
        newwidth=(image.size.width/image.size.height)*newheight;

        if(newwidth>imgview.frame.size.width){
            float diff=imgview.frame.size.width-newwidth;
            newheight=newheight+diff/newheight*newheight;
            newwidth=imgview.frame.size.width;
        }

    }
    else{
        newwidth=imgview.frame.size.width;
        newheight=(image.size.height/image.size.width)*newwidth;

        if(newheight>imgview.frame.size.height){
            float diff=imgview.frame.size.height-newheight;
            newwidth=newwidth+diff/newwidth*newwidth;
            newheight=imgview.frame.size.height;
        }
    }

    NSLog(@"image after aspect fit: width=%f height=%f",newwidth,newheight);


    //adapt UIImageView size to image size
    //imgview.frame=CGRectMake(imgview.frame.origin.x+(imgview.frame.size.width-newwidth)/2,imgview.frame.origin.y+(imgview.frame.size.height-newheight)/2,newwidth,newheight);

    return CGSizeMake(newwidth, newheight);

}

接受的答案对我没有用,但是这个答案有效。而且这个答案真正的优美之处在于它不需要传递任何UIImage的显式引用,而是从UIImageView的图像内容中获取它。它也可以在方向更改时工作。谢谢。 - Ayan Sengupta
由于这通常是在UIImageView上完成的,因此将其塑造成UIImageView类别方法可能是值得的。 - Timo
它没有返回精确的框架。 - Aiyub Munshi

12

Swift 3人类可读版本

extension UIImageView {

    /// Find the size of the image, once the parent imageView has been given a contentMode of .scaleAspectFit
    /// Querying the image.size returns the non-scaled size. This helper property is needed for accurate results.
    var aspectFitSize: CGSize {
        guard let image = image else { return CGSize.zero }

        var aspectFitSize = CGSize(width: frame.size.width, height: frame.size.height)
        let newWidth: CGFloat = frame.size.width / image.size.width
        let newHeight: CGFloat = frame.size.height / image.size.height

        if newHeight < newWidth {
            aspectFitSize.width = newHeight * image.size.width
        } else if newWidth < newHeight {
            aspectFitSize.height = newWidth * image.size.height
        }

        return aspectFitSize
    }

    /// Find the size of the image, once the parent imageView has been given a contentMode of .scaleAspectFill
    /// Querying the image.size returns the non-scaled, vastly too large size. This helper property is needed for accurate results.
    var aspectFillSize: CGSize {
        guard let image = image else { return CGSize.zero }

        var aspectFillSize = CGSize(width: frame.size.width, height: frame.size.height)
        let newWidth: CGFloat = frame.size.width / image.size.width
        let newHeight: CGFloat = frame.size.height / image.size.height

        if newHeight > newWidth {
            aspectFillSize.width = newHeight * image.size.width
        } else if newWidth > newHeight {
            aspectFillSize.height = newWidth * image.size.height
        }

        return aspectFillSize
    }

}

改为使用图像原点位置,而不是大小如何? - karthikeyan

11

我也想在应用宽高比之后计算高度,以便能够计算表视图单元格的高度。所以,我通过一点数学方法实现了这一点。

ratio = width / height

并且高度会变成

height = width / ratio

因此代码片段应为

UIImage *img = [UIImage imageNamed:@"anImage"];
float aspectRatio = img.size.width/img.size.height;
float requiredHeight = self.view.bounds.size.width / aspectRatio;

优雅。我在UITableViewCell类中使用它,所以requiredHeight变成了float requiredHeight = self.bounds.size.width / aspectRatio; - oyalhi
你太聪明了!这应该是被采纳的答案! - Marian Petrisor

9

如果使用Swift,请使用下面的代码

func imageSizeAspectFit(imgview: UIImageView) -> CGSize {
        var newwidth: CGFloat
        var newheight: CGFloat
        let image: UIImage = imgFeed.image!

        if image.size.height >= image.size.width {
            newheight = imgview.frame.size.height;
            newwidth = (image.size.width / image.size.height) * newheight
            if newwidth > imgview.frame.size.width {
                let diff: CGFloat = imgview.frame.size.width - newwidth
                newheight = newheight + diff / newheight * newheight
                newwidth = imgview.frame.size.width
            }
        }
        else {
            newwidth = imgview.frame.size.width
            newheight = (image.size.height / image.size.width) * newwidth
            if newheight > imgview.frame.size.height {
                let diff: CGFloat = imgview.frame.size.height - newheight
                newwidth = newwidth + diff / newwidth * newwidth
                newheight = imgview.frame.size.height
            }
        }

       print(newwidth, newheight)
        //adapt UIImageView size to image size
        return CGSizeMake(newwidth, newheight)
    }

调用函数

imgFeed.sd_setImageWithURL(NSURL(string:"Your image URL")))
self.imageSizeAfterAspectFit(imgFeed)

7
也许不适用于您的情况,但是这种简单方法解决了我在类似情况下遇到的问题:
    UIImageView *imageView = [[UIImageView alloc] initWithImage:bigSizeImage];
    [imageView sizeToFit];

在image view执行sizeToFit之后,如果您查询imageView.frame.size,您将获得适合新图像尺寸的新图像视图大小。


5

Swift 4: .aspectFit 图像框架为 -

import AVFoundation

let x: CGRect = AVMakeRect(aspectRatio: myImage.size, insideRect: sampleImageView.frame)

let x: CGRect = AVMakeRect(aspectRatio: myImage.size, insideRect: sampleImageView.frame)

这行代码用于根据给定的图像大小和图像视图框架,计算出一个适应于图像比例的CGRect类型的矩形变量x。


是的,我完成了,但是我的y上没有任何空间,但它返回的值是40。 - Kishore Kumar
这很意外,你尝试过使用一个没有约束条件的单个imageView的新视图控制器吗? - Jack
我在UIview xib上尝试了一下,在那里有一个ImageView,原点x值变成了y,原点y值变成了x。而且我正在使用约束。 - Kishore Kumar
就像你所说的,这是由于@Jack的限制问题。 - Kishore Kumar

4
+(UIImage *)CreateAResizeImage:(UIImage *)Img ThumbSize:(CGSize)ThumbSize 
{
    float actualHeight = Img.size.height;
    float actualWidth = Img.size.width;

    if(actualWidth==actualHeight) 
    {
        actualWidth = ThumbSize.width; 
        actualHeight = ThumbSize.height;
    }

    float imgRatio = actualWidth/actualHeight;
    float maxRatio = ThumbSize.width/ThumbSize.height; //320.0/480.0;


    if(imgRatio!=maxRatio)
    {
        if(imgRatio < maxRatio)
        {
            imgRatio = ThumbSize.height / actualHeight; //480.0 / actualHeight;
            actualWidth = imgRatio * actualWidth;
            actualHeight = ThumbSize.height; //480.0;
        }
        else
        {
            imgRatio = ThumbSize.width / actualWidth; //320.0 / actualWidth;
            actualHeight = imgRatio * actualHeight;
            actualWidth = ThumbSize.width; //320.0;
        }
    } 
    else 
    {
        actualWidth = ThumbSize.width;
        actualHeight = ThumbSize.height; 
    }


    CGRect rect = CGRectMake(0, 0, (int)actualWidth, (int)actualHeight);
    UIGraphicsBeginImageContext(rect.size);
    [Img drawInRect:rect];
    UIImage *NewImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return NewImg;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接