本文主要内容:
1.用vImage来做实时
高斯模糊
2.遇到的坑
3.爬坑
在iOS7以后,半透明模糊效果在系统中大量使用,不仅在iPhone上,Mac上也随处可见这种效果.在iOS上实现这种效果的方法很多,不同的框架(CoreImage,GPUImage…)和各种扩展(UIVisualEffectView)提供了不同的方式方法.
具体可以查看stackoverflow上这个问题:
http://stackoverflow.com/questions/17041669/creating-a-blurring-overlay-view
用vImage来做实时
高斯模糊
这是http://stackoverflow.com/questions/17041669/creating-a-blurring-overlay-view问题的回答中代码的一点修改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
//#import <Accelerate/Accelerate.h>
-(UIImage *)boxblurImageWithBlur:(CGFloat)blur oImg:(UIImage *)oImg{
if (blur < 0.f || blur > 1.f) {
blur = 0.5f;
}
int boxSize = (int)(blur * 50);
boxSize = boxSize - (boxSize % 2) + 1;
CGImageRef img = oImg.CGImage;
vImage_Buffer inBuffer, outBuffer;
vImage_Error error;
void *pixelBuffer;
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);
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(@"JFDepthView: 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);
CGImageRelease(imageRef);
return returnImage;
}
赶紧搞个本地图片,写个小Demo测试下
demo11
2UIImageView *view1=[[UIImageView alloc]initWithImage:_image1];
_view1.image=[self boxblurImageWithBlur:slider.value oImg:_image1];
效果图:
恩,效果相当不错
然后坑来了,
把本地图上传到图床,然后用SDWebImage下载之后再进行模糊
demo21
2
3
4
5
6[view2 sd_setImageWithURL:[NSURL URLWithString:@"https://img.alicdn.com/imgextra/i3/373400920/TB2KIkfmVXXXXbYXXXXXXXXXXXX_!!373400920.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
_image2=image;
}];
...
_view2.image=[self boxblurImageWithBlur:slider.value oImg:_image2];
效果图:
第一张是本地图,第二张是从网上下载的图
简直,不忍直视….
脱坑
哪有问题?
猜想:是不是下载的文件格式变了,PNG变JPG这种.
用下面的代码来测试
-(NSString )typeForImageData:(NSData )data1
2NSLog(@"image1-%@",[self typeForImageData:UIImagePNGRepresentation(_image1)]);
NSLog(@"image2-%@",[self typeForImageData:UIImagePNGRepresentation(_image2)]);
输出:image1-image/png
image2-image/png
然而格式并没有变
猜想:跟图片的Alpha有关系么.
所以来看看图片中的exif有什么不同吧
用下面的代码
-(void)readExif:(UIImage *)image1
2[self readExif:_image1];
[self readExif:_image2];
从输出的结果中发现
_image2的信息用多了一个字段HasAlpha
貌似图床把图片的Alpha通道打开了
在高斯模糊的方法中CGBitmapContextCreate函数的最后一个参数uint32_t bitmapInfo跟Alpha有点关系,从命名中就可以知道
1 | typedef CF_ENUM(uint32_t, CGImageAlphaInfo) { |
逐对之后一个参数一个个替换测试,当测试到kCGImageAlphaNoneSkipFirst时,
效果是这样的:
有Alpha通道的变成正常的了,本地图片又坑爹了,
反复测试之后:
总结出了这样的结果:
1.如果图片没有Alpha通道,高斯模糊在创建图片的时候(CGBitmapContextCreate()方法),应该设置成kCGImageAlphaNoneSkipLast
2.如果图片有Alpha通道,高斯模糊在创建图片的时候(CGBitmapContextCreate()方法),应该设置成kCGImageAlphaNoneSkipFirst
那么我在blur时候指定bitmapInfo就好了.
(还有一个思路就是直接改UIImage的exif信息,我并没有尝试)
然后写了个UIImage的扩展类
UIImage+Blur
最后效果:
本地图片和远程图片都正常了
项目地址:SampleCode