Merge and edit 2 UIImage - ios

I was looking around to find a solution but I didn’t.
Actually I have a block of code that merge 2 image in one.
It’s like I take a photo and the apply a .png on it.
But I would like to let the user move the top image in order to choose the position before save the image
Thanks for any possible help to how I could do it
Here is my func:
func mergeFrame(bottomImage: UIImage, topImage: UIImage) -> UIImage{
let size = CGSize(width: bottomImage.size.width, height: bottomImage.size.height)
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)
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}

If you need to move the top image, the topImage should have a flexible drawing area.
topImage.draw(in: topArea, blendMode: .normal, alpha: 0.8)
Then use an UIPanGesture to change the topAread.origin base on the gesture.translation during State.Changed.
In State.End of the gesture, call posted mergeFrame(::) to get the composed image.
Hope you got it.

Related

How to apply scale when drawing and composing UIImage

I have the following functions.
extension UIImage
{
var width: CGFloat
{
return size.width
}
var height: CGFloat
{
return size.height
}
private static func circularImage(diameter: CGFloat, color: UIColor) -> UIImage
{
UIGraphicsBeginImageContextWithOptions(CGSize(width: diameter, height: diameter), false, 0)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
let rect = CGRect(x: 0, y: 0, width: diameter, height: diameter)
context.setFillColor(color.cgColor)
context.fillEllipse(in: rect)
context.restoreGState()
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
private func addCentered(image: UIImage, tintColor: UIColor) -> UIImage
{
let topImage = image.withTintColor(tintColor, renderingMode: .alwaysTemplate)
let bottomImage = self
UIGraphicsBeginImageContext(size)
let bottomRect = CGRect(x: 0, y: 0, width: bottomImage.width, height: bottomImage.height)
bottomImage.draw(in: bottomRect)
let topRect = CGRect(x: (bottomImage.width - topImage.width) / 2.0,
y: (bottomImage.height - topImage.height) / 2.0,
width: topImage.width,
height: topImage.height)
topImage.draw(in: topRect, blendMode: .normal, alpha: 1.0)
let mergedImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return mergedImage
}
}
They work fine, but how do I properly apply UIScreen.main.scale to support retina screens?
I've looked at what's been done here but can't figure it out yet.
Any ideas?
Accessing UIScreen.main.scale itself is a bit problematic, as you have to access it only from main thread (while you usually want to put a heavier image processing on a background thread). So I suggest one of these ways instead.
First of all, you can replace UIGraphicsBeginImageContext(size) with
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
The last argument (0.0) is a scale, and based on docs "if you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen."
If instead you want to retain original image's scale on resulting UIImage, you can do this: after topImage.draw, instead of getting the UIImage with UIGraphicsGetImageFromCurrentImageContext, get CGImage with
let cgImage = context.makeImage()
and then construct UIImage with the scale and orientation of the original image (as opposed to defaults)
let mergedImage = UIImage(
cgImage: cgImage,
scale: image.scale,
orientation: image.opientation)

How to make image to watermarkimage in swift [duplicate]

I know there are several other ways to do this; I don't want to import anything that I don't need to. If someone can help me with his code, that would be great.
Currently, it is only saving the original image without the watermark image.
extension UIImage {
class func imageWithWatermark(image1: UIImageView, image2: UIImageView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(image1.bounds.size, false, 0.0)
image2.layer.renderInContext(UIGraphicsGetCurrentContext()!)
image1.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img
}
}
func addWatermark() {
let newImage = UIImage.imageWithWatermark(imageView, image2: watermarkImageView)
UIImageWriteToSavedPhotosAlbum(newImage, nil, nil, nil)
}
EDIT: I've got the watermark appearing on the saved images.
I had to switch the order of the layers:
image1.layer.renderInContext(UIGraphicsGetCurrentContext()!)
image2.layer.renderInContext(UIGraphicsGetCurrentContext()!)
HOWEVER, it is not appearing in the correct place.It seems to always appear in the center of the image.
If you grab the UIImageViews' images you could use the following concept:
if let img = UIImage(named: "image.png"), img2 = UIImage(named: "watermark.png") {
let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
UIGraphicsBeginImageContextWithOptions(img.size, true, 0)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextFillRect(context, rect)
img.drawInRect(rect, blendMode: .Normal, alpha: 1)
img2.drawInRect(CGRectMake(x,y,width,height), blendMode: .Normal, alpha: 1)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(result, nil, nil, nil)
}
SWIFT 4
Use this
let backgroundImage = imageData!
let watermarkImage = #imageLiteral(resourceName: "jodi_url_icon")
let size = backgroundImage.size
let scale = backgroundImage.scale
UIGraphicsBeginImageContextWithOptions(size, false, scale)
backgroundImage.draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
watermarkImage.draw(in: CGRect(x: 10, y: 10, width: size.width, height: size.height - 40))
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Use result to UIImageView, tested.

UIImage (Frame) and UIImage (Picture) merge

I have multiple sizes of frames, which can be hard coded, or server will decide. I have to select Image from Gallery, which definitely can be of many dimensions.
I am selecting Image from Gallery
I am generating white background UIImage, using code.
let size = CGSize(width: 424/2, height: 664/2)
UIGraphicsBeginImageContextWithOptions(size, true, 0)
UIColor.white.setFill()
UIRectFill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
let background_image: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Now, what I want, to make another Image, which keep Leading 20 pixel, Top 20 Pixel, and width and height 20 pixel smaller than original background.
How can I achieve it.
What I tried before coming to StackOverflow.
func mergedImageWith(frontImage:UIImage?, backgroundImage: UIImage?) -> UIImage{
if (backgroundImage == nil) {
return frontImage!
}
let size = CGSize(width: 424/2, height: 664/2)
UIGraphicsBeginImageContextWithOptions(size, true, 0)
UIColor.white.setFill()
UIRectFill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
let backgroundImage2: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
backgroundImage2?.draw(in: CGRect.init(x: 0, y: 0, width: size.width, height: size.height))
frontImage?.draw(in: getAspectFillFrame(sizeImageView: size2, sizeImage: (frontImage?.size)!))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
here background image is created with aspect fill, but issue is of starting position and complete height and width.
In very simple words. Its like making custom frames and merge them with images(aspect fill) for printing.
can anyone help me out
Thanks.
Try not ending your image context until all of the images are drawn (I am also including some code that I have working, edited down a bit)
class layeredImageView: UIImageView {
var imageBackground:UIImage!
var imageForeground:UIImage!
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, UIScreen.main.scale)
self.image?.draw(in: self.frame)
imageBackground.draw(in: CGRect(<rect>)
imageForeground.draw(in: CGRect(<rect>)
self.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}

Swift UIView with multiply effect

What I've been trying to achieve for a couple of hours is something like the following:
I would like to have a UIImage in the background and then preferably a UIView with a background color of red with some kind of multiply effect (the red area). Is this possible? I've seen a few extensions for UIImage that tints them, but that would only work if I wanted my WHOLE image to have a red multiply color effect.
Thanks
You could just add a red UIView to the top of your UIImageView. Adjust the alpha to make it transparent:
let someView = UIView(frame: someImageView.frame)
someView.backgroundColor = UIColor(colorLiteralRed: 255.0/255.0, green: 0, blue: 0, alpha: 0.5)
someImageView.addSubview(someView)
Using a multiply instead:
let img = UIImage(named: “background”)
let img2 = UIImage(named: “effect”) //Make sure this is your red image same size as the background
let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
UIGraphicsBeginImageContextWithOptions(img.size, true, 0)
let context = UIGraphicsGetCurrentContext()
// fill the background with white so that translucent colors get lighter
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextFillRect(context, rect)
img.drawInRect(rect, blendMode: .Normal, alpha: 1)
img2.drawInRect(rect, blendMode: .Multiply, alpha: 1)
// grab the finished image and return it
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Swift 3 Extension (thx to #Kex):
extension UIImage{
class func multiply(image:UIImage, color:UIColor) -> UIImage? {
let rect = CGRect(origin: .zero, size: image.size)
//image colored
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
color.setFill()
UIRectFill(rect)
let coloredImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//image multiply
UIGraphicsBeginImageContextWithOptions(image.size, true, 0)
let context = UIGraphicsGetCurrentContext()
// fill the background with white so that translucent colors get lighter
context!.setFillColor(UIColor.white.cgColor)
context!.fill(rect)
image.draw(in: rect, blendMode: .normal, alpha: 1)
coloredImage?.draw(in: rect, blendMode: .multiply, alpha: 1)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
}
Example:
let image = UIImage.multiply(image: sourceImage, color: UIColor.red)
With iOS10 you can now use UIGraphicsImageRenderer to add a partial multiply effect as easy as this:
extension UIImage {
func tinted(_ color: UIColor, percentageFromBottom: CGFloat) -> UIImage? {
let imageRect = CGRect(origin: .zero, size: size)
let colorRect = CGRect(x: 0, y: (1.0 - percentageFromBottom) * size.height, width: size.width, height: percentageFromBottom * size.height)
let renderer = UIGraphicsImageRenderer(size: size)
let tintedImage = renderer.image { context in
color.set()
context.fill(colorRect)
draw(in: imageRect, blendMode: .multiply, alpha: 1)
}
return tintedImage
}
}
You can then use it like this to multiply the lower third of the original with a red multiply:
UIImage(named: "trees")?.tinted(.red, percentageFromBottom: 0.33)
Which results in this:

Merging two UIImage's

I want to merge two UIImage's but I'm having some difficulties. I'm playing around with a drawing app where the user when she or he is done will merge their final drawing with their original image they wanted to draw on.
topImage and bottomImage are both final images and need to be merged with their corresponding aspectFit aka ratio.
Then the user can at the end combine both images into one but the thing is that bottomImageView's UIImage will vary in size.
I've been trying to merge them without effecting the newImage or the Aspect ratio (fit)
Set up:
I have two UIImageView which are set to (width: 310, height: 400)
bottomImageView
bottomImage is JPEG: size ( 600, 800) //other images will vary in ratio
topImageView
topImage is PNG (for transparency): size (310, 400)
The bottomImage which is the part of that facebook post is the what the user will theoretically "draw". The topImage (red lines/circle) is the what should be merged with the bottom image.
How can I merge them together without changing the size of the UIImage's?
I've tried two different ways but to no avail.
way 1:
let size = CGSize(width: 300, height: 400)
UIGraphicsBeginImageContext(size)
let areaSize = CGRect(x: 0, y: 0, width: size.width, height: size.height)
bottomImage.drawInRect(areaSize)
topImage.drawInRect(areaSize, blendMode: CGBlendMode.Normal, alpha: 1.0)
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Way 1, doesn't work because, it creates a new canvas (300, 400) which ultimately alters the size which distorts both my bottomImage and topImage.
Way 2:
let bottomImageView: UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 310, height: 400))
let topImageView: UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 310, height: 400))
bottomImageView.image = topImage
topImageView.image = bottomImage
bottomImageView.contentMode = .ScaleAspectFit
topImageView.contentMode = .ScaleAspectFit
UIGraphicsBeginImageContext(bottomImageView.frame.size)
bottomImageView.image?.drawInRect(CGRect(x: 0, y: 0, width: bottomImageView.frame.size.width, height: bottomImageView.frame.size.height), blendMode: CGBlendMode.Normal, alpha: 1.0)
topImageView.image?.drawInRect(CGRect(x:0, y: 0, width: topImageView.frame.size.width, height: topImageView.frame.size.height), blendMode: CGBlendMode.Normal, alpha: 1.0)
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsGetImageFromCurrentImageContext()
Way 2: I thought that by putting two UIImageViews then "pressing" them together would work but it ended up distorting my newImage like way 1.
Is it possible to combine them without effecting making the newImage look distorted?

Resources