admin管理员组

文章数量:1391999

I have 2 UIImages, image1 and image2. I wish to overlay image2 onto image1, the overlaid image2 should be in the center of image1 and the result should return a UIImage and not UIImageView.

With my code below, I am able to overlay square image (this is image2) over circle image (this is image1), but the square is getting placed on the bottom right. I want the square to be in the center of the circle.

How can I achieve that with UIImage?

Note:

  • I know overlaying images is easier in SwiftUI and centering the images would be easier with UIImageView, but in my app, I have a requirement to overlay one image on top of other in the center and return it as an UIImage
  • In my case, the base image or image1 will always be a circular image, image2 could be any image, but the size will be smaller than image1 and should always be placed in the center. Just to keep this sample code simple, I am using a square image.
  • If it matters, my current circle image is 2000x2000 pixels and square image is 1200x1200 pixels.

Code:

import SwiftUI

struct ContentViewA: View {
    @State private var displayImage: Image?
    
    var body: some View {
        VStack {
            if let displayImage = displayImage {
                displayImage
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 80.0, height: 80.0)
                    .padding(.leading, 5.0)
                    .contentShape(Circle())
            } else {
                Text("There is no image to display.")
            }
        }
        .onAppear {
            displayImage = self.getImage()
        }
    }
    
    func getImage() -> Image {
        let baseCircleSymbol = UIImage.init(named: "circle")?.withTintColor(UIColor(Color.yellow), renderingMode: .alwaysTemplate) ?? UIImage()
        let squareIcon = UIImage.init(named: "square")?.withTintColor(UIColor(Color.blue), renderingMode: .alwaysTemplate) ?? UIImage()
        let displayImage = baseCircleSymbol.overlayImage(imageToOverlay: squareIcon)
        return Image(uiImage: displayImage)
    }
}

extension UIImage {
    func overlayImage(imageToOverlay: UIImage) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        let actualArea = CGRect(x: 0, y: 0, width: size.width, height: size.height)

        let overlayImageArea = CGRect(x: size.width - imageToOverlay.size.width,
                                      y: size.height - imageToOverlay.size.height,
                                      width: 900, height: 900)
        
        self.draw(in: actualArea)
        imageToOverlay.draw(in: overlayImageArea)
        
        let overlayed = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return overlayed
    }
}

Screenshot:

I have 2 UIImages, image1 and image2. I wish to overlay image2 onto image1, the overlaid image2 should be in the center of image1 and the result should return a UIImage and not UIImageView.

With my code below, I am able to overlay square image (this is image2) over circle image (this is image1), but the square is getting placed on the bottom right. I want the square to be in the center of the circle.

How can I achieve that with UIImage?

Note:

  • I know overlaying images is easier in SwiftUI and centering the images would be easier with UIImageView, but in my app, I have a requirement to overlay one image on top of other in the center and return it as an UIImage
  • In my case, the base image or image1 will always be a circular image, image2 could be any image, but the size will be smaller than image1 and should always be placed in the center. Just to keep this sample code simple, I am using a square image.
  • If it matters, my current circle image is 2000x2000 pixels and square image is 1200x1200 pixels.

Code:

import SwiftUI

struct ContentViewA: View {
    @State private var displayImage: Image?
    
    var body: some View {
        VStack {
            if let displayImage = displayImage {
                displayImage
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 80.0, height: 80.0)
                    .padding(.leading, 5.0)
                    .contentShape(Circle())
            } else {
                Text("There is no image to display.")
            }
        }
        .onAppear {
            displayImage = self.getImage()
        }
    }
    
    func getImage() -> Image {
        let baseCircleSymbol = UIImage.init(named: "circle")?.withTintColor(UIColor(Color.yellow), renderingMode: .alwaysTemplate) ?? UIImage()
        let squareIcon = UIImage.init(named: "square")?.withTintColor(UIColor(Color.blue), renderingMode: .alwaysTemplate) ?? UIImage()
        let displayImage = baseCircleSymbol.overlayImage(imageToOverlay: squareIcon)
        return Image(uiImage: displayImage)
    }
}

extension UIImage {
    func overlayImage(imageToOverlay: UIImage) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        let actualArea = CGRect(x: 0, y: 0, width: size.width, height: size.height)

        let overlayImageArea = CGRect(x: size.width - imageToOverlay.size.width,
                                      y: size.height - imageToOverlay.size.height,
                                      width: 900, height: 900)
        
        self.draw(in: actualArea)
        imageToOverlay.draw(in: overlayImageArea)
        
        let overlayed = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return overlayed
    }
}

Screenshot:

Share Improve this question asked Mar 13 at 4:32 tech_humantech_human 7,17617 gold badges76 silver badges135 bronze badges 1
  • what's problem using ZStack this ? that may help to identify – Dipesh Pokhrel Commented Mar 13 at 7:23
Add a comment  | 

2 Answers 2

Reset to default 0

Here is the updated dynamic frame for the imageToOverlay with calculation of center position. Used same size for the overlay image.

let imageToOverlaySize = imageToOverlay.size
let overlayImageArea = CGRect(x: size.width/2 - imageToOverlaySize.width/2,
                              y: size.height/2 - imageToOverlaySize.height/2,
                              width: imageToOverlaySize.width, height: imageToOverlaySize.height)
    

let overlaySize = imageToOverlay.size
let overlayOrigin = CGPoint(x: (size.width - overlaySize.width) / 2,
                                    y: (size.height - overlaySize.height) / 2)
let overlayImageArea = CGRect(origin: overlayOrigin, size: overlaySize)

Here, you can use overlayOrigin to get the center of the base image

本文标签: swiftOverlay one UIImage onto another UIImage in the centerStack Overflow