skip to Main Content

I have a UIBezierPath which crops part of an UIImage and then I want to apply feather/fade effect starting from bezierpath towards inside in Objective-C but I dont want to use any gradient color or shadow or any tricks like that. I want the actual image’s alpha in its borders, go from 100% to 0%. I’ve searched a lot but non of the solutions like this one:

has worked for me yet. The result that I want is similar to the image below. How can I achieve this? Any help is much appreciated.enter image description here

3

Answers


  1. Chosen as BEST ANSWER

    So here is the Objective-c version I used which worked much better than I expected. There is an important thing to consider. In my personal experience, I got the best Fade/Feather effect when the value for @inputRadius was between 6-8, even though the documentation says it can be between 1-10, you can basically set higher values than 10 too but if you want to get the best Edge feathering result, 6-8 is the best. Here's my code.

     UIImage* Img =  [UIImage imageNamed:@"1"];
        UIImageView * imageview = [[UIImageView alloc]initWithImage:Img];
        [imageview setFrame:CGRectMake(0, 0, Img.size.width, Img.size.height)];
    
        UIBezierPath * newPath = //Your Custom drawn bezierpath.
        newPath.lineWidth = 2;
        CAShapeLayer*shapeLayer = [CAShapeLayer new];
        shapeLayer.path=newPath.CGPath;
        [shapeLayer setFillColor:[UIColor redColor].CGColor];
        [shapeLayer fillColor];
    
        UIGraphicsImageRenderer * renderer = [[UIGraphicsImageRenderer alloc] initWithSize:Img.size];
        UIImage *shapeImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull context){
            [shapeLayer renderInContext: context.CGContext];}];
    
        CIImage * shapeCimage = [[CIImage alloc] initWithImage:shapeImage];
        CIFilter * gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"];
        [gaussianBlurFilter setValue:shapeCimage forKey: @"inputImage"];
        [gaussianBlurFilter setValue:@8 forKey:@"inputRadius"];
    
        CIImage * blurredCIImage = [gaussianBlurFilter valueForKey:kCIOutputImageKey];
        UIImage * blurredImage = [UIImage imageWithCIImage:blurredCIImage];
    
        UIImageView *maskedImageView = [[UIImageView alloc]initWithImage:blurredImage];
        maskedImageView.contentMode = UIViewContentModeScaleAspectFit;
        maskedImageView.frame = imageview.frame;
        imageview.layer.mask=maskedImageView.layer;
    
        [self.view addSubview:imageview];
    

  2. You actually don’t need a gradient for this you can use a dropShadow with a white color to achieve this effect. You will need two separate views. One view should have its layer.mask set to a CAShapeLayer equal to the UIBezierPath.cgPath. You have to also turn on maskToBounds for this to work. Unfortunately maskToBounds will prevent the shadow from drawing on this layer because the shadow is outside of the bounds, which is why you need a second view. It should have a layer = a CAShapeLayer with the same path, and a dropShadow applied with white.

    Login or Signup to reply.
  3. Here is playground showing how to do it. I felt the shadow blur was too weak so I used Core Image’s gaussian blur instead. I thought core image is supposed to be faster these days, but it still seems pretty bad; not sure if its the play ground or not. Try GPU Image if it needs to be faster.

    import UIKit
    import PlaygroundSupport        
    let image = UIImage(named: "1.jpg")
    var imageView = UIImageView(image: image)
    let path = UIBezierPath(arcCenter: imageView.center, radius: 100, startAngle: 0, endAngle: CGFloat.pi * 0.5, clockwise: true).cgPath
    let shape = CAShapeLayer()
    shape.path = path
    shape.fillColor = UIColor.red.cgColor
    let shapeImage = UIGraphicsImageRenderer(size: imageView.frame.size).image { context in
        shape.render(in: context.cgContext)
    }
    let shapeCimage = CIImage(image: shapeImage)
    let gaussianBlurFilter = CIFilter(name: "CIGaussianBlur")!
    gaussianBlurFilter.setValue(shapeCimage, forKey: "inputImage")
    gaussianBlurFilter.setValue(NSNumber(value: 5), forKey: "inputRadius")
    let blurredImage = UIImage(ciImage: gaussianBlurFilter.value(forKey: "outputImage") as! CIImage)
    let maskView = UIImageView(image: blurredImage)
    maskView.contentMode = .scaleAspectFill
    maskView.frame = imageView.frame
    imageView.mask = maskView
    
    PlaygroundPage.current.liveView = imageView
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search