• 首页
  • 关于
    • zerone-z photo

      zerone-z

      记录下自己学习的过程、点滴,也为了分享自己的收获。

    • Learn More
    • Email
    • Github
  • 博客
    • 博客
    • 标签
  • 随笔
  • 项目

iOS实现模糊效果的几种方案

13 Oct 2017

Reading time ~2 minutes

Core Image

Core Image是苹果用来简化图片处理的框架,在iOS6.0才开始支持模糊。

func blurImage(_ image: UIImage, blurLevel:CGFloat) -> UIImage {
    // 创建属性
    let ciImage = CIImage(image: image);
    
    // 滤镜效果 高斯模糊
    let filter = CIFilter(name: "CIGaussianBlur");
    filter?.setValue(ciImage, forKey: kCIInputImageKey);
    // 指定模糊值 默认为10, 范围为0-100
    filter?.setValue(blurLevel, forKey: kCIInputRadiusKey);
    
    // 生成图片
    let context = CIContext(options: nil);
    // 创建输出
    let result = filter?.value(forKey: kCIOutputImageKey) as! CIImage;
    
    // 下面这一行的代码耗费时间内存最多,可以开辟线程处理然后回调主线程给imageView赋值
    // result.extent 指原来的大小size
    let outImage = context.createCGImage(result, from: result.extent);
    
    let blurImage = UIImage(cgImage: outImage!);
    
    return blurImage;
}

vImage

vImage也是苹果推出的库,在Accelerate.framework中。

func blurImage(_ image: UIImage, blurLevel:CGFloat) -> UIImage? {
    //需要引入import Accelerate
    
    //模糊度
    var blur = blurLevel;
    if (blur < 0.025) {
        blur = 0.025;
    } else if (blur > 1.0) {
        blur = 1.0;
    }
    
    //boxSize必须大于0
    var boxSize = Int(blur * 100);
    boxSize -= (boxSize % 2) + 1;
    
    //图像处理
    let cgImage = image.cgImage!;
    
    //图像缓存,输入缓存,输出缓存
    var inBuffer = vImage_Buffer();
    var outBuffer = vImage_Buffer();
    
    //数据源提供者,Defines an opaque type that supplies Quartz with data.
    var inProvider = cgImage.dataProvider;
    let inBitmapData = inProvider?.data;
    
    //宽,高,字节/行,data
    inBuffer.width = vImagePixelCount(cgImage.width);
    inBuffer.height = vImagePixelCount(cgImage.height);
    inBuffer.rowBytes = cgImage.bytesPerRow;
    inBuffer.data = UnsafeMutableRawPointer(mutating: CFDataGetBytePtr(inBitmapData!));
    
    //像数缓存,字节行*图片高
    let pixelBuffer = malloc(cgImage.bytesPerRow * cgImage.height);
    outBuffer.data = pixelBuffer;
    outBuffer.width = vImagePixelCount(cgImage.width);
    outBuffer.height = vImagePixelCount(cgImage.height);
    outBuffer.rowBytes = cgImage.bytesPerRow;
    // 第三个中间的缓存区,抗锯齿的效果
    let pixelBuffer2 = malloc(cgImage.bytesPerRow * cgImage.height);
    var outBuffer2 = vImage_Buffer();
    outBuffer2.data = pixelBuffer2;
    outBuffer2.width = vImagePixelCount(cgImage.width);
    outBuffer2.height = vImagePixelCount(cgImage.height)
    outBuffer2.rowBytes = cgImage.bytesPerRow;
    //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.
    var error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer2, nil, vImagePixelCount(0), vImagePixelCount(0), UInt32(boxSize), UInt32(boxSize), nil, vImage_Flags(kvImageEdgeExtend));
    if (error != kvImageNoError) {
        return nil;
    }
    error = vImageBoxConvolve_ARGB8888(&outBuffer2, &inBuffer, nil, vImagePixelCount(0), vImagePixelCount(0), UInt32(boxSize), UInt32(boxSize), nil, vImage_Flags(kvImageEdgeExtend));
    if (error != kvImageNoError) {
        return nil;
    }
    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, vImagePixelCount(0), vImagePixelCount(0), UInt32(boxSize), UInt32(boxSize), nil, vImage_Flags(kvImageEdgeExtend));
    
    if (error != kvImageNoError) {
        return nil;
    }
    
    //颜色空间DeviceRGB
    let colorSpace = CGColorSpaceCreateDeviceRGB();
    //用图片创建上下文,CGImageGetBitsPerComponent(img),7,8
    let ctx = CGContext(
        data: outBuffer.data,
        width: Int(outBuffer.width),
        height: Int(outBuffer.height),
        bitsPerComponent: 8,
        bytesPerRow: outBuffer.rowBytes,
        space: colorSpace,
        bitmapInfo: cgImage.bitmapInfo.rawValue);
    
    //根据上下文,处理过的图片,重新组件
    let imageRef = ctx?.makeImage();
    let returnImage = UIImage(cgImage: imageRef!);
    //clean up
    free(pixelBuffer);
    free(pixelBuffer2);
    
    return returnImage;
}

UIVisualEffectView

UIVisualEffectView是iOS8.0以后苹果才提供的方法,且不能修改模糊半径,有一定的局限性,但是使用简单。

let blurEffect = UIBlurEffect(style: .light);
let effectView = UIVisualEffectView(effect: blurEffect);
effectView.frame = imageView.frame;
self.view.addSubview(effectView);

第三方工具/库推荐

FXBlurView

FXBlurView是一个UIView的子类,效果和iOS7的背景实时模糊效果一样。FXBlurView 有两种模式,一种是 static 静态模糊:也就是只模糊一次,后面即使背景图片变化了,模糊效果也不会变化;另外就是 dynamic 动态模糊:这会实时的对背景图片进行模糊,是会不断变化的。

GPUImage

GPUImage 是一个基于GPU图像和视频处理开源的iOS framework,适用面很广。

UIImageEffects

UIImageEffects苹果官方提供的利用vImage实现的模糊处理。