How to crop image inside the circle in UIImageView in iOS

后端 未结 3 782
梦谈多话
梦谈多话 2020-12-04 08:03

I have an app where I have a UIImageView which displays main image and another UIImageView being used as a mask which shows a circle which is trans

3条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-04 08:36

    Same code reused to play with Square, it may be helpful for other.

    #import "ViewController.h"
    
    @interface ViewController () 
    
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    
    @property (nonatomic) CGFloat circleRadius;
    @property (nonatomic) CGPoint circleCenter;
    @property (nonatomic) CGRect frame;
    
    
    @property (nonatomic, weak) CAShapeLayer *maskLayer;
    @property (nonatomic, weak) CAShapeLayer *circleLayer;
    
    @property (nonatomic, weak) UIPinchGestureRecognizer *pinch;
    @property (nonatomic, weak) UIPanGestureRecognizer   *pan;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        // create layer mask for the image
    
        CAShapeLayer *maskLayer = [CAShapeLayer layer];
        self.imageView.layer.mask = maskLayer;
        self.maskLayer = maskLayer;
    
        // create shape layer for circle we'll draw on top of image (the boundary of the circle)
    
        CAShapeLayer *circleLayer = [CAShapeLayer layer];
        circleLayer.lineWidth = 3.0;
        circleLayer.fillColor = [[UIColor clearColor] CGColor];
        circleLayer.strokeColor = [[UIColor blackColor] CGColor];
        [self.imageView.layer addSublayer:circleLayer];
        self.circleLayer = circleLayer;
    
        // create circle path
    
        [self updateCirclePathAtLocation:CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0) radius:self.view.bounds.size.width * 0.30];
    
        // create pan gesture
    
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
        pan.delegate = self;
        [self.imageView addGestureRecognizer:pan];
        self.imageView.userInteractionEnabled = YES;
        self.pan = pan;
    
        // create pan gesture
    
        UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
        pinch.delegate = self;
        [self.view addGestureRecognizer:pinch];
        self.pinch = pinch;
    }
    
    - (void)updateCirclePathAtLocation:(CGPoint)location radius:(CGFloat)radius
    {
        self.circleCenter = location;
        self.circleRadius = radius;
        self.frame =CGRectMake(self.circleCenter.x/2, self.circleCenter.y/2, self.circleRadius, self.circleRadius);
        UIBezierPath *path =     [UIBezierPath bezierPathWithRoundedRect:self.frame cornerRadius:0];
    //    [path addArcWithCenter:self.circleCenter
    //                    radius:self.circleRadius
    //                startAngle:0.0
    //                  endAngle:M_PI * 2.0
    //                 clockwise:YES];
    
    
        self.maskLayer.path = [path CGPath];
        self.circleLayer.path = [path CGPath];
    }
    
    - (IBAction)didTouchUpInsideSaveButton:(id)sender
    {
        NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
        NSString *path = [documentsPath stringByAppendingPathComponent:@"image.png"];
    
        CGFloat scale  = [[self.imageView.window screen] scale];
    
        CGRect frame = CGRectMake(self.frame.origin.x *scale,
                                  self.frame.origin.y *scale,
                                  self.frame.size.width*scale,
                                  self.frame.size.width*scale);
    
        // temporarily remove the circleLayer
    
        CALayer *circleLayer = self.circleLayer;
        [self.circleLayer removeFromSuperlayer];
    
        // render the clipped image
    
        UIGraphicsBeginImageContextWithOptions(self.imageView.frame.size, NO, 0.0);
        CGContextRef context = UIGraphicsGetCurrentContext();
        if ([self.imageView respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)])
        {
            // if iOS 7, just draw it
    
            [self.imageView drawViewHierarchyInRect:self.imageView.bounds afterScreenUpdates:YES];
        }
        else
        {
            // if pre iOS 7, manually clip it
    
            CGContextAddRect(context, self.frame);
            CGContextClip(context);
            [self.imageView.layer renderInContext:context];
        }
    
        // capture the image and close the context
    
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        // add the circleLayer back
    
        [self.imageView.layer addSublayer:circleLayer];
    
        // crop the image
        NSLog(@"circle fram %@",NSStringFromCGRect(frame));
        NSLog(@"self fram %@",NSStringFromCGRect(self.frame));
    
        CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], frame);
        UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
    
        // save the image
    
        NSData *data = UIImagePNGRepresentation(croppedImage);
        [data writeToFile:path atomically:YES];
    
        // tell the user we're done
    
        [[[UIAlertView alloc] initWithTitle:nil message:@"Saved" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil] show];
    }
    
    
    #pragma mark - Gesture recognizers
    
    - (void)handlePan:(UIPanGestureRecognizer *)gesture
    {
        static CGPoint oldCenter;
        CGPoint tranlation = [gesture translationInView:gesture.view];
    
        if (gesture.state == UIGestureRecognizerStateBegan)
        {
            oldCenter = self.circleCenter;
        }
    
        CGPoint newCenter = CGPointMake(oldCenter.x + tranlation.x, oldCenter.y + tranlation.y);
    
        [self updateCirclePathAtLocation:newCenter radius:self.circleRadius];
    }
    
    - (void)handlePinch:(UIPinchGestureRecognizer *)gesture
    {
        static CGFloat oldRadius;
        CGFloat scale = [gesture scale];
    
        if (gesture.state == UIGestureRecognizerStateBegan)
        {
            oldRadius = self.circleRadius;
        }
    
        CGFloat newRadius = oldRadius * scale;
    
        [self updateCirclePathAtLocation:self.circleCenter radius:newRadius];
    }
    
    
    #pragma mark - UIGestureRecognizerDelegate
    
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {
        if ((gestureRecognizer == self.pan   && otherGestureRecognizer == self.pinch) ||
            (gestureRecognizer == self.pinch && otherGestureRecognizer == self.pan))
        {
            return YES;
        }
    
        return NO;
    }
    
    @end
    

提交回复
热议问题