Make Background Transparent w/ rounded effect - UIImage? - ios

Using this function rounds the image, but it leaves a white background, how do I turn the background transparent?
func roundImage() -> UIImage
{
let newImage = self.copy() as! UIImage
let cornerRadius = self.size.height/2
UIGraphicsBeginImageContextWithOptions(self.size, false , 0.0)
let bounds = CGRect(origin: CGPointZero, size: self.size)
UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).addClip()
newImage.drawInRect(bounds)
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return finalImage
}

Related

Why is my image quality decreasing when setting the radius and size?

I am using the following methods in a UIImage extension to use an image from a URL and displaying it as a UIBarButtonItem. However, when I use the following to adjust the corner radius and size, the quality of the image gets significantly worse. What needs to change to prevent it from decreasing in quality?
extension UIImage {
public func withRoundedCornersAndSetSize(radius: CGFloat? = nil, size: CGSize) -> UIImage? {
let maxRadius = min(size.width, size.height) / 2
let cornerRadius: CGFloat
if let radius = radius, radius > 0 && radius <= maxRadius {
cornerRadius = radius
} else {
cornerRadius = maxRadius
}
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let rect = CGRect(origin: .zero, size: size)
UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).addClip()
draw(in: rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
I figured out that I could resize the UIImage without losing quality using the resize() method in the following code. Then, I just used this in the withRoundedCornersAndSetSize() method that I had initially asked about.
extension UIImage {
func withRoundedCornersAndSetSize(radius: CGFloat? = nil, targetSize: CGSize) -> UIImage? {
let resizedImage = self.resize(targetSize: targetSize)
let maxRadius = min(resizedImage.size.width, resizedImage.size.height) / 2
let cornerRadius: CGFloat
if let radius = radius, radius > 0 && radius <= maxRadius {
cornerRadius = radius
} else {
cornerRadius = maxRadius
}
UIGraphicsBeginImageContextWithOptions(resizedImage.size, false, resizedImage.scale)
let rect = CGRect(origin: .zero, size: resizedImage.size)
UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).addClip()
draw(in: rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
func resize(targetSize: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size:targetSize).image { _ in
self.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
}

Screenshot a view with label and transparent background in iOS and upload it to server

I want to screenshot a view and create an UIImage from it. I want the transparency attribute of the view to be maintained in my image. I tried this method after creating an extension of UIImage but the background is not transparent in the resultant image when uploaded to the server.
Kindly help or point me if I am doing something wrong!! This means that the resultant png was not having transparency.
class func createTransparentImageFrom(label: UILabel, imageSize: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(imageSize, false, 2.0)
let currentView = UIView.init(frame: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
currentView.backgroundColor = UIColor.clear
currentView.addSubview(label)
currentView.layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
This was due to the fact that when we render a view the image is JPEG/JPG, so we need to convert it to png in order to get layer information.
Try this :
extension UIImage {
class func createTransparentPNGFrom(label: UILabel, imageSize: CGSize) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0)
let currentView = UIView.init(frame: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
currentView.backgroundColor = UIColor.clear
currentView.addSubview(label)
currentView.layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let newImg = img else {
return nil
}
guard let imageData = UIImagePNGRepresentation(newImg) else {
return nil
}
return UIImage.init(data: imageData)
}
}
Swift 5 UIImage extension: screen UIView with transparent background
this is for taking a screenshot of a view which should have .backgroundColor = .clear
extension UIView {
func takeSnapshotOfView() -> UIImage? {
let size = CGSize(width: frame.size.width, height: frame.size.height)
let rect = CGRect.init(origin: .init(x: 0, y: 0), size: frame.size)
UIGraphicsBeginImageContext(size)
drawHierarchy(in: rect, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let imageData = image?.pngData() else {
return nil
}
return UIImage.init(data: imageData)
}
}
You need to put opaque value true for transparent result
Extension of UIView Of transparent screenshot
func screenShot() -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, UIScreen.main.scale)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img
}

How to crop a UIImage without losing it's scale property?

Goal: Crop a UIImage (that starts with a scale property of 2.0)
I perform the following code:
let croppedCGImage = originalUIImage.cgImage!.cropping(to: cropRect)
let croppedUIImage = UIImage(cgImage: croppedCGImage!)
This code works, however the result, croppedUIImage, has an incorrect scale property of 1.0.
I've tried specifying the scale when creating the final image:
let croppedUIImage = UIImage(cgImage: croppedCGImage!, scale: 2.0, orientation: .up)
This yields the correct scale, but it cuts the size dimensions in half incorrectly.
What should I do here?
(*Note: the scale property on the UIImage is important because I later save the image with UIImagePNGRepresentation(_ image: UIImage) which is affected by the scale property)
Edit:
I got the following to work. Unfortunately it's just substantially slower than the CGImage cropping function.
extension UIImage {
func cropping(to rect: CGRect) -> UIImage {
UIGraphicsBeginImageContextWithOptions(rect.size, false, self.scale)
self.draw(in: CGRect(x: -rect.origin.x, y: -rect.origin.y, width: self.size.width, height: self.size.height))
let croppedImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return croppedImage
}
}
Try this:
extension UIImage {
func imageByCropToRect(rect:CGRect, scale:Bool) -> UIImage {
var rect = rect
var scaleFactor: CGFloat = 1.0
if scale {
scaleFactor = self.scale
rect.origin.x *= scaleFactor
rect.origin.y *= scaleFactor
rect.size.width *= scaleFactor
rect.size.height *= scaleFactor
}
var image: UIImage? = nil;
if rect.size.width > 0 && rect.size.height > 0 {
let imageRef = self.cgImage!.cropping(to: rect)
image = UIImage(cgImage: imageRef!, scale: scaleFactor, orientation: self.imageOrientation)
}
return image!
}
}
Use this Extension :-
extension UIImage {
func cropping(to quality: CGInterpolationQuality, rect: CGRect) -> UIImage {
UIGraphicsBeginImageContextWithOptions(rect.size, false, self.scale)
let context = UIGraphicsGetCurrentContext()! as CGContext
context.interpolationQuality = quality
let drawRect : CGRect = CGRect(x: -rect.origin.x, y: -rect.origin.y, width: self.size.width, height: self.size.height)
context.clip(to: CGRect(x:0, y:0, width: rect.size.width, height: rect.size.height))
self.draw(in: drawRect)
let croppedImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return croppedImage
}
}
I'm using the ImageHelper Pod for iOS and tvOS and it's working perfectly and might also fit your needs.
It brings a lot UIImage Extensions such as:
Crop and Resize
// Crops an image to a new rect
func crop(bounds: CGRect) -> UIImage?
// Crops an image to a centered square
func cropToSquare() -> UIImage? {
// Resizes an image
func resize(size:CGSize, contentMode: UIImageContentMode = .ScaleToFill) -> UIImage?
Screen Density
// To create an image that is Retina aware, use the screen scale as a multiplier for your size. You should also use this technique for padding or borders.
let width = 140 * UIScreen.mainScreen().scale
let height = 140 * UIScreen.mainScreen().scale
let image = UIImage(named: "myImage")?.resize(CGSize(width: width, height: height))
Also stuff like: Image Effects
// Applies a light blur effect to the image
func applyLightEffect() -> UIImage?
// Applies a extra light blur effect to the image
func applyExtraLightEffect() -> UIImage?
// Applies a dark blur effect to the image
func applyDarkEffect() -> UIImage?
// Applies a color tint to an image
func applyTintEffect(tintColor: UIColor) -> UIImage?
// Applies a blur to an image based on the specified radius, tint color saturation and mask image
func applyBlur(blurRadius:CGFloat, tintColor:UIColor?, saturationDeltaFactor:CGFloat, maskImage:UIImage? = nil) -> UIImage?
-(UIImage *)getNeedImageFrom:(UIImage*)image cropRect:(CGRect)rect
{
CGImageRef subImage = CGImageCreateWithImageInRect(image.CGImage, rect);
UIImage *croppedImage = [UIImage imageWithCGImage:subImage];
CGImageRelease(subImage);
return croppedImage;
}
calling
UIImage *imageSample=image;
CGRect rectMake1=CGRectMake(0, 0,imageSample.size.width*1/4, imageSample.size.height);
UIImage *img1=[[JRGlobal sharedInstance] getNeedImageFrom:imageSample cropRect:rectMake1];

Make UIImage a Circle without Losing quality? (swift)

The image becomes blurry once applying roundImage:
Making a UIImage to a circle form
extension UIImage
{
func roundImage() -> UIImage
{
let newImage = self.copy() as! UIImage
let cornerRadius = self.size.height/2
UIGraphicsBeginImageContextWithOptions(self.size, false, 1.0)
let bounds = CGRect(origin: CGPointZero, size: self.size)
UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).addClip()
newImage.drawInRect(bounds)
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return finalImage
}
}
Why are you using bezierpath? Just set cornerradius for uiimageview.
If your image is larger than the imageview then you have to resize your image to your imageview size and then set cornerradius for that uiimageview.
It will work. Works for me
Replace the following line
UIGraphicsBeginImageContextWithOptions(self.size, false, 1.0)
with
UIGraphicsBeginImageContextWithOptions(self.size, view.opaque , 0.0)
try this one
let image = UIImageView(frame: CGRectMake(0, 0, 100, 100))
I recommend that you can use AlamofireImage (https://github.com/Alamofire/AlamofireImage)
It's very easily to make rounded image or circle image without losing quality.
just like this:
let image = UIImage(named: "unicorn")!
let radius: CGFloat = 20.0
let roundedImage = image.af_imageWithRoundedCornerRadius(radius)
let circularImage = image.af_imageRoundedIntoCircle()
Voila!
Your issue is that you are using scale 1, which is the lowest "quality".
Setting the scale to 0 will use the device scale, which just uses the image as is.
A side note: Functions inside a class that return a new instance of that class can be implemented as class functions. This makes it very clear what the function does. It does not manipulate the existing image. It returns a new one.
Since you were talking about circles, I also corrected your code so it will now make a circle of any image and crop it. You might want to center this.
extension UIImage {
class func roundImage(image : UIImage) -> UIImage? {
// copy
guard let newImage = image.copy() as? UIImage else {
return nil
}
// start context
UIGraphicsBeginImageContextWithOptions(newImage.size, false, 0.0)
// bounds
let cornerRadius = newImage.size.height / 2
let minDim = min(newImage.size.height, newImage.size.width)
let bounds = CGRect(origin: CGPointZero, size: CGSize(width: minDim, height: minDim))
UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).addClip()
// new image
newImage.drawInRect(bounds)
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// crop
let maybeCrop = UIImage.crop(finalImage, cropRect: bounds)
return maybeCrop
}
class func crop(image: UIImage, cropRect : CGRect) -> UIImage? {
guard let imgRef = CGImageCreateWithImageInRect(image.CGImage, cropRect) else {
return nil
}
return UIImage(CGImage: imgRef)
}
}

ios: how to blur a image with CGPath?

I create a CGPath area as shown green circle. The CGPath area need to be clear, and the rest of image will be applied blurry or translucent effect, I can clip image inside CGPath with following code:
UIGraphicsBeginImageContext(view.frame.size);
CGContextAddPath(ctx, path);
CGContextClip(ctx);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *clipImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(clipImage, nil, nil, nil);
CGPathRelease(path);
but I don't know how to apply blurry or translucent effect with CGPath simultaneously. I think I can blur origin image and merge it with clip image, but I don't know how to implement it.
You required 2 concept to achieved end result :-
i) CGBlendMode
ii) CIFilter
CGBlendMode is Used to remove the desired portion from image. Compositing operations on paths residing one another in the Current Context .
Clear mode whose rawValue is 16 help to clear the desired portion.
CIFilter help to blur the final image.
class ConvertToBlurryImage:UIView {
var originalImage:UIImage!
var finalImage:UIImage!
override func draw(_ rect: CGRect) {
super.draw(rect)
//Original Image
originalImage = UIImage(named: "originalImage.png")
//Intermediate Image
let intermediateImage = UIImage().returnBlurImage(image: originalImage)
//Final Result Image
finalImage = blendImage(image: intermediateImage)
let attachedImage = UIImageView(image: finalImage)
addSubview(attachedImage)
}
func blurryImage(image:UIImage) -> UIImage {
UIGraphicsBeginImageContext(frame.size)
image.draw(in: CGRect(origin: frame.origin, size: frame.size) )
// 16 === clear
let mode = CGBlendMode(rawValue: 16)
UIGraphicsGetCurrentContext()!.setBlendMode(mode!)
//Path that need to crop
pathToCrop()
let mode2 = CGBlendMode(rawValue: 16)
UIGraphicsGetCurrentContext()!.setBlendMode(mode2!)
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
return finalImage!
}
func pathToCrop() {
let path = UIBezierPath(ovalIn: CGRect(x: frame.width/2 - 50, y: frame.height/2 - 100 , width: 150, height: 150) )
path.fill()
path.stroke()
}
}
extension UIImage {
func returnBlurImage(image:UIImage) -> UIImage {
let beginImage = CIImage(cgImage: image.cgImage!)
let blurfilter = CIFilter(name: "CIGaussianBlur")
blurfilter?.setValue(beginImage, forKey: "inputImage")
let resultImage = blurfilter?.value(forKey: "outputImage") as! CIImage
let blurredImage = UIImage(ciImage: resultImage)
return blurredImage
}
}
Mission Achived
Final Github Demo

Resources