4

我相信 NDA 已经关闭,所以我可以问这个问题。我有一个 UIView 子类:

BlurView *blurredView = ((BlurView *)[self.view snapshotViewAfterScreenUpdates:NO]);
blurredView.frame = self.view.frame;
[self.view addSubview:blurredView];

到目前为止,它在捕获屏幕方面完成了它的工作,但现在我想模糊那个视图。我该怎么做呢?从我读过的内容来看,我需要捕获视图的当前内容(上下文?!)并将其转换为 CIImage(不是?),然后对其应用 CIGaussianBlur 并将其绘制回视图。

我该怎么做?

PS 视图不是动画的,所以性能应该没问题。

编辑:这是我到目前为止所拥有的。问题是我无法将快照捕获到 UIImage,我得到一个黑屏。但是如果我直接将视图添加为子视图,我可以看到快照在那里。

// Snapshot
UIView *view = [self.view snapshotViewAfterScreenUpdates:NO];

// Convert to UIImage
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// Apply the UIImage to a UIImageView
BlurView *blurredView = [[BlurView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
[self.view addSubview:blurredView];
blurredView.imageView.image = img;

// Black screen -.-

模糊视图.m:

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self) {
        // Initialization code
        self.imageView = [[UIImageView alloc] init];
        self.imageView.frame = CGRectMake(20, 20, 200, 200);
        [self addSubview:self.imageView];
    }
    return self;
}
4

4 回答 4

13

这个问题有一半没有得到回答,所以我认为值得补充。

UIScreen 的问题

- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates

和 UIView 的

- (UIView *)resizableSnapshotViewFromRect:(CGRect)rect 
                      afterScreenUpdates:(BOOL)afterUpdates 
                           withCapInsets:(UIEdgeInsets)capInsets

是你不能从他们那里得到一个 UIImage - “黑屏”问题。

在 iOS7 Apple 提供了第三个 API 用于提取 UIImages,UIView 上的一个方法

- (BOOL)drawViewHierarchyInRect:(CGRect)rect 
             afterScreenUpdates:(BOOL)afterUpdates  

它不如 快snapshotView,但与之相比也不错renderInContext(在 Apple 提供的示例中,它比 快 5 倍,比renderInContext慢 3 倍snapshotView

示例使用:

 UIGraphicsBeginImageContextWithOptions(image.size, NULL, 0);
 [view drawViewHierarchyInRect:rect];
 UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();  

然后得到一个模糊的版本

 UIImage* lightImage = [newImage applyLightEffect];  

applyLightEffect在接受的答案中提到的Apple 类别中的 Blur 类别方法之一在哪里UIImage+ImageEffects(在接受的答案中指向此代码示例的诱人链接不起作用,但这个可以让您进入正确的页面:您想要的文件是iOS_UIImageEffects) .

主要参考 WWDC2013 session 226, Implementing Engaging UI on iOS

顺便说一句,Apple 的参考文档中有一个有趣的注释renderInContext暗示了黑屏问题。

重要提示:此方法的 OS X v10.5 实现不支持整个 Core Animation 合成模型。QCCompositionLayer、CAOpenGLLayer 和 QTMovieLayer 图层不会被渲染。此外,不会渲染使用 3D 变换的图层,也不会渲染指定背景过滤器、过滤器、合成过滤器或遮罩值的图层。OS X 的未来版本可能会增加对渲染这些层和属性的支持。

该注释自 10.5 以来没有更新,所以我猜“未来版本”可能还有一段时间,我们可以将我们的新版本CASnapshotLayer(或其他版本)添加到列表中。

于 2014-01-18T00:36:46.910 回答
9

来自 WWDC ios_uiimageeffects的示例代码

有一个UIImage类别叫UIImage+ImageEffects

这是它的 API:

- (UIImage *)applyLightEffect;
- (UIImage *)applyExtraLightEffect;
- (UIImage *)applyDarkEffect;
- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;

- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius 
                       tintColor:(UIColor *)tintColor 
           saturationDeltaFactor:(CGFloat)saturationDeltaFactor 
                       maskImage:(UIImage *)maskImage;

由于法律原因,我不能在这里展示实现,里面有一个演示项目。应该很容易上手。

于 2013-09-22T09:08:37.967 回答
4

要总结如何使用 Foundry 的示例代码执行此操作,请使用以下内容:

为了我的目的,我想稍微模糊整个屏幕,所以我将使用主屏幕边界。

CGRect screenCaptureRect = [UIScreen mainScreen].bounds;
UIView *viewWhereYouWantToScreenCapture = [[UIApplication sharedApplication] keyWindow];

//screen capture code
UIGraphicsBeginImageContextWithOptions(screenCaptureRect.size, NO, [UIScreen mainScreen].scale);
[viewWhereYouWantToScreenCapture drawViewHierarchyInRect:screenCaptureRect afterScreenUpdates:NO];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

//blur code
UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0];
UIImage *blurredImage = [capturedImage applyBlurWithRadius:1.5 tintColor:tintColor saturationDeltaFactor:1.2 maskImage:nil];
//or use [capturedImage applyLightAffect] but I thought that was too much for me

//use blurredImage in whatever way you so desire!

截屏部分注意事项

UIGraphicsBeginImageContextWithOptions()第二个论点是不透明度。应该是NO,除非你alpha除了1. 如果您返回 yes,则屏幕截图将不会查看透明度值,因此它会更快,但可能会出错。

UIGraphicsBeginImageContextWithOptions()第三个参数是比例。可能想像我一样放入设备的规模,以确保和区分视网膜和非视网膜。但我还没有真正测试过这个,我认为0.0f也可以。

drawViewHierarchyInRect:afterScreenUpdates:注意你返回的屏幕更新BOOL。我尝试在后台运行之前执行此操作,如果我不放置NO应用程序,当我返回前台时,应用程序会因故障而发疯。YES如果您不离开该应用程序,您也许可以逃脱。

模糊注意事项

我这里有一个非常轻微的模糊。更改 blurRadius 会使其更模糊,您可以更改 tint color 和 alpha 以制作各种其他效果。

您还需要为模糊方法添加一个类别才能工作......

如何添加 UIImage+ImageEffects 类别

您需要下载类别 UIImage+ImageEffects 才能使模糊工作。登录后在此处下载:https ://developer.apple.com/downloads/index.action?name=WWDC%202013

搜索“UIImageEffects”,你会找到它。只需拉出 2 个必要的文件并将它们添加到您的项目中。UIImage+ImageEffects.h 和 UIImage+ImageEffects.m。

此外,我必须在构建设置中启用模块,因为我有一个不是使用 xCode 5 创建的项目。为此,请转到您的目标构建设置并搜索“模块”并确保“启用模块”和“自动链接框架”都设置为是,否则您将遇到新类别的编译器错误。

祝你好运模糊!

于 2014-03-27T20:00:56.633 回答
0

检查 WWDC 2013 示例应用程序“快速运行”。

模糊是作为一个类别实现的。

于 2013-09-22T09:04:40.233 回答