iOS 图片部分模糊,类似于美图秀秀
演示效果
演示效果

代码结构
项目结构截图如下:

该模块的核心源码部分为 MBPartBlurView,要放到自己的工程中,直接把该目录copy进去。剩余部分是测试用的。
使用介绍
使用方法
头文件 MBPartBlurView.h 中的注释很详细,使用起来也很简单,目前支持三种形式的图形,圆形、正方形和长方形。
@interface MBPartBlurView : UIView
/**
 * 原始图片
 */
@property (nonatomic, strong) UIImage *rawImage;
/**
 * 处理完的图片
 */
@property (nonatomic, strong, readonly) UIImage *currentImage;
@property (nonatomic, assign) CGFloat blurRadius;
/**
 * 不进行blur的区域
 */
@property (nonatomic, assign) CGRect excludeBlurArea;
/**
 * 不进行blur的区域是否是圆形 (目前只支持正方形)
 */
@property (nonatomic, assign) BOOL excludeAreaCircle;
@end
程序实现
局部模糊的实现
局部模糊实际上是两张图片叠加在一起的效果,底部是一张全部模糊的图片,顶部是一张未经过模糊的图片。对顶部图片加上mask,然后贴在底部图上。
a. 底部的图片放在 imageView 的 layer 上。顶部图片放在 rawImageLayer 上。
maskLayer 就是遮罩层,作为 rawImageLayer 的遮罩。他们分别由以下三个属性保持
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) CALayer *rawImageLayer;
@property (nonatomic, strong) CAShapeLayer *maskLayer;
b. 初始化的过程。图层一目了然
- (void)commonInit
{
	[self.imageView 	addGestureRecognizer:self.tapGesture];
    [self.imageView addGestureRecognizer:self.pinchGesture];
	[self.brushView addGestureRecognizer:self.panGesture];
    [self addSubview:self.imageView];
    [self.imageView.layer addSublayer:self.rawImageLayer];
	[self.imageView addSubview:self.brushView];
    self.rawImageLayer.mask = self.maskLayer;
    [self setExcludeAreaCircle:true];
    [self setExcludeBlurArea:CGRectMake(100, 100, 100, 100)];
    [self showBrush:false];
}
1. 图片模糊算法
算法用的是业界广泛使用的高斯模糊。
     (UIImage *)blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur
    {
    NSData *imageData = UIImageJPEGRepresentation(image, 1); // convert to jpeg
    UIImage* destImage = [UIImage imageWithData:imageData];
    int boxSize = (int)(blur * 100);
    if (blur > 0.5) {
        boxSize = (int)(blur * 100) + 50;
    }else if (blur <= 0.5) {
        boxSize = (int)(blur * 100);
    }
    boxSize = boxSize - (boxSize % 2) + 1;
    CGImageRef img = destImage.CGImage;
    vImage_Buffer inBuffer, outBuffer;
    vImage_Error error;
    void *pixelBuffer;
    //create vImage_Buffer with data from CGImageRef
    CGDataProviderRef inProvider = CGImageGetDataProvider(img);
    CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
    inBuffer.width = CGImageGetWidth(img);
    inBuffer.height = CGImageGetHeight(img);
    inBuffer.rowBytes = CGImageGetBytesPerRow(img);
    inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
    //create vImage_Buffer for output
    pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
    if(pixelBuffer == NULL)
    NSLog(@"No pixelbuffer");
    outBuffer.data = pixelBuffer;
    outBuffer.width = CGImageGetWidth(img);
    outBuffer.height = CGImageGetHeight(img);
    outBuffer.rowBytes = CGImageGetBytesPerRow(img);
    // Create a third buffer for intermediate processing
    void *pixelBuffer2 = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
    vImage_Buffer outBuffer2;
    outBuffer2.data = pixelBuffer2;
    outBuffer2.width = CGImageGetWidth(img);
    outBuffer2.height = CGImageGetHeight(img);
    outBuffer2.rowBytes = CGImageGetBytesPerRow(img);
    //perform convolution
    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer2, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    if (error) {
        NSLog(@"error from convolution %ld", error);
    }
    error = vImageBoxConvolve_ARGB8888(&outBuffer2, &inBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    if (error) {
        NSLog(@"error from convolution %ld", error);
    }
    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    if (error) {
        NSLog(@"error from convolution %ld", error);
    }
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(outBuffer.data,
                                             outBuffer.width,
                                             outBuffer.height,
                                             8,
                                             outBuffer.rowBytes,
                                             colorSpace,
                                             (CGBitmapInfo)kCGImageAlphaNoneSkipLast);
    CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
    UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
    //clean up
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);
    free(pixelBuffer);
    free(pixelBuffer2);
    CFRelease(inBitmapData);
    CGImageRelease(imageRef);
    return returnImage;
    }
2.手势处理
主要是实现缩放的手势,在处理 UIPanGestureRecognizer 的函数- (void)handlePinch:(UIPinchGestureRecognizer *)gestureRecognizer 中,当 state 为 UIGestureRecognizerStateChanged 时候调用核心缩放函数 - (void)scaleMask:(CGFloat)scale,代码具体如下:
- (void)scaleMask:(CGFloat)scale
{
    CGFloat mS = MIN(self.imageView.frame.size.width/self.brushView.frame.size.width, self.imageView.frame.size.height/self.brushView.frame.size.height);
    CGFloat s = MIN(scale, mS);
    [CATransaction setDisableActions:YES];
    CGAffineTransform zoomTransform = CGAffineTransformScale(self.brushView.layer.affineTransform, s, s);
    self.brushView.layer.affineTransform = zoomTransform;
    zoomTransform = CGAffineTransformScale(self.maskLayer.affineTransform, s, s);
    self.maskLayer.affineTransform = zoomTransform;
    [CATransaction setDisableActions:false];
}
在这个函数中,更新maskLayer 的 affineTransform 就可以扩大或者缩小 mask 的范围。表现出来就是不模糊的区域扩大或者缩小。
3. 处理相机图片自动旋转问题
 - (void)setRawImage:(UIImage *)rawImage
  {
    UIImage *newImage = [self fixedOrientation:rawImage]; //从相册出来的自带90度旋转
    _rawImage = newImage;
    CGFloat w,h;
    if (newImage.size.width >= newImage.size.height) {
        w = self.frame.size.width;
        h = newImage.size.height/newImage.size.width * w;
    }
    else {
        h = self.frame.size.height;
        w = newImage.size.width/newImage.size.height * h;
    }
    self.imageView.frame = CGRectMake(0.5 *(self.frame.size.width-w), 0.5 *(self.frame.size.height-h), w, h);
    self.rawImageLayer.frame = self.imageView.bounds;
    self.imageView.image = [self blurryImage:newImage withBlurLevel:self.blurRadius];
    self.rawImageLayer.contents = (id)newImage.CGImage;
   }
补充
暂时没有
[1]: http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.htmliOS 图片部分模糊,类似于美图秀秀
注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权
iOS 图片部分模糊,类似于美图秀秀的更多相关文章
- iOS开发系列--打造自己的“美图秀秀”
		--绘图与滤镜全面解析 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz ... 
- iOS开发系列--打造自己的“美图秀秀”
		概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz 2D绘制2D图形和Co ... 
- iOS:iOS开发系列–打造自己的“美图秀秀”(下)
		来源: KenshinCui 链接:http://www.cnblogs.com/kenshincui/p/3959951.html 运行效果: 其他图形上下文 前面我们也说过,Quartz 2D的图 ... 
- thinkphp + 美图秀秀api 实现图片裁切上传,带数据库
		思路: 1.数据库 创建test2 创建表img,字段id,url,addtime 2.前台页: 1>我用的是bootstrap 引入必要的js,css 2>引入美图秀秀的js 3.后台: ... 
- 美图秀秀api实现图片的裁剪及美化
		美图秀秀不仅有PC版.手机版等客户端的软件,还有Web开方接口,可以在web页面上调用美图秀秀的api接口,实现图片的编辑.像淘宝.网易.qq空间.新浪微博等大厂都使用过该接口. 官网地址:http: ... 
- 利用Photos 框架搭建美图秀秀相册选择器
		简介:Photos框架是iOS8.0后推出的一个新的用于对系统相册进行相关操作的,在iOS8.0之前,开发中只能使用AssetsLibrary框架来访问移动设备的图片库.本文中不再对AssetsLib ... 
- 强大的Core Image(教你做自己的美图秀秀))
		iOS5新特性:强大的Core Image(教你做自己的美图秀秀)) iOS5给我们带来了很多很好很强大的功能和API.Core Image就是其中之一,它使我们很容易就能处理图片的各种效 ... 
- Qt Quick 图像处理实例之美图秀秀(附源代码下载)
		在<Qt Quick 之 QML 与 C++ 混合编程具体解释>一文中我们解说了 QML 与 C++ 混合编程的方方面面的内容,这次我们通过一个图像处理应用.再来看一下 QML 与 C++ ... 
- PHP流式上传和表单上传(美图秀秀)
		最近需要开发一个头像上传的功能,找了很多都需要授权的,后来找到了美图秀秀,功能非常好用. <?php /** * Note:for octet-stream upload * 这个是流式上传PH ... 
随机推荐
- 在没有界面的类中,实现弹出UIAlertView  ||  在没有界面的类中,刷新程序界面 思路
			+(DisplayErrorMsg *)sharedDisplayErrorMsg { static DisplayErrorMsg *instance = nil; @synchronized(in ... 
- C#Arcengine通过坐标点生成面(环形)
			来自:http://www.cnblogs.com/lee24789229/p/5481978.html 通过传入坐标点,返回几何图形,此代码部分可以生成环形面. 方法一 private IGeome ... 
- Myeclipse反编译插件(jad)的安装和使用
			在开发过程中我们肯定会遇到这样的问题,当我们调试程序的时候,走到一个地方发现引用了一个第三方的东西,点进去一看,会出现一下的画面,没有源代码!!!! 这让人很头疼,今天给大家介绍一个Myeclipse ... 
- Android 项目的代码混淆,Android proguard 使用说明
			简单介绍 Java代码是非常easy反编译的. 为了非常好的保护Java源码,我们往往会对编译好的class文件进行混淆处理. ProGuard是一个混淆代码的开源项目.它的主要作用就是混淆,当然它还 ... 
- 第九章 JVM调优推荐
			说明:本文主要参考自<分布式Java应用:基础与实践> 1.JVM的调优主要是内存的调优,主要调两个方面: 各个代的大小 垃圾收集器选择 2.各个代的大小 常用的调节参数 -Xmx -Xm ... 
- ajax与java前后台传值及数据表查询解决一个bug的问题
			前台选中某些表,确定提交到后台,偶尔会报500错误,通过排查发现:由于后台代码写的不严谨,导致前台选中的表名如果全不存在的话就会导致后台走异常报500错误,所以决定在前台先对数据进行一次过滤,使至少有 ... 
- C++类模板的三种特化
			说起C++的模板及模板特化, 相信很多人都很熟悉 ,但是说到模板特化的几种类型,相信了解的人就不是很多.我这里归纳了针对一个模板参数的类模板特化的几种类型, 一是特化为绝对类型: 二是特化为引用,指针 ... 
- iframe之onload事件小记
			项目上做了一个具有wizard(向导)功能的菜单导航页面,子页面的引入通过主页面上iframe的src属性切换实现.为了有个良好的交互体验,每次更新iframe的src时,主页面上都显示一个模态的lo ... 
- yeoman-angular-gulp
			1.安装 yeoman npm install -g yo gulp bower 2.安装genarate-angular //npm install generator-angular npm in ... 
- UML建模学习1:UML统一建模语言简单介绍
			一什么是UML? Unified Modeling Language(UML又称为统一建模语言或标准建模语言)是国际对象管理组织OMG制定的一个通 用的.可视化建模语言标准.能够用来描写叙述(spec ... 
