Getting black and white image after applying mask - swift

I am removing background from image containing at least one human body. I am applying mask to UIImage and successfully masked image containing only human body with transparent background, but if I tried to convert to UIImage back after applying mask I am getting black and white cropped image.
I am using this snippet to apply mask and get result as UIImage
func maskImage(image:UIImage, mask:(UIImage))->UIImage{
let imageReference = image.cgImage
let maskReference = mask.cgImage
let imageMask = CGImage(maskWidth: maskReference!.width,
height: maskReference!.height,
bitsPerComponent: maskReference!.bitsPerComponent,
bitsPerPixel: maskReference!.bitsPerPixel,
bytesPerRow: maskReference!.bytesPerRow,
provider: maskReference!.dataProvider!, decode: nil, shouldInterpolate: true)
let maskedReference = imageReference!.masking(imageMask!)
let maskedImage = UIImage(cgImage:maskedReference!)
return maskedImage
}
but I am getting black and white image with only human body instead of coloured.

After doing much research I finally got answer as below:
UIGraphicsBeginImageContextWithOptions(imgView1.frame.size, _: false, _: 0.0)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: 0.0, y: (imgView1?.frame.size.height)!)
context?.scaleBy(x: 1.0, y: -1.0)
let maskImage = maskImg.cgImage
context?.clip(to: imgView1!.bounds, mask: maskImage!)
context?.translateBy(x: 0.0, y: (imgView1?.frame.size.height)!)
context?.setStrokeColor(UIColor.red.cgColor)
context?.stroke(imgView1!.frame, width: 15.0)
context?.scaleBy(x: 1.0, y: -1.0)
imgView1?.image?.draw(in: imgView1?.bounds ?? CGRect.zero)
let image: UIImage? = UIGraphicsGetImageFromCurrentImageContext()

Related

Adding gradient behind image returns empty image

I have a round avatar image with a transparent background. I want to create a new round image of the same size out of the initial image, with a gradient background behind it. So it looks like standing in sky instead of having a transparent background.
Since I will use this image as tabbaritem’s image, I couldn’t use uiview and edit it’s background layer.
And to make it reusable I wanted to create a UIImage extension.
Below is what I do:
extension UIImage {
func gradientImage() -> UIImage? {
let width = self.size.width
let height = self.size.height
UIGraphicsBeginImageContextWithOptions(size, false, 0)
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let bitmapContext = CGContext(data: nil,
width: Int(width),
height: Int(height),
bitsPerComponent: 8,
bytesPerRow: 0,
space: colorSpace,
bitmapInfo: bitmapInfo.rawValue) else { return nil }
let locations: [CGFloat] = [0.0, 1.0]
let top = R.color.duckDimDarkGrey()?.cgColor
let bottom = R.color.duckPencilDark()?.cgColor
let colors = [top, bottom] as CFArray
guard let gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: locations) else {
return nil
}
bitmapContext.drawLinearGradient(gradient, start: CGPoint.zero, end: CGPoint(x: 0, y: size.height), options: CGGradientDrawingOptions())
guard let cgImage = UIGraphicsGetImageFromCurrentImageContext()?.cgImage else { return nil }
UIGraphicsEndImageContext()
let img = UIImage(cgImage: cgImage)
return img
}
}
Here is how I use it:
Let image1 = UIImage(named: “test.png”)
self.tabBar.items[3].image = image1.gradientImage()
However I am getting an empty image somehow.

How to make a UIImage be a blur effect view?

Ok, Im working in Swift here and there are a lot of answers like this How to use UIVisualEffectView? that talk about how to apply a UIVisualEffectView OVER an image, so that it blurs it like a background.
My problem is I need to have my image, or rather the outline of my image BE the Blur view - meaning I create a blur UIVisualEffectView in the shape of my image so the "color" of the image itself is the blur. An example mockup (pretend that is a blur):
I know you can trace a UIImage into a custom color like this:
func overlayImage(color: UIColor, img: UIImage) -> UIImage {
UIGraphicsBeginImageContextWithOptions(img.size, false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
color.setFill()
context!.translateBy(x: 0, y: img.size.height)
context!.scaleBy(x: 1.0, y: -1.0)
context!.setBlendMode(CGBlendMode.colorBurn)
let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
context!.draw(img.cgImage!, in: rect)
context!.setBlendMode(CGBlendMode.sourceIn)
context!.addRect(rect)
context!.drawPath(using: CGPathDrawingMode.fill)
let coloredImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return coloredImage!
}
But I cant get my UIImageView to "mask" the blur view and achieve the effect. Right now with this attempt:
var img = UIImageView(image: UIImage(named: "dudeIco"))
img.frame = CGRect(x: 0, y: 0, width: self.bounds.width * 0.7, height: self.bounds.width * 0.7)
img.center = CGPoint(x: self.bounds.width/2, y: self.bounds.height/2)
self.addSubview(img)
let blur = UIVisualEffectView(effect: UIBlurEffect(style:
UIBlurEffectStyle.light))
blur.frame = img.bounds
blur.isUserInteractionEnabled = false
img.insertSubview(blur, at: 0)
I just get a blurred square. I need the shape of the image. How can I do this? Is this impossible?

Merging two Images & text on a final image

What I'm trying to do in Swift is merge two images together, the images I'm merging together is me dragging one image on top of another image with touch gestures. I get the images to composite, BUT the image I dragged on top of the main image does not keep it's position. How do I get it to stay where I placed it for the composite?
Here's my code:
extension CIHHatSelectionViewController{
// Return composite image of image2 overlayed on image1
//
func compositeImage(_ image1: UIImage, image2: UIImage, drawText: String, imageView1: CGPoint, imageView2:CGRect) -> UIImage {
let catPos = (image1.size.height - imageView2.origin.y) - imageView2.height
let bounds1 = CGRect(x: 0, y: 0, width: image1.size.width, height: image1.size.height)
let bounds2 = CGRect(x:imageView2.origin.x, y:catPos, width:imageView2.size.width, height:imageView2.size.height)
_ = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
let ctx = CGContext(data: nil,
width: image1.cgImage!.width,
height: image1.cgImage!.height,
bitsPerComponent: image1.cgImage!.bitsPerComponent,
bytesPerRow: image1.cgImage!.bytesPerRow,
space: image1.cgImage!.colorSpace!,
bitmapInfo: bitmapInfo.rawValue)!
ctx.draw(image1.cgImage!, in: bounds1, byTiling: false)
ctx.setBlendMode(.normal) // one image over the other
ctx.draw(image2.cgImage!, in: bounds2, byTiling: false)
let finalImage = textToImage(drawText, inImage: UIImage(cgImage: ctx.makeImage()!), atPoint: imageView1)
return finalImage
}

how to change specific color in image to a different color

I have an UIView that its layer contents is an image.
let image = UIImage(names: "myImage")
layer.contents = image.CGImage
This image has a few colors.
Is there a way to change a specific color to any other color of my choice?
I found answers for changing the all of the colors in the image but not a specific one.
answer
You can't change specific color in PNG with transparent background, but.. i found the solution.
extension UIImage {
func maskWithColors(color: UIColor) -> UIImage? {
let maskingColors: [CGFloat] = [100, 255, 100, 255, 100, 255] // We should replace white color.
let maskImage = cgImage! //
let bounds = CGRect(x: 0, y: 0, width: size.width * 3, height: size.height * 3) // * 3, for best resolution.
let sz = CGSize(width: size.width * 3, height: size.height * 3) // Size.
var returnImage: UIImage? // Image, to return
/* Firstly we will remove transparent background, because
maskingColorComponents don't work with transparent images. */
UIGraphicsBeginImageContextWithOptions(sz, true, 0.0)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
context.scaleBy(x: 1.0, y: -1.0) // iOS flips images upside down, this fix it.
context.translateBy(x: 0, y: -sz.height) // and this :)
context.draw(maskImage, in: bounds)
context.restoreGState()
let noAlphaImage = UIGraphicsGetImageFromCurrentImageContext() // new image, without transparent elements.
UIGraphicsEndImageContext()
let noAlphaCGRef = noAlphaImage?.cgImage // get CGImage.
if let imgRefCopy = noAlphaCGRef?.copy(maskingColorComponents: maskingColors) { // Magic.
UIGraphicsBeginImageContextWithOptions(sz, false, 0.0)
let context = UIGraphicsGetCurrentContext()!
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: 0, y: -sz.height)
context.clip(to: bounds, mask: maskImage) // Remove background from image with mask.
context.setFillColor(color.cgColor) // set new color. We remove white color, and set red.
context.fill(bounds)
context.draw(imgRefCopy, in: bounds) // draw new image
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
returnImage = finalImage! // YEAH!
UIGraphicsEndImageContext()
}
return returnImage
}
}
For call this function use code like this...
let image = UIImage(named: "Brush").maskWithColor(color: UIColor.red)
Result:
You can not change the image color... The only way is to change the image on any event or something...
Another variant is to create one image with transparent color, and set the background color of the view or something where you put the image...

How can I add a watermark to an image using this code?

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.