浅谈iOS的模糊效果

iOS的模糊效果实现方法有好几种,基本分为两种方式,一种是将图片进行模糊,一种是将模糊的控件放在UI界面上,使控件覆盖的区域达到模糊的效果。每种方式我各选了2种方法,下面介绍一下它们的实现方式以及对比一下它们的优缺点。

coreImage

该方法实现的模糊效果较好,模糊程度的可调范围很大,可以根据实际的需求随意调试。缺点就是耗时,我在模拟器上跑需要1-2秒的时间,所有该方法需要放在子线程中执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dispatch_async(dispatch_get_global_queue(0, 0), ^{
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setValue:ciImage forKey:kCIInputImageKey];
//设置模糊程度
[filter setValue:@30.0f forKey: @"inputRadius"];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGRect frame = [ciImage extent];
NSLog(@"%f,%f,%f,%f",frame.origin.x,frame.origin.y,frame.size.width,frame.size.height);
CGImageRef outImage = [context createCGImage: result fromRect:ciImage.extent];
UIImage * blurImage = [UIImage imageWithCGImage:outImage];
dispatch_async(dispatch_get_main_queue(), ^{
coreImgv.image = blurImage;
});
});

vImage

该方法效率高,但是模糊程度低,而且我在使用它对网络加载的图片进行模糊时,整个图片会变红。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//使用前需要导入头文件
#import <Accelerate/Accelerate.h>
+ (UIImage *)boxblurImage:(UIImage *)image withBlurNumber:(CGFloat)blur {
if (blur < 0.f || blur > 1.f) {
blur = 0.5f;
}
int boxSize = (int)(blur * 40);
boxSize = boxSize - (boxSize % 2) + 1;

CGImageRef img = image.CGImage;

vImage_Buffer inBuffer, outBuffer;
vImage_Error error;

void *pixelBuffer;
//从CGImage中获取数据
CGDataProviderRef inProvider = CGImageGetDataProvider(img);
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
//设置从CGImage获取对象的属性
inBuffer.width = CGImageGetWidth(img);
inBuffer.height = CGImageGetHeight(img);
inBuffer.rowBytes = CGImageGetBytesPerRow(img);

inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);

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);

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,
kCGImageAlphaNoneSkipLast);
CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
UIImage *returnImage = [UIImage imageWithCGImage:imageRef];

//clean up
CGContextRelease(ctx);
CGColorSpaceRelease(colorSpace);

free(pixelBuffer);
CFRelease(inBitmapData);

CGColorSpaceRelease(colorSpace);
CGImageRelease(imageRef);

return returnImage;
}

BlurEffect

BlurEffect是在iOS8之后才出现的,它和toolbar实现的效果基本一样,比toolbar多了一种颜色更深的样式,有一种渐变的效果

1
2
3
4
5
6
7
UIImageView *blurImgv = [[UIImageView alloc]initWithFrame:CGRectMake(50, 500, 150, 150)];
blurImgv.image = image;
[self.view addSubview:blurImgv];
UIBlurEffect *beffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *view = [[UIVisualEffectView alloc]initWithEffect:beffect];
view.frame = blurImgv.frame;
[self.view addSubview:view];

toolbar

近似的全模糊效果,几乎看不清原图了

1
2
3
4
5
6
UIImageView *toolImgv = [[UIImageView alloc]initWithFrame:CGRectMake(210, 500, 150, 150)];
toolImgv.image = image;
[self.view addSubview:toolImgv];
UIToolbar *toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(210, 500, 150, 150)];
toolBar.barStyle = UIBarStyleDefault;
[self.view addSubview:toolBar];

GPUImage

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

大家使用cocoapods安装就可以了。

另外介绍一种手动添加方法:

  • 在 github 上 clone 源码
  • 将它的 framework 整个文件夹拷贝到你的工程文件夹下
  • 将 framework 下的 GPUImage.xcodeproj 文件拖到你的 Xcode project 中
  • 到工程的 target 的 Build Phases 界面,添加 GPUImage 到 Target Dependencies
  • 继续将 libGPUImage.a 添加到Build Phases 界面的 Link Binary With Libraries
  • 在 Link Binary With Libraries 继续添加 GPUImage 的支持库:

    1.CoreMedia
    2.CoreVideo
    3.OpenGLES
    4.AVFoundation
    5.QuartzCore
    
  • 最后,到工程的 Build Settings 设置 Header Search Paths,搜索 Header Search Paths 后在 Header Search Paths 一栏添加 framework 的头文件路径,不想手动输入可以将 framework 文件夹拖入即可自动生成路径,然后将后面的选项设置为recursive

  • 在工程使用 #import “GPUImage.h” 即可开始使用了

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

1
2
3
4
5
6
7
8
9
- (UIImage *)blurryGPUImage:(UIImage *)image withBlurLevel:(CGFloat)blur {

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

return blurredImage;
}

UIImage+ImageEffects

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

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

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

1
2
3
4
5
6
// 通用模糊,默认模糊半径为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];