【问题标题】:Resize UIImage by keeping Aspect ratio and width通过保持纵横比和宽度调整 UIImage 的大小
【发布时间】:2011-11-30 12:30:23
【问题描述】:

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

【问题讨论】:

    标签: iphone objective-c ios aspect-ratio fixed-width


    【解决方案1】:

    最简单的方法是设置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。相反,他可能想直接调整 [a] UIImage 的 [copy of a] UIImage 的纵横比,这在您进行 CoreGraphics 工作时非常方便。
    【解决方案2】:

    如果您知道新尺寸的高度宽度,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;
    }
    

    【讨论】:

    • 这里其实不需要newWidth 变量,它已经是i_width
    • 您还需要除以高度,并使用更接近 0 的值比较缩放因子。上面的代码仅适用于宽度大于高度的图像
    • 如果我还想知道我的高度比率并通过缩放宽度或高度来适应,我只需要除以高度。但由于 TO 明确要求保持比例和宽度,而不是宽度或高度,我的回答是完全正确的。
    • 很好的答案,谢谢。还有一件事:如果您使用此方法遇到任何图像质量损失,请使用UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0); 而不是UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
    【解决方案3】:

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

    假设您有一个UIImage *myLargeImage,比例为 4: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];
    }
    

    【讨论】:

    • 这是最好的,但它总是返回我定义大小的两倍
    • 如果你只想缩小而不是放大,不要忘记启动 imageWithImage:scaledToMaxWidth:maxHeight: 方法: if (image.size.width
    • 要适应最大宽度和最大高度,您需要最小比率作为比例因子:min(ratioX, ratioY)。否则,如果宽度较大,它可能不适合最大高度。
    • ImageUtilities 在哪里?
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      改进 Ryan 的回答:

         + (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];
          }
      

      【讨论】:

        【解决方案6】:

        感谢@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
        }
        

        【讨论】:

          【解决方案7】:

          此方法是 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
          

          【讨论】:

          • 发现这可以为我提供最好的结果,同时占用最少的内存。 +1
          【解决方案8】:

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

          【讨论】:

            【解决方案9】:

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

            我的要求是

            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 ,我使用了他的方法来调整大小。

            您也可以查看this 以进行调整大小计算。

            【讨论】:

              【解决方案10】:

              我用更简单的方法解决了它

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

              缩放倍数将定义图像的缩放,倍数越大图像越小。这样您就可以检查适合您的屏幕的内容。

              或者您也可以通过除以图像宽度/屏幕宽度来获得乘数。

              【讨论】:

                【解决方案11】:

                最佳答案 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!
                }
                

                【讨论】:

                  【解决方案12】:

                  以编程方式:

                  imageView.contentMode = UIViewContentModeScaleAspectFit;
                  

                  故事板:

                  【讨论】:

                  • 它有效,但减少了内存占用,您可以使应用程序运行得更快,例如加载大量缩略图。
                  • 那是 UIImageView,不是 UIImage。有时,您需要在没有 UIImageView 的情况下进行绘图。
                  【解决方案13】:

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

                  【讨论】:

                    【解决方案14】:

                    这个对我来说是完美的。保持纵横比并采用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;
                    }
                    

                    【讨论】:

                      【解决方案15】:

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

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

                      【讨论】:

                      • 如果有人要回答这个问题,则需要“import AVFoundation”才能使其适用于 Swift 5,
                      【解决方案16】:
                      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)
                              
                              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
                          }
                      }
                      

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

                      【讨论】:

                        【解决方案17】:

                        Swift 5 版本的 aspect-fit-to-height,基于 @János 的回答

                        使用现代的UIGraphicsImageRenderer API,因此保证返回有效的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 图像资源结合使用,以在任何渲染尺寸下保持质量。

                        【讨论】:

                          【解决方案18】:

                          Swift 5 中的 Zeeshan Tufail 和 Womble 答案略有改进。 在这里,我们有 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)
                              }
                          }
                          

                          【讨论】:

                            【解决方案19】:

                            如果有人在 Swift 5 中需要这个解决方案:

                            private func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
                                
                                let scale = newHeight / image.size.height
                                let newWidth = image.size.width * scale
                                UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
                                image.draw(in:CGRect(x:0, y:0, width:newWidth, height:newHeight))
                                let newImage = UIGraphicsGetImageFromCurrentImageContext()
                                UIGraphicsEndImageContext()
                            
                                return newImage
                            }
                            

                            【讨论】:

                              猜你喜欢
                              • 2013-07-29
                              • 1970-01-01
                              • 2015-05-22
                              • 2010-12-14
                              • 1970-01-01
                              • 1970-01-01
                              • 2020-06-14
                              • 2013-06-26
                              相关资源
                              最近更新 更多