Search code examples
swiftswiftuiuiimagecore-graphics

UIImage and UIimage.pngData returns two different image


enter image description here

MRE

import SwiftUI

struct SwiftUIView: View {
    
    func maskImage(image: UIImage, mask: UIImage) -> UIImage {
        let imageReference = image.cgImage!
        let maskReference = mask.cgImage!

        let width = maskReference.width
        let height = maskReference.height
        let bitsPerComponent = maskReference.bitsPerComponent
        let bitsPerPixel = maskReference.bitsPerPixel
        let bytesPerRow = maskReference.bytesPerRow

        let context = CGContext(
            data: nil,
            width: width,
            height: height,
            bitsPerComponent: bitsPerComponent,
            bytesPerRow: bytesPerRow,
            space: CGColorSpaceCreateDeviceGray(),
            bitmapInfo: CGImageAlphaInfo.none.rawValue
        )

        context!.draw(maskReference, in: CGRect(x: 0, y: 0, width: width, height: height))

        let maskImage = context!.makeImage()!

        let maskedReference = imageReference.masking(maskImage)!

        return UIImage(cgImage: maskedReference)
    }
    
    var body: some View {
        VStack {
            Image(uiImage: maskImage(image: UIImage(named: "uni")!, mask: UIImage(named: "mask")!))
                .background(.red)
            
            Image(uiImage: UIImage(data: maskImage(image: UIImage(named: "uni")!, mask: UIImage(named: "mask")!).pngData()!)!)
                .background(.red)
        }
    }
}

This code masks an image and returns a UIImage

You can see in the VStack that the first image is correct. It shows the masked image with a red background behind the masked area.

In the second image of the VStack, you can see that the transparency is gone.

So what I need to do is upload temp.pngData() to a server and expects to be able to view a png file with transparency preserved as shown in the preview code. But instead, when the file is uploaded I get the original without transparency.

How to fix?


Solution

  • You should make another image from the masked image if you need a merged one like a PNG:

    let renderer = UIGraphicsImageRenderer(size: maskedImage.size)
    let newImage = renderer.image { _ in maskedImage.draw(at: .zero) }
    

    Now the masked area has been removed and you can use newImage.pngData() as expected