├── README.md └── SureBokehEffect ├── SureBokehEffect.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── liushuo.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── liushuo.xcuserdatad │ └── xcschemes │ ├── SureBokehEffect.xcscheme │ └── xcschememanagement.plist └── SureBokehEffect ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── IMG_0856.JPG ├── IMG_0857.JPG ├── IMG_1018.JPG ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m /README.md: -------------------------------------------------------------------------------- 1 | # SureBokehEffect 2 | 滤镜初探,三步集成美图软件背景虚化效果 3 | 4 | ######【前文提要】 5 | 因工作一直没有接触过滤镜领域,所以在闲暇之余粗略的阅读了下文档,尝试实现某些效果,纯属娱乐,大神无视勿喷。 6 | ![左侧为原图,右侧为背景虚化后的效果图](http://upload-images.jianshu.io/upload_images/1767950-f82f3377879d68de.JPG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 7 | 8 | 大致为突显女主上半身形象,并以上半身为中心渐变模糊扩散的效果。 9 | ######一、为图片添加高斯模糊滤镜 10 | 既然需要执行滤镜操作,那肯定离不开[Core Image](https://developer.apple.com/reference/coreimage?language=objc)这一强大的框架了,感兴趣的童鞋可以点击进入查看文档。本篇文章中主要使用其几种常用的滤镜。对于模糊效果,系统提供了很多样式,但毕竟不是设计,无法通过肉眼区别它们之间的区别,因此这里简单的选取了高斯模糊效果。 11 | 12 | 首先我们来创建高斯模糊滤镜,对于** CIFilter**就不做过多的介绍了。将具体滤镜名称传入即可创建对应滤镜样式。这里需要注意的我们传入的图片信息并非我们常用的**UIImage**,因为**UIImage**是不可变的,只能通过已存在的图片创建它,而滤镜需要对原始图片进行修改,因此这里我们需要将**UIImage**转换为**CIImage**类型做处理。 13 | ``` 14 | //高斯模糊滤镜 15 | CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"]; 16 | UIImage *image = [UIImage imageNamed:@"IMG_0857.JPG"]; 17 | //将UIImage转换为CIImage类型 18 | CIImage *ciImage = [[CIImage alloc]initWithImage:image]; 19 | //设置输入的图片信息 20 | [filter setValue:ciImage forKey:kCIInputImageKey]; 21 | //设置模糊程度 22 | [filter setValue:@8 forKey:kCIInputRadiusKey];//默认为10 23 | ``` 24 | 执行如上操作生成的效果如下,也即是文章顶部效果图中的模糊效果: 25 | ![高斯模糊效果图](http://upload-images.jianshu.io/upload_images/1767950-7d1cda504f0818fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 26 | 27 | ######二、确定显示区域 28 | 常用美图软件的童鞋们会发现背景虚化效果是存在两种显示调节形式的,一种为两个同心圆确定区域,一种为平行矩形确定区域。以美图秀秀为例。 29 | ![美图秀秀操作效果](http://upload-images.jianshu.io/upload_images/1767950-4526aaa2d64667d8.JPG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 30 | 31 | ######那如何通过代码实现如上效果呢? 32 | 其实同心圆与平行矩形在代码中对应分别为[CIRadialGradient](https://developer.apple.com/library/content/documentation/GraphicsImaging/Reference/CoreImageFilterReference/#//apple_ref/doc/filter/ci/CIRadialGradient)和[CILinearGradient](https://developer.apple.com/library/content/documentation/GraphicsImaging/Reference/CoreImageFilterReference/#//apple_ref/doc/filter/ci/CILinearGradient)滤镜。我们可称其为径向渐变滤镜。 33 | 34 | 这里拿同心圆的径向渐变滤镜为例通过代码生成一个内圆半径为300,外圆半径为500的同心圆。需要注意的是设置圆点或半径并不是以iOS设备的屏幕分辨率为参照的,而是由原图像信息来决定的。例如原图片像素为(750,1334),若想将同心圆的圆点定位在图片中心,需要将inputCenter设置为(375,667),同理对于同心圆中内圆与外圆的半径设置也是一样。并且还需要坐标系问题,在这里(0,0)点属于屏幕左下角而非左上角。也就说他使用的是现实中的直角坐标系。 35 | ``` 36 | //径向渐变滤镜(同心圆) 37 | CIFilter *radialFilter = [CIFilter filterWithName:@"CIRadialGradient"]; 38 | //圆点 39 | [radialFilter setValue:[CIVector vectorWithX:image.size.width / 2 Y:image.size.height / 2] forKey:@"inputCenter"]; 40 | //内圆半径 41 | [radialFilter setValue:@300 forKey:@"inputRadius0"]; 42 | //外圆半径 43 | [radialFilter setValue:@500 forKey:@"inputRadius1"]; 44 | ``` 45 | 上述代码可生成如下图效果: 46 | ![径向渐变滤镜(同心圆)效果图](http://upload-images.jianshu.io/upload_images/1767950-e45b3c770d76dfbc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 47 | 48 | 根据效果图我们可以看出,内圆部分是完全透明的,内圆与外圆之间部分呈现渐变模糊效果。 49 | ######三、背景虚化效果合成 50 | 通过上两步的操作我们生成了高斯模糊后的图片并且确定了所需显示的区域,接下来我们要通过**CIBlendWithMask**滤镜来进行效果合成。对于**CIBlendWithMask**滤镜,字面意思为遮盖物混合滤镜,文档解释过于草率,我们根据文档给予的效果图来分析: 51 | 52 | ![CIBlendWithMask滤镜](http://upload-images.jianshu.io/upload_images/1767950-3a014b0dd8341cc0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 53 | 54 | 如图所示,** CIBlendWithMask**滤镜可将左侧的三张图片合成为右侧的输出图片。具体的执行流程是,左一图做为左二图的填充,后续在与左三进行混合。**(这张图建议大家仔细观察下)** 55 | 56 | ######那如何通过这种混合方式实现自己的需求呢? 57 | 58 | 我们可以将左三图分别替换为原图、同心圆、高斯模糊滤镜生成的效果图。这样即可实现我们想要的背景虚化的效果了。也可理解为我们将需要高亮显示的位置在原图上扣出来再与整体的模糊效果进行混合,代码如下: 59 | ``` 60 | //滤镜混合 61 | CIFilter *maskFilter = [CIFilter filterWithName:@"CIBlendWithMask"]; 62 | //原图 63 | [maskFilter setValue:ciImage forKey:kCIInputImageKey]; 64 | //高斯模糊处理后的图片 65 | [maskFilter setValue:filter.outputImage forKey:kCIInputBackgroundImageKey]; 66 | //遮盖图片,这里为径向渐变所生成的同心圆或同轴矩形 67 | [maskFilter setValue:radialFilter.outputImage forKey:kCIInputMaskImageKey]; 68 | ``` 69 | 70 | 最后通过**CIContext**生成执行滤镜操作后的图片,给**imageView**赋值。 71 | 72 | ⚠️注意:若需要测试高斯模糊等效果,均需要调用下方代码,将对应的输出图像更改下即可,比如想测试高斯模糊效果,将下方代码**maskFilter.outputImage **更改为**filter.outputImage**即可。 73 | ``` 74 | CIContext *context = [CIContext contextWithOptions:nil]; 75 | CGImageRef endImageRef = [context createCGImage:maskFilter.outputImage fromRect:ciImage.extent]; 76 | imageView.image = [UIImage imageWithCGImage:endImageRef]; 77 | ``` 78 | 因滤镜操作**CPU**渲染会比**GPU**要慢,所以效果呈现会慢一些,换做真机就没问题啦。另外仍可以继续优化,将当前的**context**替换为**OpenGL**的**context**,代码如下: 79 | ``` 80 | CIContext *context = [CIContext contextWithEAGLContext:[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]]; 81 | ``` 82 | 使用它的优点是渲染的图像保存在**GPU**上,并不需要拷贝回**CPU**内存。并且如果需要实时滤镜处理的话,这种创建形式更好。 83 | 84 | 最后不要忘记内存泄漏问题,对于非OC对象要手动进行内存释放,前一篇文章[关于内存泄漏,还有哪些是你不知道的?](http://www.jianshu.com/p/d465831aebbf)也有描述过。因此需要添加内存释放代码 85 | ``` 86 | CGImageRelease(endImageRef); 87 | ``` 88 | 89 | 本文暂时写到这里,demo已上传Github,喜欢的可以点个赞关注我,比心(。・ω・。)ノ♡ 90 | [https://github.com/LSure/SureBokehEffect](https://github.com/LSure/SureBokehEffect) 91 | 92 | 最后放一张模拟器中的效果图 93 | 94 | ![最终效果图](http://upload-images.jianshu.io/upload_images/1767950-596529984356b8f9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 95 | 96 | 另附感言:P图软件公司的开发真不容易啊~ 97 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 88D1B8611EE6408C00C0F8A8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D1B8601EE6408C00C0F8A8 /* main.m */; }; 11 | 88D1B8641EE6408C00C0F8A8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D1B8631EE6408C00C0F8A8 /* AppDelegate.m */; }; 12 | 88D1B8671EE6408C00C0F8A8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D1B8661EE6408C00C0F8A8 /* ViewController.m */; }; 13 | 88D1B86A1EE6408C00C0F8A8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 88D1B8681EE6408C00C0F8A8 /* Main.storyboard */; }; 14 | 88D1B86C1EE6408C00C0F8A8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 88D1B86B1EE6408C00C0F8A8 /* Assets.xcassets */; }; 15 | 88D1B86F1EE6408C00C0F8A8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 88D1B86D1EE6408C00C0F8A8 /* LaunchScreen.storyboard */; }; 16 | 88D1B8781EE640C500C0F8A8 /* IMG_0856.JPG in Resources */ = {isa = PBXBuildFile; fileRef = 88D1B8761EE640C500C0F8A8 /* IMG_0856.JPG */; }; 17 | 88D1B8791EE640C500C0F8A8 /* IMG_0857.JPG in Resources */ = {isa = PBXBuildFile; fileRef = 88D1B8771EE640C500C0F8A8 /* IMG_0857.JPG */; }; 18 | 88D1B87B1EE6424A00C0F8A8 /* IMG_1018.JPG in Resources */ = {isa = PBXBuildFile; fileRef = 88D1B87A1EE6424A00C0F8A8 /* IMG_1018.JPG */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 88D1B85C1EE6408C00C0F8A8 /* SureBokehEffect.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SureBokehEffect.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 88D1B8601EE6408C00C0F8A8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 24 | 88D1B8621EE6408C00C0F8A8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 25 | 88D1B8631EE6408C00C0F8A8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 26 | 88D1B8651EE6408C00C0F8A8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 27 | 88D1B8661EE6408C00C0F8A8 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 28 | 88D1B8691EE6408C00C0F8A8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 88D1B86B1EE6408C00C0F8A8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | 88D1B86E1EE6408C00C0F8A8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | 88D1B8701EE6408C00C0F8A8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 88D1B8761EE640C500C0F8A8 /* IMG_0856.JPG */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = IMG_0856.JPG; sourceTree = ""; }; 33 | 88D1B8771EE640C500C0F8A8 /* IMG_0857.JPG */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = IMG_0857.JPG; sourceTree = ""; }; 34 | 88D1B87A1EE6424A00C0F8A8 /* IMG_1018.JPG */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = IMG_1018.JPG; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | 88D1B8591EE6408C00C0F8A8 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | 88D1B8531EE6408C00C0F8A8 = { 49 | isa = PBXGroup; 50 | children = ( 51 | 88D1B85E1EE6408C00C0F8A8 /* SureBokehEffect */, 52 | 88D1B85D1EE6408C00C0F8A8 /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | 88D1B85D1EE6408C00C0F8A8 /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 88D1B85C1EE6408C00C0F8A8 /* SureBokehEffect.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | 88D1B85E1EE6408C00C0F8A8 /* SureBokehEffect */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 88D1B87A1EE6424A00C0F8A8 /* IMG_1018.JPG */, 68 | 88D1B8761EE640C500C0F8A8 /* IMG_0856.JPG */, 69 | 88D1B8771EE640C500C0F8A8 /* IMG_0857.JPG */, 70 | 88D1B8621EE6408C00C0F8A8 /* AppDelegate.h */, 71 | 88D1B8631EE6408C00C0F8A8 /* AppDelegate.m */, 72 | 88D1B8651EE6408C00C0F8A8 /* ViewController.h */, 73 | 88D1B8661EE6408C00C0F8A8 /* ViewController.m */, 74 | 88D1B8681EE6408C00C0F8A8 /* Main.storyboard */, 75 | 88D1B86B1EE6408C00C0F8A8 /* Assets.xcassets */, 76 | 88D1B86D1EE6408C00C0F8A8 /* LaunchScreen.storyboard */, 77 | 88D1B8701EE6408C00C0F8A8 /* Info.plist */, 78 | 88D1B85F1EE6408C00C0F8A8 /* Supporting Files */, 79 | ); 80 | path = SureBokehEffect; 81 | sourceTree = ""; 82 | }; 83 | 88D1B85F1EE6408C00C0F8A8 /* Supporting Files */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 88D1B8601EE6408C00C0F8A8 /* main.m */, 87 | ); 88 | name = "Supporting Files"; 89 | sourceTree = ""; 90 | }; 91 | /* End PBXGroup section */ 92 | 93 | /* Begin PBXNativeTarget section */ 94 | 88D1B85B1EE6408C00C0F8A8 /* SureBokehEffect */ = { 95 | isa = PBXNativeTarget; 96 | buildConfigurationList = 88D1B8731EE6408C00C0F8A8 /* Build configuration list for PBXNativeTarget "SureBokehEffect" */; 97 | buildPhases = ( 98 | 88D1B8581EE6408C00C0F8A8 /* Sources */, 99 | 88D1B8591EE6408C00C0F8A8 /* Frameworks */, 100 | 88D1B85A1EE6408C00C0F8A8 /* Resources */, 101 | ); 102 | buildRules = ( 103 | ); 104 | dependencies = ( 105 | ); 106 | name = SureBokehEffect; 107 | productName = SureBokehEffect; 108 | productReference = 88D1B85C1EE6408C00C0F8A8 /* SureBokehEffect.app */; 109 | productType = "com.apple.product-type.application"; 110 | }; 111 | /* End PBXNativeTarget section */ 112 | 113 | /* Begin PBXProject section */ 114 | 88D1B8541EE6408C00C0F8A8 /* Project object */ = { 115 | isa = PBXProject; 116 | attributes = { 117 | LastUpgradeCheck = 0830; 118 | ORGANIZATIONNAME = "刘硕"; 119 | TargetAttributes = { 120 | 88D1B85B1EE6408C00C0F8A8 = { 121 | CreatedOnToolsVersion = 8.3.2; 122 | ProvisioningStyle = Automatic; 123 | }; 124 | }; 125 | }; 126 | buildConfigurationList = 88D1B8571EE6408C00C0F8A8 /* Build configuration list for PBXProject "SureBokehEffect" */; 127 | compatibilityVersion = "Xcode 3.2"; 128 | developmentRegion = English; 129 | hasScannedForEncodings = 0; 130 | knownRegions = ( 131 | en, 132 | Base, 133 | ); 134 | mainGroup = 88D1B8531EE6408C00C0F8A8; 135 | productRefGroup = 88D1B85D1EE6408C00C0F8A8 /* Products */; 136 | projectDirPath = ""; 137 | projectRoot = ""; 138 | targets = ( 139 | 88D1B85B1EE6408C00C0F8A8 /* SureBokehEffect */, 140 | ); 141 | }; 142 | /* End PBXProject section */ 143 | 144 | /* Begin PBXResourcesBuildPhase section */ 145 | 88D1B85A1EE6408C00C0F8A8 /* Resources */ = { 146 | isa = PBXResourcesBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | 88D1B86F1EE6408C00C0F8A8 /* LaunchScreen.storyboard in Resources */, 150 | 88D1B86C1EE6408C00C0F8A8 /* Assets.xcassets in Resources */, 151 | 88D1B8781EE640C500C0F8A8 /* IMG_0856.JPG in Resources */, 152 | 88D1B87B1EE6424A00C0F8A8 /* IMG_1018.JPG in Resources */, 153 | 88D1B8791EE640C500C0F8A8 /* IMG_0857.JPG in Resources */, 154 | 88D1B86A1EE6408C00C0F8A8 /* Main.storyboard in Resources */, 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXResourcesBuildPhase section */ 159 | 160 | /* Begin PBXSourcesBuildPhase section */ 161 | 88D1B8581EE6408C00C0F8A8 /* Sources */ = { 162 | isa = PBXSourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | 88D1B8671EE6408C00C0F8A8 /* ViewController.m in Sources */, 166 | 88D1B8641EE6408C00C0F8A8 /* AppDelegate.m in Sources */, 167 | 88D1B8611EE6408C00C0F8A8 /* main.m in Sources */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXSourcesBuildPhase section */ 172 | 173 | /* Begin PBXVariantGroup section */ 174 | 88D1B8681EE6408C00C0F8A8 /* Main.storyboard */ = { 175 | isa = PBXVariantGroup; 176 | children = ( 177 | 88D1B8691EE6408C00C0F8A8 /* Base */, 178 | ); 179 | name = Main.storyboard; 180 | sourceTree = ""; 181 | }; 182 | 88D1B86D1EE6408C00C0F8A8 /* LaunchScreen.storyboard */ = { 183 | isa = PBXVariantGroup; 184 | children = ( 185 | 88D1B86E1EE6408C00C0F8A8 /* Base */, 186 | ); 187 | name = LaunchScreen.storyboard; 188 | sourceTree = ""; 189 | }; 190 | /* End PBXVariantGroup section */ 191 | 192 | /* Begin XCBuildConfiguration section */ 193 | 88D1B8711EE6408C00C0F8A8 /* Debug */ = { 194 | isa = XCBuildConfiguration; 195 | buildSettings = { 196 | ALWAYS_SEARCH_USER_PATHS = NO; 197 | CLANG_ANALYZER_NONNULL = YES; 198 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 199 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 200 | CLANG_CXX_LIBRARY = "libc++"; 201 | CLANG_ENABLE_MODULES = YES; 202 | CLANG_ENABLE_OBJC_ARC = YES; 203 | CLANG_WARN_BOOL_CONVERSION = YES; 204 | CLANG_WARN_CONSTANT_CONVERSION = YES; 205 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 206 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 207 | CLANG_WARN_EMPTY_BODY = YES; 208 | CLANG_WARN_ENUM_CONVERSION = YES; 209 | CLANG_WARN_INFINITE_RECURSION = YES; 210 | CLANG_WARN_INT_CONVERSION = YES; 211 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 212 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 213 | CLANG_WARN_UNREACHABLE_CODE = YES; 214 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 215 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 216 | COPY_PHASE_STRIP = NO; 217 | DEBUG_INFORMATION_FORMAT = dwarf; 218 | ENABLE_STRICT_OBJC_MSGSEND = YES; 219 | ENABLE_TESTABILITY = YES; 220 | GCC_C_LANGUAGE_STANDARD = gnu99; 221 | GCC_DYNAMIC_NO_PIC = NO; 222 | GCC_NO_COMMON_BLOCKS = YES; 223 | GCC_OPTIMIZATION_LEVEL = 0; 224 | GCC_PREPROCESSOR_DEFINITIONS = ( 225 | "DEBUG=1", 226 | "$(inherited)", 227 | ); 228 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 229 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 230 | GCC_WARN_UNDECLARED_SELECTOR = YES; 231 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 232 | GCC_WARN_UNUSED_FUNCTION = YES; 233 | GCC_WARN_UNUSED_VARIABLE = YES; 234 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 235 | MTL_ENABLE_DEBUG_INFO = YES; 236 | ONLY_ACTIVE_ARCH = YES; 237 | SDKROOT = iphoneos; 238 | }; 239 | name = Debug; 240 | }; 241 | 88D1B8721EE6408C00C0F8A8 /* Release */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | ALWAYS_SEARCH_USER_PATHS = NO; 245 | CLANG_ANALYZER_NONNULL = YES; 246 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 247 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 248 | CLANG_CXX_LIBRARY = "libc++"; 249 | CLANG_ENABLE_MODULES = YES; 250 | CLANG_ENABLE_OBJC_ARC = YES; 251 | CLANG_WARN_BOOL_CONVERSION = YES; 252 | CLANG_WARN_CONSTANT_CONVERSION = YES; 253 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 254 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 255 | CLANG_WARN_EMPTY_BODY = YES; 256 | CLANG_WARN_ENUM_CONVERSION = YES; 257 | CLANG_WARN_INFINITE_RECURSION = YES; 258 | CLANG_WARN_INT_CONVERSION = YES; 259 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 260 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 261 | CLANG_WARN_UNREACHABLE_CODE = YES; 262 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 263 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 264 | COPY_PHASE_STRIP = NO; 265 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 266 | ENABLE_NS_ASSERTIONS = NO; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | GCC_C_LANGUAGE_STANDARD = gnu99; 269 | GCC_NO_COMMON_BLOCKS = YES; 270 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 271 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 272 | GCC_WARN_UNDECLARED_SELECTOR = YES; 273 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 274 | GCC_WARN_UNUSED_FUNCTION = YES; 275 | GCC_WARN_UNUSED_VARIABLE = YES; 276 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 277 | MTL_ENABLE_DEBUG_INFO = NO; 278 | SDKROOT = iphoneos; 279 | VALIDATE_PRODUCT = YES; 280 | }; 281 | name = Release; 282 | }; 283 | 88D1B8741EE6408C00C0F8A8 /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 287 | INFOPLIST_FILE = SureBokehEffect/Info.plist; 288 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 289 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 290 | PRODUCT_BUNDLE_IDENTIFIER = com.Sure.SureBokehEffect; 291 | PRODUCT_NAME = "$(TARGET_NAME)"; 292 | }; 293 | name = Debug; 294 | }; 295 | 88D1B8751EE6408C00C0F8A8 /* Release */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 299 | INFOPLIST_FILE = SureBokehEffect/Info.plist; 300 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 301 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 302 | PRODUCT_BUNDLE_IDENTIFIER = com.Sure.SureBokehEffect; 303 | PRODUCT_NAME = "$(TARGET_NAME)"; 304 | }; 305 | name = Release; 306 | }; 307 | /* End XCBuildConfiguration section */ 308 | 309 | /* Begin XCConfigurationList section */ 310 | 88D1B8571EE6408C00C0F8A8 /* Build configuration list for PBXProject "SureBokehEffect" */ = { 311 | isa = XCConfigurationList; 312 | buildConfigurations = ( 313 | 88D1B8711EE6408C00C0F8A8 /* Debug */, 314 | 88D1B8721EE6408C00C0F8A8 /* Release */, 315 | ); 316 | defaultConfigurationIsVisible = 0; 317 | defaultConfigurationName = Release; 318 | }; 319 | 88D1B8731EE6408C00C0F8A8 /* Build configuration list for PBXNativeTarget "SureBokehEffect" */ = { 320 | isa = XCConfigurationList; 321 | buildConfigurations = ( 322 | 88D1B8741EE6408C00C0F8A8 /* Debug */, 323 | 88D1B8751EE6408C00C0F8A8 /* Release */, 324 | ); 325 | defaultConfigurationIsVisible = 0; 326 | defaultConfigurationName = Release; 327 | }; 328 | /* End XCConfigurationList section */ 329 | }; 330 | rootObject = 88D1B8541EE6408C00C0F8A8 /* Project object */; 331 | } 332 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect.xcodeproj/project.xcworkspace/xcuserdata/liushuo.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSure/SureBokehEffect/f0f8ea186147b6c99d27c231c659c8523ff79576/SureBokehEffect/SureBokehEffect.xcodeproj/project.xcworkspace/xcuserdata/liushuo.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect.xcodeproj/xcuserdata/liushuo.xcuserdatad/xcschemes/SureBokehEffect.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect.xcodeproj/xcuserdata/liushuo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SureBokehEffect.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 88D1B85B1EE6408C00C0F8A8 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SureBokehEffect 4 | // 5 | // Created by 刘硕 on 2017/6/6. 6 | // Copyright © 2017年 刘硕. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // SureBokehEffect 4 | // 5 | // Created by 刘硕 on 2017/6/6. 6 | // Copyright © 2017年 刘硕. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/IMG_0856.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSure/SureBokehEffect/f0f8ea186147b6c99d27c231c659c8523ff79576/SureBokehEffect/SureBokehEffect/IMG_0856.JPG -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/IMG_0857.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSure/SureBokehEffect/f0f8ea186147b6c99d27c231c659c8523ff79576/SureBokehEffect/SureBokehEffect/IMG_0857.JPG -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/IMG_1018.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSure/SureBokehEffect/f0f8ea186147b6c99d27c231c659c8523ff79576/SureBokehEffect/SureBokehEffect/IMG_1018.JPG -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // SureBokehEffect 4 | // 5 | // Created by 刘硕 on 2017/6/6. 6 | // Copyright © 2017年 刘硕. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SureBokehEffect 4 | // 5 | // Created by 刘硕 on 2017/6/6. 6 | // Copyright © 2017年 刘硕. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.view.bounds]; 21 | [self.view addSubview:imageView]; 22 | 23 | //高斯模糊滤镜 24 | CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"]; 25 | UIImage *image = [UIImage imageNamed:@"IMG_1018.JPG"]; 26 | //将UIImage转换为CIImage类型 27 | CIImage *ciImage = [[CIImage alloc]initWithImage:image]; 28 | [filter setValue:ciImage forKey:kCIInputImageKey]; 29 | //设置模糊程度 30 | [filter setValue:@8 forKey:kCIInputRadiusKey];//默认为10 31 | 32 | //径向渐变滤镜(同心圆) 33 | CIFilter *radialFilter = [CIFilter filterWithName:@"CIRadialGradient"]; 34 | //图像像素为(1080,1920); 35 | //将圆点设置为人物头像位置,粗略估计为中心点偏上480 36 | [radialFilter setValue:[CIVector vectorWithX:image.size.width / 2 Y:image.size.height / 2 + 480] forKey:@"inputCenter"]; 37 | //内圆半径 38 | [radialFilter setValue:@300 forKey:@"inputRadius0"]; 39 | //外圆半径 40 | [radialFilter setValue:@500 forKey:@"inputRadius1"]; 41 | 42 | CIFilter *linefilter = [CIFilter filterWithName:@"CILinearGradient"]; 43 | [linefilter setValue:[CIVector vectorWithCGPoint:CGPointMake(0, 200)] forKey:@"inputPoint0"]; 44 | [linefilter setValue:[CIVector vectorWithCGPoint:CGPointMake(200, 200)] forKey:@"inputPoint1"]; 45 | 46 | //滤镜混合 47 | CIFilter *maskFilter = [CIFilter filterWithName:@"CIBlendWithMask"]; 48 | //原图 49 | [maskFilter setValue:ciImage forKey:kCIInputImageKey]; 50 | //高斯模糊处理后的图片 51 | [maskFilter setValue:filter.outputImage forKey:kCIInputBackgroundImageKey]; 52 | //遮盖图片,这里为径向渐变所生成 53 | [maskFilter setValue:radialFilter.outputImage forKey:kCIInputMaskImageKey]; 54 | 55 | CIContext *context = [CIContext contextWithOptions:nil]; 56 | CGImageRef endImageRef = [context createCGImage:maskFilter.outputImage fromRect:ciImage.extent]; 57 | imageView.image = [UIImage imageWithCGImage:endImageRef]; 58 | 59 | CGImageRelease(endImageRef); 60 | 61 | // Do any additional setup after loading the view, typically from a nib. 62 | } 63 | 64 | 65 | - (void)didReceiveMemoryWarning { 66 | [super didReceiveMemoryWarning]; 67 | // Dispose of any resources that can be recreated. 68 | } 69 | 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /SureBokehEffect/SureBokehEffect/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SureBokehEffect 4 | // 5 | // Created by 刘硕 on 2017/6/6. 6 | // Copyright © 2017年 刘硕. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | --------------------------------------------------------------------------------