在 UIImage 中更改 JUST .scale?

Posted

技术标签:

【中文标题】在 UIImage 中更改 JUST .scale?【英文标题】:Changing JUST .scale in UIImage? 【发布时间】:2016-11-06 17:39:53 【问题描述】:

在这里,我正在动态创建一个典型的图形(它是全屏大小,在所有设备上)...

func buildImage()->UIImage
        
        let wrapperA:UIView = say, a picture
        let wrapperB:UIView = say, some text to go on top
                
        let mainSize = basicImage.bounds.size
        
        UIGraphicsBeginImageContextWithOptions(mainSize, false, 0.0)
        
        basicImage.drawHierarchy(in: basicImage.bounds, afterScreenUpdates:true)
        wrapperA.drawHierarchy(in: wrapperA.bounds, afterScreenUpdates:true)
        wrapperB.drawHierarchy(in: wrapperB.bounds, afterScreenUpdates: true)
        
        let result:UIImage? = UIGraphicsGetImageFromCurrentImageContext()
        
        UIGraphicsEndImageContext()
        
        // so we've just created a nice big image for some reason,
        // no problem so far

        print( result?.scale  )
        
        // I want to change that image to have a scale of 1.
        // I don't know how to do that, so I actually just
        // make a new identical one, with scale of 1
        
        let resultFixed:UIImage = UIImage(cgImage: result!.cgImage!,
                            scale: 1.0,
                            orientation: result!.imageOrientation)
        
        print( resultFixed.scale )
        
        print("Let's use only '1-scale' images to upload to things like Instagram")
        
        // return result
        return resultFixed
        
        // be sure to ask on SO if there's a way to
        // just "change the scale" rather than make new.
        

我需要最终图像为 1 的 .scale - 但 .scale 是只读属性。

我唯一知道如何做的就是制作一个全新的图像副本......但在创建时将比例设置为 1。

有没有更好的办法?


小贴士 -

这样做的动机是:假设您正在将大图像保存到用户的相册,并且还允许 UIActivityViewController 发布到(示例)Instagram。作为一般规则,最好在发送到(示例)Instagram 之前将比例设为 1;如果比例为 3,您实际上只是在 Instagram 帖子上获得图像的左上角 1/3。就将其保存到 ios 相册而言,将比例设置为 1 似乎是无害的(也许在某些方面更好)。(我只说“更好”,因为如果图像是,例如,最终会说通过电子邮件发送给 PC 上的朋友,如果比例为 1,则可以减少混淆。)但有趣的是,如果您只使用 iOS 相册,拍摄 2 或 3 比例的图像,然后将其分享到 Instagram:事实上确实如此在 Instagram 上正确显示! (也许 Apple 的 Photos 确实知道最好将其缩放为 1,然后再将其发送到 Instagram 之类的地方!)。

【问题讨论】:

【参考方案1】:

正如您所说,UIImagescale 属性是只读的,因此您不能直接更改它。

但是,使用 UIImageinit(cgImage:scale:orientation) 初始化程序并不会真正复制图像 - 它所包装的底层 CGImage(包含实际的位图数据)仍然相同实例。它只是创建了一个新的 UIImage 包装器。

尽管如此,在这种情况下,您可以通过CGContextmakeImage() 方法直接从上下文中获取CGImage,从而去掉中间的UIImage 包装器。例如:

func buildImage() -> UIImage? 

    // ...

    let mainSize = basicImage.bounds.size

    UIGraphicsBeginImageContextWithOptions(mainSize, false, 0.0)
    defer 
        UIGraphicsEndImageContext()
    

    // get the current context
    guard let context = UIGraphicsGetCurrentContext() else  return nil 

    // -- do drawing here --

    // get the CGImage from the context by calling makeImage() – then wrap in a UIImage
    // through using Optional's map(_:) (as makeImage() can return nil)
    // by default, the scale of the UIImage is 1.
    return context.makeImage().map(UIImage.init(cgImage:))

【讨论】:

附带说明,我建议不要强制解开生成的图像,而是处理无法创建图像的情况。在此示例中,我将 nil 返回给调用者。 (2) 啊.. 你是说,而不是我去哪里let result:UIImage? = UIGraphicsGetImageFromCurrentImageContext() ...事实上,我可以在返回 CGImage 的当前上下文中使用这个 'makeImage()' - 然后使用 UIImage.init 将其包装成 UIImage ...太好了! @JoeBlow 准确地说:) 知识渊博的答案,再次感谢@Hamish【参考方案2】:

顺便说一句,您可以更改结果图像的比例以创建新图像

let newScaleImage = UIImage(cgImage: oldScaleImage.cgImage!, scale: 1.0, orientation: oldScaleImage.imageOrientation)

【讨论】:

以上是关于在 UIImage 中更改 JUST .scale?的主要内容,如果未能解决你的问题,请参考以下文章

如何裁剪 UIImage 而不会丢失它的 scale 属性?

无法强制解开非可选类型“UIImage”的值

iOS:更改自我的内容(UIImage)

将UIImage转换为NSData并在Swift中转换回UIImage?

在 iOS 中 x 秒后从 UIButton 更改 UIImage

设备方向更改时更改 UIImage