如果 UIImage 不适合矩形,则用背景颜色在矩形中绘制 UIImage?

Draw UIImage in Rectangle with background color if it doesn't fit in a rectangle?

我是这个主题的新手,所以我想问一下如何实现以下行为:我想创建一个具有特定大小的图像。如果原始图像不适合正方形,我想用一种颜色填充边,所以我想将该图像绘制在一个带有颜色的矩形中,并希望将其存储在一个新的 UIImage 变量中。

要调整图像大小,我发现了类似的东西。但是我怎样才能将图像放入具有特定颜色的矩形中并创建一个可以存储的新图像?

UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
return UIGraphicsGetImageFromCurrentImageContext()

一种可能的方法是在示例代码开始时为 UIImage 创建一个扩展方法。

然后创建一个所需大小的新图像并用UIRectFill填充背景颜色。

下一步是计算新尺寸,以便通过考虑纵横比来缩放图像内容以适合图像:

let scale = min(size.width / originalSize.width, size.height / originalSize.height)
let newSize = CGSize(width: originalSize.width * scale, height: originalSize.height * scale)
let origin = CGPoint(x: (size.width - newSize.width) / 2, y: (size.height - newSize.height) / 2)

然后你基本上只需要将图像绘制到由原点和背景区域内图像的实际大小产生的矩形中。

完整地,扩展方法看起来像这样:

func image(size: CGSize, background: UIColor) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
    defer { UIGraphicsEndImageContext() }
    background.setFill()
    let completeRect = CGRect(origin: .zero, size: size)
    UIRectFill(completeRect)

    let originalSize = self.size
    let scale = min(size.width / originalSize.width, size.height / originalSize.height)
    let newSize = CGSize(width: originalSize.width * scale, height: originalSize.height * scale)
    let origin = CGPoint(x: (size.width - newSize.width) / 2, y: (size.height - newSize.height) / 2)
    let imageRect = CGRect(origin: origin, size: newSize)
    draw(in: imageRect, blendMode: .normal, alpha: 1.0)
    return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}

Self-Contained 完整示例

最后一个self-contained完整的测试示例:

import UIKit

class ViewController: UIViewController {
    
    private let image1 = UIImage(named: "country")
    private let image2 = UIImage(named: "regensburg")
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let imageView1 = createImageView()
        imageView1.image = image1?.image(size: CGSize(width: 200, height: 200), background: .blue)

        let imageView2 = createImageView()
        imageView2.image = image2?.image(size: CGSize(width: 200, height: 200), background: .blue)

        NSLayoutConstraint.activate([
            imageView1.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24),
            imageView1.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24),
            imageView1.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24),
            imageView2.topAnchor.constraint(equalTo: imageView1.bottomAnchor, constant: 24),
            imageView2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24),
            imageView2.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24),
            imageView2.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -24),
            imageView2.widthAnchor.constraint(equalTo: imageView1.widthAnchor),
            imageView2.heightAnchor.constraint(equalTo: imageView1.heightAnchor)
        ])
    }

    private func createImageView() -> UIImageView {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(imageView)
        return imageView
    }

}


extension UIImage {

    func image(size: CGSize, background: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
        defer { UIGraphicsEndImageContext() }
        background.setFill()
        let completeRect = CGRect(origin: .zero, size: size)
        UIRectFill(completeRect)

        let originalSize = self.size
        let scale = min(size.width / originalSize.width, size.height / originalSize.height)
        let newSize = CGSize(width: originalSize.width * scale, height: originalSize.height * scale)
        let origin = CGPoint(x: (size.width - newSize.width) / 2, y: (size.height - newSize.height) / 2)
        let imageRect = CGRect(origin: origin, size: newSize)
        draw(in: imageRect, blendMode: .normal, alpha: 1.0)
        return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
    }

}

以上代码的输出结果为:

指定的实际图片尺寸为正方形。因此,在所选背景颜色(蓝色)的图像边缘处有相应的垂直或水平条纹。