You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据CGRect从UIImageView中提取子UIImage?

从UIImageView中提取指定区域的原图子图(适配任意contentMode)

问题场景

给定一个UIImageView,以及该视图内部的一个CGRect,需要提取该区域对应的原图子图。当图片与UIImageView尺寸匹配时,用CGImageCreateWithImageInRect()就能实现,但二者尺寸不匹配、且contentMode为任意内置值时,常规方法无法得到正确结果,使用renderInContext:也会因为视图渲染特性(比如包含背景、边框等)导致结果不符合预期。

解决方案

核心思路是:先计算原图在UIImageView中的实际显示区域与变换关系,将视图坐标系下的目标CGRect转换为原图坐标系下的对应区域,再从原图中提取子图。

代码实现(UIImageView分类)

#import <UIKit/UIKit.h>

@interface UIImageView (ImageExtraction)
- (UIImage *)extractedOriginalImageFromViewRect:(CGRect)viewRect;
@end

@implementation UIImageView (ImageExtraction)

- (UIImage *)extractedOriginalImageFromViewRect:(CGRect)viewRect {
    if (!self.image) return nil;
    
    // 1. 获取原图尺寸和视图尺寸
    CGSize imageSize = self.image.size;
    CGSize viewSize = self.bounds.size;
    
    // 2. 计算原图在视图中的实际显示区域(适配所有contentMode)
    CGRect imageDisplayRect = AVMakeRectWithAspectRatioInsideRect(imageSize, self.bounds);
    
    // 3. 计算缩放比例:原图尺寸 / 显示区域尺寸
    CGFloat scaleX = imageSize.width / imageDisplayRect.size.width;
    CGFloat scaleY = imageSize.height / imageDisplayRect.size.height;
    
    // 4. 将视图坐标系的Rect转换为原图坐标系的Rect
    // 先把viewRect转换为相对于imageDisplayRect的坐标
    CGRect relativeRect = CGRectMake(
        viewRect.origin.x - imageDisplayRect.origin.x,
        viewRect.origin.y - imageDisplayRect.origin.y,
        viewRect.size.width,
        viewRect.size.height
    );
    // 再缩放得到原图中的Rect
    CGRect imageRect = CGRectMake(
        relativeRect.origin.x * scaleX,
        relativeRect.origin.y * scaleY,
        relativeRect.size.width * scaleX,
        relativeRect.size.height * scaleY
    );
    
    // 5. 修正CGImage坐标系(Y轴与UIKit相反)
    CGFloat correctedY = imageSize.height - imageRect.origin.y - imageRect.size.height;
    CGRect correctedImageRect = CGRectMake(imageRect.origin.x, correctedY, imageRect.size.width, imageRect.size.height);
    
    // 6. 提取子图
    CGImageRef subImageRef = CGImageCreateWithImageInRect(self.image.CGImage, correctedImageRect);
    UIImage *subImage = [UIImage imageWithCGImage:subImageRef scale:self.image.scale orientation:self.image.imageOrientation];
    CGImageRelease(subImageRef);
    
    return subImage;
}

@end

关键步骤说明

  • 计算显示区域:AVMakeRectWithAspectRatioInsideRect会根据contentMode自动计算原图在视图中的实际显示位置和尺寸,不管是ScaleAspectFit、ScaleAspectFill还是其他对齐模式,都能准确得到显示区域。
  • 坐标转换:先把视图中的目标Rect转换成相对于显示区域的相对坐标,再通过缩放比例映射到原图坐标系,确保提取的是原图对应位置的像素。
  • 坐标系修正:CGImage的Y轴原点在左下角,而UIKit的Y轴原点在左上角,所以需要反转Y轴坐标才能得到正确的区域。
  • 适配Retina屏:最终生成的UIImage保留了原图的scale和imageOrientation,保证子图的清晰度和方向正确。

使用示例

// 假设imageView是目标UIImageView,targetRect是视图内的目标区域
UIImage *extractedImage = [imageView extractedOriginalImageFromViewRect:targetRect];

内容的提问来源于stack exchange,提问作者DescendantOfLoto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 01:42:44