iOS 实现高斯模糊的三种方案

1.使用 CoreImage.framework 框架提供的方法

+ (UIImage *)coreBlurImage:(UIImage *)image withBlurNumber:(CGFloat)blur {
    CIContext *context = [CIContext contextWithOptions:nil];
    CIImage *inputImage = [CIImage imageWithCGImage:image.CGImage];
    //设置filter
    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [filter setValue:inputImage forKey:kCIInputImageKey];
    [filter setValue:@(blur) forKey: @"inputRadius"];
    //模糊图片
    CIImage *result = [filter valueForKey:kCIOutputImageKey];
    CGImageRef outImage = [context createCGImage:result fromRect:[result extent]];
    UIImage *blurImage = [UIImage imageWithCGImage:outImage];
    CGImageRelease(outImage);
    return blurImage;
}

2.基于 GPUImage 框架

#import "GPUImage.h"

+ (UIImage *)coreBlurImage:(UIImage *)image withBlurNumber:(CGFloat)blur {

    GPUImageGaussianBlurFilter * blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
    blurFilter.blurRadiusInPixels = blur;
    UIImage *blurredImage = [blurFilter imageByFilteringImage:image];
    return blurredImage;
}

3.基于 Accelerate.framework 框架

#import <Accelerate/Accelerate.h>

+ (UIImage *)coreBlurImage:(UIImage *)image withBlurNumber:(CGFloat)blur {

    if (blur < 0.f || blur > 1.f) {
        blur = 0.5f;
    }
    int boxSize = (int)(blur * 100);
    boxSize = boxSize - (boxSize % 2) + 1;
    CGImageRef img = image.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(@"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); 
    CGColorSpaceRelease(colorSpace); 
    CGImageRelease(imageRef); 
    return returnImage;
}

自己测试这三种方法,最后使用了方法三,方法三的内存占用最小,算上整体的内存占用大约在 90M 左右,滑动列表不卡顿。方案二的 GPUImage 整体内存占用会上升到150+M左右的内存占用。方案一的内存占用达到200M左右的内存占用。