在 iOS7 中创建模糊效果

Posted

技术标签:

【中文标题】在 iOS7 中创建模糊效果【英文标题】:Creating a blur effect in iOS7 【发布时间】:2013-10-17 16:55:19 【问题描述】:

几个小时后,我一直在寻找这个问题的答案,但我就是想不通。当我按下按钮“按钮”时,我想为图像添加高斯模糊效果。用户是添加图像的人。

我根据来自 SO 和网络上其他地方的来源为“按钮”创建了一个操作。不起作用。我究竟做错了什么?任何代码将不胜感激。这是我的“按钮”操作:

- (IBAction)test:(id)sender 
    CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"];
    [gaussianBlurFilter setValue:imageView.image forKey: @"inputImage"];
    [gaussianBlurFilter setValue:[NSNumber numberWithFloat: 10] forKey: @"inputRadius"];

如果您需要我为回答问题所做的任何其他事情,请告诉我:D

【问题讨论】:

【参考方案1】:

三个观察:

    您需要将inputImage 设置为UIImage 中的CIImage

    [gaussianBlurFilter setValue:[CIImage imageWithCGImage:[imageView.image CGImage]] forKey:kCIInputImageKey];
    

    我没有看到你在抢outputImage,例如:

    CIImage *outputImage = [gaussianBlurFilter outputImage];
    

    您大概想将 CIImage 转换回 UIImage

所以,把所有这些放在一起:

CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
[gaussianBlurFilter setDefaults];
CIImage *inputImage = [CIImage imageWithCGImage:[imageView.image CGImage]];
[gaussianBlurFilter setValue:inputImage forKey:kCIInputImageKey];
[gaussianBlurFilter setValue:@10 forKey:kCIInputRadiusKey];

CIImage *outputImage = [gaussianBlurFilter outputImage];
CIContext *context   = [CIContext contextWithOptions:nil];
CGImageRef cgimg     = [context createCGImage:outputImage fromRect:[inputImage extent]];  // note, use input image extent if you want it the same size, the output image extent is larger
UIImage *image       = [UIImage imageWithCGImage:cgimg];
CGImageRelease(cgimg);

或者,如果您转到WWDC 2013 sample code(需要付费开发者订阅)并下载ios_UIImageEffects,则可以获取UIImage+ImageEffects 类别。这提供了一些新方法:

- (UIImage *)applyLightEffect;
- (UIImage *)applyExtraLightEffect;
- (UIImage *)applyDarkEffect;
- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;
- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage;

因此,要模糊和成像并使其变亮(给出“毛玻璃”效果),您可以这样做:

UIImage *newImage = [image applyLightEffect];

有趣的是,Apple 的代码使用CIFilter,而是调用vImage high-performance image processing framework 中的vImageBoxConvolve_ARGB8888

这项技术在 WWDC 2013 视频Implementing Engaging UI on iOS 中有说明。


我知道问题是关于 iOS 7,但现在在 iOS 8 中,可以使用 UIBlurEffect 为任何 UIView 对象添加模糊效果:

UIVisualEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];    
effectView.frame = imageView.bounds;
[imageView addSubview:effectView];

【讨论】:

可以说我在 ibaction 中没有任何代码,我会在 ibaction 中写什么?这是你写的最后一段代码吗?顺便说一句,感谢您的精彩回复,很抱歉没有这么多理解:D 我收到一条警告“未使用的变量图像”,这是代码的倒数第二行 @user2891448 我不确定你想用image 做什么。也许更新imageView.image = image; 最后一件事,我想用一个变量设置模糊量的值,我该怎么做?这是在 [gaussianBlurFilter setValue:@10 forKey:kCIInputRadiusKey]; @user2891448 假设你有一些名为CGFloat 的变量radius,那么你会做[gaussianBlurFilter setValue:@(radius) forKey:kCIInputRadiusKey];【参考方案2】:

这对我有用,但是速度很慢。我将在应用程序加载时进行转换,并在许多地方使用转换后的图像。

此模糊效果适用于 iOS 8.4。 Swift 语言。

override func viewDidLoad()

    super.viewDidLoad()

    var backgroundImage = self.blurImage(UIImage(named: "background.jpg")!)

    self.view.backgroundColor = UIColor(patternImage:backgroundImage)


func blurImage(imageToBlur:UIImage) -> UIImage

    var gaussianBlurFilter = CIFilter(name: "CIGaussianBlur")
    gaussianBlurFilter.setValue(CIImage(CGImage: imageToBlur.CGImage), forKey:kCIInputImageKey)

    var inputImage = CIImage(CGImage: imageToBlur.CGImage)

    var outputImage = gaussianBlurFilter.outputImage
    var context = CIContext(options: nil)
    var cgimg = context.createCGImage(outputImage, fromRect: inputImage.extent())

    return UIImage(CGImage: cgimg)!

【讨论】:

这很有趣.. 但也很慢.. :/ 至少在 Apple TV 上 是的,它很慢:/。您可以进行“按需”模糊,这可能会有所帮助,或者如果您在应用程序中有一些加载,则调用 blurImage 函数。在某些时候我保存了模糊的图像,所以当我需要它们时,我可以从内存或其他地方加载它们,而不是再次调用该函数。希望这对您有所帮助或指出正确的方向:)))【参考方案3】:

CIFilter 的输入必须是 CIImage 而不是 UIImage

【讨论】:

【参考方案4】:

Swift 4 UIImage 扩展,无需强制解包:

extension UIImage 
    /// Applies a gaussian blur to the image.
    ///
    /// - Parameter radius: Blur radius.
    /// - Returns: A blurred image.
    func blur(radius: CGFloat = 6.0) -> UIImage? 
        let context = CIContext()
        guard let inputImage = CIImage(image: self) else  return nil 

        guard let clampFilter = CIFilter(name: "CIAffineClamp") else  return nil 
        clampFilter.setDefaults()
        clampFilter.setValue(inputImage, forKey: kCIInputImageKey)

        guard let blurFilter = CIFilter(name: "CIGaussianBlur") else  return nil 
        blurFilter.setDefaults()
        blurFilter.setValue(clampFilter.outputImage, forKey: kCIInputImageKey)
        blurFilter.setValue(radius, forKey: kCIInputRadiusKey)

        guard let blurredImage = blurFilter.value(forKey: kCIOutputImageKey) as? CIImage,
            let cgImage = context.createCGImage(blurredImage, from: inputImage.extent) else  return nil 

        let resultImage = UIImage(cgImage: cgImage, scale: scale, orientation: imageOrientation)
        return resultImage
    

我强烈建议在后台线程上模糊图像:

let image = UIImage(named: "myImage")
DispatchQueue.global(qos: .userInitiated).async 
    let blurredImage = image.blur()
    DispatchQueue.main.async 
        self.myImageView.image = blurredImage
    

【讨论】:

这样做后图像会被裁剪,有什么方法可以避免这种情况吗?【参考方案5】:

Swift 2.0

对 UIImageView 进行扩展。 (File-New-File-Empty Swift File - 将其命名为扩展名。)

import Foundation
import UIKit

extension UIImageView

 //Method 1
 func makeBlurImage(targetImageView:UIImageView?)
 
  let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Dark)
  let blurEffectView = UIVisualEffectView(effect: blurEffect)
  blurEffectView.frame = targetImageView!.bounds

  blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] // for supporting device rotation
  targetImageView?.addSubview(blurEffectView)
 
 //Method 2
 func convertToBlurImage(imageToBlur:UIImage) -> UIImage
 
  let gaussianBlurFilter = CIFilter(name: "CIGaussianBlur")
  gaussianBlurFilter!.setValue(CIImage(CGImage: imageToBlur.CGImage!), forKey:kCIInputImageKey)

  let initialImage = CIImage(CGImage: imageToBlur.CGImage!)

  let finalImage = gaussianBlurFilter!.outputImage
  let finalImagecontext = CIContext(options: nil)

  let finalCGImage = finalImagecontext.createCGImage(finalImage!, fromRect: initialImage.extent)
  return UIImage(CGImage: finalCGImage)
 

用法:

使用方法一:

override func viewDidLoad() 
  super.viewDidLoad()

  let sampleImageView = UIImageView(frame: CGRectMake(0, 200, 300, 325))
  let sampleImage:UIImage = UIImage(named: "ic_120x120")!
  sampleImageView.image =  sampleImage

  //Convert To Blur Image Here
  sampleImageView.makeBlurImage(sampleImageView)

  self.view.addSubview(sampleImageView)
 

使用方法二:

   override func viewDidLoad() 
      super.viewDidLoad()

      let sampleImageView = UIImageView(frame: CGRectMake(0, 200, 300, 325))
      let sampleImage:UIImage = UIImage(named: "ic_120x120")!

      //Convert to Blurred Image Here
      let sampleImage2 =  sampleImageView.convertToBlurImage(sampleImage)
      sampleImageView.image =  sampleImage2

      self.view.addSubview(sampleImageView)
     

【讨论】:

【参考方案6】:

这是一个图像模糊的扩展

斯威夫特 3

extension UIImage 

    public func blurImage(radius: CGFloat) -> UIImage 

        let inputImage = CIImage(image: self)!

        let parameters: [String:Any] = [
            kCIInputRadiusKey: radius,
            kCIInputImageKey: inputImage
        ]
        let filter = CIFilter(name: "CIGaussianBlur",
                              withInputParameters: parameters)!

        let cgimg = CIContext().createCGImage(filter.outputImage!, from: inputImage.extent)
        return UIImage(cgImage: cgimg!)
    


【讨论】:

以上是关于在 iOS7 中创建模糊效果的主要内容,如果未能解决你的问题,请参考以下文章

iOS 7 导航栏背景模糊效果在 iPhone 4 中不起作用

转css3实现ios7“毛玻璃”模糊效果

iOS 7 对 videoPlayer 的模糊效果

如何在 UITableViewCell 后台实现实时 iOS 7 模糊效果

如何产生类似于 iOS 7 模糊视图的效果?

iOS 7 TableView 中的 ViewController 和 NavigationBar 模糊效果