Swift: draw image and border using UIGraphicsBeginImageContextWithOptions - swift

I need to draw an image like this
What provided is: green bubble with down arrow image(green bubble image already have border so I don't need to draw it) and center photo. And I need to draw white border around the photo + rounded corner it
This is the code I have so far:
let rect = CGRect(origin: .zero, size: CGSize(width: 60, height: 67))
let width = CGFloat(50)
let borderWidth: CGFloat = 1.0
let imageRect = CGRect(x: 5, y: 5, width: width, height: width)
let bubbleImg = #imageLiteral(resourceName: "pinGreen")
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
bubbleImg.draw(in: rect)
let path = UIBezierPath(roundedRect: imageRect.insetBy(dx: borderWidth / 2, dy: borderWidth / 2), cornerRadius: width/2)
context!.saveGState()
path.addClip()
image.draw(in: imageRect)
context!.restoreGState()
UIColor.purple.setStroke()
path.lineWidth = borderWidth
path.stroke()
let roundedImage = UIGraphicsGetImageFromCurrentImageContext();
let img = roundedImage?.cgImage!
UIGraphicsEndImageContext();
and this is the result
Can anyone help me with this?
Is there anyway to design and get this type of image from xib file?

I will tell you the simplest way:
You need imageView1 for green bubble image, imageView2 for the photo (width=height). Their centers are the same.
The imageView2 has corner radius equal to its frame width/2.
Set border color of imageView2's layer to White, and border width is about 5 px. Dont forget to set maskToBounds=true.
Please try.
DaijDjan: this answer in one image (showing IB + code + app):

Related

How to overlay an image on top of another image

I am working on creating a small word guessing app for a school assignment in uikit and I have been trying to figure out a way to overlay an image that updates based on the amount of incorrect guesses left on top of another image. I've spent almost 2 1/2 hours checking and I could not find a single method that worked.
So far this is what I've tried
let bgimg = UIImage(named: "background") // The image used as a background
let bgimgview = UIImageView(image: bgimg) // Create the view holding the image
bgimgview.frame = CGRect(x: 0, y: 0, width: 500, height: 500) // The size of the background image
let frontimg = UIImage(named: "Tree \(currentGame.incorrectMovesRemaining)") // The image in the foreground
let frontimgview = UIImageView(image: frontimg) // Create the view holding the image
frontimgview.frame = CGRect(x: 150, y: 300, width: 50, height: 50) // The size and position of the front image
bgimgview.addSubview(frontimgview) // Add the front image on top of the background
I commented this one out so that my code could work
let bottomImage = UIImage(named: "background")!
// let topImage = UIImage(named: "Tree \(currentGame.incorrectMovesRemaining)")!
// let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 100, height: 100))
// let newSize = rect.size // set this to what you need
// UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
//
// bottomImage.draw(in: rect)
// topImage.draw(in: rect)
//
// let newImage = UIGraphicsGetImageFromCurrentImageContext()
// UIGraphicsEndImageContext()
// }
//
// var backgroundImageButton: UIButton! {
// backgroundImageButton.setBackgroundImage(newImage)
You should be able to do this by adjusting the alpha value of the foreground image view. Alpha controls the transparency of a view-- an alpha of 1.0 makes it opaque, a value of 0 is invisible, and values between 0 and 1 make a view more or less transparent. If you have the two image views aligned so that one covers the other, you can set the foreground image alpha to any value from 0 to 1 to adjust how transparent it is.

Erasing pixels from image and then reverting them back

I'm creating an eraser app where i have a picture and the user can erase the background with the following func :
func eraseImage( image: UIImage ,line: [CGPoint] ,brushSize: CGFloat) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(proxy.size, false, 0)
let context = UIGraphicsGetCurrentContext()
let rect = AVMakeRect(aspectRatio: image.size, insideRect: CGRect(x: 0, y:0, width: proxy.size.width, height: proxy!.size.height))
//lassoImageView.image?.draw(in: calculateRectOfImageInImageView(imageView: lassoImageView))
image.draw(in: rect, blendMode: .normal, alpha: 1)
context?.move(to: CGPoint(x: line.first!.x - 50, y: line.first!.y - 50))
for pointIndex in 1..<line.count {
context?.addLine(to: CGPoint(x: line[pointIndex].x - 50, y: line[pointIndex].y - 50))
}
context?.setBlendMode(.clear)
context?.setLineCap(.round)
context?.setLineWidth(brushSize)
context?.setShadow(offset: CGSize(width: 0, height: 0), blur: 8)
context?.strokePath()
if let img = UIGraphicsGetImageFromCurrentImageContext() {
return img
}
UIGraphicsEndImageContext()
return nil
}
I'm struggling with figuring out how can i add a drawing function where the user can correct it's earaser mistake and draw back some parts.
I'm thinking of drawing on the edited image the original image with a mask of the path which tracks the cgpoints of the users location. is that possible?
I would suggest setting up your image with a second CALayer installed as a mask. Install an image view into the mask layer's contents, and draw with clear/opaque colors into the mask to mask/expose pixels from the image layer.

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?

Cropping an image from the top in Swift

I am trying to crop this image, which is a SKSpriteNode:
I am trying to crop this image from the top, so that I maintain the bottom semi circle of this shape. For instance, it'd be cropped to this:
So I use these two methods to accomplish this task:
func recalculateScore() {
currentScore -= decreaseRate
let image = UIImage(cgImage: (vial.texture?.cgImage())!)
vial.texture = SKTexture(image: cropBottomImage(image: image))
}
func cropBottomImage(image: UIImage) -> UIImage {
let height = CGFloat(image.size.height / 3)
let rect = CGRect(x: 0, y: image.size.height - height, width: image.size.width, height: height)
return cropImage(image: image, toRect: rect)
}
func cropImage(image:UIImage, toRect rect:CGRect) -> UIImage {
let imageRef:CGImage = image.cgImage!.cropping(to: rect)!
let croppedImage:UIImage = UIImage(cgImage:imageRef)
return croppedImage
}
However, this leads to this result:
It is as if it was being compressed. I think my issue might be in this line:
let rect = CGRect(x: 0, y: image.size.height - height, width: image.size.width, height: height)
Does the CGRect coordinate of (0,0) lie within the top most left corner? I am a bit confused on what the x and y parameters for the CGRect mean?
Resize your sprite, what is happening is the cropped texture is stretching to fill the sprite, and since you only crop vertically, it will only stretch vertically
func recalculateScore() {
currentScore -= decreaseRate
let image = UIImage(cgImage: (vial.texture?.cgImage())!)
vial.texture = SKTexture(image: cropBottomImage(image: image))
vial.size = vial.texture.size
}

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...