【问题标题】:Finding the biggest centered square from a landscape or a portrait UIImage and scale it to a size从横向或纵向 UIImage 中找到最大的中心正方形并将其缩放到一个大小
【发布时间】:2013-02-01 18:57:15
【问题描述】:

我需要从缩放到某个尺寸的纵向或横向图像中找到最大的居中正方形。 例如。如果我得到一个尺寸为 1200x800 的图像,我需要将居中的正方形缩小到 300x300。

【问题讨论】:

    标签: ios uiimage crop


    【解决方案1】:

    我在 stackoverflow 上找到了这个问题的答案,该答案已被广泛复制。但是这个答案是不正确的,所以想发布正确的答案如下:

    + (UIImage*) cropBiggestCenteredSquareImageFromImage:(UIImage*)image withSide:(CGFloat)side
    {
      // Get size of current image
      CGSize size = [image size];
      if( size.width == size.height && size.width == side){
        return image;
      }
    
      CGSize newSize = CGSizeMake(side, side);
      double ratio;
      double delta;
      CGPoint offset;
    
      //make a new square size, that is the resized imaged width
      CGSize sz = CGSizeMake(newSize.width, newSize.width);
    
      //figure out if the picture is landscape or portrait, then
      //calculate scale factor and offset
      if (image.size.width > image.size.height) {
        ratio = newSize.height / image.size.height;
        delta = ratio*(image.size.width - image.size.height);
        offset = CGPointMake(delta/2, 0);
      } else {
        ratio = newSize.width / image.size.width;
        delta = ratio*(image.size.height - image.size.width);
        offset = CGPointMake(0, delta/2);
      }
    
      //make the final clipping rect based on the calculated values
      CGRect clipRect = CGRectMake(-offset.x, -offset.y,
                                   (ratio * image.size.width),
                                   (ratio * image.size.height));
    
      //start a new context, with scale factor 0.0 so retina displays get
      //high quality image
      if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions(sz, YES, 0.0);
      } else {
        UIGraphicsBeginImageContext(sz);
      }
      UIRectClip(clipRect);
      [image drawInRect:clipRect];
      UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
    
      return newImage;
    }
    

    我之前发现的错误答案如下:

    + (UIImage*) cropBiggestCenteredSquareImageFromImage:(UIImage*)image withSide:(CGFloat)side
    {
      // Get size of current image
      CGSize size = [image size];
      if( size.width == size.height && size.width == side){
        return image;
      }
    
      CGSize newSize = CGSizeMake(side, side);
      double ratio;
      double delta;
      CGPoint offset;
    
      //make a new square size, that is the resized imaged width
      CGSize sz = CGSizeMake(newSize.width, newSize.width);
    
      //figure out if the picture is landscape or portrait, then
      //calculate scale factor and offset
      if (image.size.width > image.size.height) {
        ratio = newSize.width / image.size.width;
        delta = (ratio*image.size.width - ratio*image.size.height);
        offset = CGPointMake(delta/2, 0);
      } else {
        ratio = newSize.width / image.size.height;
        delta = (ratio*image.size.height - ratio*image.size.width);
        offset = CGPointMake(0, delta/2);
      }
    
      //make the final clipping rect based on the calculated values
      CGRect clipRect = CGRectMake(-offset.x, -offset.y,
                                   (ratio * image.size.width) + delta,
                                   (ratio * image.size.height) + delta);
    
    
      //start a new context, with scale factor 0.0 so retina displays get
      //high quality image
      if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions(sz, YES, 0.0);
      } else {
        UIGraphicsBeginImageContext(sz);
      }
      UIRectClip(clipRect);
      [image drawInRect:clipRect];
      UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
    
      return newImage;
    }
    

    这段代码的问题是它没有正确裁剪。

    这两种代码都可以在下图上试用: https://s3.amazonaws.com/anandprakash/ImageWithPixelGrid.jpg

    正确的算法在上述基本 url 上生成以下图像: https://s3.amazonaws.com/anandprakash/ScreenshotCorrectAlgo.png

    错误的算法在上面的基本 url 上生成了以下图像 - 请注意每边宽度上的额外 50px。 https://s3.amazonaws.com/anandprakash/ScreenshotWrongAlgo.png

    【讨论】:

      【解决方案2】:

      上面的答案与 UIImage 上的 Swift 扩展相同:

      private extension UIImage {
          func cropBiggestCenteredSquareImage(withSide side: CGFloat) -> UIImage {
              if self.size.height == side && self.size.width == side {
                  return self
              }
              let newSize = CGSizeMake(side, side)
              let ratio: CGFloat
              let delta: CGFloat
              let offset: CGPoint
              if self.size.width > self.size.height {
                  ratio = newSize.height / self.size.height
                  delta = ratio * (self.size.width - self.size.height)
                  offset = CGPointMake(delta / 2, 0)
              }
              else {
                  ratio = newSize.width / self.size.width
                  delta = ratio * (self.size.height - self.size.width)
                  offset = CGPointMake(0, delta / 2)
              }
              let clipRect = CGRectMake(-offset.x, -offset.y, ratio * self.size.width, ratio * self.size.height)
              if UIScreen.mainScreen().respondsToSelector(#selector(NSDecimalNumberBehaviors.scale)) {
                  UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0)
              } else {
                  UIGraphicsBeginImageContext(newSize);
              }
              UIRectClip(clipRect)
              self.drawInRect(clipRect)
              let newImage = UIGraphicsGetImageFromCurrentImageContext()
              UIGraphicsEndImageContext()
              return newImage
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-23
        • 1970-01-01
        • 1970-01-01
        • 2011-08-29
        相关资源
        最近更新 更多