Hemang
Hemang

Reputation: 27050

How to merge two UIImages while keeping the aspect ratio and size?

The code is added to Github to let you understand the real problem.


This is the hierarchy:

-- ViewController.View P [width: 375, height: 667]
---- UIImageView A       [width: 375, height: 667] Name: imgBackground
                         [A is holding an image of size(1287,1662)]
---- UIImageView B       [width: 100, height: 100] Name: imgForeground
                         [B is holding an image of size(2400,982)]

I am trying to merge A with B but the result is stretched.

This is the merge code:

func mixImagesWith(frontImage:UIImage?, backgroundImage: UIImage?, atPoint point:CGPoint, ofSize signatureSize:CGSize) -> UIImage {
    let size = self.imgBackground.frame.size
    UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
    backgroundImage?.draw(in: CGRect.init(x: 0, y: 0, width: size.width, height: size.height))
    frontImage?.draw(in: CGRect.init(x: point.x, y: point.y, width: signatureSize.width, height: signatureSize.height))
    let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return newImage
}

Note:

Here's the screenshot to understand the problem:

enter image description here

What should I do to get the proper output of merge function?

Upvotes: 6

Views: 868

Answers (2)

mixel
mixel

Reputation: 25846

You have two bugs in your code:

  1. You should also calculate aspect for document image to fit it into UIImageView. In mergeImages() replace:

    img.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    

    with:

    img.draw(in: getAspectFitFrame(sizeImgView: size, sizeImage: img.size))
    
  2. When calculating aspect you center image horizontally/vertically if its width/height less then UIImageView width/height. But instead of comparing newWidth and newHeight you should compare factors:

    if hfactor > vfactor {
        y = (sizeImgView.height - newHeight) / 2
    } else {
        x = (sizeImgView.width - newWidth) / 2
    }
    

Upvotes: 2

Patel Jigar
Patel Jigar

Reputation: 2151

Try bellow code it works for me, hope it works for you too,

func addWaterMarkToImage(img:UIImage, sizeWaterMark:CGRect, waterMarkImage:UIImage, completion : ((UIImage)->())?){
     handler = completion
    let img2:UIImage = waterMarkImage
    let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
    UIGraphicsBeginImageContext(img.size)
    img.draw(in: rect)
    let frameAspect:CGRect = getAspectFitFrame(sizeImgView: sizeWaterMark.size, sizeImage: waterMarkImage.size)
    let frameOrig:CGRect = CGRect(x: sizeWaterMark.origin.x+frameAspect.origin.x, y: sizeWaterMark.origin.y+frameAspect.origin.y, width: frameAspect.size.width, height: frameAspect.size.height)
    img2.draw(in: frameOrig, blendMode: .normal, alpha: 1)

    let result = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    if handler != nil {
        handler!(result!)
    }
}
//MARK - Get Aspect Fit frame of UIImage
func getAspectFitFrame(sizeImgView:CGSize, sizeImage:CGSize) -> CGRect{

    let imageSize:CGSize  = sizeImage
    let viewSize:CGSize = sizeImgView

    let hfactor : CGFloat = imageSize.width/viewSize.width
    let vfactor : CGFloat = imageSize.height/viewSize.height

    let factor : CGFloat = max(hfactor, vfactor)

    // Divide the size by the greater of the vertical or horizontal shrinkage factor
    let newWidth : CGFloat = imageSize.width / factor
    let newHeight : CGFloat = imageSize.height / factor

    var x:CGFloat = 0.0
    var y:CGFloat = 0.0
    if newWidth > newHeight{
        y = (sizeImgView.height - newHeight)/2
    }
    if newHeight > newWidth{
        x = (sizeImgView.width - newWidth)/2
    }
    let newRect:CGRect = CGRect(x: x, y: y, width: newWidth, height: newHeight)

    return newRect

}

Upvotes: 2

Related Questions