【问题标题】:How to crop a UIImageView to a new UIImage in 'aspect fit' mode?如何在“方面适合”模式下将 UIImageView 裁剪为新的 UIImage?
【发布时间】:2012-06-07 06:02:45
【问题描述】:

我想通过在 UIImageView 中裁剪图像来创建一个新的 UIImage。例如在上面的图片中,我想要一个以绿色勾勒出的区域的新 UIImage。我找到了执行此操作的代码,通常它看起来像这样(作为 UIImage 类别):

- (UIImage *)croppedImage:(CGRect)bounds {
    CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
    UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    return croppedImage;
}

非常有道理。但是,我的 UIImageView 处于 contentMode 'aspect fit' 中。似乎这使 CGImageCreateWithImageInRect 的 CGRect 计算复杂化,我一直无法找出正确的解决方案。

我想我需要对绿色矩形应用与对图像所做的相同的转换吗?

另外:我在这里发现了另一个问题 (How to know the image size after applying aspect fit for the image in an UIImageView),这似乎显示了一种获取尺寸的蛮力方法,但我仍然不确定这如何适合种植情况。

有什么想法吗?

编辑:在我的例子中,我确实在 UIImageView 上的覆盖视图中绘制了一个如上所示的正方形。因此,当我意识到我正在裁剪 UIImage(在 UIImageView 内)时,我需要以某种方式更改绿色 CGRect,使其“匹配”应用“方面适合”时完成的转换。例如,如果我让 UIImageView 处于“左上”模式,那么一切正常,因为底层 UIImage 和 UIImageView 之间存在 1:1 映射。 “左上角”模式的问题是整个图像并不总是显示,因为它可能比我的 UIImageView 大。

【问题讨论】:

    标签: ios uiimageview uiimage


    【解决方案1】:

    基于我的other answer 到一个类似的问题,我为 UIImageView 类别编写了这个方法:

    -(CGRect) cropRectForFrame:(CGRect)frame
    {
        NSAssert(self.contentMode == UIViewContentModeScaleAspectFit, @"content mode must be aspect fit");
    
        CGFloat widthScale = self.bounds.size.width / self.image.size.width;
        CGFloat heightScale = self.bounds.size.height / self.image.size.height;
    
        float x, y, w, h, offset;
        if (widthScale<heightScale) {
            offset = (self.bounds.size.height - (self.image.size.height*widthScale))/2;
            x = frame.origin.x / widthScale;
            y = (frame.origin.y-offset) / widthScale;
            w = frame.size.width / widthScale;
            h = frame.size.height / widthScale;
        } else {
            offset = (self.bounds.size.width - (self.image.size.width*heightScale))/2;
            x = (frame.origin.x-offset) / heightScale;
            y = frame.origin.y / heightScale;
            w = frame.size.width / heightScale;
            h = frame.size.height / heightScale;
        }
        return CGRectMake(x, y, w, h);
    }
    

    您可以传入绿色矩形的框架(假设它是图像视图的子视图)并获取裁剪矩形以裁剪 UIImage。请注意,它仅适用于“方面适合”模式!不过我还没有测试过。所以,告诉我它是否有效!

    【讨论】:

    • 还没有机会实现这个,但我会尽快的。谢谢你,看起来很有道理。
    • 谢谢!那是完美的
    • 您将如何调整此算法以考虑 2x 和 3x 的图像?对于 1x 图像,这可以完美地工作,但对于 2x 和 3x 比例的图像不能准确裁剪。
    • @Felix 不错的答案!
    【解决方案2】:

    我知道答案是正确的,但我遇到了一些问题,所以我也不会发布我的解决方案。

    问题是图像以宽高比进行缩放,但我们知道宽度和高度的比例因子。然后我们可以很容易地计算出正确的裁剪矩形:

    -(UIImage*)crop:(CGRect)frame
    {
        // Find the scalefactors  UIImageView's widht and height / UIImage width and height
        CGFloat widthScale = self.bounds.size.width / self.image.size.width;
        CGFloat heightScale = self.bounds.size.height / self.image.size.height;
    
        // Calculate the right crop rectangle 
        frame.origin.x = frame.origin.x * (1 / widthScale);
        frame.origin.y = frame.origin.y * (1 / heightScale);
        frame.size.width = frame.size.width * (1 / widthScale);
        frame.size.height = frame.size.height * (1 / heightScale);
    
        // Create a new UIImage
        CGImageRef imageRef = CGImageCreateWithImageInRect(self.image.CGImage, frame);
        UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
        CGImageRelease(imageRef);
    
        return croppedImage;
    }
    

    【讨论】:

      【解决方案3】:

      我想你不明白你在做什么。您不能“裁剪” UIImageView - 只有 UIImages。因此,您的 croppedImage 方法应该属于 UIImage 类别而不是 UIImageView 类别。 您传递给裁剪方法的边界矩形必须与图像大小相关,而不是与图像视图边界相关。 图像视图的 contentMode 是什么无关紧要 - 图像的裁剪将始终相同。首先从图像视图中获取图像。然后从中创建一个新的裁剪图像,最后为图像视图设置裁剪图像。这可以在一行代码中完成:

      imageView.image = [imageView.image croppedImage:rect];
      

      由于您的 contentMode 是“宽高比适合”,新图像将自动拉伸以适合视图框架。您也可以尝试根据 image.size 更改视图框架以避免像素化效果。

      【讨论】:

      • 我试图改写这个问题。我确实了解 UIImageView 和 UIImage 之间的区别。看看我上面的编辑,现在有意义吗?
      • 我不确定我是否理解正确。是否要屏蔽图像视图以使其仅显示绿色矩形中的部分?那么就不需要裁剪了。还是您只想在正确的位置绘制绿色矩形?
      • 我想为绿色矩形内的部分创建一个全新的 uiimage。
      【解决方案4】:

      我使用下面的方法。

      -(UIImage *)getNeedImageFrom:(UIImage*)image cropRect:(CGRect)rect
      {
         CGSize cropSize = rect.size;
         CGFloat widthScale =  
         image.size.width/self.imageViewOriginal.bounds.size.width;
         CGFloat heightScale = 
         image.size.height/self.imageViewOriginal.bounds.size.height;
         cropSize = CGSizeMake(rect.size.width*widthScale,  
         rect.size.height*heightScale);
         CGPoint  pointCrop = CGPointMake(rect.origin.x*widthScale, 
         rect.origin.y*heightScale);
         rect = CGRectMake(pointCrop.x, pointCrop.y, cropSize.width, 
         cropSize.height);
         CGImageRef subImage = CGImageCreateWithImageInRect(image.CGImage, rect);
         UIImage *croppedImage = [UIImage imageWithCGImage:subImage];
         CGImageRelease(subImage);
         return croppedImage;
      
         }
      

      【讨论】:

      • 添加对该方法如何满足 OP 要求的说明。
      猜你喜欢
      • 2017-09-28
      • 2012-07-03
      • 2019-08-08
      • 2014-05-18
      • 2011-10-06
      • 2011-09-25
      相关资源
      最近更新 更多