如何在保持位置、大小和纵横比的同时合并两个 UIImages? [英] How to merge two UIImages while keeping their position, size and aspect ratios?

查看:20
本文介绍了如何在保持位置、大小和纵横比的同时合并两个 UIImages?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我有 UIImage A 的尺寸如下:1287 × 1662 像素而 UIImage B 的大小如下:200 × 200 像素<小时>我在以下 UIImageView s 中显示 A 和 B.

I have UIImage A is of the following size: 1287 × 1662 pixels And UIImage B is of the following size: 200 × 200 pixels


I am showing A and B in following UIImageViews.

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

UIImageView backgroundImageView of the size: 375 x 667 And UIImageView foregroundImageView of the size: 100 x 100

用户可以将foregroundImageView移动到backgroundImageView上方的任意位置.<小时>这是合并代码:

User can move foregroundImageView to any position above the backgroundImageView.


This is the merging code:

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
}

这实际上是合并并提供了我正在寻找的东西.但它正在减少合并图像的大小.正如您在 mergeImages 函数中看到的这一行.

This is actually merging and giving me what I am looking for. But it's reducing the size of merged image. As you can see this line in the mergeImages function.

    let size = self.imgBackground.frame.size

我希望大小应该是原始的 UIImage A 大小.所以如果我把它改成这个,

I want the size should be the original UIImage A size. So if I change it to this,

    let size = self.imgBackground.image!.size

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

This will change the location of the B over A, after merging.

要进行测试,您可以从此处下载并查看源代码.

For testing, you can download and check the source code from here.

我应该怎么做才能保持原始尺寸不变,同时以适当的纵横比获得 B 与 A 的准确位置?

推荐答案

我将实用程序函数设为静态(最好将它们移动到单独的文件中)以确保它们没有使用 ViewController 实例属性和方法.

I made utility functions static (it's even better to move them in separate file) to be sure that they are not using ViewController instance properties and methods.

mergeImages 中我删除了:

let size = self.imgBackground.frame.size

并将 size 替换为 img.size.这与您在问题中描述的使用 self.imgBackground.image!.size 相同.

and replaced size with img.size. It's the same as using self.imgBackground.image!.size as you described in question.

因为源图像和目标图像大小相同,所以无需调整宽高比,我们只需替换:

Because source and target image sizes are the same there is no need to adjust aspect and we simply replace:

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 还返回纵横因数(以后会用到).

Also I extracted aspect factor calculation to separate function getFactor to make code more granular and made getAspectFitFrame return not only CGRect but also aspect factor (it'll be useful later).

所以效用函数现在看起来像:

So utility functions are now looking like:

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))
}

您还需要另一个效用函数来计算缩放水印的原点和大小:

Also you need another utility function to calculate scaled water mark origin and size:

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)
    )
}

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

Now you are ready to render merged image:

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

这篇关于如何在保持位置、大小和纵横比的同时合并两个 UIImages?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆