Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cropping an Image to the shape of an Overlay - iOS

I'm adding the overlay using pickerController's view and the uinavigationcontrollerdelegate as below.

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:  (UIViewController *)viewController animated:(BOOL)animated{
    if ([navigationController.viewControllers count] == 3)
     {
       CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;

       UIView *plCropOverlay = [[[viewController.view.subviews objectAtIndex:1]subviews] objectAtIndex:0];

       plCropOverlay.hidden = YES;

       int position = 0;

       if (screenHeight == 568)
       {
           position = 124;
       }
       else
       {
          position = 80;
      }

      CAShapeLayer *circleLayer = [CAShapeLayer layer];

      UIBezierPath *path2 = [UIBezierPath bezierPathWithOvalInRect:
                           CGRectMake(0.0f, position, 320.0f, 320.0f)];
      [path2 setUsesEvenOddFillRule:YES];

      [circleLayer setPath:[path2 CGPath]];

      [circleLayer setFillColor:[[UIColor clearColor] CGColor]];
      UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 320, screenHeight-72) cornerRadius:0];

      [path appendPath:path2];
      [path setUsesEvenOddFillRule:YES];

      CAShapeLayer *fillLayer = [CAShapeLayer layer];
      fillLayer.path = path.CGPath;
      fillLayer.fillRule = kCAFillRuleEvenOdd;
      fillLayer.fillColor = [UIColor blackColor].CGColor;
      fillLayer.opacity = 0.8;
      [viewController.view.layer addSublayer:fillLayer];

  }
}

When the overlay defined above is added, I tend to get this view:

enter image description here

I can crop the image exactly to a square using a defined CGRect.

   CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect);

   UIImage *cropped = [UIImage imageWithCGImage:imageRef];
   CGImageRelease(imageRef);

How about approaching this problem where there is a circular overlay and imagePickers editing property is YES? I can zoom in and zoom out of the pic. How can i make use of the BezierPath here?

like image 676
DesperateLearner Avatar asked Sep 09 '14 22:09

DesperateLearner


2 Answers

the short answer to your question addClip , but you mention you're a beginner, so here's all the steps from A to Z!!

Firstly, try this category, see if it helps. (If you're not familiar w/ categories have a google or just ask here in a comment.)

-(UIImage *)doMask
    {
    UIImage *maskImage = [UIImage imageNamed:@"yourMask.png"];
    
    CGImageRef maskRef = maskImage.CGImage;
    
    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef), NULL, false);
    
    CGImageRef maskedImageRef = CGImageCreateWithMask([self CGImage], mask);
    UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];
    
    CGImageRelease(mask);
    CGImageRelease(maskedImageRef);
    
    return maskedImage;
    }

just create (I mean in photoshop) a png mask, and get familiar with that process.

I encourage you to master that process first...

Here are critical categories that will help...

-(UIImage *)becomeSquare
    {
    CGSize imageSize = self.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    
    UIImage *result = self;
    
    if (width != height)
        {
        CGFloat newDimension = MIN(width, height);
        CGFloat widthOffset = (width - newDimension) / 2;
        CGFloat heightOffset = (height - newDimension) / 2;
        
        UIGraphicsBeginImageContextWithOptions(
            CGSizeMake(newDimension, newDimension), NO, 0. );
        
        [result drawAtPoint:CGPointMake(-widthOffset, -heightOffset)
            blendMode:kCGBlendModeCopy alpha:1. ];
        result = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        }
    
    return result;
    }

and a couple more ...

-(UIImage *)doScale
    {
    UIImage *result = self;
    
    CGSize size = CGSizeMake(320,320);
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
    [result drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)];
    result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return result;
    }

-(UIImage *)scaled640AnyShape
    {
    if ( self.size.height < 5.0 ) return nil;
    if ( self.size.width < 5.0 ) return nil;
    
    UIImage *result = self;
    
    float widthShouldBe = 640.0;
    float heightShouldBe = widthShouldBe * ( self.size.height / self.size.width );
    
    CGSize size = CGSizeMake( widthShouldBe ,heightShouldBe );
    
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
    [result drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)];
    result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return result;
    }

(obviously change the hard-coded output sizes as you wish.)

Note that your final result, will be achieved, by a combination in the appropriate order, such as:

yourImage = [yourImage doSquare];
yourImage = [yourImage doMask];

once you've got that working ...

Then ....

for LITERALLY what you ask, there are many example codes about .. e.g., what about https://stackoverflow.com/a/13870097/294884

As you can see, you fundamentally...

UIGraphicsBeginImageContextWithOptions(...);
UIBezierPath * path = [UIBezierPath
    bezierPathWithRoundedRect:imageRect cornerRadius:10.f];
[path addClip];
[yourImage drawInRect:imageRect];
... then ... UIGraphicsGetImageFromCurrentImageContext();
.. see the extensive code above for how to save it and so on.

You just have to get the zoom right with the scaling examples above.

Also note this, when you are changing the "area cropped"... https://stackoverflow.com/a/17884863/294884

here's an example of that critical technique...

-(UIImage *)squareAndSmall
    {
    // genius credits: https://stackoverflow.com/a/17884863/294884
    
    CGSize finalsize = CGSizeMake(640,640);
    
    CGFloat scale = MAX(
        finalsize.width/self.size.width,
        finalsize.height/self.size.height);
    CGFloat width = self.size.width * scale;
    CGFloat height = self.size.height * scale;
    
    // for example, the central area....
    CGRect imageRect = CGRectMake(
                  (finalsize.width - width)/2.0f,
                  (finalsize.height - height)/2.0f,
                  width, height);
    
    // or, the top area... CGRect imageRect = CGRectMake( 0, 0, width, height);
    
    UIGraphicsBeginImageContextWithOptions(finalsize, NO, 0);
    [self drawInRect:imageRect];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
    }

Hope it all helps!

like image 133
Fattie Avatar answered Nov 09 '22 11:11

Fattie


Found this blog post entry very interesting, neat and simple to follow by Nimit Parekh.

Following code is copy/paste into your “viewcontroller.h” file:

#import &lt;UIKit/UIKit.h&gt;

@interface UIImagePickerDemoViewController : UIViewController&lt; UIImagePickerControllerDelegate, UINavigationControllerDelegate&gt;

@property(nonatomic,retain) UIImagePickerController *imgPicker;
@property(nonatomic,retain) IBOutlet UIImageView *image_view;

//- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect;
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage;
@end

Following Code copy/paste into “viewcontroller.m” file:

// Following method is use for the mask the image.

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {

    CGImageRef maskRef = maskImage.CGImage; 

    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                        CGImageGetHeight(maskRef),
                                        CGImageGetBitsPerComponent(maskRef),
                                        CGImageGetBitsPerPixel(maskRef),
                                        CGImageGetBytesPerRow(maskRef),
                                        CGImageGetDataProvider(maskRef), NULL, false);

    CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
    return [UIImage imageWithCGImage:masked];
}

// Following method is use for Cropping the image for a perticular size.

- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
{
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef currentContext = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(currentContext, 0.0, rect.size.height);
    CGContextScaleCTM(currentContext, 1.0, -1.0);   

    CGRect clippedRect = CGRectMake(0, 0, rect.size.width, rect.size.height);
    CGContextClipToRect( currentContext, clippedRect);
    CGRect drawRect = CGRectMake(rect.origin.x * -1,rect.origin.y * -1,imageToCrop.size.width,imageToCrop.size.height);
    CGContextDrawImage(currentContext, drawRect, imageToCrop.CGImage);
    CGContextScaleCTM(currentContext, 1.0, -1.0);

    UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return cropped;
}

// Calling the method of maskimage.

//=============================Camera Enable(display)============================================
-(IBAction)next:(id)sender{

    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        self.imgPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    }
    [self presentModalViewController:self.imgPicker animated:YES];
}

-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
    [picker dismissModalViewControllerAnimated:YES];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [picker dismissModalViewControllerAnimated:YES];
    UIImage *img =  [info objectForKey:@"UIImagePickerControllerOriginalImage"];
        self.image_view.image=[self maskImage:img withMask:[UIImage imageNamed:@"frame.png"]];
}
//===============================================================================================

// Calling the method of cropping the image.

//=============================Camera Enable(display)============================================
-(IBAction)next:(id)sender{

    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        self.imgPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    }
    [self presentModalViewController:self.imgPicker animated:YES];
}

-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
    [picker dismissModalViewControllerAnimated:YES];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [picker dismissModalViewControllerAnimated:YES];
    UIImage *img =  [info objectForKey:@"UIImagePickerControllerOriginalImage"];
    self.image_view.image = [self imageByCropping:img toRect:CGRectMake(0, 0, 420, 40)];
}
//===============================================================================================

Output:

iPhone output

Grab the source code here.

like image 36
GrandSteph Avatar answered Nov 09 '22 11:11

GrandSteph