如何在Swift中制作IBDesignable图像下采样功能?

How to make an IBDesignable image down sampling function in Swift?

提问人:Zyfe3r 提问时间:6/1/2023 更新时间:9/25/2023 访问量:32

问:

我在运行应用程序时遇到图像使用过多内存的问题。一个 905kb 的 SVG 图像在呈现时占用了大约 150mb,并且该图像正在被系统缓存。在不同的页面上加载多个不同的 SVG 图像会导致内存压力问题。

因此,我开始研究图像缩减采样,并找到了解决方案。我设法创建了一个函数,根据图像的大小对图像进行下采样(有帮助)。目前,我可以使用下采样器类对图像进行下采样,该类需要设置为要启用下采样的每个 imageView 的自定义类。

我正在尝试为 UIImageView 创建一个 IBDesignable 扩展,以便我可以使用任何自定义类,但仍然可以获得对图像进行缩减采样的好处。

这是缩减采样类的代码

import UIKit

class DownsamplingImageView: UIImageView {
    
    @IBInspectable
    var downSample: Bool = true {
        didSet {
            setNeedsLayout()
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        if downSample, let image = self.image {
            let targetSize = self.bounds.size
            let downsampledImage = image.downsample(to: targetSize)
            self.image = downsampledImage
        }
    }
}

extension UIImage {
    
    func downsample(to targetSize: CGSize) -> UIImage? {
        let sourceSize = self.size
        let widthRatio = targetSize.width / sourceSize.width
        let heightRatio = targetSize.height / sourceSize.height
        let scaleFactor = max(widthRatio, heightRatio)
        
        let scaledSize = CGSize(width: sourceSize.width * scaleFactor, height: sourceSize.height * scaleFactor)
        
        UIGraphicsBeginImageContextWithOptions(scaledSize, false, 0.0)
        self.draw(in: CGRect(origin: CGPoint.zero, size: scaledSize))
        let downsampledImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return downsampledImage
    }
}

这就是我尝试进行扩展的方式,但不幸的是它不起作用。

import UIKit
@IBDesignable
extension UIImageView {
    
    @IBInspectable
    var downSample: Bool {
        get {
            return image != nil
        }
        set {
            setNeedsLayout()
        }
    }
    
    override open func layoutSubviews() {
        super.layoutSubviews()
        
        if downSample, let image = self.image {
            let targetSize = self.bounds.size
            let downsampledImage = image.downsample(to: targetSize)
            self.image = downsampledImage
        }
    }
}

extension UIImage {
    
    func downsample(to targetSize: CGSize) -> UIImage? {
        let sourceSize = self.size
        let widthRatio = targetSize.width / sourceSize.width
        let heightRatio = targetSize.height / sourceSize.height
        let scaleFactor = max(widthRatio, heightRatio)
        
        let scaledSize = CGSize(width: sourceSize.width * scaleFactor, height: sourceSize.height * scaleFactor)
        
        UIGraphicsBeginImageContextWithOptions(scaledSize, false, 0.0)
        self.draw(in: CGRect(origin: CGPoint.zero, size: scaledSize))
        let downsampledImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return downsampledImage
    }
}

有人可以帮忙或解释为什么UIImageView上的扩展不起作用,但使用自定义类有效吗?还有没有办法使扩展工作?

PS:150mb的使用量减少到只有6mb的使用量,幸运的是,当用户离开页面时,它就会被释放! 以防万一有人想要启用缩减采样,第一个代码可以完美运行,您所要做的就是将 UIImageView 自定义类设置为DownsamplingImageView

Swift UIImImageView IBDejectable 缩减采样

评论

0赞 DonMag 6/5/2023
“A 905kb SVG image...” -- SVG 文件是矢量定义。如果使用“呈现时为 150mb”,则正在将其初始化为非常大的大小。您使用什么代码将 SVG 文件呈现为 ?UIImage

答:

0赞 Zyfe3r 9/25/2023 #1

我最终使用图像下采样器来解决这个问题。

import UIKit

class DownsamplingImageView: UIImageView {
    
    @IBInspectable
    var downSample: Bool = true {
        didSet {
            setNeedsLayout()
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        if downSample, let image = self.image {
            let targetSize = self.bounds.size
            let downsampledImage = image.downsample(to: targetSize)
            self.image = downsampledImage
        }
    }
}

extension UIImage {
    
    func downsample(to targetSize: CGSize) -> UIImage? {
        let sourceSize = self.size
        let widthRatio = targetSize.width / sourceSize.width
        let heightRatio = targetSize.height / sourceSize.height
        let scaleFactor = max(widthRatio, heightRatio)
        
        let scaledSize = CGSize(width: sourceSize.width * scaleFactor, height: sourceSize.height * scaleFactor)
        
        UIGraphicsBeginImageContextWithOptions(scaledSize, false, 0.0)
        self.draw(in: CGRect(origin: CGPoint.zero, size: scaledSize))
        let downsampledImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return downsampledImage
    }
}

学分 : 我忘了我从哪里得到这个。我只是在回答这个问题,以防有人面临同样的问题。归原所有者所有。