How to make UItabbar image rounded in swift programmatically - swift

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
}

Related

Draw UIImage in Rectangle with background color if it doesn't fit in a rectangle?

I'm new to this topic so I want to ask how I can achieve this following behavior: I would like to create a image with a specific size. If the original Image doesn't fit in a square I would like to fill the sides with a color, so I want to draw that image in a rectangle with a color and want to store it in a new UIImage variable.
To resize a Image I found something like this. But how can I fit the image in a Rectangle with a specific color and create a new Image that can be stored?
UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
return UIGraphicsGetImageFromCurrentImageContext()
One possible way would be to create an extension method to UIImage as you started in your sample code.
Then create a new image of the desired size and fill the background color with UIRectFill.
The next step would be to calculate the new size so that the image content is scaled to fit into the image by taking the aspect ratio into account:
let scale = min(size.width / originalSize.width, size.height / originalSize.height)
let newSize = CGSize(width: originalSize.width * scale, height: originalSize.height * scale)
let origin = CGPoint(x: (size.width - newSize.width) / 2, y: (size.height - newSize.height) / 2)
Then you basically just need to draw the image into the rectangle that results from the origin and the actual size of the image inside the background area.
Completely, the extension method could then look something like this:
func image(size: CGSize, background: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
defer { UIGraphicsEndImageContext() }
background.setFill()
let completeRect = CGRect(origin: .zero, size: size)
UIRectFill(completeRect)
let originalSize = self.size
let scale = min(size.width / originalSize.width, size.height / originalSize.height)
let newSize = CGSize(width: originalSize.width * scale, height: originalSize.height * scale)
let origin = CGPoint(x: (size.width - newSize.width) / 2, y: (size.height - newSize.height) / 2)
let imageRect = CGRect(origin: origin, size: newSize)
draw(in: imageRect, blendMode: .normal, alpha: 1.0)
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}
Self-Contained Complete Example
Finally a self-contained complete example for testing:
import UIKit
class ViewController: UIViewController {
private let image1 = UIImage(named: "country")
private let image2 = UIImage(named: "regensburg")
override func viewDidLoad() {
super.viewDidLoad()
let imageView1 = createImageView()
imageView1.image = image1?.image(size: CGSize(width: 200, height: 200), background: .blue)
let imageView2 = createImageView()
imageView2.image = image2?.image(size: CGSize(width: 200, height: 200), background: .blue)
NSLayoutConstraint.activate([
imageView1.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24),
imageView1.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24),
imageView1.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24),
imageView2.topAnchor.constraint(equalTo: imageView1.bottomAnchor, constant: 24),
imageView2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24),
imageView2.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24),
imageView2.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -24),
imageView2.widthAnchor.constraint(equalTo: imageView1.widthAnchor),
imageView2.heightAnchor.constraint(equalTo: imageView1.heightAnchor)
])
}
private func createImageView() -> UIImageView {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
return imageView
}
}
extension UIImage {
func image(size: CGSize, background: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
defer { UIGraphicsEndImageContext() }
background.setFill()
let completeRect = CGRect(origin: .zero, size: size)
UIRectFill(completeRect)
let originalSize = self.size
let scale = min(size.width / originalSize.width, size.height / originalSize.height)
let newSize = CGSize(width: originalSize.width * scale, height: originalSize.height * scale)
let origin = CGPoint(x: (size.width - newSize.width) / 2, y: (size.height - newSize.height) / 2)
let imageRect = CGRect(origin: origin, size: newSize)
draw(in: imageRect, blendMode: .normal, alpha: 1.0)
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}
}
The output of the above code is then:
The specified actual image size is square. Accordingly, there are corresponding vertical or horizontal stripes at the edges of the image in the selected background color (blue).

Resize UIImage Keep Image Quality in Swift

I have created an image from UIView using UIGraphicsGetCurrentContext. It's work fine but when I resized that image to larger size its be blurred with bad quality. Can it possibility to keep quality when resize? I have tried many ways but not work.
- code image:
func image(with view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
context.setAllowsAntialiasing(true)
context.setShouldAntialias(true)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
return nil
}
code I have used to resize, this extension of UIImage
func resizedImage(newSize: CGSize) -> UIImage {
// Guard newSize is different
guard self.size != newSize else { return self }
let aspect_ratio = self.size.width / self.size.height
var image_w = newSize.height * aspect_ratio
let finalSize = CGSize(width: image_w, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(finalSize, false, 0.0)
self.draw(in: CGRect(x: 0, y: 0, width: (CGFloat)(finalSize.width), height: (CGFloat)(newSize.height)))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
and the example image:image
Thanks
Try this:
extension UIImage {
func resizeImage(targetSize: CGSize) -> UIImage {
let size = self.size
let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height
let newSize = widthRatio > heightRatio ? CGSize(width: size.width * heightRatio, height: size.height * heightRatio) : CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
self.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}

How to apply an inverse text mask in Swift?

I am trying programmatically create a layer with transparent text. Everything I try doesn't seem to work. My end goal is to create an inner shadow on text.
Instead of a circle as in the code below I want text.
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = .white
// MASK
let blackSquare = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
blackSquare.backgroundColor = .black
view.addSubview(blackSquare)
let maskLayer = CAShapeLayer()
// Create a path with the rectangle in it.
let path = CGMutablePath()
path.addArc(center: CGPoint(x: 100, y: 100), radius: 50, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: false)
path.addRect(CGRect(x: 0, y: 0, width: blackSquare.frame.width, height: blackSquare.frame.height))
maskLayer.backgroundColor = UIColor.black.cgColor
maskLayer.path = path;
maskLayer.fillRule = kCAFillRuleEvenOdd
blackSquare.layer.mask = maskLayer
maskLayer.masksToBounds = false
maskLayer.shadowRadius = 4
maskLayer.shadowOpacity = 0.5
maskLayer.shadowOffset = CGSize(width: 5, height: 5)
view.addSubview(blackSquare)
I'm also able to use text as a mask but I'm unable to invert the mask. Any help is appreciated.
EDIT:
I figured it out based on Rob's answer as suggested by Josh. Here's my playground code.
import Foundation
import UIKit
import PlaygroundSupport
// view
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = .black
// button
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
button.setTitle("120", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont(name: "AvenirNextCondensed-UltraLight", size: 200)
view.addSubview(button)
addInnerShadow(button: button)
func addInnerShadow(button: UIButton) {
// text
let text = button.titleLabel!.text!
// get context
UIGraphicsBeginImageContextWithOptions(button.bounds.size, true, 0)
let context = UIGraphicsGetCurrentContext()
context?.scaleBy(x: 1, y: -1)
context?.translateBy(x: 0, y: -button.bounds.size.height)
let font = button.titleLabel!.font!
// draw the text
let attributes = [
NSAttributedStringKey.font: font,
NSAttributedStringKey.foregroundColor: UIColor.white
]
let size = text.size(withAttributes: attributes)
let point = CGPoint(x: (button.bounds.size.width - size.width) / 2.0, y: (button.bounds.size.height - size.height) / 2.0)
text.draw(at: point, withAttributes: attributes)
// capture the image and end context
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// create image mask
let cgimage = image?.cgImage!
let bytesPerRow = cgimage?.bytesPerRow
let dataProvider = cgimage?.dataProvider!
let bitsPerPixel = cgimage?.bitsPerPixel
let width = cgimage?.width
let height = cgimage?.height
let bitsPerComponent = cgimage?.bitsPerComponent
let mask = CGImage(maskWidth: width!, height: height!, bitsPerComponent: bitsPerComponent!, bitsPerPixel: bitsPerPixel!, bytesPerRow: bytesPerRow!, provider: dataProvider!, decode: nil, shouldInterpolate: false)
// create background
UIGraphicsBeginImageContextWithOptions(button.bounds.size, false, 0)
UIGraphicsGetCurrentContext()!.clip(to: button.bounds, mask: mask!)
view.backgroundColor!.setFill()
UIBezierPath(rect: button.bounds).fill()
let background = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let backgroundView = UIImageView(image: background)
// add shadows
backgroundView.layer.shadowOffset = CGSize(width: 2, height: 2)
backgroundView.layer.shadowRadius = 2
backgroundView.layer.shadowOpacity = 0.75
button.addSubview(backgroundView)
}
PlaygroundPage.current.liveView = view
Whilst not exactly the same, please refer to the answer provided here by Rob who answered a similar question:
How do I style a button to have transparent text?
This should get you started at the very least...
Stumbled on a possible solution that I've updated to proper syntax:
func mask(withRect rect: CGRect, inverse: Bool = false) {
let path = UIBezierPath(rect: rect)
let maskLayer = CAShapeLayer()
if inverse {
path.append(UIBezierPath(rect: self.view.bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.cgPath
self.view.layer.mask = maskLayer
}
You'll obviously need to pick parts out to see if it works for you.

Change the Size of Marker in GoogleMap using Swift

I have placed a marker in GoogleMap which contains Image. but the size of image is much bigger. so how can i decrease the size of an marker. i have tried this :
marker.icon = self.image(marker.icon, scaledToSize: CGSize(width: 3.0, height: 3.0))
To resize the image refer to :The simplest way to resize an UIImage?
Now the set the resized image as marker icon ,i.e,
marker.icon = self.imageWithImage(image: UIImage(named: "imageName")!, scaledToSize: CGSize(width: 3.0, height: 3.0))
Edit:
func imageWithImage(image:UIImage, scaledToSize newSize:CGSize) -> UIImage{
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
image.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
Edit (swift 4)
func imageWithImage(image:UIImage, scaledToSize newSize:CGSize) -> UIImage{
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
If you want to use an extension you can implement like this:
Swift 4.2
extension GMSMarker {
func setIconSize(scaledToSize newSize: CGSize) {
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
icon?.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
icon = newImage
}
}
and use the extension like This:
let position = CLLocationCoordinate2D(latitude: yourLatitude,longitude: yourLongitude)
let marker = GMSMarker(position: position)
marker.title = "Receiver"
marker.icon = UIImage(named: "receiver_set")
marker. setIconSize(scaledToSize: .init(width: 40, height: 40))
marker.map = self.mapView
Based in the answer of #PGDev
My implementation for Swift 3 is:
func imageWithImage(image:UIImage, scaledToSize newSize:CGSize) -> UIImage{
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
//image.draw(in: CGRectMake(0, 0, newSize.width, newSize.height))
image.draw(in: CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: newSize.width, height: newSize.height)) )
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
And used in this way:
marker.icon = self.imageWithImage(image: UIImage(named: place.icon)!, scaledToSize: CGSize(width: 100.0, height: 100.0))
Another easy way is to use the new UIGraphicsImageRenderer
marker.icon = UIGraphicsImageRenderer(size: .init(width: 3.0, height: 3.0)).image { context in
UIImage(named: "pin").draw(in: .init(origin: .zero, size: context.format.bounds.size))
}
you can override this callback when camera position changed
func mapView(_ mapView: GMSMapView, idleAt cameraPosition: GMSCameraPosition) {
self.mapView?.clear()
//redraw your marker use smaller UIImage...
....
var smallerImage : UIImage = UIImage(named: "example_icon")
marker.icon = smallerImage
}

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.