How to Merge Two Uiimages

How to merge two UIImages?

Hope this may help you,

var bottomImage = UIImage(named: "bottom.png")
var topImage = UIImage(named: "top.png")

var size = CGSize(width: 300, height: 300)
UIGraphicsBeginImageContext(size)

let areaSize = CGRect(x: 0, y: 0, width: size.width, height: size.height)
bottomImage!.draw(in: areaSize)

topImage!.draw(in: areaSize, blendMode: .normal, alpha: 0.8)

var newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()

All the Best :)

How to combine two UIImages into a single Image in Swift?

You are drawing both images into the same rect. You also should not use force-unwrapping. That causes your app to crash if anything goes wrong.

There are also various other small mistakes.

Change your function like this:

// Return an Optional so we can return nil if something goes wrong
func combine(bottomImage: Data, topImage: Data) -> UIImage? {

// Use a guard statement to make sure
// the data can be converted to images
guard
let bottomImage = UIImage(data: bottomImage),
let topImage = UIImage(data: topImage) else {
return nil
}
// Use a width wide enough for the widest image
let width = max(bottomImage.size.width, topImage.size.width)

// Make the height tall enough to stack the images on top of each other.
let size = CGSize(width: width, height: bottomImage.size.height + topImage.size.height)
UIGraphicsBeginImageContext(size)
let bottomRect = CGRect(
x: 0,
y: 0,
width: bottomImage.size.width,
height: bottomImage.size.height)

// Position the bottom image under the top image.
let topRect = CGRect(
x: 0,
y: bottomImage.size.height,
width: topImage.size.width,
height: topImage.size.height)

bottomImage.draw(in: bottomRect)

topImage!.draw(in: topRect)

let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}

(And you should really be using a UIGraphicsImageRenderer rather than than calling UIGraphicsBeginImageContext()/ UIGraphicsEndImageContext().)

Edit:

Note that if the 2 images are different widths the above code will leave a "dead space" on the right of the narrower image. You could also make the code center the narrower image, or scale it up to be the same width. (If you do scale it up I suggest scaling it up in both dimensions to preserve the original aspect ratio. Otherwise it will look stretched and unnatural.)

How to combine/ merge 2 images into 1

  1. Create a subview for adding images.
  2. Add all your images in that view instead of the main view.
  3. Let the buttons and other stuff stay on the main view.
  4. Render only the view with images in the bitmap context instead of the main view like you are doing right now.

How to merge two UIImages while keeping their position, size and aspect ratios?

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.

In mergeImages I removed:

let size = self.imgBackground.frame.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))

with

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

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

Merge two UIImages

That code looks correct (though I would recommend converting it to use a created CGBitmapContext for thread-safety), but is imageB supposed to be a JPEG? JPEGs don't support transparency, so, in order for the blending to work, it should really be a PNG.

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

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
    }

Swift generate single UIImage out of two UIImages side by side

You can use the idea from the linked question of using UIGraphicsContext and UIImage.draw to draw the 2 images side-by-side and then create a new UIImage from the context.

extension UIImage {
func mergedSideBySide(with otherImage: UIImage) -> UIImage? {
let mergedWidth = self.size.width + otherImage.size.width
let mergedHeight = max(self.size.height, otherImage.size.height)
let mergedSize = CGSize(width: mergedWidth, height: mergedHeight)
UIGraphicsBeginImageContext(mergedSize)
self.draw(in: CGRect(x: 0, y: 0, width: mergedWidth, height: mergedHeight))
otherImage.draw(in: CGRect(x: self.size.width, y: 0, width: mergedWidth, height: mergedHeight))
let mergedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return mergedImage
}
}

Usage (assuming leftImage and rightImage are both UIImages):

let mergedImage = leftImage.mergedSideBySide(with: rightImage)

Demo of the function (using SwiftUI for quicker display using previews):

struct Playground_Previews: PreviewProvider {
static let leftImage = UIColor.blue.image(CGSize(width: 128, height: 128))
static let rightImage = UIColor.red.image(CGSize(width: 128, height: 128))

static let mergedImage = leftImage.mergedSideBySide(with: rightImage) ?? UIImage()

static var previews: some View {
VStack(spacing: 10) {
Image(uiImage: leftImage)
Image(uiImage: rightImage)
Image(uiImage: mergedImage)
}
}
}

merged result

The UIColor.image function is from Create UIImage with solid color in Swift.

How to combine two images

As per as your question You have to add two images and show up in a single UIImageView.

Here is a simple example of adding two images vertically and showing up in an UIImageView -

    let topImage = UIImage(named: "image1.png") // 355 X 200
let bottomImage = UIImage(named: "image2.png") // 355 X 60

let size = CGSize(width: (topImage?.size.width)!, height: (topImage?.size.height)! + (bottomImage?.size.height)!)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)

topImage?.draw(in: CGRect(x:0, y:0, width:size.width, height: (topImage?.size.height)!))
bottomImage?.draw(in: CGRect(x:0, y:(topImage?.size.height)!, width: size.width, height: (bottomImage?.size.height)!))

let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()

// I've added an UIImageView, You can change as per your requirement.
let mergeImageView = UIImageView(frame: CGRect(x:0, y: 200, width: 355, height: 260))

// Here is your final combined images into a single image view.
mergeImageView.image = newImage

I hope it will help you to start with.

merge two different images in Swift

If you don't care about performance you can use Core Image

let volleyballImage = CIImage(image: UIImage(named:"volleyball.png")!)
let otherImage = CIImage(image: UIImage(named:"other.png")!)
let compositeFilter = CIFilter(name: "CIAdditionCompositing")!

compositeFilter.setValue(volleyballImage,
forKey: kCIInputImageKey)
compositeFilter.setValue(otherImage,
forKey: kCIInputBackgroundImageKey)

if let compositeImage = compositeFilter.outputImage{
let image = UIImage(CIImage: compositeImage)
// do something with the "merged" image
}


Related Topics



Leave a reply



Submit