通过保持纵横比和宽度来调整UIImage的大小


136

我在许多帖子中看到通过保持宽高比来调整图像大小。这些函数在调整大小时使用RECT的固定点(宽度和高度)。但是在我的项目中,我需要仅根据“宽度”调整视图的大小,应根据长宽比自动选择“高度”。任何人都可以帮助我实现这一目标。

Answers:


228

如果您同时知道新Size的高度宽度,则Srikar的方法效果很好。例如,如果您只知道要缩放的宽度,而不关心高度,则首先必须计算高度的缩放系数。

+(UIImage*)imageWithImage: (UIImage*) sourceImage scaledToWidth: (float) i_width
{
    float oldWidth = sourceImage.size.width;
    float scaleFactor = i_width / oldWidth;

    float newHeight = sourceImage.size.height * scaleFactor;
    float newWidth = oldWidth * scaleFactor;

    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
    [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
}

22
您实际上并不需要在newWidth这里的变量,它已经是i_width
马修·基罗斯

2
您还需要除以高度,并使用更接近0的比例来比较比例因子。上面的代码仅适用于宽于高的图像
IceForge 2014年

1
如果我也想知道自己的身高比例,然后按比例缩放宽度或高度,就只需要除以身高即可。但是由于TO明确要求保持比例和宽度,而不是宽度或高度,因此我的回答是完全正确的。
Maverick1st 2015年

12
好答案,谢谢。还有一两件事:如果你使用这种方法遇到图像质量的损失,然后使用UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0);而不是UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
skornos

57

如果您不知道图像是纵向还是横向(例如,用户使用相机拍摄照片),我创建了另一种采用最大宽度和高度参数的方法。

假设您有一个UIImage *myLargeImage4:3的比率。

UIImage *myResizedImage = [ImageUtilities imageWithImage:myLargeImage 
                                        scaledToMaxWidth:1024 
                                               maxHeight:1024];

如果使用横向,则调整后的UIImage尺寸将为1024x768。如果是纵向,则为768x1024。此方法还将为视网膜显示生成更高分辨率的图像。

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
    } else {
        UIGraphicsBeginImageContext(size);
    }
    [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();

    return newImage;
}

+ (UIImage *)imageWithImage:(UIImage *)image scaledToMaxWidth:(CGFloat)width maxHeight:(CGFloat)height {
    CGFloat oldWidth = image.size.width;
    CGFloat oldHeight = image.size.height;

    CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

    CGFloat newHeight = oldHeight * scaleFactor;
    CGFloat newWidth = oldWidth * scaleFactor;
    CGSize newSize = CGSizeMake(newWidth, newHeight);

    return [ImageUtilities imageWithImage:image scaledToSize:newSize];
}

1
这是最好的事情,但它总是返回我定义的大小的两倍
Mashhadi 2014年

2
如果您只想缩小尺寸而不是缩小尺寸,请不要忘记使用以下方法启动imageWithImage:scaledToMaxWidth:maxHeight:方法:if(image.size.width <width && image.size.height <height){返回图像;}
Arjan 2015年

5
为了适合最大宽度和最大高度,您需要最小比例作为比例因子:min(ratioX, ratioY)。否则,如果宽度较大,则可能不适合最大高度。
杰森·斯特吉斯

ImageUtilities在哪里?
tong

42

最佳答案Maverick 1st已正确翻译为Swift(使用最新的swift 3):

func imageWithImage (sourceImage:UIImage, scaledToWidth: CGFloat) -> UIImage {
    let oldWidth = sourceImage.size.width
    let scaleFactor = scaledToWidth / oldWidth

    let newHeight = sourceImage.size.height * scaleFactor
    let newWidth = oldWidth * scaleFactor

    UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
    sourceImage.draw(in: CGRect(x:0, y:0, width:newWidth, height:newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage!
}

38

感谢@ Maverick1st算法,我实现了它Swift,在我的情况下,高度是输入参数

class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {

    let scale = newHeight / image.size.height
    let newWidth = image.size.width * scale
    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
    image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}

18

此方法是UIImage上的类别。使用AVFoundation进行缩放以适合几行代码。不要忘记导入#import <AVFoundation/AVFoundation.h>

@implementation UIImage (Helper)

- (UIImage *)imageScaledToFitToSize:(CGSize)size
{
    CGRect scaledRect = AVMakeRectWithAspectRatioInsideRect(self.size, CGRectMake(0, 0, size.width, size.height));
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    [self drawInRect:scaledRect];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

@end

2
发现这一点以最小的内存占用为我提供最佳结果。+1
Tommie C.

11

斯威夫特5版方面配合-TO-的高度,通过@亚诺什基于答案

使用现代UIGraphicsImageRendererAPI,因此UIImage可以保证返回有效值。

extension UIImage
{
    /// Given a required height, returns a (rasterised) copy
    /// of the image, aspect-fitted to that height.

    func aspectFittedToHeight(_ newHeight: CGFloat) -> UIImage
    {
        let scale = newHeight / self.size.height
        let newWidth = self.size.width * scale
        let newSize = CGSize(width: newWidth, height: newHeight)
        let renderer = UIGraphicsImageRenderer(size: newSize)

        return renderer.image { _ in
            self.draw(in: CGRect(origin: .zero, size: newSize))
        }
    }
}

您可以将其与(基于矢量的)PDF图像资产结合使用,以保持任何渲染尺寸的质量。


7

最简单的方法是设置边框UIImageView并将其设置contentMode为调整大小选项之一。

代码像这样-可用作实用程序方法-

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
}

请记住,OP没有提到UIImageView。相反,他大概想直接对UIImage的副本进行宽高比拟合,这在您执行CoreGraphics工作时非常方便。
Womble

6

以编程方式:

imageView.contentMode = UIViewContentModeScaleAspectFit;

故事板:

在此处输入图片说明


它可以正常工作,但是可以减少内存占用,您可以使应用程序运行更快,例如加载很多缩略图。
ingconti

那是一个UIImageView,而不是UIImage。有时,您需要在没有UIImageView的情况下进行绘制。
Womble

5

好吧,我们在这里没有很好的答案来调整图像大小,但是我只是根据需要进行修改。希望这可以帮助像我这样的人。

我的要求是

  1. 如果图像宽度大于1920,则将其调整为1920宽度,并保持原始纵横比的高度。
  2. 如果图像高度大于1080,则将其调整为1080高度,并保持原始宽高比的宽度。

 if (originalImage.size.width > 1920)
 {
        CGSize newSize;
        newSize.width = 1920;
        newSize.height = (1920 * originalImage.size.height) / originalImage.size.width;
        originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];        
 }

 if (originalImage.size.height > 1080)
 {
            CGSize newSize;
            newSize.width = (1080 * originalImage.size.width) / originalImage.size.height;
            newSize.height = 1080;
            originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];

 }

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
        UIGraphicsBeginImageContext(newSize);
        [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return newImage;
}

感谢@ Srikar Appal,我使用他的方法来调整大小。

您可能还需要检查此内容以进行大小调整。


4

只需导入AVFoundation并使用 AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)


2

为了改善瑞安的答案:

   + (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
CGFloat oldWidth = image.size.width;
        CGFloat oldHeight = image.size.height;

//You may need to take some retina adjustments into consideration here
        CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

return [UIImage imageWithCGImage:image.CGImage scale:scaleFactor orientation:UIImageOrientationUp];
    }

2
extension UIImage {

    /// Returns a image that fills in newSize
    func resizedImage(newSize: CGSize) -> UIImage? {
        guard size != newSize else { return self }

    let hasAlpha = false
    let scale: CGFloat = 0.0
    UIGraphicsBeginImageContextWithOptions(newSize, !hasAlpha, scale)
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)

        draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }

    /// Returns a resized image that fits in rectSize, keeping it's aspect ratio
    /// Note that the new image size is not rectSize, but within it.
    func resizedImageWithinRect(rectSize: CGSize) -> UIImage? {
        let widthFactor = size.width / rectSize.width
        let heightFactor = size.height / rectSize.height

        var resizeFactor = widthFactor
        if size.height > size.width {
            resizeFactor = heightFactor
        }

        let newSize = CGSize(width: size.width / resizeFactor, height: size.height / resizeFactor)
        let resized = resizedImage(newSize: newSize)

        return resized
    }
}

当scale设置为0.0时,将使用主屏幕的比例因子,对于Retina显示屏,该比例因子为2.0或更高(iPhone 6 Plus为3.0)。


1

快速代码中的Ryan解决方案@Ryan

用:

 func imageWithSize(image: UIImage,size: CGSize)->UIImage{
    if UIScreen.mainScreen().respondsToSelector("scale"){
        UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.mainScreen().scale);
    }
    else
    {
         UIGraphicsBeginImageContext(size);
    }

    image.drawInRect(CGRectMake(0, 0, size.width, size.height));
    var newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

//Summon this function VVV
func resizeImageWithAspect(image: UIImage,scaledToMaxWidth width:CGFloat,maxHeight height :CGFloat)->UIImage
{
    let oldWidth = image.size.width;
    let oldHeight = image.size.height;

    let scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

    let newHeight = oldHeight * scaleFactor;
    let newWidth = oldWidth * scaleFactor;
    let newSize = CGSizeMake(newWidth, newHeight);

    return imageWithSize(image, size: newSize);
}

1

Swift 3中有一些更改。这是UIImage的扩展:

public extension UIImage {
    public func resize(height: CGFloat) -> UIImage? {
        let scale = height / self.size.height
        let width = self.size.width * scale
        UIGraphicsBeginImageContext(CGSize(width: width, height: height))
        self.draw(in: CGRect(x:0, y:0, width:width, height:height))
        let resultImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return resultImage
    }
}

1

Zeeshan Tufail和Womble在Swift 5中做了一些小的改进。在这里,我们扩展了2个功能,可以将图像缩放到maxLength任意尺寸并进行jpeg压缩。

extension UIImage {
    func aspectFittedToMaxLengthData(maxLength: CGFloat, compressionQuality: CGFloat) -> Data {
        let scale = maxLength / max(self.size.height, self.size.width)
        let format = UIGraphicsImageRendererFormat()
        format.scale = scale
        let renderer = UIGraphicsImageRenderer(size: self.size, format: format)
        return renderer.jpegData(withCompressionQuality: compressionQuality) { context in
            self.draw(in: CGRect(origin: .zero, size: self.size))
        }
    }
    func aspectFittedToMaxLengthImage(maxLength: CGFloat, compressionQuality: CGFloat) -> UIImage? {
        let newImageData = aspectFittedToMaxLengthData(maxLength: maxLength, compressionQuality: compressionQuality)
        return UIImage(data: newImageData)
    }
}

0

这对我来说是完美的。保持宽高比并采用maxLength。宽度或高度不得超过maxLength

-(UIImage*)imageWithImage: (UIImage*) sourceImage maxLength: (float) maxLength
{
    CGFloat scaleFactor = maxLength / MAX(sourceImage.size.width, sourceImage.size.height);

    float newHeight = sourceImage.size.height * scaleFactor;
    float newWidth = sourceImage.size.width * scaleFactor;

    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
    [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

0

为可用宽度计算图像的最佳高度。

import Foundation

public extension UIImage {
    public func height(forWidth width: CGFloat) -> CGFloat {
        let boundingRect = CGRect(
            x: 0,
            y: 0,
            width: width,
            height: CGFloat(MAXFLOAT)
        )
        let rect = AVMakeRect(
            aspectRatio: size,
            insideRect: boundingRect
        )
        return rect.size.height
    }
}

-1

我已经用一种更简单的方法解决了

UIImage *placeholder = [UIImage imageNamed:@"OriginalImage.png"];
self.yourImageview.image = [UIImage imageWithCGImage:[placeholder CGImage] scale:(placeholder.scale * 1.5)
                                  orientation:(placeholder.imageOrientation)];

比例乘数将定义图像的缩放比例,乘数越大图像越小。因此您可以检查适合您的屏幕。

或者,您也可以通过除以imagewidth / screenwidth来获得乘数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.