IOS中模糊效果实现的几种方法(毛玻璃)(转载)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IOS中模糊效果实现的几种方法(毛玻璃)(转载)相关的知识,希望对你有一定的参考价值。
在手机里面经常可以看到模糊效果,比如说控制中心。
那么这种效果怎么去实现的呢,一般有一下几种办法。
1.CoreImage
2.vImage(UIImageView+Effective)
3.GPUImage
4.UIVisualEfftiveView
下面来说说这几种方法的使用方法:
一、CoreImage
1 - (void)test1 { 2 //原始图片 3 UIImage *originImage = [UIImage imageNamed:@"bg1.jpg"]; 4 //创建上下文 5 CIContext *context = [CIContext contextWithOptions:nil]; 6 //将原始图片转换成CIImage 7 CIImage *inputImage = [CIImage imageWithCGImage:originImage.CGImage]; 8 //创建滤镜 9 CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"]; 10 //设置滤镜的属性 11 [filter setValue:inputImage forKey:kCIInputImageKey]; 12 //模糊半径 13 [filter setValue:@10.f forKey:@"inputRadius"]; 14 //输出图片 15 CIImage *outputImage = [filter valueForKey:kCIOutputImageKey]; 16 //转换成CGImage 17 CGImageRef ref = [context createCGImage:outputImage fromRect:[outputImage extent]]; 18 //转换成UIImage 19 UIImage *newImage = [UIImage imageWithCGImage:ref]; 20 //释放 21 CGImageRelease(ref); 22 }
二、vImage
vImage是苹果推出的库,是在Accelerate.framework中
Accelerate这个framework主要是用来做数字信号处理、图像处理相关的向量、矩阵运算的库。我们可以认为我们的图像都是由向量或者矩阵数据构成的,Accelerate里既然提供了高效的数学运算API,自然就能方便我们对图像做各种各样的处理。
基于vImage我们可以根据图像的处理原理直接做模糊效果,或者使用现有的工具。UIImage+ImageEffects是个很好的图像处理库,看名字也知道是对UIImage做的分类扩展。这个工具被广泛地使用着。
1 @import UIKit; 2 3 @interface UIImage (ImageEffects) 4 5 #pragma mark - Blur Image 6 7 /** 8 * Get blured image. 9 * 10 * @return Blured image. 11 */ 12 - (UIImage *)blurImage; 13 14 /** 15 * Get the blured image masked by another image. 16 * 17 * @param maskImage Image used for mask. 18 * 19 * @return the Blured image. 20 */ 21 - (UIImage *)blurImageWithMask:(UIImage *)maskImage; 22 23 /** 24 * Get blured image and you can set the blur radius. 25 * 26 * @param radius Blur radius. 27 * 28 * @return Blured image. 29 */ 30 - (UIImage *)blurImageWithRadius:(CGFloat)radius; 31 32 /** 33 * Get blured image at specified frame. 34 * 35 * @param frame The specified frame that you use to blur. 36 * 37 * @return Blured image. 38 */ 39 - (UIImage *)blurImageAtFrame:(CGRect)frame; 40 41 #pragma mark - Grayscale Image 42 43 /** 44 * Get grayScale image. 45 * 46 * @return GrayScaled image. 47 */ 48 - (UIImage *)grayScale; 49 50 #pragma mark - Some Useful Method 51 52 /** 53 * Scale image with fixed width. 54 * 55 * @param width The fixed width you give. 56 * 57 * @return Scaled image. 58 */ 59 - (UIImage *)scaleWithFixedWidth:(CGFloat)width; 60 61 /** 62 * Scale image with fixed height. 63 * 64 * @param height The fixed height you give. 65 * 66 * @return Scaled image. 67 */ 68 - (UIImage *)scaleWithFixedHeight:(CGFloat)height; 69 70 /** 71 * Get the image average color. 72 * 73 * @return Average color from the image. 74 */ 75 - (UIColor *)averageColor; 76 77 /** 78 * Get cropped image at specified frame. 79 * 80 * @param frame The specified frame that you use to crop. 81 * 82 * @return Cropped image 83 */ 84 - (UIImage *)croppedImageAtFrame:(CGRect)frame; 85 86 @end
1 #import "UIImage+ImageEffects.h" 2 #import <float.h> 3 @import Accelerate; 4 5 @implementation UIImage (ImageEffects) 6 7 8 - (UIImage *)applyLightEffect{ 9 10 UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; 11 return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 12 } 13 14 15 - (UIImage *)applyExtraLightEffect { 16 17 UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; 18 return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 19 } 20 21 22 - (UIImage *)applyDarkEffect { 23 24 UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; 25 return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 26 } 27 28 29 - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor { 30 31 const CGFloat EffectColorAlpha = 0.6; 32 UIColor *effectColor = tintColor; 33 int componentCount = (int)CGColorGetNumberOfComponents(tintColor.CGColor); 34 35 if (componentCount == 2) { 36 37 CGFloat b; 38 if ([tintColor getWhite:&b alpha:NULL]) { 39 40 effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; 41 } 42 43 } else { 44 45 CGFloat r, g, b; 46 if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { 47 48 effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; 49 } 50 } 51 52 return [self applyBlurWithRadius:20 tintColor:effectColor saturationDeltaFactor:1.4 maskImage:nil]; 53 } 54 55 - (UIImage *)blurImage { 56 57 return [self applyBlurWithRadius:20 58 tintColor:[UIColor colorWithWhite:0 alpha:0.0] 59 saturationDeltaFactor:1.4 60 maskImage:nil]; 61 } 62 63 - (UIImage *)blurImageWithRadius:(CGFloat)radius { 64 65 return [self applyBlurWithRadius:radius 66 tintColor:[UIColor colorWithWhite:0 alpha:0.0] 67 saturationDeltaFactor:1.4 68 maskImage:nil]; 69 } 70 71 - (UIImage *)blurImageWithMask:(UIImage *)maskImage { 72 73 return [self applyBlurWithRadius:20 74 tintColor:[UIColor colorWithWhite:0 alpha:0.0] 75 saturationDeltaFactor:1.4 76 maskImage:maskImage]; 77 } 78 79 - (UIImage *)blurImageAtFrame:(CGRect)frame { 80 81 return [self applyBlurWithRadius:20 82 tintColor:[UIColor colorWithWhite:0 alpha:0.0] 83 saturationDeltaFactor:1.4 84 maskImage:nil 85 atFrame:frame]; 86 } 87 88 - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage { 89 90 // Check pre-conditions. 91 if (self.size.width < 1 || self.size.height < 1) { 92 93 NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); 94 return nil; 95 } 96 97 if (!self.CGImage) { 98 99 NSLog (@"*** error: image must be backed by a CGImage: %@", self); 100 return nil; 101 } 102 103 if (maskImage && !maskImage.CGImage) { 104 105 NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage); 106 return nil; 107 } 108 109 CGRect imageRect = { CGPointZero, self.size }; 110 UIImage *effectImage = self; 111 112 BOOL hasBlur = blurRadius > __FLT_EPSILON__; 113 BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; 114 if (hasBlur || hasSaturationChange) { 115 116 UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 117 CGContextRef effectInContext = UIGraphicsGetCurrentContext(); 118 CGContextScaleCTM(effectInContext, 1.0, -1.0); 119 CGContextTranslateCTM(effectInContext, 0, -self.size.height); 120 CGContextDrawImage(effectInContext, imageRect, self.CGImage); 121 122 vImage_Buffer effectInBuffer; 123 effectInBuffer.data = CGBitmapContextGetData(effectInContext); 124 effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); 125 effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); 126 effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); 127 128 UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 129 CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); 130 vImage_Buffer effectOutBuffer; 131 effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); 132 effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); 133 effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); 134 effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); 135 136 if (hasBlur) { 137 138 // A description of how to compute the box kernel width from the Gaussian 139 // radius (aka standard deviation) appears in the SVG spec: 140 // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement 141 // 142 // For larger values of ‘s‘ (s >= 2.0), an approximation can be used: Three 143 // successive box-blurs build a piece-wise quadratic convolution kernel, which 144 // approximates the Gaussian kernel to within roughly 3%. 145 // 146 // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) 147 // 148 // ... if d is odd, use three box-blurs of size ‘d‘, centered on the output pixel. 149 // 150 CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; 151 NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); 152 if (radius % 2 != 1) { 153 154 radius += 1; // force radius to be odd so that the three box-blur methodology works. 155 } 156 157 vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); 158 vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); 159 vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); 160 } 161 162 BOOL effectImageBuffersAreSwapped = NO; 163 if (hasSaturationChange) { 164 165 CGFloat s = saturationDeltaFactor; 166 CGFloat floatingPointSaturationMatrix[] = { 167 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, 168 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, 169 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, 170 0, 0, 0, 1, 171 }; 172 const int32_t divisor = 256; 173 NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); 174 int16_t saturationMatrix[matrixSize]; 175 176 for (NSUInteger i = 0; i < matrixSize; ++i) { 177 178 saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); 179 } 180 181 if (hasBlur) { 182 183 vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 184 effectImageBuffersAreSwapped = YES; 185 186 } else { 187 188 vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 189 } 190 } 191 192 if (!effectImageBuffersAreSwapped) { 193 194 effectImage = UIGraphicsGetImageFromCurrentImageContext(); 195 } 196 197 UIGraphicsEndImageContext(); 198 199 if (effectImageBuffersAreSwapped) { 200 201 effectImage = UIGraphicsGetImageFromCurrentImageContext(); 202 } 203 204 UIGraphicsEndImageContext(); 205 } 206 207 // Set up output context. 208 UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 209 CGContextRef outputContext = UIGraphicsGetCurrentContext(); 210 CGContextScaleCTM(outputContext, 1.0, -1.0); 211 CGContextTranslateCTM(outputContext, 0, -self.size.height); 212 213 // Draw base image. 214 CGContextDrawImage(outputContext, imageRect, self.CGImage); 215 216 // Draw effect image. 217 if (hasBlur) { 218 219 CGContextSaveGState(outputContext); 220 221 if (maskImage) { 222 223 CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); 224 } 225 226 CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); 227 CGContextRestoreGState(outputContext); 228 } 229 230 // Add in color tint. 231 if (tintColor) { 232 233 CGContextSaveGState(outputContext); 234 CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); 235 CGContextFillRect(outputContext, imageRect); 236 CGContextRestoreGState(outputContext); 237 } 238 239 // Output image is ready. 240 UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); 241 UIGraphicsEndImageContext(); 242 243 return outputImage; 244 } 245 246 - (UIImage *)grayScale { 247 248 int width = self.size.width; 249 int height = self.size.height; 250 251 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); 252 253 CGContextRef context = CGBitmapContextCreate(nil, 254 width, 255 height, 256 8, // bits per component 257 0, 258 colorSpace, 259 kCGBitmapByteOrderDefault); 260 261 CGColorSpaceRelease(colorSpace); 262 263 if (context == NULL) { 264 265 return nil; 266 } 267 268 CGContextDrawImage(context, 269 CGRectMake(0, 0, width, height), self.CGImage); 270 CGImageRef image = CGBitmapContextCreateImage(context); 271 UIImage *grayImage = [UIImage imageWithCGImage:image]; 272 CFRelease(image); 273 CGContextRelease(context); 274 275 return grayImage; 276 } 277 278 - (UIImage *)scaleWithFixedWidth:(CGFloat)width { 279 280 float newHeight = self.size.height * (width / self.size.width); 281 CGSize size = CGSizeMake(width, newHeight); 282 UIGraphicsBeginImageContextWithOptions(size, NO, 0); 283 284 CGContextRef context = UIGraphicsGetCurrentContext(); 285 286 CGContextTranslateCTM(context, 0.0, size.height); 287 CGContextScaleCTM(context, 1.0, -1.0); 288 289 CGContextSetBlendMode(context, kCGBlendModeCopy); 290 CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), self.CGImage); 291 292 UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext(); 293 294 UIGraphicsEndImageContext(); 295 296 return imageOut; 297 } 298 299 - (UIImage *)scaleWithFixedHeight:(CGFloat)height { 300 301 float newWidth = self.size.width * (height / self.size.height); 302 CGSize size = CGSizeMake(newWidth, height); 303 304 UIGraphicsBeginImageContextWithOptions(size, NO, 0); 305 306 CGContextRef context = UIGraphicsGetCurrentContext(); 307 308 CGContextTranslateCTM(context, 0.0, size.height); 309 CGContextScaleCTM(context, 1.0, -1.0); 310 311 CGContextSetBlendMode(context, kCGBlendModeCopy); 312 CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), self.CGImage); 313 314 UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext(); 315 316 UIGraphicsEndImageContext(); 317 318 return imageOut; 319 } 320 321 - (UIColor *)averageColor { 322 323 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 324 unsigned char rgba[4]; 325 CGContextRef context = CGBitmapContextCreate(rgba, 1, 1, 8, 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 326 327 CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), self.CGImage); 328 CGColorSpaceRelease(colorSpace); 329 CGContextRelease(context); 330 331 if(rgba[3] > 0) { 332 CGFloat alpha = ((CGFloat)rgba[3])/255.0; 333 CGFloat multiplier = alpha/255.0; 334 return [UIColor colorWithRed:((CGFloat)rgba[0])*multiplier 335 green:((CGFloat)rgba[1])*multiplier 336 blue:((CGFloat)rgba[2])*multiplier 337 alpha:alpha]; 338 } 339 else { 340 return [UIColor colorWithRed:((CGFloat)rgba[0])/255.0 341 green:((CGFloat)rgba[1])/255.0 342 blue:((CGFloat)rgba[2])/255.0 343 alpha:((CGFloat)rgba[3])/255.0]; 344 } 345 } 346 347 - (UIImage *)croppedImageAtFrame:(CGRect)frame { 348 349 frame = CGRectMake(frame.origin.x * self.scale, 350 frame.origin.y * self.scale, 351 frame.size.width * self.scale, 352 frame.size.height * self.scale); 353 354 CGImageRef sourceImageRef = [self CGImage]; 355 CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, frame); 356 UIImage *newImage = [UIImage imageWithCGImage:newImageRef scale:[self scale] orientation:[self imageOrientation]]; 357 CGImageRelease(newImageRef); 358 return newImage; 359 } 360 361 - (UIImage *)addImageToImage:(UIImage *)img atRect:(CGRect)cropRect { 362 363 CGSize size = CGSizeMake(self.size.width, self.size.height); 364 UIGraphicsBeginImageContextWithOptions(size, NO, self.scale); 365 366 CGPoint pointImg1 = CGPointMake(0,0); 367 [self drawAtPoint:pointImg1]; 368 369 CGPoint pointImg2 = cropRect.origin; 370 [img drawAtPoint: pointImg2]; 371 372 UIImage* result = UIGraphicsGetImageFromCurrentImageContext(); 373 UIGraphicsEndImageContext(); 374 375 return result; 376 } 377 378 - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius 379 tintColor:(UIColor *)tintColor 380 saturationDeltaFactor:(CGFloat)saturationDeltaFactor 381 maskImage:(UIImage *)maskImage 382 atFrame:(CGRect)frame 383 { 384 UIImage *blurredFrame = 385 [[self croppedImageAtFrame:frame] applyBlurWithRadius:blurRadius 386 tintColor:tintColor 387 saturationDeltaFactor:saturationDeltaFactor 388 maskImage:maskImage]; 389 390 return [self addImageToImage:blurredFrame atRect:frame]; 391 } 392 393 @end
使用方法很简单,如下所示:
1 - (void)test2 { 2 //原始图片 3 UIImage *originImage = [UIImage imageNamed:@"bg1.jpg"]; 4 //整体模糊 5 UIImage *newImage1 = [originImage blurImage]; 6 //局部模糊 7 UIImage *newImage2 = [originImage blurImageAtFrame:CGRectMake(0, 100, 320, 200)]; 8 //设置模糊半径 9 UIImage *newImage3 = [originImage blurImageWithRadius:10.f]; 10 }
三、GPUImage
GPUImage框架如何导入,我之前的文章有说过了(戳我)。
使用起来也是很简单的:
1 - (void)test3 { 2 //创建滤镜 3 GPUImageGaussianBlurFilter *filter = [[GPUImageGaussianBlurFilter alloc] init]; 4 //设置模糊半径 5 filter.blurRadiusInPixels = 10.f; 6 //原始图片 7 UIImage *image = [UIImage imageNamed:@"bg1.jpg"]; 8 //模糊后的图片 9 UIImage *newImage = [filter imageByFilteringImage:image]; 10 }
四、UIVisualEffectView
注意:这个只能在ios8以上才能使用,并且可以动态的模糊哟~
效果图:
- (void)viewDidLoad { [super viewDidLoad]; //初始化scrollView self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bg1.jpg"]]; [self.scrollVi
以上是关于IOS中模糊效果实现的几种方法(毛玻璃)(转载)的主要内容,如果未能解决你的问题,请参考以下文章
iOS 8 模糊视图(毛玻璃效果)的简单实现UIVisualEffectView
移动端UI设计越来越流行的高斯模糊(Gaussian blur)和毛玻璃效果(磨砂效果),如何使用Android RenderScript简单实现?