美文网首页
[IOS] 自定义View绘制UIImage出现锯齿如何解决

[IOS] 自定义View绘制UIImage出现锯齿如何解决

作者: kross | 来源:发表于2021-03-31 11:31 被阅读0次

    我需要制作一个快速更新 UIImage 的功能,一开始使用 UIImageView 来显示图片,所以需要频繁的调用 UIImageView.image = newImage 方法来更新图片。代码看起来像这样。

    func onSomethingChanged() {
        myUIImageView.image = newImage
    }
    

    这样更新图片非常的卡顿,操作和画面响应有一定的滞后,体验不好,因此考虑自己做一个 UIView 来绘制图片,看看是否可以解决。

    于是自己自定义了一个 View,继承 UIView 来做,在 draw(rect:) 方法里面做文章。

    首先当然是简单粗暴直接 UIImage.draw(in: bounds) 先看看效果。

    var image: UIImage? {
        didSet {
            setNeedsDisplay()
        }
    }
        
    override func draw(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }
        ctx.addRect(bounds)
        ctx.setFillColor(UIColor.black.cgColor)
        ctx.fillPath()
    
        if var im = image {
            im.draw(in: bounds)
        }
    }
    

    很好,更新速度很快,是理想的效果,不过目前画面是拉伸的,同时还有锯齿。

    下图中左边是理想的显示效果,右边则是实际的显示效果,可以看到明显的锯齿。

    image.png

    经过我一番搜索尝试了以下配置,均无任何帮助:

    ctx.setShouldAntialias(true)
    ctx.setAllowsAntialiasing(true)
    ctx.interpolationQuality = .high
    layer.allowsEdgeAntialiasing = true
    layer.minificationFilter = .trilinear
    

    我回忆起之前用 CGImageContext 缩放图片的时候也没有这个问题啊,难道是因为 UIView 自带的这个 CGContext 无法很好的缩放图片?

    于是我想到一个方案:先用一个 CGImageContext 把图片画上去,再弄出一个 CGImage 来,再把这个 CGImage 放到 UIView 的 CGContext 上是否可以呢?

    override func draw(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }
        ctx.addRect(bounds)
        ctx.setFillColor(UIColor.black.cgColor)
        ctx.fillPath()
    
        if var im = image {
            // 计算出在当前view的bounds内,保持图片比例最大的size
            let size = Math.getMaxSizeWithAspect(size: CGSize(width: bounds.width, height: bounds.height), radioWidthToHeight: im.size.width / im.size.height)
            // 再换算成pixel size
            let pixelSize = CGSize(width: size.width * layer.contentsScale, height: size.height * layer.contentsScale)
            
            // 创建一个和 pixel size 一样大的 ImageContext
            UIGraphicsBeginImageContextWithOptions(pixelSize, true, 1)
            guard let imgCtx = UIGraphicsGetCurrentContext() else { return }
            
            // 把 UIImage 画到这个 ImageContext 上
            im.draw(in: CGRect(x: 0, y: 0, width: pixelSize.width, height: pixelSize.height))
            
            // 再把 cgImg 搞出来
            guard let cgImg = imgCtx.makeImage() else { return }
            
            // 图片直接绘制的话,会上下翻转,因此先翻转一下
            ctx.scaleBy(x: 1, y: -1)
            ctx.translateBy(x: 0, y: -bounds.height)
            
            // 再把cgImg 画到 UIView 的 Context 上,大功告成
            ctx.draw(cgImg, in: CGRect(x: (bounds.width - size.width) / 2, y: (bounds.height - size.height) / 2, width: size.width, height: size.height))
        }
    }
    

    问题就此得到解决。

    其实我的本身需求是能快速的更新 image,因为是在做一块类似后期调照片的软件,有很多滑块,拖动后通过 CIFilter 修改照片,所以需要一直更新图像,如果有更好的方法,不妨告诉我一下:D

    如果以上内容对你有所帮助,请在这些平台上关注我吧,谢谢:P

    相关文章

      网友评论

          本文标题:[IOS] 自定义View绘制UIImage出现锯齿如何解决

          本文链接:https://www.haomeiwen.com/subject/wepohltx.html