createCGImage(_:from :)没有使用正确的rect

时间:2018-03-02 18:50:25

标签: ios swift uiimage core-image

我试图模糊图像的一部分:

extension UIImage {
    func blur(rect: CGRect, radius: CGFloat) -> UIImage? {
        let context = CIContext(options: nil)
        let inputImage = CIImage(cgImage: self.cgImage!)
        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: rect)
            if let cgImage = cgImage {
                return UIImage(cgImage: cgImage)
            }
        }
        return nil
    }
}

用法:

guard let blurredImage = self.imageView.image?.blur(rect: self.blur.frame, radius: 2.0) else { fatalError("could not blur image") }
let img = UIImageView(image: blurredImage)
img.frame = self.blur.frame
self.view.addSubview(img)

然而,当应用程序启动时,图片的错误部分会模糊不清。下面是图像;底部的矩形应该模糊背后的图像,但它会模糊其他部分。

image

3 个答案:

答案 0 :(得分:1)

您是否注意到您的插图图像不仅模糊,而且放大了?那应该是一个提示......

UIKit视图,框架和图像大小位于“点”中,这是一个用于进行布局的与显示分辨率无关的单元。即使iPhone X有更多像素,您的iPhone X显示屏也具有与iPhone 6/7/8显示屏相同的宽度。 (也就是说,它们的比例因子不同:iPhone 6/7/8是2倍,iPhone X是3倍。)

CGImageCIImage衡量像素,而不是点数,因此在使用UIKit的视图尺寸时,您需要考虑屏幕的比例因子。由于您要从整个视图创建要模糊的图像,然后仅渲染模糊图像的一部分,因此处理比例因子的位置将在您的createCGImage(_:from:)调用中 - 只需乘以整个视图的contentScaleFactor

的直径的原点和大小

此外,请注意,您不一定需要通过CGImage才能从UIImage转到CIImage并返回 - 您可以将外部图片视图的图片传递给{{3} },以及过滤器CIImage(image:)的结果。在这种情况下,UIKit和CoreImage会为您管理渲染上下文,并且可能确保更好的性能(例如,通过将整个管道保留在GPU上)。但由于您使用渲染调用来指定裁剪矩形,因此您需要在其他地方执行此操作 - 例如,CIImage UIImage(ciImage:)调用。

答案 1 :(得分:1)

看起来你走在正确的轨道上。有几件事情需要通过......

可以通过将屏幕比例传递到您的方法并更新您的rect的原点和大小来调整比例

由于CoreGraphics和UIKit坐标系之间的转换,模糊部分的定位已关闭。为了解决这个问题,您只需要通过想要模糊的矩形的位置和高度减去窗口的高度(考虑到比例)

请查看以下代码:

extension UIImage {
    func blur(rect: CGRect, radius: CGFloat, scale: CGFloat) -> UIImage? {

        if let cgImage = self.cgImage {
            let inputImage = CIImage(cgImage: cgImage)
            let context = CIContext(options: nil)
            let filter = CIFilter(name: "CIGaussianBlur")
            filter?.setValue(inputImage, forKey: kCIInputImageKey)
            filter?.setValue(radius, forKey: kCIInputRadiusKey)

            // Rect bounds need to be adjusted for based on Image's Scale and Container's Scale
            // Y Position Needs to be Inverted because of UIKit <-> CoreGraphics Coordinate Systems

            let newRect = CGRect(
                x: rect.minX * scale,
                y: ((((CGFloat(cgImage.height) / scale)) - rect.minY - rect.height) * scale),
                width: rect.width * scale,
                height: rect.height * scale
            )


            if let outputImage = filter?.outputImage,
                let cgImage = context.createCGImage(outputImage, from: newRect) {
                return UIImage(
                    cgImage: cgImage,
                    scale: scale,
                    orientation: imageOrientation
                )
            }
        }
        return nil
    }
}

let blurredImage = self.imageView.image?.blur(rect: self.blur.frame, radius: 2.0, scale: UIScreen.main.scale)

答案 2 :(得分:0)

问题是在viewDidLoad内添加任何叠加层都没有提供正确的框架尺寸将其添加到viewDidAppear