使用 iOS 7 的快照 API 模糊屏幕



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

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

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

我究竟该怎么做?

附言视图没有动画,因此在性能方面应该没问题。

编辑:这是我到目前为止所拥有的。问题是我无法将快照捕获到 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 -.-

BlurView.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;
}

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

UIScreen的问题

- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates

和UIView的

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

是你不能从他们那里得出一个UIImage——"黑屏"问题。

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

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

它没有snapshotView那么快,但与renderInContext相比还不错(在Apple提供的示例中,它比renderInContext快五倍,比snapshotView慢三倍(

使用示例:

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

然后得到一个模糊的版本

 UIImage* lightImage = [newImage applyLightEffect];  

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

主要参考是WWDC2013会话 226,在 iOS 上实现引人入胜的 UI

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

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

该注释自 10.5 以来就没有更新过,所以我想"未来版本"可能还需要一段时间,我们可以将我们的新CASnapshotLayer(或其他(添加到列表中。

来自

WWDC的示例代码ios_uiimageeffects

有一个名为UIImage+ImageEffectsUIImage类别

这是它的API:

- (UIImage *)applyLightEffect;
- (UIImage *)applyExtraLightEffect;
- (UIImage *)applyDarkEffect;
- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;
- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius 
                       tintColor:(UIColor *)tintColor 
           saturationDeltaFactor:(CGFloat)saturationDeltaFactor 
                       maskImage:(UIImage *)maskImage;

由于法律原因,我无法在此处显示实现,其中有一个演示项目。 应该很容易上手。

要总结如何使用 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的,除非你除了1之外没有任何alpha。如果返回 yes,屏幕捕获将不会查看透明度值,因此它会更快,但可能是错误的。

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

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

关于模糊的注意事项

我这里有一个非常轻微的模糊。更改blurRadius将使其更模糊,您可以更改色调颜色和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 创建的项目。为此,请转到目标构建设置并搜索"模块",并确保"启用模块"和"自动链接框架"都设置为"是",否则新类别会出现编译器错误。

祝你好运模糊!

> 检查 WWDC 2013 示例应用程序"快速运行"。

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

最新更新