【问题标题】:How to apply scale when drawing and composing UIImage绘制和合成 UIImage 时如何应用比例
【发布时间】:2021-12-21 16:47:54
【问题描述】:

我有以下functions。

extension UIImage
{
    var width: CGFloat
    {
        return size.width
    }
    
    var height: CGFloat
    {
        return size.height
    }
    
    private static func circularImage(diameter: CGFloat, color: UIColor) -> UIImage
    {
        UIGraphicsBeginImageContextWithOptions(CGSize(width: diameter, height: diameter), false, 0)
        let context = UIGraphicsGetCurrentContext()!
        context.saveGState()

        let rect = CGRect(x: 0, y: 0, width: diameter, height: diameter)
        context.setFillColor(color.cgColor)
        context.fillEllipse(in: rect)

        context.restoreGState()
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        return image
    }
    
    private func addCentered(image: UIImage, tintColor: UIColor) -> UIImage
    {            
        let topImage = image.withTintColor(tintColor, renderingMode: .alwaysTemplate)
        let bottomImage = self
        
        UIGraphicsBeginImageContext(size)
        
        let bottomRect = CGRect(x: 0, y: 0, width: bottomImage.width, height: bottomImage.height)
        bottomImage.draw(in: bottomRect)
        
        let topRect = CGRect(x: (bottomImage.width - topImage.width) / 2.0,
                             y: (bottomImage.height - topImage.height) / 2.0,
                             width: topImage.width,
                             height: topImage.height)
        topImage.draw(in: topRect, blendMode: .normal, alpha: 1.0)
        
        let mergedImage = UIGraphicsGetImageFromCurrentImageContext()!
        
        UIGraphicsEndImageContext()
        
        return mergedImage
    }
}

它们工作正常,但我如何正确应用 UIScreen.main.scale 来支持视网膜屏幕?

我查看了here 的操作,但还没有弄清楚。

有什么想法吗?

【问题讨论】:

    标签: ios swift uiimage scale uigraphicscontext


    【解决方案1】:

    访问UIScreen.main.scale 本身有点问题,因为您只能从主线程访问它(而您通常希望在后台线程上进行较重的图像处理)。所以我建议使用其中一种方法。

    首先,您可以将UIGraphicsBeginImageContext(size)替换为

    UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
    

    最后一个参数(0.0)是一个scale,并基于docs“如果您指定的值为0.0,则比例因子设置为设备主屏幕的比例因子。”

    如果您想在生成的UIImage 上保留原始图像的比例,您可以这样做:在topImage.draw 之后,不要使用UIGraphicsGetImageFromCurrentImageContext 获取 UIImage,而是使用 CGImage 获取

    let cgImage = context.makeImage()
    

    然后使用原始图像的比例和方向构造 UIImage(而不是默认值)

    let mergedImage = UIImage(
        cgImage: cgImage, 
        scale: image.scale, 
        orientation: image.opientation)
    

    【讨论】:

    • 谢谢。几个问题:UIImage 没有makeImage()。您的建议不会返回在bottomImage 之上绘制的topImage;因为您跳过了UIGraphicsGetImageFromCurrentImageContext,所以现在只返回topImage。替换 UIGraphicsBeginImageContext(size) 就足够了。我很高兴知道为什么。
    • 好吧,我在第二个选项中遗漏了几件事:makeImage 不是 UIImage 的函数,它是 context 的函数。通常,您是在上下文(来自 UIGraphicsBeginImageContext)中绘制,而不是在 UIImage 中绘制,就像您在 circularImage 函数中所做的那样(即通常在两个地方都是 context.draw,而不是 topImage.draw),然后构建UIImage 从它作为最后一步。而makeImage 是上下文的函数,而不是 UIImage 的函数 - 这是我的错误,不知何故认为你调用了你的上下文 topImage
    • 为什么会起作用:嗯,首先你跳过了UIGraphicsBeginImageContext 返回值,这将是上下文(参见你的其他函数)。就像我说的那样,你通常会得到上下文并在其中绘制。但是,即使您跳过它,仍然会创建上下文。当您调用UIImage.draw 时,它将在“当前图形上下文”中绘制,这恰好是您刚刚创建的上下文。因此,即使直接在图像内部绘制,操作您正在创建的上下文也会影响结果。
    • 非常感谢 Kiril 的广泛回答和 cmets!
    猜你喜欢
    • 1970-01-01
    • 2012-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多