iOS实现模糊效果的几种方法

iOS7后,半透明模糊效果得到了广泛的使用,所以iOS开发过程中经常需要用到半透明模糊效果,本文对比列举几种实现半透明模糊效果的方法,包括Core Image、vImage、BlurEffect,第三方库FXBlurView、GPUImage等。

一、苹果原生API

1、Core Image

Core Image 是苹果用来简化图片处理的框架;在 iOS 平台上,5.0 之后就出现了 Core Image 的 API。Core Image 的 API 被放在 CoreImage.framework 库中。不过直到iOS6.0才开始支持模糊。这个API调用起来很方便简洁。

在 iOS 和 OS X 平台上,Core Image 都提供了大量的滤镜(Filter),这也是 Core Image 库中比较核心的东西之一。按照官方文档记载,在 OS X 上有 120 多种 Filter,而在 iOS 上也有 90 多种。

下面是一段 Core Image 做模糊的示例代码:

- (UIImage *)blurryImage:(UIImage *)image withMaskImage:(UIImage *)maskImage blurLevel:(CGFloat)blur {
    
    // 创建属性
    CIImage *ciImage = [[CIImage alloc] initWithImage:image];
    
    // 滤镜效果 高斯模糊
//    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
//    [filter setValue:cimage forKey:kCIInputImageKey];
//    // 指定模糊值 默认为10, 范围为0-100
//    [filter setValue:[NSNumber numberWithFloat:blur] forKey:@"inputRadius"];
    
    /**
     *  滤镜效果 VariableBlur
     *  此滤镜模糊图像具有可变模糊半径。你提供和目标图像相同大小的灰度图像为它指定模糊半径
     *  白色的区域模糊度最高,黑色区域则没有模糊。
     */
    CIFilter *filter = [CIFilter filterWithName:@"CIMaskedVariableBlur"];
    // 指定过滤照片
    [filter setValue:ciImage forKey:kCIInputImageKey];
    CIImage *mask = [CIImage imageWithCGImage:maskImage.CGImage] ;
    // 指定 mask image
    [filter setValue:mask forKey:@"inputMask"];
    // 指定模糊值  默认为10, 范围为0-100
    [filter setValue:[NSNumber numberWithFloat:blur] forKey: @"inputRadius"];
    
    // 生成图片
    CIContext *context = [CIContext contextWithOptions:nil];
    // 创建输出
    CIImage *result = [filter valueForKey:kCIOutputImageKey];
    
    // 下面这一行的代码耗费时间内存最多,可以开辟线程处理然后回调主线程给imageView赋值
    //result.extent 指原来的大小size
//    NSLog(@"%@",NSStringFromCGRect(result.extent));
//    CGImageRef outImage = [context createCGImage: result fromRect: result.extent];
    
    CGImageRef outImage = [context createCGImage: result fromRect:CGRectMake(0, 0, 320.0 * 2, 334.0 * 2)];
    UIImage * blurImage = [UIImage imageWithCGImage:outImage];
    
    return blurImage;
}
coreImage.png

更多的滤镜效果可以参见这个 Filter官方列表

2、vImage

vImage 也是苹果推出的库,在 Accelerate.framework 中。

Accelerate这个framework主要是用来做数字信号处理、图像处理相关的向量、矩阵运算的库。我们可以认为我们的图像都是由向量或者矩阵数据构成的,Accelerate里既然提供了高效的数学运算API,自然就能方便我们对图像做各种各样的处理。

基于vImage我们可以根据图像的处理原理直接做模糊效果,或者使用现有的工具。UIImage+ImageEffects是个很好的图像处理库,看名字也知道是对UIImage做的分类扩展。这个工具被广泛地使用着,后面会做介绍。

下面是一段使用 vImage 实现模糊效果的代码:

// 添加通用模糊效果
// image是图片,blur是模糊度
- (UIImage *)blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur
{
    if (image==nil)
    {
        NSLog(@"error:为图片添加模糊效果时,未能获取原始图片");
        return nil;
    }
    //模糊度,
    if (blur < 0.025f) {
        blur = 0.025f;
    } else if (blur > 1.0f) {
        blur = 1.0f;
    }
    
    //boxSize必须大于0
    int boxSize = (int)(blur * 100);
    boxSize -= (boxSize % 2) + 1;
    NSLog(@"boxSize:%i",boxSize);
    //图像处理
    CGImageRef img = image.CGImage;
    //需要引入#import <Accelerate/Accelerate.h>
    
    //图像缓存,输入缓存,输出缓存
    vImage_Buffer inBuffer, outBuffer;
    vImage_Error error;
    //像素缓存
    void *pixelBuffer;
    
    //数据源提供者,Defines an opaque type that supplies Quartz with data.
    CGDataProviderRef inProvider = CGImageGetDataProvider(img);
    // provider’s data.
    CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
    
    //宽,高,字节/行,data
    inBuffer.width = CGImageGetWidth(img);
    inBuffer.height = CGImageGetHeight(img);
    inBuffer.rowBytes = CGImageGetBytesPerRow(img);
    inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
    
    //像数缓存,字节行*图片高
    pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
    outBuffer.data = pixelBuffer;
    outBuffer.width = CGImageGetWidth(img);
    outBuffer.height = CGImageGetHeight(img);
    outBuffer.rowBytes = CGImageGetBytesPerRow(img);
    // 第三个中间的缓存区,抗锯齿的效果
    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);
    //Convolves a region of interest within an ARGB8888 source image by an implicit M x N kernel that has the effect of a box filter.
    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer2, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    error = vImageBoxConvolve_ARGB8888(&outBuffer2, &inBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    if (error) {
        NSLog(@"error from convolution %ld", error);
    }
    //    NSLog(@"字节组成部分:%zu",CGImageGetBitsPerComponent(img));
    //颜色空间DeviceRGB
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    //用图片创建上下文,CGImageGetBitsPerComponent(img),7,8
    CGContextRef ctx = CGBitmapContextCreate(
                                             outBuffer.data,
                                             outBuffer.width,
                                             outBuffer.height,
                                             8,
                                             outBuffer.rowBytes,
                                             colorSpace,
                                             CGImageGetBitmapInfo(image.CGImage));
    
    //根据上下文,处理过的图片,重新组件
    CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
    UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
    //clean up
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);
    free(pixelBuffer);
    free(pixelBuffer2);
    CFRelease(inBitmapData);
    //CGColorSpaceRelease(colorSpace);   //多余的释放
    CGImageRelease(imageRef);
    return returnImage;
}
vImage.png

3、UIVisualEffectView

UIVisualEffectView只支持iOS 8以后的设备,所以有一定的局限性,但是使用起来非常简单,并且能通过代码或 storyboard 实现模糊效果,下面是一段实现模糊效果的示例代码,其中 effectWithStyle 有 Light、ExtraLight、dark 三种,如下:

UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
effectView.frame = self.view.frame;
[self.view addSubview:effectView];
blurEffect.png

实现中间透明文字效果的代码为:

- (void)configBlurEffect{
    
    // 原始图片 self.imageView
    // 为了更好的看到UIVisualEffectView的即时渲染效果添加平移手势 此处通过 storyBoard 添加
//    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)];
//    [self.imageView addGestureRecognizer:pan];
    
    // 创建模糊View
    UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
    effectView.layer.cornerRadius = 10.0f;
    effectView.layer.masksToBounds = YES;
    effectView.frame = CGRectMake(80, 300, 160, 80);
    [self.view addSubview:effectView];
    
    
    UILabel *label = [[UILabel alloc] initWithFrame:effectView.bounds];
    label.text = @"Blur Effect";
    label.textAlignment = NSTextAlignmentCenter;
    label.font = [UIFont systemFontOfSize:20];
    //    [effectView.contentView addSubview:label];
    // 在创建的模糊View的上面再添加一个子模糊View
    UIVisualEffectView *subEffectView = [[UIVisualEffectView alloc] initWithEffect:[UIVibrancyEffect effectForBlurEffect:(UIBlurEffect *)effectView.effect]];
    
    subEffectView.frame = effectView.bounds;
    
    [effectView.contentView addSubview:subEffectView];
    
    [subEffectView.contentView addSubview:label];
}

- (IBAction)panGesture:(UIPanGestureRecognizer *)sender {
    
    CGPoint point = [sender translationInView:sender.view];
    sender.view.center = CGPointMake(sender.view.center.x + point.x,
                                      sender.view.center.y + point.y);
    [sender setTranslation:CGPointZero inView:sender.view];

}

二、第三方库/工具

1、FXBlurView

FXBlurView 是一个UIView的子类,效果和iOS7的背景实时模糊效果一样,但是支持到了 iOS 5.0。

FXBlurView 有两种模式,一种是 static 静态模糊:也就是只模糊一次,后面即使背景图片变化了,模糊效果也不会变化;另外就是 dynamic 动态模糊:这会实时的对背景图片进行模糊,是会不断变化的。

FXBlurView 的使用非常简单,看一下它的源码就明白了,一个示例代码如下:

FXBlurView *blurView = [[FXBlurView alloc] init];
[blurView setFrame:CGRectMake(40.0, 60.0, 240.0, 240.0)];
[blurView setBackgroundColor:[UIColor whiteColor]];
//设置模式
self.blurView.dynamic = YES;
//设置模糊半径
self.blurView.blurRadius = 10.0;
FXBlurView.png

2、GPUImage

GPUImage 是一个基于GPU图像和视频处理开源的iOS framework,适用面很广。

顺便说一下 GPUImage 的一种使用方法:

  1. 在 github 上 clone 源码
  2. 将它的 framework 整个文件夹拷贝到你的工程文件夹下
  3. 将 framework 下的 GPUImage.xcodeproj 文件拖到你的 Xcode project 中
  4. 到工程的 target 的 Build Phases 界面,添加 GPUImage 到 Target Dependencies
  5. 继续将 libGPUImage.a 添加到Build Phases 界面的 Link Binary With Libraries
  6. Link Binary With Libraries 继续添加 GPUImage 的支持库:
    • CoreMedia
    • CoreVideo
    • OpenGLES
    • AVFoundation
    • QuartzCore
  7. 最后,到工程的 Build Settings 设置 Header Search Paths,搜索 Header Search Paths 后在 Header Search Paths 一栏添加 framework 的头文件路径,不想手动输入可以将 framework 文件夹拖入即可自动生成路径,然后将后面的选项设置为 recursive
  8. 在工程使用 #import "GPUImage.h" 即可开始使用了
HeaderSearchPaths.png

如果要使用 GPUImage 实现高斯模糊,则非常简单,代码如下:

- (UIImage *)blurryGPUImage:(UIImage *)image withBlurLevel:(CGFloat)blur {

    // 高斯模糊
    GPUImageGaussianBlurFilter * blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
    blurFilter.blurRadiusInPixels = blur;
    UIImage *blurredImage = [blurFilter imageByFilteringImage:image];
    
    return blurredImage;
}
GPUImage.png

3、UIImage+ImageEffects

Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur.

摘要:这是UIImage的category,增加方法来对图像进行模糊和着色效果。这就是你想要的如何有效利用 vImage实现模糊效果的代码

UIImage+ImageEffects 的模糊效果非常美观,对 UIImage+ImageEffects 进行修改后可以对图片进行局模糊;

UIImage+ImageEffects 提供了很多方法可以使用,常用的几个方法使用示例如下:

// 通用模糊,默认模糊半径为20.0
self.blurView.image = [[UIImage imageNamed:@"WID-small"] blurImage];
// 局部模糊
self.partBlurView.image = [[UIImage imageNamed:@"WID-small"] blurImageAtFrame:CGRectMake(0.0, 0.0, 155.0*2 , 235.0*4.0)];
// 灰度锐化图
self.grayScaleView.image = [[UIImage imageNamed:@"WID-small"] grayScale];
UIImage+ImageEffects.png

后续若又发现好用的实现模糊效果的方法再更新吧

附上代码的github地址 BlurViewExample

推荐阅读:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Swift版本点击这里欢迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh阅读 25,210评论 7 249
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,943评论 4 60
  • 潜能拼图这一块,是考察人间的这个游戏到底有什么功课要做的… 人间有很多功课,每个人的具体呈现都不同! 搞清楚潜能,...
    建设现代生活阅读 273评论 0 0
  • 我们两家离得不远,他比我大三岁,但并不记得小时候和他有什么交集,他和我哥哥年龄相仿,也并不记得他们曾是玩伴。知道有...
    朝饮木兰之坠露兮Y阅读 155评论 0 0
  • 1. 辞职的第三天夜里,出去跟朋友嗨皮到后半夜。 我都不知道几点回的家,我在距离家里还有一站地的时候,提前下的车。...
    87b2ca3db634阅读 317评论 2 4