将图像裁剪为叠加层的形状 - iOS

Posted

技术标签:

【中文标题】将图像裁剪为叠加层的形状 - iOS【英文标题】:Cropping an Image to the shape of an Overlay - iOS 【发布时间】:2014-09-09 22:42:01 【问题描述】:

我正在使用 pickerController 的视图和 uinavigationcontrollerdelegate 添加叠加层,如下所示。

-(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];

  

当添加上面定义的叠加层时,我倾向于得到这个视图:

我可以使用定义的 CGRect 将图像精确地裁剪为正方形。

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

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

如果存在圆形叠加层且 imagePickers 编辑属性为 YES,如何解决此问题?我可以放大和缩小图片。我如何在这里使用 BezierPath?

【问题讨论】:

目标到底是什么?您不能以圆形图像结束,所以您只想将覆盖层下的图像擦除为白色?缩放与叠加层有何关系?您已经可以自己处理缩放了吗? UIImage 位于缩放比例为 2.0 的滚动视图之上。当图像被缩放并预计被裁剪时,该覆盖清晰视图内的缩放图像应该被裁剪掉。 是的,要正确缩放非常非常困难。我已经在下面给了你你需要的所有代码! 你好@DesperateLearner 还有什么问题吗?!运气好吗? 【参考方案1】:

您的问题addClip 的简短回答,但您提到您是初学者,所以这里是从A 到Z 的所有步骤!!

首先,试试这个类别,看看它是否有帮助。 (如果您不熟悉类别,请使用 google 或在评论中询问。)

-(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;
    

只需创建(我的意思是在 Photoshop 中)一个 png 蒙版,然后熟悉该过程。

我鼓励你先掌握这个过程......

这里有一些重要的类别会有所帮助...

-(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;
    

还有更多...

-(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;
    

(显然可以根据需要更改硬编码的输出大小。)

请注意,您的最终结果将通过按适当顺序组合来实现,例如:

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

一旦你得到它的工作......

然后....

从字面上看,有很多关于 .. 的示例代码,例如 https://***.com/a/13870097/294884 呢

如你所见,你从根本上...

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.

您只需使用上面的缩放示例正确缩放即可。

还要注意这一点,当您更改“裁剪区域”时...https://***.com/a/17884863/294884

这是该关键技术的一个示例...

-(UIImage *)squareAndSmall
    
    // genius credits: https://***.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;
    

希望对您有所帮助!

【讨论】:

【参考方案2】:

发现这个 blog post 条目非常有趣、简洁且易于 Nimit Parekh 关注。

以下代码复制/粘贴到您的“viewcontroller.h”文件中:

#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

以下代码复制/粘贴到“viewcontroller.m”文件中:

// 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)];

//===============================================================================================

输出:

Grab the source code here.

【讨论】:

【参考方案3】:

我拥有与您完全相同的个人资料图像选择器控制器。这是我的委托代码。我认为你不需要所有东西,但你可以在这里找到一些有用的信息

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

    NSString *mediaType = info[UIImagePickerControllerMediaType];

    if([mediaType isEqualToString:(NSString *) kUTTypeImage]) 

        UIImage *image = info[UIImagePickerControllerOriginalImage];
        UIImage *editedImage = (UIImage *) [info objectForKey:UIImagePickerControllerEditedImage];
        CGRect croppingRect = [info[UIImagePickerControllerCropRect] CGRectValue];

        if (editedImage) 
            image = editedImage;
         else 
            CGFloat smaller = 1;
            if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) 
                smaller = 0.9;
            

            CGFloat width = MIN(image.size.width * smaller, image.size.height * (smaller * 0.95));
            croppingRect = CGRectMake(0 + (image.size.width - width) / 2,
                                      0 + (image.size.height - width) / 2,
                                      width, width);
        

        UIImage *finalImage = nil;
        if (editedImage) 
            finalImage = [UIImage image:editedImage byScalingAndCroppingForSize:kCroppedImageSize];
         else 
            finalImage = [UIImage image:image byScalingAndCroppingForSize:kCroppedImageSize];
        

        if ([self.imagePickerDelegate respondsToSelector:@selector(profileImagePicker:didSelectImage:)]) 
            [self.imagePickerDelegate profileImagePicker:self didSelectImage:finalImage];
         else 
            NSAssert(nil, @"Delegate should confirm ProfileImagePickerControllerDelegate protocol");
        

     else if ([mediaType isEqualToString:(NSString *) kUTTypeVideo]) 
        NSAssert(nil, @"Movie is not supported");
    

【讨论】:

以上是关于将图像裁剪为叠加层的形状 - iOS的主要内容,如果未能解决你的问题,请参考以下文章

图像视图裁剪为特定形状

裁剪不规则形状的图像

如何根据触摸时创建的形状裁剪图像?

以另一个 ImageView 的形状裁剪 ImageView

基于像素数Java创建/裁剪图像

如何在 iOS 中将图像裁剪为多边形?