如何合并两个UIImages,同时保持其位置,大小和纵横比?

我正在尝试合并两个不同大小的UIImage

我有UIImage A是以下大小: 1287 × 1662像素和UIImage B具有以下大小: 200 × 200像素


我在下面的UIImageView显示A和B.

UIImageView backgroundImageView的大小: 375 x 667UIImageView foregroundImageView的大小: 100 x 100

用户可以将foregroundImageView移动到backgroundImageView上方的任何位置。


这是合并代码:

 let previewImage:UIImage? = mergeImages(img: imgBackground.image!, sizeWaterMark: CGRect.init(origin: imgForeground.frame.origin, size: CGSize.init(width: 100, height: 100)), waterMarkImage: imgForeground.image!) func mergeImages(img:UIImage, sizeWaterMark:CGRect, waterMarkImage:UIImage) -> UIImage { let size = self.imgBackground.frame.size UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) img.draw(in: getAspectFitFrame(sizeImgView: size, sizeImage: img.size)) 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) waterMarkImage.draw(in: frameOrig, blendMode: .normal, alpha: 1) let result:UIImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return result } 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 hfactor > vfactor { y = (sizeImgView.height - newHeight) / 2 } else { x = (sizeImgView.width - newWidth) / 2 } let newRect:CGRect = CGRect(x: x, y: y, width: newWidth, height: newHeight) return newRect } 

这实际上是融合并给我我正在寻找的东西。 但是它减less了合并图像的大小。 正如你可以在mergeImages函数中看到这一行。

  let size = self.imgBackground.frame.size 

我想要的大小应该是原来的UIImage A大小。 所以,如果我改变这个,

  let size = self.imgBackground.image!.size 

合并之后,这将改变B在A上的位置。

为了testing,您可以从这里下载并检查源代码。

我应该怎么做才能保持原来的大小,而在确定B的确切位置和适当的宽高比?

我将实用函数设为静态(将它们移动到单独的文件中更好),以确保它们不使用ViewController实例属性和方法。

mergeImages我删除了:

 let size = self.imgBackground.frame.size 

并用img.sizereplacesize 。 就像你所描述的那样,使用self.imgBackground.image!.size是一样的。

由于源图像和目标图像大小相同,因此无需调整方面,我们只需更换:

 img.draw(in: getAspectFitFrame(sizeImgView: size, sizeImage: img.size)) 

 img.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: img.size)) 

此外,我提取了方面因素计算分离函数getFactor使代码更细粒度,使getAspectFitFrame返回不仅CGRect而且方面因素(稍后将有用)。

所以实用function现在看起来像:

 static func mergeImages(img: UIImage, sizeWaterMark: CGRect, waterMarkImage: UIImage) -> UIImage { UIGraphicsBeginImageContextWithOptions(img.size, false, UIScreen.main.scale) img.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: img.size)) let (frameAspect, _) = getAspectFitFrame(from: sizeWaterMark.size, to: waterMarkImage.size) let frameOrig = CGRect(x: sizeWaterMark.origin.x + frameAspect.origin.x, y: sizeWaterMark.origin.y + frameAspect.origin.y, width: frameAspect.size.width, height: frameAspect.size.height) waterMarkImage.draw(in: frameOrig, blendMode: .normal, alpha: 1) let result = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return result } static func getAspectFitFrame(from: CGSize, to: CGSize) -> (CGRect, CGFloat) { let (hfactor, vfactor, factor) = ViewController.getFactor(from: from, to: to) // Divide the size by the greater of the vertical or horizontal shrinkage factor let newWidth = to.width / factor let newHeight = to.height / factor var x: CGFloat = 0.0 var y: CGFloat = 0.0 if hfactor > vfactor { y = (from.height - newHeight) / 2 } else { x = (from.width - newWidth) / 2 } return (CGRect(x: x, y: y, width: newWidth, height: newHeight), factor) } static func getFactor(from: CGSize, to: CGSize) -> (CGFloat, CGFloat, CGFloat) { let hfactor = to.width / from.width let vfactor = to.height / from.height return (hfactor, vfactor, max(hfactor, vfactor)) } 

另外还需要另一个实用function来计算缩放水印的来源和大小:

 static func getScaledFrame(from: CGSize, to: CGSize, target: CGRect) -> CGRect { let (aspectFitFrame, factor) = ViewController.getAspectFitFrame(from: from, to: to) return CGRect( origin: CGPoint( x: (target.origin.x - aspectFitFrame.origin.x) * factor, y: (target.origin.y - aspectFitFrame.origin.y) * factor), size: CGSize(width: target.width * factor, height: target.height * factor) ) } 

现在您已准备好渲染合并的图像:

  let previewImage = ViewController.mergeImages( img: imgBackground.image!, sizeWaterMark: ViewController.getScaledFrame(from: imgBackground.frame.size, to: imgBackground.image!.size, target: imgForeground.frame), waterMarkImage: imgForeground.image! )