【问题标题】:Create CGImage From CGBitmapContext and Add to UIImageView从 CGBitmapContext 创建 CGImage 并添加到 UIImageView
【发布时间】:2013-09-10 22:16:34
【问题描述】:

我正在尝试通过创建 CGBitMapContext 来创建 UICollectionViewCell 的快照。我并不完全清楚如何执行此操作或如何使用相关类,但经过一番研究,我编写了以下方法,该方法从我的 UICollectionViewCell 子类中调用:

- (void)snapShotOfCell
{
    float scaleFactor = [[UIScreen mainScreen] scale];
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, self.frame.size.width * scaleFactor, self.frame.size.height * scaleFactor, 8, self.frame.size.width * scaleFactor * 4, colorSpace, kCGImageAlphaPremultipliedFirst);

    CGImageRef image = CGBitmapContextCreateImage(context);
    UIImage *snapShot = [[UIImage alloc]initWithCGImage:image];

    UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.frame];
    imageView.image = snapShot;
    imageView.opaque = YES;
    [self addSubview:imageView];

     CGImageRelease(image);
     CGContextRelease(context);
     CGColorSpaceRelease(colorSpace);
}

结果是图像没有出现。调试后,我可以确定我有一个有效的(非零)上下文、CGImage、UIImage 和 UIImageView,但屏幕上什么也没有出现。谁能告诉我我错过了什么?

【问题讨论】:

    标签: objective-c core-graphics cgimageref cgbitmapcontextcreate cgbitmapcontext


    【解决方案1】:

    您可以将此作为类别添加到 UIView 中,任何视图都可以访问它

    - (UIImage*) snapshot
    {
        UIGraphicsBeginImageContextWithOptions(self.frame.size, YES /*opaque*/, 0 /*auto scale*/);
        [self.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image;
    }
    

    那么你只需要从你的单元格对象中执行[self addSubview:[[UIImageView alloc] initWithImage:self.snapshot]]

    [编辑]

    如果需要异步渲染(完全可以理解),这可以使用调度队列来实现。我认为这会起作用:

    typedef void(^ImageOutBlock)(UIImage* image);
    
    - (void) snapshotAsync:(ImageOutBlock)block
    {
        CGFloat scale = [[UIScreen mainScreen] scale];
        CALayer* layer = self.layer;
        CGRect frame = self.frame;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
            CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
            CGContextRef context = CGBitmapContextCreate(NULL, frame.size.width * scaleFactor, frame.size.height * scaleFactor, 8, frame.size.width * scaleFactor * 4, colorSpace, kCGImageAlphaPremultipliedFirst);
            UIGraphicsBeginImageContextWithOptions(frame.size, YES /*opaque*/, scale);
            [layer renderInContext:UIGraphicsGetCurrentContext()];
            UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            CGContextRelease(context);
            CGColorSpaceRelease(colorSpace);
            dispatch_async(dispatch_get_main_queue(), ^() {
                block(image);
            });
        });
    }
    

    [编辑]

    - (void) execute
    {
        __weak typeof(self) weakSelf = self;
        [self snapshotAsync:^(UIImage* image) { 
            [weakSelf addSubview:[[UIImageView alloc] initWithImage:image]] 
        }];
    }
    

    【讨论】:

    • 我的回复假定 ARC 已开启
    • 谢谢,我的代码可以正常工作,但问题是执行时间过长,并且在执行时导致集合视图的滚动无响应。有人建议我改为“在后台线程上将每个单元格重新绘制到您自己的位图上下文中”。所以我想弄清楚如何开始这样做。
    • 更新了我的答案。最终,无论你做什么,我都需要先渲染到上下文中,然后再从上下文中获取图像,这是关键。
    • 感谢更新的答案。我尝试了这段代码并这样称呼它: [self snapshotAsync:^(UIImage *image) { UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.frame]; imageView.image = 图像; imageView.opaque = 是; [自我添加子视图:图像视图]; }];它实际上可以工作,但是在运行程序几秒钟后会因 EXC_BAD_ACCESS 错误而崩溃
    • 好的,我想我知道发生了什么......因为我正在处理集合视图中的单元格,如果一个单元格在其快照被拍摄之前出列,但拍摄快照的请求是仍然在队列中然后它崩溃了。因此,我会将您的答案标记为正确,否则它会起作用。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    相关资源
    最近更新 更多