Cropping a captured still image - swift

I want just a specific part of my captured image to be cropped in a circular shape right before it's viewed.
Here is the code for capturing still images:
#IBAction func takePhoto(sender: UIButton) {
self.stillImageOutput!.captureStillImageAsynchronouslyFromConnection(self.stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo)) { (buffer:CMSampleBuffer!, error:NSError!) -> Void in
var image = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
var data_image = UIImage(data: image)
self.previewImage.image = data_image
}
}
Thank you

if let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer) {
if let image = UIImage(data: imageData) {
let square = image.size.width < image.size.height ? CGSize(width: image.size.width, height: image.size.width) : CGSize(width: image.size.height, height: image.size.height)
let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: square))
imageView.contentMode = UIViewContentMode.ScaleAspectFill
imageView.image = image
imageView.layer.cornerRadius = square.width/2
imageView.layer.masksToBounds = true
UIGraphicsBeginImageContext(imageView.bounds.size)
imageView.layer.renderInContext(UIGraphicsGetCurrentContext())
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.previewImage.image = result
}
}

Related

How to increase quality of rendered image for UIImageView?

I have an UIImageView with contentMode = .aspectFit. I have an image in imageView, which dimension is bigger than size of imageView. User can draw some lines and save them as sublayer. After that I need to save the edited image. But quality of saved image is worse than quality of image which I load.
What am I doing wrong? I tried to use transform, but it didn't work.
import UIKit
extension UIImageView {
var contentClippingRect: CGRect {
let imgViewSize = self.frame.size
let imgSize = self.image?.size ?? .zero
let scaleW = imgViewSize.width / imgSize.width
let scaleH = imgViewSize.height / imgSize.height
let aspect = fmin(scaleW, scaleH)
let width = imgSize.width * aspect
let height = imgSize.height * aspect
let imageRect = CGRect(x: (imgViewSize.width-width)/2 + self.frame.origin.x, y: (imgViewSize.height-height)/2 + self.frame.origin.y, width: width, height: height)
return imageRect
}
func asImage() -> UIImage {
let imageRect = self.contentClippingRect
let renderer = UIGraphicsImageRenderer(bounds: imageRect)
let renderedImage = renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
return renderedImage
}
}
You can use UIGraphicsImageRendererFormat().scale it will increase quality of the rendered image a bit.
import UIKit
extension UIImageView {
var contentClippingRect: CGRect {
let imgViewSize = self.frame.size
let imgSize = self.image?.size ?? .zero
let scaleW = imgViewSize.width / imgSize.width
let scaleH = imgViewSize.height / imgSize.height
let aspect = fmin(scaleW, scaleH)
let width = imgSize.width * aspect
let height = imgSize.height * aspect
let imageRect = CGRect(x: (imgViewSize.width-width)/2 + self.frame.origin.x, y: (imgViewSize.height-height)/2 + self.frame.origin.y, width: width, height: height)
return imageRect
}
func asImage() -> UIImage {
let imageRect = self.contentClippingRect
//add this
let format = UIGraphicsImageRendererFormat()
format.scale = 2
let renderer = UIGraphicsImageRenderer(bounds: imageRect, format: format)
let renderedImage = renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
return renderedImage
}
}

Why does my photo captured in portrait change to landscape?

I have this cameraView and on top of it I have this UIImageView. The UIImageView is basically a filter that changes the color of the cameraView. I was able to take a picture with the code below and the output image changes the portrait image to landscape. Why does that happen? Thanks!
#IBAction func takePicture(_ sender: Any) {
let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
stillImageOutput.capturePhoto(with: settings, delegate: self)
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo:
AVCapturePhoto, error: Error?) {
let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { ctx in
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
}
if let imageData = photo.fileDataRepresentation() {
if let cameraImage = UIImage(data: imageData) {
let newImage = self.composite(image:cameraImage, overlay: image, scaleOverlay:true)
captureImageView.image = newImage
}
}
}
//combine imageview with uiview
func composite(image:UIImage, overlay:(UIImage), scaleOverlay: Bool = false)->UIImage?{
UIGraphicsBeginImageContext(image.size)
var rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
image.draw(in: rect)
if scaleOverlay == false {
rect = CGRect(x: 0, y: 0, width: overlay.size.width, height: overlay.size.height)
}
overlay.draw(in: rect)
return UIGraphicsGetImageFromCurrentImageContext()
}

Write Text on an NSImage in Swift-OSX

I have the following objective C Code to write text onto an Image. I'm new to Swift. How can I do this in Swift?
float width = 10.0;
float height = 10.0;
NSImage *finalImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
// obtain images - your sources may vary
NSImage *overlay = [[NSImage alloc] initWithData:[NSData dataWithContentsOfFile:#"/path/to/overlay_image.jpg"]];
NSImage *mainImage = [[NSImage alloc] initWithData:[NSData dataWithContentsOfFile:#"/path/to/main_image.jpg"]];
[finalImage lockFocus];
// draw the base image
[mainImage drawInRect:NSMakeRect(0, 0, width, height)
fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
// draw the overlay image at some offset point
[overlay drawInRect:NSMakeRect(10, 10, [overlay size].width, [overlay size].height)
fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[finalImage unlockFocus];
NSData *finalData = [finalImage TIFFRepresentation];
[[[NSBitmapImageRep imageRepWithData:finalData] representationUsingType:NSJPEGFileType properties:nil] writeToFile:[NSString stringWithFormat:#"/path/to/folder/new_image.jpg"] atomically:YES];
UPDATE:
I have the following method to draw a string onto an Image..But it when I use this method I get cropped out image portions..Seems something is wrong with it..Please advice.
func drawText(image :NSImage) ->NSImage
{
let text = "Sample Text"
let font = NSFont.boldSystemFont(ofSize: 18)
let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
let textRect = CGRect(x: 5, y: 5, width: image.size.width - 5, height: image.size.height - 5)
let textStyle = NSMutableParagraphStyle.default().mutableCopy() as! NSMutableParagraphStyle
let textFontAttributes = [
NSFontAttributeName: font,
NSForegroundColorAttributeName: NSColor.white,
NSParagraphStyleAttributeName: textStyle
]
let im:NSImage = NSImage(size: image.size)
let rep:NSBitmapImageRep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(image.size.width), pixelsHigh: Int(image.size.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSCalibratedRGBColorSpace, bytesPerRow: 0, bitsPerPixel: 0)!
im.addRepresentation(rep)
im.lockFocus()
image.draw(in: imageRect)
text.draw(in: textRect, withAttributes: textFontAttributes)
im.unlockFocus()
return im
}
Here's this code in Swift 3
let width: CGFloat = 10.0
let height: CGFloat = 10.0
let finalImage = NSImage(size: NSMakeSize(width, height))
// obtain images - your sources may vary
var overlay: NSImage?
var mainImage: NSImage?
if let url = URL(string: "/path/to/overlay_image.jpg") {
do {
let data = try Data(contentsOf: url)
overlay = NSImage(data: data)
} catch {
print("Unable to get data")
}
}
if let url = URL(string: "/path/to/main_image.jpg") {
do {
let data = try Data(contentsOf: url)
mainImage = NSImage(data: data)
} catch {
print("Unable to get data")
}
}
finalImage.lockFocus()
// draw the base image
mainImage?.draw(in: NSMakeRect(0, 0, width, height), from: NSZeroRect, operation: NSCompositingOperation.sourceOver, fraction: 1.0)
// draw the overlay image at some offset point
if overlay != nil {
overlay?.draw(in: NSMakeRect(10, 10, overlay!.size.width, overlay!.size.height), from: NSZeroRect, operation: NSCompositingOperation.sourceOver, fraction: 1.0)
}
finalImage.unlockFocus()
if let finalData = finalImage.tiffRepresentation, let url = URL(string: "/path/to/folder/new_image.jpg") {
do {
try NSBitmapImageRep(data: finalData)?.representation(using: NSJPEGFileType, properties: [:])?.write(to: url)
} catch {
print("Failed to write")
}
}

How to make UItabbar image rounded in swift programmatically

I want to create something like image as below
could you help me any code how to make it rounded
thanks for your help!
I think you need to
(Optional) Resize the image if image is bigger than standard bar button image size)
Make the image round
before using it as UItabBarItem image. Below is an extension for UIImage with these two functions:
extension UIImage{
var roundedImage: UIImage {
let rect = CGRect(origin:CGPoint(x: 0, y: 0), size: self.size)
UIGraphicsBeginImageContextWithOptions(self.size, false, 1)
UIBezierPath(
roundedRect: rect,
cornerRadius: self.size.height
).addClip()
self.draw(in: rect)
return UIGraphicsGetImageFromCurrentImageContext()!
}
func resizedImage(newWidth: CGFloat) -> UIImage {
let scale = newWidth / self.size.width
let newHeight = self.size.height * scale
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
self.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
Example usage:
let barImage: UIImage = UIImage(named: "avatar_copy.png")!.resizedImage(newWidth: 40).roundedImage.withRenderingMode(.alwaysOriginal)
let roundTabBar = UITabBarItem(title: nil, image: barImage.withRenderingMode(.alwaysOriginal), selectedImage: barImage)
self.bottomTabbar.items = [roundTabBar]
I changed and added a new function to #firstinq answer. And this way works for me.
extension UIImage{
var roundMyImage: UIImage {
let rect = CGRect(origin:CGPoint(x: 0, y: 0), size: self.size)
UIGraphicsBeginImageContextWithOptions(self.size, false, 1)
UIBezierPath(
roundedRect: rect,
cornerRadius: self.size.height
).addClip()
self.draw(in: rect)
return UIGraphicsGetImageFromCurrentImageContext()!
}
func resizeMyImage(newWidth: CGFloat) -> UIImage {
let scale = newWidth / self.size.width
let newHeight = self.size.height * scale
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
self.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
func squareMyImage() -> UIImage {
UIGraphicsBeginImageContext(CGSize(width: self.size.width, height: self.size.width))
self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.width))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
In TabBarController I changed it to:
let barImage: UIImage = UIImage(named: "landingpage_image2")!.squareMyImage().resizeMyImage(newWidth: 40).roundMyImage.withRenderingMode(.alwaysOriginal)
self.tabBar.items?[1].image = barImage
let profileImg : UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.contentMode = .scaleAspectFill
iv.image = #imageLiteral(resourceName: "user")
iv.clipsToBounds = true
iv.layer.cornerRadius = 25
return iv
}()
// add constraint
override func viewDidLoad() {
super.viewDidLoad()
profileImg.leftAnchor.constraint(equalTo: view.leftAnchor, constant : 8).isActive = true
profileImg.topAnchor.constraint(equalTo: view.topAnchor , constant : 8).isActive = true
profileImg.widthAnchor.constraint(equalToConstant: 50).isActive = true
profileImg.heightAnchor.constraint(equalToConstant: 50).isActive = true
}

Masking an image in Swift 2.0

I have searched everywhere and found a few examples on how to mask an image, but none of them seem to work for me... I am running on iOS9 and using Swift2.0
Right now this is what I have:
class func maskImage(background: UIImage, withMask mask: UIImage) -> UIImage {
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue).rawValue
let colorSpace = CGColorSpaceCreateDeviceRGB()!
let context = CGBitmapContextCreate(nil, CGImageGetWidth(mask.CGImage), CGImageGetHeight(mask.CGImage), 8, 0, colorSpace, bitmapInfo)
CGContextDrawImage(context, CGRectMake(0, 0, mask.size.width * mask.scale, mask.size.height * mask.scale), mask.CGImage)
let maskRef: CGImageRef = CGBitmapContextCreateImage(context)!
let masked: CGImageRef = CGImageCreateWithMask(background.CGImage, maskRef)!
let icon: UIImage = UIImage(CGImage: masked, scale: mask.scale, orientation: mask.imageOrientation)
return icon
}
I am passing two pngs in and getting the error: EXC_BAD_INSTRUCTION on the line where I initialize masked. I don't have enough rep to post the image.
I am probably missing something super simple, but would love your help. Thank you!
With Swift 3.0 we have had the great name change....
so this appears to function now after some renaming... and cleaning...
based on this example: ( https://www.innofied.com/implementing-image-masking-in-ios/ )
func maskImage(image:UIImage, mask:UIImage )->UIImage{
let imageReference = (image.cgImage)!
let maskReference = (mask.cgImage)!
let imageMask = CGImage.init(
maskWidth: maskReference.width
,height: maskReference.height
,bitsPerComponent: maskReference.bitsPerComponent
,bitsPerPixel: maskReference.bitsPerPixel
,bytesPerRow: maskReference.bytesPerRow
,provider: maskReference.dataProvider!
,decode: nil
,shouldInterpolate: true
)
return (UIImage(cgImage:(imageReference.masking(imageMask!))!))
}
I am also running the latest versions and had a lot of trouble with this. I was finally able to use the below code to crop part of an image and overlay a puzzle piece with an image mask.
import UIKit
import CoreGraphics
class ViewController2: UIViewController {
#IBOutlet var imageView: UIImageView!
var p1PosX: CGFloat = 0.0
var p1PosY: CGFloat = 0.0
var p1Width: CGFloat = 0.0
var p1Height: CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
let panda = UIImage(named: "panda.jpeg")!
let puzzle1 = UIImage(named: "PP-4-1.gif")!
//Crop
let contextSize: CGSize = panda.size
let rect = CGRect(x: 0, y: 0, width: 200, height: 200)
p1PosX = 0
p1PosY = 0
p1Width = contextSize.width / 2
p1Height = contextSize.height / 2
let rect1: CGRect = CGRectMake(p1PosX, p1PosY, 350, 350)
let imageRef1: CGImageRef = CGImageCreateWithImageInRect(panda.CGImage, rect1)!
let panda1: UIImage = UIImage(CGImage: imageRef1, scale: panda.scale, orientation: panda.imageOrientation)
imageView.image = panda1
//Mask
UIGraphicsBeginImageContext(imageView.frame.size)
panda1.drawInRect(rect)
puzzle1.drawInRect(CGRectMake(0, 0, imageView.frame.size.width , imageView.frame.size.height), blendMode: CGBlendMode.DestinationIn, alpha: 1.0)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
imageView.image = newImage
}
}
In case anybody stumbles across this same situation and is looking for a clean solution, here's a function to mask an image. It works for .jpg, .png and .gif images.
func maskImage(image:UIImage, mask:(UIImage))->UIImage{
let imageReference = image.CGImage
let maskReference = mask.CGImage
let imageMask = CGImageMaskCreate(CGImageGetWidth(maskReference),
CGImageGetHeight(maskReference),
CGImageGetBitsPerComponent(maskReference),
CGImageGetBitsPerPixel(maskReference),
CGImageGetBytesPerRow(maskReference),
CGImageGetDataProvider(maskReference), nil, true)
let maskedReference = CGImageCreateWithMask(imageReference, imageMask)
let maskedImage = UIImage(CGImage:maskedReference!)
return maskedImage
}
Add the following declaration lines in your viewDidLoad() or init() as needed :
let image = UIImage(named: "image.png")
let maskingImage = UIImage(named: "mask.png")
let imageView = UIImageView(image: maskingImage)
imageView.image = maskImage(image!, mask: maskingImage!)
Thanks to Manish Kumar's solution Implementing Image Masking in iOS