使用旋转和缩放从UIimageview创建CGpath以用作cglayer掩码

时间:2013-01-10 04:12:26

标签: ios ios6 uiimageview calayer cgpath

我仍然是iOS新手,但我无法弄清楚为什么这不起作用。

我有2个单独的UIImageView的

  1. '背景'。这是一张将应用了图层蒙版的图片,以便您只能看到图像的一部分。
  2. 'Mask Image'这是它自己的独立图像,可以旋转,平移,捏缩放。旋转/缩放的代码工作正常,是标准代码。
  3. 我要做的是创建一个与“Mask Image”的当前位置/旋转/比例相匹配的CGPath

    这是我的代码,用于抓取“蒙版图像”的位置并创建一个CGPAth用作图层蒙版。

    如果您转到Xcode并创建一个新的“单一视图应用程序”项目,这里是ViewController的完整复制粘贴

    ViewController.h:

    #import <UIKit/UIKit.h>
    
    @interface ViewController : UIViewController <UIGestureRecognizerDelegate>
    {
        UIImageView *makskedImageView;
        UIImageView *maskImageView;
    }
    
    @end
    

    ViewController.m

    #import "ViewController.h"
    #import <QuartzCore/QuartzCore.h>
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        UIImage *sourceImage = [UIImage imageNamed:@"forest.jpg"];
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, (sourceImage.size.width/2), (sourceImage.size.height/2))];
        imageView.image = sourceImage;
    
        [self.view addSubview:imageView];
    
        makskedImageView = imageView;
    
        //    Movable Mask
        UIImage *frameBorder = [UIImage imageNamed:@"semiTransSquare.png"];
        maskImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, (frameBorder.size.width/2), (frameBorder.size.height/2))];
        maskImageView.image = frameBorder;
    
        UIPanGestureRecognizer *panGesture2 = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
        [panGesture2 setDelegate:self];
        [maskImageView addGestureRecognizer:panGesture2];
        UIPinchGestureRecognizer *pinchGesture2 = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
        [pinchGesture2 setDelegate:self];
        [maskImageView addGestureRecognizer:pinchGesture2];
        UIRotationGestureRecognizer *rotateGesture2 = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotate:)];
        [rotateGesture2 setDelegate:self];
        [maskImageView addGestureRecognizer:rotateGesture2];
    
        UITapGestureRecognizer *tapGR =[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)];
        [tapGR setDelegate:self];
        [tapGR setNumberOfTapsRequired:1];
        [maskImageView addGestureRecognizer:tapGR];
    
        [maskImageView setUserInteractionEnabled:YES];
        // Add to view to make visible;
        [self.view addSubview:maskImageView];
    
        // apply layer mask to makskedImageView
        [self grabTransform:maskImageView];
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    - (void)grabTransform:(UIView *)currentView
    {
        // build the transform you want
        CGAffineTransform t = CGAffineTransformIdentity;
        CGFloat angle = [(NSNumber *)[currentView valueForKeyPath:@"layer.transform.rotation.z"] floatValue];
        CGFloat scale = [(NSNumber *)[currentView valueForKeyPath:@"layer.transform.scale"] floatValue];
        t = CGAffineTransformConcat(t, CGAffineTransformMakeScale(scale, scale));
        t = CGAffineTransformConcat(t, CGAffineTransformMakeRotation(angle));
        NSLog(@"angle: %f, scale: %f", angle, scale);
    
        // Create a mask layer
        // Create a mask layer and the frame to determine what will be visible in the view.
        CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
        // CGRect maskRect = currentView.bounds;
        // Frame works a lot better.
        CGRect maskRect = currentView.frame;
    
        maskRect.origin.x = currentView.frame.origin.x;
        maskRect.origin.y = currentView.frame.origin.y;
    
        // Make a Path friendly transform.
    
        CGPoint center = CGPointMake(CGRectGetMidX(currentView.frame), CGRectGetMidY(currentView.frame));
        CGAffineTransform transform = CGAffineTransformIdentity;
    
        transform = CGAffineTransformTranslate(transform, center.x, center.y);
        transform = CGAffineTransformScale(transform, scale, scale);
        transform = CGAffineTransformRotate(transform, angle);
        transform = CGAffineTransformTranslate(transform, -center.x, -center.y);
    
        // Create a path and from the rectangle in it.
        CGPathRef path = CGPathCreateWithRect(maskRect, &transform);
        // Set the path to the mask layer.
        [maskLayer setPath:path];
        // Release the path since it's not covered by ARC.
        CGPathRelease(path);
        // Set the mask of the view.
        makskedImageView.layer.mask = maskLayer;
    
    
    }
    
    #pragma mark - Gestures
    
    -(void)handlePan:(UIPanGestureRecognizer *)recognizer
    {
        CGPoint translation = [recognizer translationInView:self.view];
        recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
                                             recognizer.view.center.y + translation.y);
        [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
        [self grabTransform:[recognizer view]];
    }
    
    -(void)handlePinch:(UIPinchGestureRecognizer *)recognizer
    {
        recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
    
        recognizer.scale = 1;
        [self grabTransform:[recognizer view]];
    }
    
    -(void)handleRotate:(UIRotationGestureRecognizer *)recognizer
    {
        recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
        recognizer.rotation = 0;
    valueForKeyPath:@"layer.transform.rotation"] floatValue];
        [self grabTransform:[recognizer view]];
    }
    
    -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {
        return YES;
    }
    
    - (void)handleTap:(UIGestureRecognizer *)recognizer
    {
        [self grabTransform:[recognizer view]];
    
    }
    
    @end
    

    加2张图片:Forest.jpg&amp; semiTransSquare.png

    现在,当它运行时,它可用于平移,直到我缩放。旋转图像。 (由于其他一些代码,现在轮流工作)。

    据我所知,尺度与中心一起作为它生长/收缩的点,其中路径似乎从根x,y坐标向外扩展。

    这可能是设计的(CGPathCreateWithRect per the docs),但我看不到将变换应用于CGPath的方法,并让它出现在与UIImageView“Mask Image”相同的位置

    性能是一个大问题,CIImage的类似解决方案非常滞后,所以想要在CGPath创建层掩码的情况下解决这个问题,如果可能的话,或者同样快的东西。

    我错过了什么?仅适用于iOS 6解决方案。

    更新:我发现从界限到帧的变化让我获得90%的胜利:

    CGRect maskRect = currentView.frame;
    

    路径现在将匹配视图的旋转和位置。剩下的唯一问题是规模是错误的。它匹配原始大小,但如果你缩小,那么它会变得太小,或者如果你长大,它会变得太大。看起来比例不是1:1。现在这么近了。

2 个答案:

答案 0 :(得分:0)

您是否看过该功能

  

CGPathCreateCopyByTransformingPath

它需要CGRect和仿射变换才能实现您的目标。

仅供参考,它是iOS 5 +

答案 1 :(得分:0)

您可以使用以下方式获取有效比例因子:

CGFloat zoomScale = sqrtf( powf(currentView.transform.a, 2) + powf(currentView.transform.c, 2) );

不等于:

CGFloat scale = [(NSNumber *)[currentView valueForKeyPath:@"layer.transform.scale"] floatValue];