iOS高斯模糊的两种方法
2018-11-21 本文已影响0人
小冰山口
本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含Java
, 数据结构与算法
, iOS
, 安卓
, python
, flutter
等等, 如有需要, 联系微信tsaievan
.
网上有很多类似的文章了, 但还是想自己总结一下.
UIBlurEffect
貌似效果一般, 并不能满足需求, UIBlurEffect
的原理是生成一个模糊的蒙版view
盖在原来的view
上.
而我现在在项目中使用的方法是直接对图片进行高斯模糊
高斯模糊后高斯模糊前
思路就是: 首先把固定区域的view
转换成图片, 然后将图片进行高斯模糊, 盖在原来的view
上.
- 第一步: 将固定区域的
view
转换成图片
+ (UIImage *)tg_makeImageWithView:(UIView *)view withSize:(CGSize)size {
// 下面方法,第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数就是屏幕密度了,关键就是第三个参数 [UIScreen mainScreen].scale。
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
这里我写了一个分类方法: 两个参数, 一个传入想转换成图片的view
, 另一个传想转成图片的size
.
- 第二步, 将图片进行高斯模糊: 有两种方法
- 一种是
vImage
:
- 一种是
+ (UIImage *)tg_blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur {
if(image==nil){
return nil;
}
int boxSize = blur;
if (blur<1||blur>100) {
boxSize=25;
}
boxSize = boxSize - (boxSize % 2) + 1;
CGImageRef img = image.CGImage;
vImage_Buffer inBuffer, outBuffer, rgbOutBuffer;
vImage_Error error;
void *pixelBuffer, *convertBuffer;
CGDataProviderRef inProvider = CGImageGetDataProvider(img);
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
convertBuffer = malloc( CGImageGetBytesPerRow(img) * CGImageGetHeight(img) );
rgbOutBuffer.width = CGImageGetWidth(img);
rgbOutBuffer.height = CGImageGetHeight(img);
rgbOutBuffer.rowBytes = CGImageGetBytesPerRow(img);
rgbOutBuffer.data = convertBuffer;
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);
void *rgbConvertBuffer = malloc( CGImageGetBytesPerRow(img) * CGImageGetHeight(img) );
vImage_Buffer outRGBBuffer;
outRGBBuffer.width = CGImageGetWidth(img);
outRGBBuffer.height = CGImageGetHeight(img);
outRGBBuffer.rowBytes = CGImageGetBytesPerRow(img);//3
outRGBBuffer.data = rgbConvertBuffer;
error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, 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);
}
const uint8_t mask[] = {2, 1, 0, 3};
vImagePermuteChannels_ARGB8888(&outBuffer, &rgbOutBuffer, mask, kvImageNoFlags);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(rgbOutBuffer.data,
rgbOutBuffer.width,
rgbOutBuffer.height,
8,
rgbOutBuffer.rowBytes,
colorSpace,
kCGImageAlphaNoneSkipLast);
CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
//clean up
CGContextRelease(ctx);
free(pixelBuffer);
free(convertBuffer);
free(rgbConvertBuffer);
CFRelease(inBitmapData);
CGColorSpaceRelease(colorSpace);
CGImageRelease(imageRef);
return returnImage;
}
这代码就是我copy过来的, 繁杂的很, 高斯模糊的效果一般.
- 另一种是利用
CGImage
:
+ (UIImage *)tg_blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur {
if (image == nil) {
return nil;
}
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setValue:ciImage forKey:kCIInputImageKey];
//设置模糊程度
[filter setValue:@(blur) forKey: @"inputRadius"];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGImageRef outImage = [context createCGImage: result fromRect:ciImage.extent];
UIImage * blurImage = [UIImage imageWithCGImage:outImage];
CGImageRelease(outImage);
return blurImage;
}
这个代码就简洁的多了, 并且步骤可以理得很清楚:
先将UIImage
转换成CIImage
, 然后设置滤镜, 给滤镜的@"inputRadius"
的值设置value
进行高斯模糊, 将CIImage
转换成UIImage
返回.
- 拿到已经完成高斯模糊的图片盖在原来的
view
上即可.