Edit image into circle shape and insert into another image in Swift - ios

I have image1, I would like to make that image circle shape and then insert it into image2. How to do it using swift? I can't do this with photoshop or other image editing tool, because my image1 will may be different every time.
EDIT: This what I am trying to achieve:
Flower is image1.
EDIT 2: What I have tried and kind of works:
let image2 = UIImage(named: "RedPin")
let newSize = CGSizeMake(image2!.size.width, image2!.size.height)
UIGraphicsBeginImageContext(newSize)
image2!.drawInRect(CGRectMake(0,0,newSize.width,newSize.height))
let imageView: UIImageView = UIImageView(image: image1)
var layer: CALayer = CALayer()
layer = imageView.layer
layer.masksToBounds = true
layer.cornerRadius = CGFloat(65)
UIGraphicsBeginImageContext(imageView.bounds.size)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// decrease top image size
roundedImage.drawInRect(CGRectMake(10,10,45,45), blendMode: .Normal, alpha:1.0)
let createdNewImage = UIGraphicsGetImageFromCurrentImageContext()
Yet image1 is more a square with rounded edges and in general image seems to be low quality. Here is what that function above does:
EDIT 3: Toucan library is great at creating rounded images (let roundedImage = Toucan(image: newImage).maskWithEllipse().image), however final image version still looks blurry. Why's that?

I have Set image like this with rounded corner with same code like you.
func UserImageForAnnotation() -> UIImage {
let userPinImg : UIImage = UIImage(named: "pin_user.png")!
UIGraphicsBeginImageContextWithOptions(userPinImg.size, false, 0.0);
userPinImg.drawInRect(CGRect(origin: CGPointZero, size: userPinImg.size))
let roundRect : CGRect = CGRectMake(2, 2, userPinImg.size.width-4, userPinImg.size.width-4)
let myUserImgView = UIImageView(frame: roundRect)
myUserImgView.image = UIImage(named: "pic.png")
// myUserImgView.backgroundColor = UIColor.blackColor()
// myUserImgView.layer.borderColor = UIColor.whiteColor().CGColor
// myUserImgView.layer.borderWidth = 0.5
let layer: CALayer = myUserImgView.layer
layer.masksToBounds = true
layer.cornerRadius = myUserImgView.frame.size.width/2
UIGraphicsBeginImageContextWithOptions(myUserImgView.bounds.size, myUserImgView.opaque, 0.0)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
roundedImage.drawInRect(roundRect)
let resultImg : UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImg
}
Which gives me exact result what I want in my pin image.

Related

iOS: Image blending with Core Graphics

I would like to blend two images using Core Graphics.
For example, I have an image:
This image represents the frame. I would like to have this image sliceable.
Another image represents the background:
What I am trying to achieve, is to blind those two images like:
The important thing, that this image might not necessary be circle. It might be sliceable.
How can I achieve this by using Core Graphics?
Try following method that uses masking (maskImage is the one that represents "frame", so in your example it would be that black circle, surrounding of the black circle has to be transparent):
import UIKit
class ViewController: UIViewController {
fileprivate let imageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(imageView)
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
let cons = [
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
imageView.heightAnchor.constraint(equalToConstant: 130),
imageView.widthAnchor.constraint(equalToConstant: 300),
]
NSLayoutConstraint.activate(cons)
setup(image: #imageLiteral(resourceName: "image"), withMask: #imageLiteral(resourceName: "masking"))
}
fileprivate func setup(image: UIImage, withMask maskImage: UIImage) {
imageView.superview?.layoutIfNeeded()
imageView.image = maskImage
let slicedMask = captureView(imageView: imageView)
imageView.image = image
let mask = CALayer()
mask.contents = slicedMask.cgImage
mask.frame = imageView.bounds
imageView.layer.mask = mask
}
func captureView(imageView: UIImageView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, UIScreen.main.scale)
let context: CGContext = UIGraphicsGetCurrentContext()!
imageView.layer.render(in: context)
let img: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return img
}
}
I deal with slicing here quite "hacky": first I render the mask in the imageView to get it sliced, then I take a "screenshot" of the rendered sliced mask, and use the screenshot as a mask.
Keep in mind that mask.frame = imageView.bounds has to set frame properly, thus at that point the layout should be done. If later layout of the image changes, you will have to setup the mask again. mask.frame always have to fit the imageView.bounds (so if the layout changes in time, re-setup the image after layout changed).

creating circular pics for tableview cell images

I'm trying to make images circular in a tableview cell, I've the various ways I've seen on stackoverflow but this is the closest I've gotten:
As you can see they look more like elipses than circles. In storyboard I have the constraints set to keeping the aspect ratio 1:1 and the view mode "aspect fill". I'm using this UIImage extension for the circular shape:
extension UIImage {
var circleMask: UIImage {
let square = CGSize(width: min(size.width, size.height), height: min(size.width, size.height))
let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: square))
imageView.contentMode = UIViewContentMode.scaleAspectFill
imageView.image = self
imageView.layer.cornerRadius = square.width/2
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = 5
imageView.layer.masksToBounds = true
UIGraphicsBeginImageContext(imageView.bounds.size)
imageView.layer.render(in: UIGraphicsGetCurrentContext()!)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result!
}
}
This is how my cellForRowAt IndexPath looks:
let cell = detailTableView.dequeueReusableCell(withIdentifier: castResuseIdentifier)
as! CastCell
let cast = castArray[indexPath.row]
cell.actorName.text = cast.name
cell.characterName.text = cast.character
cell.actorProfileImage.image = castImageArray[indexPath.row].circleMask
self.detailTableView.rowHeight = 100
detailTableView.allowsSelection = true
return cell
Not sure why they aren't perfect circles, any idea?
That is a really non-performant way of achieving that effect, since you're creating a UIImageView and rendering it to a separate image context every time.
For a quick and easy way to do it, just set the cornerRadius property for the layer of the actorProfileImage view inside your CastCell.
By not using the extension and instead adding this to the cellForRowAtIndexPath the images came out circular
cell.actorProfileImage.layer.cornerRadius = cell.actorProfileImage.frame.size.height/2
cell.actorProfileImage.clipsToBounds = true
cell.actorProfileImage.layer.masksToBounds = true

How to set corner radius for all corners with image view rendered from UIGraphicsGetImageFromCurrentImageContext

This is how it looks before:
and after I generate dragging view:
and this is how I generate the dragging view from cell:
private func setupDraggingViewForCell(cell: BWStudentWishlistBookCollectionViewCell) {
UIGraphicsBeginImageContextWithOptions(cell.bounds.size, false, 0)
cell.bookImageView.layer.renderInContext(UIGraphicsGetCurrentContext()!)
draggingView = UIImageView(image: UIGraphicsGetImageFromCurrentImageContext())
draggingView?.clipsToBounds = true
draggingView?.contentMode = .ScaleAspectFit
draggingView?.layer.masksToBounds = true
draggingView?.layer.cornerRadius = 10
view.addSubview(draggingView!)
UIGraphicsEndImageContext()
}
As you can see, only one corner is rounded. Why?
You can set the clipsToBounds to false, and probably it would solve the problem in your case. Otherwise it will show you the full frame of the cover, and you can decide afterwards what to do.
draggingView?.clipsToBounds = false
You Can Directly add this code into your custom cell otherwise as per your need.......
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
imageView.layer.shadowColor = UIColor.blackColor().CGColor
imageView.layer.shadowOpacity = 1
imageView.layer.cornerRadius = 5
imageView.layer.shadowOffset = CGSizeZero
imageView.layer.shadowRadius = 2
//If you added Aspect to Fill
imageView.clipsToBounds = true
}
I hope this will help you... (Y)
don't know but try to round image than imageView
func makeRoundedImage(image: UIImage, radius: Float) -> UIImage {
var imageLayer: CALayer = CALayer.layer
imageLayer.frame = CGRectMake(0, 0, image.size.width, image.size.height)
imageLayer.contents = (image.CGImage as! AnyObject)
imageLayer.masksToBounds = true
imageLayer.cornerRadius = 10
UIGraphicsBeginImageContext(image.size)
imageLayer.renderInContext(UIGraphicsGetCurrentContext())
var roundedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return roundedImage
}
and then set image to you image view. and clear background color of dragableView
Hope it will help..!

Apply a mask to AVCaptureStillImageOutput

I'm working on a project where I'd like to mask a photo that the user has just taken with their camera. The mask is created at a specific aspect ratio to add letterboxes to a photo.
I can successfully create the image, create the mask, and save both to the camera roll, but I can't apply the mask to the image. Here's the code I have now
func takePhoto () {
dispatch_async(self.sessionQueue) { () -> Void in
if let photoOutput = self.output as? AVCaptureStillImageOutput {
photoOutput.captureStillImageAsynchronouslyFromConnection(self.outputConnection) { (imageDataSampleBuffer, err) -> Void in
if err == nil {
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
let image = UIImage(data: imageData)
if let _ = image {
let maskedImage = self.maskImage(image!)
print("masked image: \(maskedImage)")
self.savePhotoToLibrary(maskedImage)
}
} else {
print("Error while capturing the image: \(err)")
}
}
}
}
}
func maskImage (image: UIImage) -> UIImage {
let mask = createImageMask(image)
let maskedImage = CGImageCreateWithMask(image.CGImage, mask!)
return UIImage(CGImage: maskedImage!)
}
func createImageMask (image: UIImage) -> CGImage? {
let width = image.size.width
let height = width / CGFloat(store.state.aspect.rawValue)
let x = CGFloat(0.0)
let y = (image.size.height - height) / 2
let maskRect = CGRectMake(0.0, 0.0, image.size.width, image.size.height)
let maskContents = CGRectMake(x, y, width, height)
var color = UIColor(white: 1.0, alpha: 0.0)
UIGraphicsBeginImageContextWithOptions(CGSizeMake(maskRect.size.width, maskRect.size.height), false, 0.0)
color.setFill()
UIRectFill(maskRect)
color = UIColor(white: 0.0, alpha: 1.0)
color.setFill()
UIRectFill(maskContents)
let maskImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
print("mask: \(maskImage)")
savePhotoToLibrary(image)
savePhotoToLibrary(maskImage)
let mask = CGImageMaskCreate(
CGImageGetWidth(maskImage.CGImage),
CGImageGetHeight(maskImage.CGImage),
CGImageGetBitsPerComponent(maskImage.CGImage),
CGImageGetBitsPerPixel(maskImage.CGImage),
CGImageGetBytesPerRow(maskImage.CGImage),
CGImageGetDataProvider(maskImage.CGImage),
nil,
false)
return mask
}
From what I understand, CGImageCreateWithMask requires that the image to be masked has an alpha channel. I've tried everything I've seen here to add an alpha channel to the jpeg representation, but I'm not having any luck. Any help would be super.
This may be a bug, or maybe it's just a bit misleading. CGImageCreateWithMask() doesn't actually modify the image - it just associates the mask data with the image data, and uses the mask when you draw the image to a context (such as in a UIImageView), but not when you save the image to disk.
There are a couple approaches to generating a "rendered" version of the masked image, but if I understand your intent, you don't really want a "mask" ... you want a letter-boxed version of the image.
Here is one option that will effectively draw black bars on the top and bottom of your image (the bars / frame color is an optional parameter, if you don't want black). You can then save the modified image.
In your code above, replace
let maskedImage = self.maskImage(image!)
with
let height = image.size.width / CGFloat(store.state.aspect.rawValue)
let maskedImage = self.doLetterBox(image!, visibleHeight: height)
and add this function:
func doLetterBox(sourceImage: UIImage, visibleHeight: CGFloat, frameColor: UIColor?=UIColor.blackColor()) -> UIImage! {
// local rect based on sourceImage size
let imageRect: CGRect = CGRectMake(0.0, 0.0, sourceImage.size.width, sourceImage.size.height)
// rect for "visible" part of letter-boxed image
let clipRect: CGRect = CGRectMake(0.0, (imageRect.size.height - visibleHeight) / 2.0, imageRect.size.width, visibleHeight)
// setup the image context, using sourceImage size
UIGraphicsBeginImageContextWithOptions(imageRect.size, true, UIScreen.mainScreen().scale)
let ctx: CGContextRef = UIGraphicsGetCurrentContext()!
CGContextSaveGState(ctx)
// fill new empty image with frameColor (defaults to black)
CGContextSetFillColorWithColor(ctx, frameColor?.CGColor)
CGContextFillRect(ctx, imageRect)
// set Clipping rectangle to allow drawing only in desired area
UIRectClip(clipRect)
// draw the sourceImage to full-image-size (the letter-boxed portion will be clipped)
sourceImage.drawInRect(imageRect)
// get new letter-boxed image
let resultImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
// clean up
CGContextRestoreGState(ctx)
UIGraphicsEndImageContext()
return resultImage
}

DrawView save combined image (multiply)

I have 2 UIImageViews - one is at the bottom and shows a default image (like an Photo) - on the second UIImageView where you can draw.
I would like to create an UIImage from both images, and save it as new image.
How can i do that? Ill tried with:
func saveImage() {
print("save combined image")
let topImage = self.canvasView.image
let bottomImage = self.backgroundImageView.image
let size = CGSizeMake(topImage!.size.width, topImage!.size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
[topImage!.drawInRect(CGRectMake(0,0,size.width, topImage!.size.height))];
[bottomImage!.drawInRect(CGRectMake(0,0,size.width, bottomImage!.size.height))];
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(newImage, self, #selector(CanvasViewController.image(_:didFinishSavingWithError:contextInfo:)), nil)
}
But the result is not correct (stretched and no overlay)
Any ideas?
Ok ill found an solution for that, just need to add "multiply" as blend mode.
let topImage = self.canvasView.image
let bottomImage = self.backgroundImageView.image
let size = CGSizeMake(bottomImage!.size.width, bottomImage!.size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
[bottomImage!.drawInRect(CGRectMake(0,0,size.width, bottomImage!.size.height))];
[topImage!.drawInRect(CGRectMake(0,0,size.width, bottomImage!.size.height), blendMode: CGBlendMode.Multiply , alpha: 1.0)];
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

Resources