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 ...
随机推荐
- Arcgis Runtime for andriod 100 加载TPK
private void LoadTPK() { YLPub.pContext = this; String path = YLPub.getMapData() + "/gismap/map ...
- pytest文档15-使用自定义标记mark
前言 pytest可以支持自定义标记,自定义标记可以把一个web项目划分多个模块,然后指定模块名称执行.app自动化的时候,如果想android和ios公用一套代码时, 也可以使用标记功能,标明哪些是 ...
- Selenium2+python自动化34-获取百度输入联想词
前言 最近有小伙伴问百度输入后,输入框下方的联想词如何定位到,这个其实难度不大,用前面所讲的元素定位完全可以定位到的. 本篇以百度输入框输入关键字匹配后,打印出联想词汇. 一.定位输入框联想词 1.首 ...
- 游戏:贪吃虫(GreedyMaggot)
该游戏类似于贪吃蛇,但可以在二维平面上以任意方向前进.当吃到食物手,食物会从虫头向虫尾移动,移到虫尾后,贪吃虫长度会增加.本来给它取名为贪吃蛆的,并且工程的英文名Maggot就是蛆的意思,后来想想有点 ...
- libevent的hello world程序
照着例子写了一个简单的libevent hello world代码: #include <sys/signal.h> #include <event.h> void signa ...
- Informatica 常用组件Expression之一 概述
转换类型:被动.已连接 可以在写入目标前,使用表达式转换计算单行中的值.例如,您可能需要调整员工薪酬.连接姓名或将字符串转换为数字.您可以使用表达式转换执行任意非聚合计算.在将结果输出 ...
- 用于Web开发的8 个最好的跨平台编辑器
1) Best Cross Platform IDE - Brackets Brackets是一个在前端Web开发和设计人员中最流行的开放源码IDE/代码编辑器之一.它拥有一些实用工具能够将HTML ...
- Android之PowerManager&BatteryManager
PowerManager是Android平台中用于管理控制设备电源状态.重启.休眠状态.唤醒等,使用该API会影响到电池的待机时间,所以无非必要,一般不要使用. 在PowerManager中有几个比较 ...
- MongoDB社区版本和企业版本差别
MongoDB社区版本和企业版本差异主要体现在安全认证.系统认证等方面,具体信息参考下表: 版本特性 社区版本 企业版本 JSON数据模型.自由模式 支持 支持 水平扩展的自动分片功能 支持 支持 内 ...
- 整理两个PetaPoco连接SQLite数据库的方法
从https://github.com/qingask/PetaPoco.NetCore下载源文件压缩包 解压出文件PetaPoco.Multiple.cs.PetaPoco.NetCore.cs 放 ...