20

since the documentation on swiftUI isn't great yet I wanted to ask how I can convert an "image" to an "UIImage" or how to convert an "image" to pngData/jpgData

let image = Image(systemName: "circle.fill")
let UIImage = image as UIImage
nOk
  • 1,876
  • 4
  • 10
  • 26
  • hi @nOK , why you need that? and what you want to achieve? – Giuseppe Sapienza Jul 14 '19 at 15:13
  • `UIImage` is part of `UIKit`, not `SwiftUI`. What *exactly are you trying to do? without SwiftUI, you can easily - via things very documented - *convert* between `UIImage, `CGImage`, and `CIImage`. If you consider that `Image` is *much* more like a `UIImageView`, again, what are you really looking for? –  Jul 14 '19 at 15:24
  • 1
    I was trying to save an image in CoreData and with UIImage I could easily just use image.pngData() but haven't found a possibility for images in swiftUI – nOk Jul 14 '19 at 18:07
  • Also variables of type "Image" don't seem to be conforming to the "Hashable" prototype – nOk Jul 14 '19 at 18:54

2 Answers2

19

Such thing is not possible with SwiftUI, and I bet it will never be. It goes againts the whole framework concept. However, you can do:

let uiImage = UIImage(systemName: "circle.fill")
let image = Image(uiImage: uiImage)
kontiki
  • 32,877
  • 11
  • 99
  • 118
  • Variables of type "Image" don't seem to be conforming to the "Hashable" prototype that's why I was hoping to be able to convert it :/ – nOk Jul 14 '19 at 18:55
  • 6
    If you would like to get the data from an `Image` view, you do not get it from the `Image` itself, but from the same place the Image got it. For example, if you load the Image using a uiImage object, you should go to that uiImage object. If the view got the image from a file name, you should go get it from the file. You will **never** be able to interrogate Image for its binary, it is not the way the framework is designed. – kontiki Jul 14 '19 at 20:06
  • Thx for the help. I was kinda trying to avoid that but thought it might come to that :D Let's rewrite the code then :D – nOk Jul 14 '19 at 20:41
  • 2
    @kontiki Why it goes againts the whole framework concept? – villb Oct 11 '21 at 11:20
16

There is no direct way of converting an Image to UIImage. instead, you should treat the Image as a View, and try to convert that View to a UIImage. Image conforms to View, so we already have the View we need. now we just need to convert that View to a UIImage.

We need 2 components to achieve this. First, a function to change our Image/View to a UIView, and second one, to change the UIView we created to UIImage.

For more Convenience, both functions are declared as Extensions to their appropriate types.

extension View {
// This function changes our View to UIView, then calls another function
// to convert the newly-made UIView to a UIImage.
    public func asUIImage() -> UIImage {
        let controller = UIHostingController(rootView: self)
        
        controller.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1)
        UIApplication.shared.windows.first!.rootViewController?.view.addSubview(controller.view)
        
        let size = controller.sizeThatFits(in: UIScreen.main.bounds.size)
        controller.view.bounds = CGRect(origin: .zero, size: size)
        controller.view.sizeToFit()
        
// here is the call to the function that converts UIView to UIImage: `.asUIImage()`
        let image = controller.view.asUIImage()
        controller.view.removeFromSuperview()
        return image
    }
}

extension UIView {
// This is the function to convert UIView to UIImage
    public func asUIImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}

How To Use?

let image: Image = Image("MyImageName") // Create an Image anyhow you want
let uiImage: UIImage = image.asUIImage() // Works Perfectly

Bonus

As i said, we are treating the Image, as a View. In the process, we don't use any specific features of Image, the only thing that is important is that our Image is a View (conforms to View protocol). This means that with this method, you can not only convert an Image to a UIImage, but also you can convert any View to a UIImage.

var myView: some View {
// create the view here
}
let uiImage = myView.asUIImage() // Works Perfectly
Mahdi BM
  • 1,333
  • 7
  • 13
  • Thanks for your answer Mahdi, quite interesting and useful for some cases. I would remove the last P.S part though, this is not a Youtube Channel or Instagram :). – GoRoS Oct 22 '21 at 07:58
  • 1
    How should I change the line `UIApplication.shared.windows.first!.rootViewController?.view.addSubview(controller.view)` for iOS 15? I get the deprecation warning: `"'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead"`. – Rillieux Nov 28 '21 at 18:46
  • @Rillieux - Like this. Of course you could guard, etc. as well. But simply: let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene scene?.windows.first?.rootViewController?.view.addSubview(controller.view) – C6Silver May 18 '22 at 21:46