Circle image crop when using UIImagePickerController Swift - ios

I need to crop images circle when importing from photo library, just like in the stock contacts app. I found a few solutions but all of them were in Objective-C. I found them hard to translate. Does anyone know a useful swift library or so?

this works for me
profileImage.image = UIImageVar
profileImage.layer.borderWidth = 1
profileImage.layer.borderColor = UIColor.blackColor().CGColor
profileImage.layer.cornerRadius = profileImage.frame.height/2
profileImage.clipsToBounds = true

If you're seeking something like Core Graphics, you can take the following for references.
let ctx = UIGraphicsGetCurrentContext()
let image = UIImage(named: "YourImageName")!
// Oval Drawing
let width = image.size.width
let height = image.size.height
let ovalPath = UIBezierPath(ovalInRect: CGRectMake(0, 0, width, height))
CGContextSaveGState(ctx)
ovalPath.addClip()
image.drawInRect(CGRectMake(0, 0, width, height))
CGContextRestoreGState(ctx)

Related

Crop UIImage keeping the same Aspect Ratio

I am working on an app, where you can edit photos, these photos are displayed as scaleAspectFill. When I know want to save the photo the edited things are not in the right position. (The UIImageView name is ImageView).
This is why I tried to crop my image, but I don't really know which values I really should use, I tried many possibilities.
My Code Is:
func crop() -> UIImage {
let x:CGFloat = ImageView.frame.maxX
let y:CGFloat = ImageView.frame.maxY
let width:CGFloat = ImageView.frame.width
let height:CGFloat = ImageView.frame.height
let croppedCGImage = ImageView.image?.cgImage?.cropping(to: CGRect(x: x, y: y, width: width, height: height))
let croppedImage = UIImage(cgImage: croppedCGImage!)
return croppedImage
}
I tried it with maxX/maxY too this is why it is written there.
Update
So I edited the image and now I want to save it, but now is really small, so it would be nice if you would help
this is the first image, how it should be
https://i.stack.imgur.com/91RBX.jpg
and this is the result
https://i.stack.imgur.com/gpDpY.png

Draw image and text into a single image

I'm attempting to combine both an image and a text field into a single image whilst still keeping the texts initial positioning.
I'm using UIGraphicsBeginImageContext to create a bitmap context and UIGraphicsGetImageFromCurrentImageContext to draw the final image.
So far, I have the following contained within a function:
let size = CGSize(width: self.takenImage.size.width, height: self.takenImage.size.height)
UIGraphicsBeginImageContextWithOptions(takenImage.size, false, takenImage.scale)
let areaSize = CGRect(x: 0, y: 0, width: self.takenImage.size.width, height: self.takenImage.size.height)
takenImage.draw(in: areaSize)
let imageViewSize = self.takenImage.size
let multiWidth = areaSize.width / imageViewSize.width
let multiHeight = areaSize.height / imageViewSize.height
print ("multiWidth = \(multiWidth)")
print ("multiHeight = \(multiHeight)")
let textSize = CGRect(x: textOverlay.frame.origin.x * multiWidth, y: textOverlay.frame.origin.y * multiHeight, width: textOverlay.frame.size.width * multiWidth, height: textOverlay.frame.size.height * multiHeight)
textOverlay.drawText(in: textSize)
let outputImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
self.finalImage = outputImage
takenImage is the taken image from my camera (never null) and textOverlay is a UITextField containing the wanted text.
I first create the bitmap and draw takenImage using both its original width/height.
If I draw just this to my finalImage, all works fine. The problem stems from trying to add the text and keep it in the same position.
I've tried to create a second CGRect with x, y, w, h coordinates from the UITextField : textOverlay but when viewing the final image, I'm getting weird results.
The images can be seen here.
How would I go about preserving the text's position in the merged image?
you need recalculate area size to draw text.
let areaSize = CGRect(x: 0, y: 0, width: self.takenImage.size.width, height: self.takenImage.size.height)
takenImage.draw(in: areaSize)
let imageViewSize = self.imageView.size
let multiWidth = areaSize.width / imageViewSize.width
let multiHeight = areaSize.height / imageViewSize.height
let textSize = CGRect(x: textOverlay.frame.origin.x * multiWidth, y: textOverlay.frame.origin.y * multiHeight, width: textOverlay.frame.size.width * multiWidth, height: textOverlay.frame.size.height * multiHeight)
textOverlay.drawText(in: textSize)
Here, I use self.imageView - it is imageView contains your takenImage.
Hope it help.

Image in button doesn't load, i only get a blue square

I am trying to add a button to a screen and edit it programmatically, but most of the edits don't respond.
This is the button code:
#IBOutlet weak var buttonTest: UIButton!
let screen = UIScreen.mainScreen().bounds
let buttonImg = ResizeImage(UIImage(named: "Blokker")!, targetSize: CGSize(width: 50, height: 50))
buttonTest.frame = CGRect(x: 0, y: screen.height - 300, width: screen.width * 0.5, height: screen.width * 0.5)
buttonTest.setImage(buttonImg, forState: .Normal)
buttonTest.setTitle("Test", forState: .Normal)
buttonTest.imageView?.contentMode = .ScaleAspectFit
view.addSubview(buttonTest)
The ResizeImage function works, i've used it in other view controllers already. The code for this is quoted below. The buttonTest.frame method doesn't work, the button will always stay in the same place without edits to the size. The image doesn't load either, in the place where the image should be, I can only see a blue square.
Does anyone know how to solve this problem? Thanks in advance!
The ResizeImage func:
func ResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSizeMake(size.width * heightRatio, size.height * heightRatio)
} else {
newSize = CGSizeMake(size.width * widthRatio, size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
The first part of your question I already answered in comment
Use imageView.imageRenderingMode = .AlwaysOriginal if you want the image to be the same as the source
and imageView.imageRenderingMode = .AlwaysTemplate if you want the image to be the same color as its container (images with no alpha channel will be a colored square)
For the frame problem, why are you the following line? Remove it.
view.addSubview(buttonTest)
Buttontest already has a superview as it's an outlet from storyboard/xib. Also, do not change frame rect if you're designing the button using storyboard/xib. You should learn how to use constraints for this.
Using FruitAddict's comment:
let buttonImg = ResizeImage(UIImage(named: "Blokker")!, targetSize: CGSize(width: 50, height: 50)).imageWithRenderingMode(.AlwaysOriginal)
solved the image problem, for people who experience the same problem!
The frame problem hasn't changed so far..
according to me please use SDWebImage ThirdParty library please follow below link:-
https://github.com/rs/SDWebImage
or you can also install through pod also and use this library....
i show you below code using swift language:-
let imageurl: NSURL? = NSURL(string: "")
imageview1.sd_setImageWithURL(url, placeholderImage:UIImage(named:"Ahmedabad_BRTS.jpg"))

Resizing an image but preserving hard edges

I am using a piece of code from this link - Resize UIImage by keeping Aspect ratio and width, and it works perfectly, but I am wondering if it can be altered to preserve hard edges of pixels. I want to double the size of the image and keep the hard edge of the pixels.
class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
let scale = newHeight / image.size.height
let newWidth = image.size.width * scale
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
What I want it to do
What it does
In Photoshop there is the nearest neighbour interpolation when resizing, is there something like that in iOS?
Inspired by the accepted answer, updated to Swift 5.
Swift 5
let image = UIImage(named: "Foo")!
let scale: CGFloat = 2.0
let newSize = image.size.applying(CGAffineTransform(scaleX: scale, y: scale))
UIGraphicsBeginImageContextWithOptions(newSize, false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()!
context.interpolationQuality = .none
let newRect = CGRect(origin: .zero, size: newSize)
image.draw(in: newRect)
let newImage = UIImage(cgImage: context.makeImage()!)
UIGraphicsEndImageContext()
Did a bit more digging and found the answer -
https://stackoverflow.com/a/25430447/4196903
but where
CGContextSetInterpolationQuality(context, kCGInterpolationHigh)
instead write
CGContextSetInterpolationQuality(context, CGInterpolationQuality.None)
You need to use CISamplerclass (Which is only available in iOS 9) and need to create your own custom image processing filter for it i think
You can find more information here and here too

Combine overlapping UIBezierPaths to create a single mask

I'm looking to create a mask in my view that is shaped like several circles. Here blurView is the view I want to have cut outs in, and frames contains CGRect frame values for these circles/ovals.
let holes = UIBezierPath()
for f in frames {
let p = UIBezierPath(ovalInRect: f)
holes.appendPath(p)
}
let path = UIBezierPath(rect: blurView.bounds)
path.appendPath(holes)
path.usesEvenOddFillRule = true
let mask = CAShapeLayer()
mask.path = path.CGPath
mask.fillRule = kCAFillRuleEvenOdd
blurView.layer.mask = mask
This works quite well, except when circles overlap, the contents of the blurView show through instead of the view below it. How can I fix that?
Edit: Using Rob's answer, I got somewhere, but not quite where I want to be. The edges of the mask are ragged, they lack anti-aliasing:
Any way to fix that?
The basic idea is to fill a bitmap context with an opaque colour and then clear anything we want to clip. Grab an image of that bitmap context and use as a mask.
You can copy this into a playground if you like:
import UIKit
// A couple of overlapping circles to play with
let frames = [
CGRect(x: 100, y: 100, width: 200, height: 200),
CGRect(x: 50, y: 50, width: 200, height: 200)
]
let blurView = UIImageView(image: ...) // <== You can drag an image here. Literals are cool.
let size = blurView.bounds.size
let scale = UIScreen.mainScreen().scale
// First, create a bitmap context to work in.
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue)
let ctx = CGBitmapContextCreate(nil, Int(size.width*scale), Int(size.height*scale),
8, 4 * Int(size.width * scale), CGColorSpaceCreateDeviceRGB(), bitmapInfo.rawValue)
CGContextScaleCTM(ctx, scale, scale)
// iOS draws upsidedown from Core Graphics, so you'll probably want to flip your context:
CGContextConcatCTM(ctx, CGAffineTransformMake(1, 0, 0, -1, 0, size.height))
// Everything we want to draw should be opaque
// Everything we want to clip should be translucent
CGContextSetGrayFillColor(ctx, 1, 1) // white
CGContextFillRect(ctx, blurView.bounds)
// And now we clear all our circles
CGContextSetBlendMode(ctx, .Clear)
CGContextSetGrayFillColor(ctx, 1, 0) // clear
for f in frames {
CGContextFillEllipseInRect(ctx, f)
}
// Make the masking image
let maskImage = CGBitmapContextCreateImage(ctx)
// For your playground amusement (you can quicklook this line)
UIImage(CGImage: maskImage)
// Create the masking layer
let mask = CALayer()
mask.frame = blurView.layer.frame
mask.contents = maskImage
// And apply it
blurView.layer.mask = mask
// And the final so you can quicklook it
blurView

Resources