Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • .contentMode = .scaleAspectFit
  • Code works but the result is stretched.
  • See this line in code, let size = self.imgBackground.frame.size – I need to change this to fix the problem. Find the origin of subview with respect to UIImage size

Here's the screenshot to understand the problem:

enter image description here

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

like image 406
Hemang Avatar asked May 10 '17 11:05

Hemang


2 Answers

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
    }
    
like image 63
mixel Avatar answered Oct 21 '22 13:10

mixel


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

}
like image 40
Patel Jigar Avatar answered Oct 21 '22 12:10

Patel Jigar