iOS7后,半透明模糊效果得到了廣泛的使用遗菠,所以iOS開發(fā)過程中經(jīng)常需要用到半透明模糊效果联喘,本文對比列舉幾種實現(xiàn)半透明模糊效果的方法,包括Core Image辙纬、vImage豁遭、BlurEffect,第三方庫FXBlurView贺拣、GPUImage等蓖谢。
一捂蕴、蘋果原生API
1、Core Image
Core Image
是蘋果用來簡化圖片處理的框架闪幽;在 iOS 平臺上啥辨,5.0 之后就出現(xiàn)了 Core Image
的 API。Core Image
的 API 被放在 CoreImage.framework
庫中盯腌。不過直到iOS6.0才開始支持模糊委可。這個API調(diào)用起來很方便簡潔。
在 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 {
// 創(chuàng)建屬性
CIImage *ciImage = [[CIImage alloc] initWithImage:image];
// 濾鏡效果 高斯模糊
// CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
// [filter setValue:cimage forKey:kCIInputImageKey];
// // 指定模糊值 默認(rèn)為10, 范圍為0-100
// [filter setValue:[NSNumber numberWithFloat:blur] forKey:@"inputRadius"];
/**
* 濾鏡效果 VariableBlur
* 此濾鏡模糊圖像具有可變模糊半徑客们。你提供和目標(biāo)圖像相同大小的灰度圖像為它指定模糊半徑
* 白色的區(qū)域模糊度最高,黑色區(qū)域則沒有模糊材诽。
*/
CIFilter *filter = [CIFilter filterWithName:@"CIMaskedVariableBlur"];
// 指定過濾照片
[filter setValue:ciImage forKey:kCIInputImageKey];
CIImage *mask = [CIImage imageWithCGImage:maskImage.CGImage] ;
// 指定 mask image
[filter setValue:mask forKey:@"inputMask"];
// 指定模糊值 默認(rèn)為10, 范圍為0-100
[filter setValue:[NSNumber numberWithFloat:blur] forKey: @"inputRadius"];
// 生成圖片
CIContext *context = [CIContext contextWithOptions:nil];
// 創(chuàng)建輸出
CIImage *result = [filter valueForKey:kCIOutputImageKey];
// 下面這一行的代碼耗費(fèi)時間內(nèi)存最多,可以開辟線程處理然后回調(diào)主線程給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;
}
更多的濾鏡效果可以參見這個 Filter官方列表
2底挫、vImage
vImage 也是蘋果推出的庫,在 Accelerate.framework 中脸侥。
Accelerate這個framework主要是用來做數(shù)字信號處理建邓、圖像處理相關(guān)的向量、矩陣運(yùn)算的庫睁枕。我們可以認(rèn)為我們的圖像都是由向量或者矩陣數(shù)據(jù)構(gòu)成的官边,Accelerate里既然提供了高效的數(shù)學(xué)運(yùn)算API,自然就能方便我們對圖像做各種各樣的處理外遇。
基于vImage我們可以根據(jù)圖像的處理原理直接做模糊效果注簿,或者使用現(xiàn)有的工具。UIImage+ImageEffects是個很好的圖像處理庫跳仿,看名字也知道是對UIImage做的分類擴(kuò)展诡渴。這個工具被廣泛地使用著,后面會做介紹菲语。
下面是一段使用 vImage 實現(xiàn)模糊效果的代碼:
// 添加通用模糊效果
// 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;
//數(shù)據(jù)源提供者恩袱,Defines an opaque type that supplies Quartz with data.
CGDataProviderRef inProvider = CGImageGetDataProvider(img);
// provider’s data.
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
//寬,高胶哲,字節(jié)/行畔塔,data
inBuffer.width = CGImageGetWidth(img);
inBuffer.height = CGImageGetHeight(img);
inBuffer.rowBytes = CGImageGetBytesPerRow(img);
inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
//像數(shù)緩存,字節(jié)行*圖片高
pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
outBuffer.data = pixelBuffer;
outBuffer.width = CGImageGetWidth(img);
outBuffer.height = CGImageGetHeight(img);
outBuffer.rowBytes = CGImageGetBytesPerRow(img);
// 第三個中間的緩存區(qū),抗鋸齒的效果
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(@"字節(jié)組成部分:%zu",CGImageGetBitsPerComponent(img));
//顏色空間DeviceRGB
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//用圖片創(chuàng)建上下文,CGImageGetBitsPerComponent(img),7,8
CGContextRef ctx = CGBitmapContextCreate(
outBuffer.data,
outBuffer.width,
outBuffer.height,
8,
outBuffer.rowBytes,
colorSpace,
CGImageGetBitmapInfo(image.CGImage));
//根據(jù)上下文,處理過的圖片澈吨,重新組件
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;
}
3把敢、UIVisualEffectView
UIVisualEffectView只支持iOS 8以后的設(shè)備,所以有一定的局限性谅辣,但是使用起來非常簡單修赞,并且能通過代碼或 storyboard 實現(xiàn)模糊效果,下面是一段實現(xiàn)模糊效果的示例代碼桑阶,其中 effectWithStyle 有 Light柏副、ExtraLight、dark 三種蚣录,如下:
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
effectView.frame = self.view.frame;
[self.view addSubview:effectView];
實現(xiàn)中間透明文字效果的代碼為:
- (void)configBlurEffect{
// 原始圖片 self.imageView
// 為了更好的看到UIVisualEffectView的即時渲染效果添加平移手勢 此處通過 storyBoard 添加
// UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)];
// [self.imageView addGestureRecognizer:pan];
// 創(chuàng)建模糊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];
// 在創(chuàng)建的模糊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
靜態(tài)模糊:也就是只模糊一次玛歌,后面即使背景圖片變化了,模糊效果也不會變化擎椰;另外就是 dynamic
動態(tài)模糊:這會實時的對背景圖片進(jìn)行模糊支子,是會不斷變化的。
FXBlurView 的使用非常簡單达舒,看一下它的源碼就明白了译荞,一個示例代碼如下:
FXBlurView *blurView = [[FXBlurView alloc] init];
[blurView setFrame:CGRectMake(40.0, 60.0, 240.0, 240.0)];
[blurView setBackgroundColor:[UIColor whiteColor]];
//設(shè)置模式
self.blurView.dynamic = YES;
//設(shè)置模糊半徑
self.blurView.blurRadius = 10.0;
2、GPUImage
GPUImage 是一個基于GPU圖像和視頻處理開源的iOS framework休弃,適用面很廣吞歼。
順便說一下 GPUImage 的一種使用方法:
- 在 github 上 clone 源碼
- 將它的 framework 整個文件夾拷貝到你的工程文件夾下
- 將 framework 下的
GPUImage.xcodeproj
文件拖到你的 Xcode project 中 - 到工程的 target 的
Build Phases
界面,添加 GPUImage 到Target Dependencies
- 繼續(xù)將 libGPUImage.a 添加到Build Phases 界面的
Link Binary With Libraries
- 在
Link Binary With Libraries
繼續(xù)添加 GPUImage 的支持庫:- CoreMedia
- CoreVideo
- OpenGLES
- AVFoundation
- QuartzCore
- 最后塔猾,到工程的
Build Settings
設(shè)置Header Search Paths
篙骡,搜索 Header Search Paths 后在Header Search Paths
一欄添加 framework 的頭文件路徑,不想手動輸入可以將 framework 文件夾拖入即可自動生成路徑丈甸,然后將后面的選項設(shè)置為 recursive - 在工程使用
#import "GPUImage.h"
即可開始使用了
如果要使用 GPUImage 實現(xiàn)高斯模糊糯俗,則非常簡單,代碼如下:
- (UIImage *)blurryGPUImage:(UIImage *)image withBlurLevel:(CGFloat)blur {
// 高斯模糊
GPUImageGaussianBlurFilter * blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
blurFilter.blurRadiusInPixels = blur;
UIImage *blurredImage = [blurFilter imageByFilteringImage:image];
return blurredImage;
}
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得湘,增加方法來對圖像進(jìn)行模糊和著色效果。這就是你想要的如何有效利用 vImage實現(xiàn)模糊效果的代碼
UIImage+ImageEffects
的模糊效果非常美觀顿仇,對 UIImage+ImageEffects
進(jìn)行修改后可以對圖片進(jìn)行局模糊;
UIImage+ImageEffects
提供了很多方法可以使用淘正,常用的幾個方法使用示例如下:
// 通用模糊摆马,默認(rèn)模糊半徑為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];
后續(xù)若又發(fā)現(xiàn)好用的實現(xiàn)模糊效果的方法再更新吧
附上代碼的github地址 BlurViewExample
推薦閱讀: