Android上如何做出毛玻璃模糊的效果?
上图展示了一种很典型的视觉效果——文字的背景不再是固定的,而是将底层的相应区域模糊化,好似盖了一层毛玻璃。
其原理也很简单,分为三步走:
里面涉及到的技术点有两个:
ViewTreeObserver里面有一个监听器为OnPreDrawListener
当它执行时,布局文件经过了 measured 、 laid out 、 displayed ,即将被绘制到屏幕,此时调用它的 getDrawingCache() 方法可以获得其Bitmap。完整方法如下:
方案有两种:
两种方案都可以进行对Bitmap对象的模糊处理,但当模糊半径增大时,StackBlur能够保持较好的性能,且不受Renderscript半径25px的限制。
在GitHub项目有一个项目 blurring ,其实现了StackBlur算法的Java实现版FastBlur,并给出两种方案效率对比demo。经过测试,
看起来,Renderscript的性能更好,应该是Android上对Renderscript做了优化。尽管如此,考虑到Android中渲染一帧的时间应该不超过16ms(60fps),这样的性能并不友好。 blurring 作者想出了另外一种思路:
这时候,效率提升非常明显:
生成的模糊图片当然有所不同,但是都是模糊背景,所以对用户而言没有太大差别。
好了,至此Android上制作毛玻璃背景模糊效果的技术都确定了。
我在 blurring 基础上做了封装,接口如下:
相对应类有两个:
如何通过 HTML5 实现 iOS 7 的实时毛玻璃模糊效果
要想通过HTML5实现IOS7的毛玻璃模糊效果需要用代码来执行
//加模糊效果,image是图片,blur是模糊度
– (UIImage *)blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur {
//模糊度,
if ((blur 0.1f) || (blur 2.0f)) {
blur = 0.5f;
}
//boxSize必须大于0
int boxSize = (int)(blur * 100);
boxSize -= (boxSize % 2) + 1;
NSLog(@”boxSize:%i”,boxSize);
//图像处理
CGImageRef img = image.CGImage;
//需要引入#import Accelerate/Accelerate.h
/*
This document describes the Accelerate Framework, which contains C APIs for vector and matrix math, digital signal processing, large number handling, and image processing.
本文档介绍了Accelerate Framework,其中包含C语言应用程序接口(API)的向量和矩阵数学,数字信号处理,大量处理和图像处理。
*/
//图像缓存,输入缓存,输出缓存
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;
}
这里要注意的是以上的代码会有崩溃的情况
崩溃log:Assertion failed: (!space-is_singleton), function color_space_dealloc, file ColorSpaces/color-space
可以用如下方式来实现
– (UIImage *)applyBlurRadius:(CGFloat)radius toImage:(UIImage *)image
{
if (radius 0) radius = 0;
CIContext *context = [CIContextcontextWithOptions:nil];
CIImage *inputImage = [CIImageimageWithCGImage:image.CGImage];
// Setting up gaussian blur
CIFilter *filter = [CIFilterfilterWithName:@”CIGaussianBlur”];
[filter setValue:inputImageforKey:kCIInputImageKey];
[filter setValue:[NSNumbernumberWithFloat:radius] forKey:@”inputRadius”];
CIImage *result = [filtervalueForKey:kCIOutputImageKey];
CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];
UIImage *returnImage = [UIImageimageWithCGImage:cgImage];
CGImageRelease(cgImage);
return returnImage;
}
如何在 iPhone 中实现图片的毛玻璃效果
如何通过 ToolBar 模拟出图片的毛玻璃效果。首先我们新建一个工程,工程模板切换到 iOS ,选择 Single View Application ,如下图所示:
点击 Next ,命名任意,Language 选择 Objective-C,如下图所示:
输入完工程名之后,继续点击 Next ,选择一个在你 Mac 上用于存储工程文件的目录完成即可,工程建立好之后开始我们今天的代码之旅。
既然需要模拟图片的毛玻璃效果,我们首先当然就需要一张图片,我这里用了一张周杰伦第一张专辑的封面作为本节内容的图片素材,图片如下:
接下来,将这张图片拖动到刚才建立好的工程文件的文件夹 Assets.xcassets 中,如下图所示:
现在点击左侧文件列表选择 ViewController.m 文件,这时候会在文件列表右侧代码区域显示相关代码,接下来我们书写代码,完成我们今天想要达到的效果。
需要注意的是,以下代码我们需要写在 viewDidLoad 方法中,OK,开始。
第一步,我们首先对图片进行处理,将图片添加进 iPhone 界面,并全屏显示。相关代码如下:
创建 UIImageView 对象用于存储图片,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”UIImageView *imageView = span style=”color:#999988; font-style:italic”[span style=””[UIImageView alloc]/spaninit]/span;/code/pre
设置图片尺寸占据整个屏幕,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”imageView.frame = span style=”font-weight:700″self/span.view.bounds;/code/pre
指定待显示图片资源,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”imageView.image = [UIImage span style=”color:#dd1144″imageNamed:/span@span style=”color:#dd1144″”Jay.jpg”/span];/code/pre
设置图片显示模式,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”imageView.contentMode = UIViewContentModeScaleToFillspan style=”color:#999988; font-style:italic”;/span/code/pre
在 iPhone 上显示 image 图片,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”span style=”color:#9900; font-weight:700″[self.view addSubview:imageView]/spanspan style=”color:#999988; font-style:italic”;/span/code/pre
先来看一下现在效果如何,运行模拟器,效果如下:
这样我们就将这张图片添加到了 iPhone ,并进行了全屏显示,由于图片比例和 iPhone 比例不一致,所以这里略显比例失衡,大家可以找一张比例一致的图片进行测试,接下来我们看下一步如何制作毛玻璃效果 。
第二步,制作毛玻璃效果,这里我们利用 ToolBar 覆盖在图片上来模拟毛玻璃的效果,具体操作方法就是先建立一个 ToolBar 对象,然后设置它的尺寸和图片尺寸一致,即设置为屏幕尺寸,然后覆盖在图片上即可,相关操作代码如下。
创建 ToolBar 对象,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”UIToolbar *toolBar = span style=”color:#999988; font-style:italic”[span style=””[UIToolbar alloc]/spaninit]/span;/code/pre
设置 ToolBar 尺寸和图片尺寸一致,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”toolBar.frame = imageView.boundsspan style=”color:#999988; font-style:italic”;/span/code/pre
设置毛玻璃效果,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”toolBar.barStyle = UIBarStyleBlackspan style=”color:#999988; font-style:italic”;/span/code/pre
将 toolBar 添加到图片上覆盖图片,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”span style=”color:#9900; font-weight:700″[imageView addSubview:toolBar]/spanspan style=”color:#999988; font-style:italic”;/span/code/pre
运行模拟器,效果如下:
这是黑色的毛玻璃效果,关于毛玻璃还有一种默认的白色效果,只需将毛玻璃效果设置代码修改为如下代码即可:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”toolBar.barStyle = UIBarStyleDefaultspan style=”color:#999988; font-style:italic”;/span/code/pre
运行模拟器,效果如下:
但个人觉得黑色要更加好看一些,所以这里我使用黑色,我将设置代码还原为黑色效果。
现在,图片已经出现了毛玻璃效果,比较模糊,如果这时候我们在毛玻璃上写字,那么这个字一定会异常清晰,要不要试试看,OK,我们来继续在毛玻璃上面写点字看一下效果,我们就在图片下方写上这张专辑的名字吧。
第三步,添加文字,相关代码如下。
创建 Label 对象,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”UILabel *label = span style=”color:#999988; font-style:italic”[span style=””[UILabel alloc]/spaninit]/span;/code/pre
设置文字显示位置,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”label.frame = CGRectMake(self.view.frame.size.width/span style=”color:teal”2/span-span style=”color:teal”50/span, self.view.frame.size.height/span style=”color:teal”2/span+span style=”color:teal”150/span, span style=”color:teal”100/span, span style=”color:teal”100/span);/code/pre
设置文字显示颜色为白色,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”label.textColor = span style=”color:#dd1144″[UIColor whiteColor]/span;/code/pre
设置文字居中对齐,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”span style=”font-weight:700″label/span.textAlignment = NSTextAlignmentCenter;/code/pre
设置文字显示内容,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”label.span style=”color:#445588; font-weight:700″text/span = @span style=”color:#dd1144″”Jay”/span;/code/pre
将文字添加到 toolBar 上进行显示,代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”span style=”color:#9900; font-weight:700″[toolBar addSubview:label]/spanspan style=”color:#999988; font-style:italic”;/span/code/pre
运行模拟器,效果如下:
至此,全部代码写完,完成今天毛玻璃效果图片的效果演示,完整代码如下:
pre style=”font-size:11.899999618530273px; line-height:1.45; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-wrap:normal; padding:16px; overflow:auto; background-color:rgb(247,247,247); color:rgb(51,51,51); margin-top:0px!important; margin-bottom:0px!important”code style=”display:inline; overflow:visible; background-color:transparent; font-family:Consolas,’Liberation Mono’,Menlo,Courier,monospace; word-break:normal; border:0px; line-height:inherit; word-wrap:normal”- (span style=”font-weight:700″void/span)viewDidLoad { nbsp; nbsp;[span style=”font-weight:700″super/span viewDidLoad]; nbsp; nbsp; nbsp; nbsp;span style=”color:#999988; font-style:italic”// 第一步:对图片进行处理/span nbsp; nbsp;span style=”color:#086b3″UIImageView/span *imageView = [[span style=”color:#086b3″UIImageView/span alloc]init]; nbsp; nbsp;imageViewspan style=”color:teal”.frame/span = span style=”font-weight:700″self/spanspan style=”color:teal”.view/spanspan style=”color:teal”.bounds/span; nbsp; nbsp;imageViewspan style=”color:teal”.image/span = [span style=”color:#086b3″UIImage/span imageNamed:span style=”color:#dd1144″@”Jay.jpg”/span]; nbsp; nbsp;imageViewspan style=”color:teal”.contentMode/span = span style=”color:#086b3″UIViewContentModeScaleToFill/span; nbsp; nbsp; nbsp; nbsp;span style=”color:#999988; font-style:italic”// 第二步:制作毛玻璃/span nbsp; nbsp;span style=”color:#086b3″UIToolbar/span *toolBar = [[span style=”color:#086b3″UIToolbar/span alloc]init]; nbsp; nbsp;toolBarspan style=”color:teal”.frame/span = imageViewspan style=”color:teal”.bounds/span; nbsp; nbsp;toolBarspan style=”color:teal”.barStyle/span = span style=”color:#086b3″UIBarStyleBlack/span; nbsp; nbsp;[imageView addSubview:toolBar]; nbsp; nbsp; nbsp; nbsp;span style=”color:#999988; font-style:italic”// 第三步:添加文字/span nbsp; nbsp;span style=”color:#086b3″UILabel/span *label = [[span style=”color:#086b3″UILabel/span alloc]init]; nbsp; nbsp;labelspan style=”color:teal”.frame/span = span style=”color:#086b3″CGRectMake/span(span style=”font-weight:700″self/spanspan style=”color:teal”.view/spanspan style=”color:teal”.frame/spanspan style=”color:teal”.size/spanspan style=”color:teal”.width/span/span style=”color:teal”2/span-span style=”color:teal”50/span, span style=”font-weight:700″self/spanspan style=”color:teal”.view/spanspan style=”color:teal”.frame/spanspan style=”color:teal”.size/spanspan style=”color:teal”.height/span/span style=”color:teal”2/span+span style=”color:teal”150/span, span style=”color:teal”100/span, span style=”color:teal”100/span); nbsp; nbsp;labelspan style=”color:teal”.textColor/span = [span style=”color:#086b3″UIColor/span whiteColor]; nbsp; nbsp;labelspan style=”color:teal”.textAlignment/span = span style=”color:#086b3″NSTextAlignmentCenter/span; nbsp; nbsp;labelspan style=”color:teal”.text/span = span style=”color:#dd1144″@”Jay”/span; nbsp; nbsp;[toolBar addSubview:label]; nbsp; nbsp; nbsp; nbsp;[span style=”font-weight:700″self/spanspan style=”color:teal”.view/span addSubview:imageView]; }/code/pre