简体   繁体   English

如何使用 Swift 模糊 UIImageView 中的现有图像?

[英]How to blur an existing image in a UIImageView with Swift?

The setup is simple.设置很简单。

  • A ViewController with UIImageView that has an image assigned.一个带有 UIImageView 的 ViewController,它分配了一个图像。
  • A UIButton that when clicked blurs the image in the UIImageView.单击时会模糊 UIImageView 中的图像的 UIButton。

故事板

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var bg: UIImageView!

    @IBAction func blur(_ sender: Any) {
        let inputImage = CIImage(cgImage: (bg.image?.cgImage)!)

        let filter = CIFilter(name: "CIGaussianBlur")
        filter?.setValue(inputImage, forKey: "inputImage")
        filter?.setValue(10, forKey: "inputRadius")
        let blurred = filter?.outputImage
        bg.image = UIImage(ciImage: blurred!)
    }
}

When the button is clicked the screen just turns white.单击按钮时,屏幕将变为白色。 Can't figure out what I'm doing wrong.无法弄清楚我做错了什么。 Anyone know what I'm doing wrong?有人知道我在做什么错吗?

You could simply use UIVisualEffect to achieve blur effect.您可以简单地使用UIVisualEffect来实现模糊效果。 As you trying to achieve a blur effect using CoreImage.Try below code after import CoreImage to your class.当您尝试使用 CoreImage 实现模糊效果时。在import CoreImage您的类后尝试下面的代码。

var context = CIContext(options: nil)

func blurEffect() {

    let currentFilter = CIFilter(name: "CIGaussianBlur") 
    let beginImage = CIImage(image: bg.image!)
    currentFilter!.setValue(beginImage, forKey: kCIInputImageKey)
    currentFilter!.setValue(10, forKey: kCIInputRadiusKey)

    let cropFilter = CIFilter(name: "CICrop")
    cropFilter!.setValue(currentFilter!.outputImage, forKey: kCIInputImageKey)
    cropFilter!.setValue(CIVector(cgRect: beginImage!.extent), forKey: "inputRectangle")

    let output = cropFilter!.outputImage 
    let cgimg = context.createCGImage(output!, from: output!.extent)
    let processedImage = UIImage(cgImage: cgimg!)
    bg.image = processedImage
}

Output:输出:

在此处输入图像描述

Note: I recommend you to test the code in real device as Simulator performance is too slow on coreImage.注意:我建议您在真实设备中测试代码,因为模拟器在 coreImage 上的性能太慢。

for those who ❤️ protocols对于那些❤️协议的人

protocol Blurable {
    func addBlur(_ alpha: CGFloat)
}

extension Blurable where Self: UIView {
    func addBlur(_ alpha: CGFloat = 0.5) {
        // create effect
        let effect = UIBlurEffect(style: .dark)
        let effectView = UIVisualEffectView(effect: effect)
        
        // set boundry and alpha
        effectView.frame = self.bounds
        effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        effectView.alpha = alpha
        
        self.addSubview(effectView)
    }
}

// Conformance
extension UIView: Blurable {}

// use
someImageview.addBlur()

Here is how I got my expected result in SWIFT 3.1: Hope it will help.以下是我在 SWIFT 3.1 中获得预期结果的方式:希望它会有所帮助。

func blurImage(image:UIImage) -> UIImage? {
        let context = CIContext(options: nil)
        let inputImage = CIImage(image: image)
        let originalOrientation = image.imageOrientation
        let originalScale = image.scale

        let filter = CIFilter(name: "CIGaussianBlur")
        filter?.setValue(inputImage, forKey: kCIInputImageKey)
        filter?.setValue(10.0, forKey: kCIInputRadiusKey) 
        let outputImage = filter?.outputImage

        var cgImage:CGImage?

        if let asd = outputImage
        {
            cgImage = context.createCGImage(asd, from: (inputImage?.extent)!)
        }

        if let cgImageA = cgImage
        {
            return UIImage(cgImage: cgImageA, scale: originalScale, orientation: originalOrientation)
        }

        return nil
    }

There is actually a handy implementation right in CoreImage https://developer.apple.com/documentation/coreimage/ciimage/1645897-applyinggaussianblur CoreImage 实际上有一个方便的实现https://developer.apple.com/documentation/coreimage/ciimage/1645897-applyinggaussianblur

extension UIImage {

func blur(_ radius: Double) -> UIImage? {
    if let img = CIImage(image: self) {
        return UIImage(ciImage: img.applyingGaussianBlur(sigma: radius))
    }
    return nil
}

A good performing solution with decent results is StackBlur which uses a clever algorithm that efficiently approximates a blur: StackBlur是一个效果不错且性能良好的解决方案,它使用一种巧妙的算法来有效地逼近模糊:

This is a compromise between Gaussian Blur and Box blur It creates much better looking blurs than Box Blur, but is 7x faster than my Gaussian Blur implementation.这是 Gaussian Blur 和 Box blur 之间的折衷方案。它创建的模糊效果比 Box Blur 好得多,但比我的 Gaussian Blur 实现快 7 倍。 I called it Stack Blur because this describes best how this filter works internally: it creates a kind of moving stack (or maybe a "Tower of Hanoi" kind of structure) of colors whilst scanning through the image.我将其命名为堆栈模糊,因为它最好地描述了此滤镜在内部的工作方式:它在扫描图像时创建一种移动的颜色堆栈(或者可能是“河内之塔”类型的结构)。 This "tower" controls the weights of the single pixels within the convolution kernel and gives the pixel in the center the highest weight.这个“塔”控制卷积核内单个像素的权重,并赋予中心像素最高的权重。 The secret of the speed is that the algorithm just has to add one new pixel to the right side of the stack and at the same time remove the leftmost pixel.速度的秘诀在于该算法只需在堆栈的右侧添加一个新像素,同时移除最左侧的像素。 The remaining colors on the topmost layer of the stack are either added on or reduced by one, depending on if they are on the right or on the left side of the stack.堆栈最顶层的剩余颜色要么加一,要么减一,具体取决于它们是在堆栈的右侧还是左侧。

Check out StackBlur on Github .查看Github 上的 StackBlur

There are many versions out there, also Swift ports, but those are considerable slower than the Obj-C versions.那里有很多版本,还有 Swift 端口,但这些版本比 Obj-C 版本慢很多。

Addition 2019: 2019年补充:

If the images to blur are remotely loaded, I can highly recommend the Nuke framework that remotely loads images and can apply a blur filter out of the box.如果要模糊的图像是远程加载的,我强烈推荐Nuke框架,它可以远程加载图像并可以开箱即用地应用模糊过滤器。 It's application is comparable to the Glide library on Android.它的应用程序可与 Android 上的 Glide 库相媲美。 While blurring one image may be easy, blurring many images - like in a collection view - while considering device resource constraints is less trivial.虽然模糊一张图像可能很容易,但在考虑设备资源限制的同时模糊许多图像(例如在集合视图中)就不那么简单了。 Nuke is highly optimized for remote image loading, caching and processing. Nuke 针对远程图像加载、缓存和处理进行了高度优化。 It is also extendable in several aspects.它还可以在多个方面进行扩展。 From comparing available remote image loading frameworks, I think that Nuke is the most stable and most advanced for that purpose as of Nov 2019.通过比较可用的远程图像加载框架,我认为 Nuke 是截至 2019 年 11 月为止最稳定和最先进的。

Use this:用这个:

 import UIKit

    class ViewController: UIViewController {

        @IBOutlet weak var bgImageView: UIImageView!
        @IBOutlet weak var blurButton: UIButton!


        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
        }

        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }


        @IBAction func blurButtonTapped(_ sender: Any) {

                let inputImage = CIImage(cgImage: (self.bgImageView.image?.cgImage)!)
                let filter = CIFilter(name: "CIGaussianBlur")
                filter?.setValue(inputImage, forKey: "inputImage")
                filter?.setValue(10, forKey: "inputRadius")
                let blurred = filter?.outputImage

                var newImageSize: CGRect = (blurred?.extent)!
                newImageSize.origin.x += (newImageSize.size.width - (self.bgImageView.image?.size.width)!) / 2
                newImageSize.origin.y += (newImageSize.size.height - (self.bgImageView.image?.size.height)!) / 2
                newImageSize.size = (self.bgImageView.image?.size)!

                let resultImage: CIImage = filter?.value(forKey: "outputImage") as! CIImage
                let context: CIContext = CIContext.init(options: nil)
                let cgimg: CGImage = context.createCGImage(resultImage, from: newImageSize)!
                let blurredImage: UIImage = UIImage.init(cgImage: cgimg)
                self.bgImageView.image = blurredImage
        }

    }

Output:输出:

在此处输入图像描述

Gitbub link: GitHub 链接:

https://github.com/k-sathireddy/ImageBlurEffect https://github.com/k-sathireddy/ImageBlurEffect

my extension我的分机

extension UIImage {
    
    func blurImage(radius: CGFloat = 10) -> UIImage? {
        guard let cgImage = cgImage else { return nil }
        let inputCIImage = CIImage(cgImage: cgImage)
        let context = CIContext(options: nil)
        
        let filter = CIFilter(name: "CIGaussianBlur")
        filter?.setValue(inputImage, forKey: kCIInputImageKey)
        filter?.setValue(radius, forKey: kCIInputRadiusKey)
        let outputImage = filter?.outputImage
        
        if let outputImage = outputImage,
            let cgImage = context.createCGImage(outputImage, from: inputImage.extent) {
            
            return UIImage(
                cgImage: cgImage,
                scale: scale,
                orientation: imageOrientation
            )
        }
        return nil
    }
 }

I made the blur in a NSObject class, so I can use this method in whole project easily.我在一个 NSObject 类中做了模糊处理,所以我可以很容易地在整个项目中使用这个方法。

class Helper: NSObject
{
    class func addBlurView(_ inView : UIView) -> UIVisualEffectView
    {
        let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)

        //always fill the view
        blurEffectView.frame = inView.bounds
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        blurEffectView.alpha = 0.5

        return blurEffectView
    }
}

In ViewController I made object of UIVisualEffectView .在 ViewController 中,我创建了UIVisualEffectView的对象。 Then call the helper class method of to add blur.然后调用辅助类方法来添加模糊。

import UIKit

class ViewController: UIViewController
{
   var blurEffectView : UIVisualEffectView!
    override func viewDidLoad() {
        super.viewDidLoad()

      blurEffectView = Helper.addBlurView((imgView)!)
      self.imgView.addSubview(blurEffectView)
}

Check if something is coming nil.检查是否有什么东西是零。 I had a similar issue, but in my case I wasn't creating a new instance of CIImage, because of that image.ciimage was coming nil.我遇到了类似的问题,但在我的情况下,我没有创建 CIImage 的新实例,因为 image.ciimage 将为零。

You can add blur effect by UIBlurEffect and UIVisualEffectView :您可以通过UIBlurEffectUIVisualEffectView添加模糊效果:

@IBAction func blur(_ sender: Any) {

    let darkBlur = UIBlurEffect(style: UIBlurEffectStyle.dark) 
    let blurView = UIVisualEffectView(effect: darkBlur)
    blurView.frame = bg_imagview.bounds
    blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    bg_imagview.addSubview(blurView)

}

Hey to all the LAZY guys just like me.嘿,所有像我一样的懒人。

Just add SwifterSwift with cocoapods.只需将 SwifterSwift 与 cocoapods 一起添加即可。

Import SwifterSwift.导入 SwifterSwift。

import SwifterSwift

Blur your image view just like below.像下面一样模糊您的图像视图。

someImageView.blur()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM