Snapshots 快照

  一个完整的视图 ----包括视图中的一个button、继承自这个视图的的所有视图 -----可以通过调用 drawViewHierarchyInRect:afterScreenUpdates:来绘制在当前的图形上下文中。这个方法是在iOS7中新添加的(比CGLayer提供的方法 renderInContext:快很多,已经被取代了)。得到的是原始视图的一个快照,跟原始视图看起来完全一样,只不过这个只是视图的一个位图图像,一个轻量级的虚拟拷贝。因为iOS界面的动态本质,快照功能显得非常有用。例如,你可以把一个视图的快照放在这个视图之上来隐藏发生的事情,或者在动画中展示视图移动的变化过程,而实际上只是一个快照而已。

下图展示了一个快照在我的一个应用中展示的效果。用户可以点击任意三个颜色调节按钮来调节颜色值,当颜色编辑的界面显示的时候,我想要用户有种只是临时界面的感觉,可以看到原来的界面潜伏在背后,但是原始的界面不能让用户分心,所以模糊处理了。实际上,模糊的只是原始界面的快照。

下面是图中快照的生成方式:

    UIGraphicsBeginImageContextWithOptions(vc1.view.frame.size, YES, 0);[vc1.view drawViewHierarchyInRect: vc1.view.frame afterScreenUpdates:NO];UIImage* im = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();

  

接下来就是模糊化这张快照,并把它放到颜色编辑页面的下面。至于如何实现一个模糊效果就是另一个问题了。我可以会使用CIFilter(下一节的主题),但是太慢了;作为替代,我使用苹果提供的一个UIImage类别,它是作为“Blurring and Tinting an Image” 实例代码的一部分发布的。

一种更加快速获取一个视图快照的方式是使用UIView(或者UIScreen)实例方法 snapshotViewAfterScreenUpdates: 。返回的是一个UIView,而不是一个UIImage;更确切地说是一个知道怎么绘制一张图片的UIImageView,称为快照。这样的快照视图通常展示原来视图的样式,但是你也可以扩大它的边框bounds,这样快照图片也会被拉伸。如果你希望这个被拉伸的快照像可被拉伸的图片那样工作,可以用resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets方法代替。从快照视图中产生快照视图是完全合理的。

CIFilter 和CIImage

  这个“CI”在CIFilter和CIImage中代表Core Image,这是一种通过数字过滤器转换图片的技术。Core Image最初在OS X系统出现。有一些OS X提供的过滤器在iOS中不可用(或许是它们对于电话设备来说,数字处理太密集了)。

其中一个过滤器就是CIFilter。可以用的过滤器(大概120种,其中有24种是iOS7新添加的)分为几类:

* 图案和渐变(Patterns ,gradients)

  这些过滤器创建的CIImage可以和其它的CIImage组合在一起,例如单个颜色,棋盘图案,条纹,渐变。

* 混合(Compositing)

  这些过滤器可以组合多张图片,使用合成混合模式与我们使用Photoshop图片处理程序很相似。

* 颜色(Color)

  这些过滤器会适应或者修改一张图片的颜色。另外,你可以改变图片的饱和度,色度,亮度,对比度,灰度,白点,曝光度,阴影,聚焦等等。

* 几何(Geometric)

  这些过滤器在图像上执行基本的几何变换,例如缩放,旋转和裁剪。

* 变换(Transformation)

  这些过滤器可以扭曲,模糊或风格化图片。只有一部分适用于iOS。

* 过渡(Transition)

  这些过滤器提供了一个图像与另一个之间的过渡的框架。通过调用序列中的帧,可以实现图像与图像之间的过渡动画。

* 特定目的

  这些过滤器进行高度专业化的操作,如人脸检测和生成QR(二维)码。

  基本使用CIFilter是相当简单的,它本质上就如过滤器字面上的意思,只是一种由键和值组成的字典罢了。你通过调用 filterWithName:方法,并提供一个过滤器的字符串形式的名称来创建过滤器;为了明白这些过滤器名称有哪些,可以查阅苹果的 Core Image Filter Reference,或者传递一个nil 值的参数调用CIFilter 类方法 filterNamesInCategories:。每一个过滤器由一小部分的键值对来决定自身的行为。你可以完全从代码中学习这些键,但是通常你还是会查阅文档。对于你感兴趣的每个键,你提供一个键 - 值对,通过调用setValue:forKey:,或通过传递键和值以及过滤器名称参数来调用filterWithName:keysAndValues​​:方法来实践每个效果。在传递参数时,一个数字必须封装成一个NSNumber的类型,同时系统也提供了一些支持类,如CIVector(类似CGPoint 和 CGRect的结合体),CIColor,这些都是很容易理解和掌握的。

  一个CIFilter的键包括任何图像或图像上进行操作的过滤器;这样的图片必须是CIImage。你可以在过滤器的输出中获取CIImage;另外,过滤器之间可以链接在一起。但是,在过滤器链中的第一个过滤器会是什么呢?那这个过滤器操作的CIImage从哪里来呢?你可以从CGImage中,通过调用initWithCGImage:来获得一个CIImage,而你可以从UIImage的CGImage属性中获取一个CGImage。

  注意:不要视图为了方便,直接从UIImage中,通过调用实例方法CIImage来获取一个CIImage。这样不会把一个UIImage转化成CIImage,它仅仅只是指向了一个已经备份了UIImage对象的CIImage,而你的图片资源并没有被CIImage备份了,而是被CGImage备份了。我下面将会解释一个被CIImage备份的UIImage是从哪里来的。

  当你创建一个过滤器链时,实际上什么也没有发生。只有当你在过滤器链中转换最终的CIImage 为一个位图绘制时,密集的计算才会发生。有两种方式来实现这种效果:

  * 创建一个CIContext(通过调用contextWithOptions:),然后调用createCGImage:fromRect:,把最终的CIImage作为第一个参数传递进去。这里仅有的轻微棘手的事情是,CIImage没有一个框架(frame)或边界(bounds);它有一个面积。你通常会使用这个作为createCGImage:fromRect:的第二个参数。最终输出的CGImage可用于任何地方和目的,例如显示在你的应用中、转换成一个UIImage或者用来进行下一步的绘制。

  *直接通过调用UIImage类方法 imageWithCIImage:来创建一个UIImage。而获取最终的CIImage可以调用实例方法 initWithCIImage:;或者更加强大的 imageWithCIImage:scale:orientation: 又或者 initWithCIImage:scale:orientation:。你必须在这些调用之后把UIImage绘制在一些图形上下文中。最后一步是必不可少的,你需要亲自转换CIImage为一个位图,否则不会自动转换。另外,从imageWithCIImage:创建的UIImage并不能直接在UIImageView中显示,因为这个UIImage不包含任何绘制其自身的信息,它是用来绘画的,而不是用来展示的。

  为了阐明上面说的内容,我会通过一张我自己的原始图片,来创建一个圆形的插图效果:如下所示

  我们使用一个CIFilter来生成白色和黑色两种默认颜色之间的径向渐变效果。然后我们使用第二个CIFilter来把这个径向渐变当做我的头像和一个默认透明背景的混合遮罩,径向渐变为白色(一切渐变的内半径内)的地方,我们只是看到了我的头像,径向渐变为黑色的地方(一切渐变的外半径)则是透明的颜色,而在渐变的中间,使图像消失在圆带渐变的半径之间。从最终的过滤器链中输出的CIImage,我们可以把它转变成一个UIImage。

UIImage* moi = [UIImage imageNamed:@"Moi"];CIImage* moi2 = [[CIImage alloc] initWithCGImage:moi.CGImage];CGRect moiextent = moi2.extent;CIFilter* grad = [CIFilter filterWithName:@"CIRadialGradient"];CIVector* center = [CIVector vectorWithX:moiextent.size.width/2.0Y:moiextent.size.height/2.0];[grad setValue:center forKey:@"inputCenter"];[grad setValue:@85 forKey:@"inputRadius0"];[grad setValue:@100 forKey:@"inputRadius1"];CIImage *gradimage = [grad valueForKey: @"outputImage"];CIFilter* blend = [CIFilter filterWithName:@"CIBlendWithMask"];[blend setValue:moi2 forKey:@"inputImage"];[blend setValue:gradimage forKey:@"inputMaskImage"];CGImageRef moi3 =[[CIContext contextWithOptions:nil]createCGImage:blend.outputImagefromRect:moiextent];UIImage* moi4 = [UIImage imageWithCGImage:moi3];CGImageRelease(moi3);

  我们可以直接捕捉CIImage作为一个UIImage,而不用由来自于链中的最后CIImage产生的CGImage来转化成一个UIImage-----但是我们在之后绘制它,以让它生成一个从过滤器链输出的位图。例如,我们可以把它绘制在图片上下文中:

UIGraphicsBeginImageContextWithOptions(moiextent.size, NO, 0);[[UIImage imageWithCIImage:blend.outputImage] drawInRect:moiextent];UIImage* moi4 = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();

  一个过滤器链可以包含在一个简单的自定义的CIFilter子类中。你的子类需要实现 outputImage(同时还有其他方法,例如 setDefaults),下面是我子类化的CIFilter

@interface MyVignetteFilter ()@property (nonatomic, strong) CIImage* inputImage;@end@implementation MyVignetteFilter-(CIImage *)outputImage {CGRect inextent = self.inputImage.extent;CIFilter* grad = [CIFilter filterWithName:@"CIRadialGradient"];CIVector* center = [CIVector vectorWithX:inextent.size.width/2.0Y:inextent.size.height/2.0];[grad setValue:center forKey:@"inputCenter"];[grad setValue:@85 forKey:@"inputRadius0"];[grad setValue:@100 forKey:@"inputRadius1"];CIImage *gradimage = [grad valueForKey: @"outputImage"];CIFilter* blend = [CIFilter filterWithName:@"CIBlendWithMask"];[blend setValue:self.inputImage forKey:@"inputImage"];[blend setValue:gradimage forKey:@"inputMaskImage"];return blend.outputImage;
} @end

而下面的这是如何使用这个CIFilter的子类,同时展示它的输出:

CIFilter* vig = [MyVignetteFilter new];CIImage* im =[CIImage imageWithCGImage:[UIImage imageNamed:@"Moi"].CGImage];[vig setValue:im forKey:@"inputImage"];CIImage* outim = vig.outputImage;UIGraphicsBeginImageContextWithOptions(outim.extent.size, NO, 0);[[UIImage imageWithCIImage:outim] drawInRect:outim.extent];UIImage* result = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();self.iv.image = result;

转载于:https://www.cnblogs.com/YungMing/p/3732547.html

iOS 绘画学习(2)相关推荐

  1. 概念艺术绘画学习教程 Schoolism – Foolproof Concept Painting with Airi Pan

    Schoolism--万无一失的概念绘画潘 大小解压后:3.19G 含课程素材文件 1920X1080 .mp4 语言:英语+中英文字幕(根据原英文字幕机译更准确) 信息: 万无一失的概念绘画潘 本课 ...

  2. ios开发学习-手势交互(Gesture)效果源码分享

    qianqianlianmeng ios开发学习-手势交互(Gesture)效果源码分享 All Around Pull View 介绍:实现视图四个方向(上下左右)都能够拖动更新(pull to r ...

  3. ios开发学习笔记--Core Motion

    iOS开发学习笔记之CoreMotion-运动传感器 官网文档:CoreMotion Framework Reference 一.     简介 现在的苹果手机都基本有运动传感器,能够过获取到设备的加 ...

  4. ios网络学习------4 UIWebView的加载本地数据的三种方式

    ios网络学习------4 UIWebView的加载本地数据的三种方式 分类: IOS2014-06-27 12:56 959人阅读 评论(0) 收藏 举报 UIWebView是IOS内置的浏览器, ...

  5. IOS之学习笔记十五(协议和委托的使用)

    1.协议和委托的使用 1).协议可以看下我的这篇博客 IOS之学习笔记十四(协议的定义和实现) https://blog.csdn.net/u011068702/article/details/809 ...

  6. 开源中国iOS客户端学习——(八)网络通信AFNetworking类库

    AFNetworking是一个轻量级的iOS网络通信类库,继ASI类库不在更新之后开发者们有一套不错选择: AFNetworking类库×××和使用教程: https://github.com/AFN ...

  7. iOS手势学习UIGestureRecognizer cocos2d 手势推荐

    iOS手势学习UIGestureRecognizer & cocos2d 手势推荐 手势识别类型: UILongPressGestureRecognizer  // 长按 UIPanGestu ...

  8. IOS开发学习笔记-----UILabel 详解

    IOS开发学习笔记-----UILabel 详解 01 //创建uilabel 02 UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMa ...

  9. iOS开发学习48 OC的lambda block

    iOS开发学习48 lambda表达式 一.block 简介 二.block使用 1. block的写法大概就是这样: 2. 带参数的话可以这样写: 3. 如果不写入参,可以写: 4. 当然返回也可以 ...

最新文章

  1. MySQL 报错MySQL server syntax to use near 'OPTION SQL_SELECT_LIMIT=DEFAULT'
  2. ud分区删除工具_如何用DiskGenius对硬盘进行分区
  3. struts2 spring jfreechart 整合
  4. iview中的Col在vue/html-self-closing中识别错误
  5. python程序框架的描述_简单介绍Python下自己编写web框架的一些要点
  6. Ubuntu 常用工具、指令安装
  7. 计算营业额python_ARIMA时间序列分析-----Python实例(一周销售营业额预测)
  8. 图论:二分图多重匹配
  9. 【iOS开发】使用XCode 8进行真机调试的方法(各种报错信息的解决方法)
  10. LoadRunner入门教程(4)—web性能测试常用指标
  11. 自定义 Behavior - 仿新浪微博发现页的实现
  12. beautifulsoup_Py之Beautiful Soup:Beautiful Soup 4.2.0的简介、安装、使用方法
  13. 测试和维修电脑软件,常用的电脑维修软件有哪些?
  14. 【LitJson】如何判断字符串中是否有某个key
  15. [EXUI][原创]菜单简单创建和点击事件的触发
  16. c# 模拟串口通信 SerialPort
  17. 985硕士程序员年薪80万!邻居眼中不如一个老师?你怎么看?
  18. 形形色色的Linux 发行版代号都在这里
  19. 计算机主板供电,你也可以看懂主板供电相数和用料情况,轻松选好主板
  20. 7.网络基础配置实验报告(2)

热门文章

  1. 深度学习工具的「计算显微镜」预测蛋白质相互作用,以及新抗生素的潜在途径...
  2. 我在codegym学Java(level5)
  3. 单例设计模式详解(5种)
  4. Java中finalize方法
  5. 测试行业的迅猛发展带来一些新的挑战和机遇,所以到底自动化测试怎么样呢?
  6. Android运行时动态全屏以及旋转屏幕时不重新装载
  7. 信息收集----目录扫描搜集与Git收集信息
  8. STM32关于触摸芯片 BS8112A-3 BS8116A-3 I2C 源程序 及问题
  9. [运维] kimchi配置noVNC
  10. 问题追踪定位常用工具