SnK
SnK

Reputation: 528

Image mask without transparant part

I've been looking into this for a while now.

I'm trying to put a gray image over a cup

enter image description here

Currently i'm stretching an uiimageview with a grey background to the amount the slider has gone.

-(void) sliderChanged:(CGFloat) value{
drinksView.grayArea.frame = CGRectMake( 0 , -value ,372 ,value);

I know this is very dirty ,not what i want...

What i want is that the grey part only covers the part where there is a cup (e.g the part where the image is not transparant). The image of the cup just has a transparant background

Does anybody have an idea of how to achieve this ? i'm a noob with masks and many tutorials have led me nowhere and i don't even know if it's possible.

P.S: drawing a path around the cup is not possible because the cup image can change to a glass

Upvotes: 0

Views: 387

Answers (3)

SnK
SnK

Reputation: 528

    drinksView.grayLayer = [CALayer new];
    drinksView.grayLayer.frame = CGRectMake(0, 0, 372, 0);
    drinksView.grayLayer.contentsGravity = kCAGravityTop;

    CALayer * topLayer = [CALayer new];
    topLayer.frame = CGRectMake(0, 0, 372, 367);
    UIImage * grayImage = [UIImage imageNamed:@"grayDrink.png"];
    topLayer.contents = (id) grayImage.CGImage;

    CALayer * maskLayer = [CALayer new];
    maskLayer.contents = (id)cupImage.CGImage;
    maskLayer.masksToBounds = YES;

    maskLayer.bounds = CGRectMake(0, 0, 372, 367);
    maskLayer.position = CGPointMake(186,184);

    [topLayer setMask:maskLayer];
    [drinksView.grayLayer addSublayer:topLayer];
    [drinksView.grayLayer setMasksToBounds:YES];
    [[drinksView layer]addSublayer:drinksView.grayLayer];

Upvotes: 0

mohsenr
mohsenr

Reputation: 7255

The easiest way I can think of is to use a masked CALayer. This is what you need to do:

  1. Instead of using a UIImageView, use a CALayer with gray background as your overlay. Your sliderChanged: method would remain untouched, except that drinksView.grayArea would be a layer instead of a view.
  2. So far the effect will be exactly the same as before. Now, you need to set the grayArea's mask. Do the following:

    CALayer * maskLayer = [CALayer new];
    maskLayer.contents = myCupImage.CGImage;
    grayArea.mask = maskLayer;
    
  3. I think by default the layer will stretch the content as the scale is changed. We don't want that. You can fix this by setting the layer's contentsGravity to, say, kCAGravityTop.

That should do what you want.

One caveat: I'm not quite sure how masks cope with changing content gravity. If you have issues on that front, you can fixed it by adding a container layer:

  1. Set a fixed frame for grayArea (equal to the size of the cup image).

  2. Instead of adding grayArea directly, introduce a container layer for it:

    CALayer * container = [CALayer new];
    container.masksToBounds = YES;
    [container addSublayer:grayArea];
    [drinksView.layer addSublayer:container];
    
  3. In your sliderChanged:, change the frame of container instead of the grayArea.

Hope this works.

Upvotes: 1

rinzler
rinzler

Reputation: 236

First of all you will need to get familiar with this method

    // masks the item based on the MaskImage
- (UIImage*) itemMask : (UIImage*)image withMask:(UIImage*)maskImage
{
    UIImage* afterMasking = nil;

    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);
    CFRelease(mask);
    afterMasking = [UIImage imageWithCGImage:masked];
    CFRelease(masked);
    return afterMasking;
}

What that does is that you feed it your Cup image and the mask Image together and it will mask your cup image. It will only mask your cup image and nothing underneath so you don't have to worry.

The problem you have is that the grey box resizes. How I would approach this is to crop the mask according to the slider value. So make a black box and change it size how you do with the grayBG BEFORE you feed it through the method. That should be quick to do so so I won't elaborate but at the end you will have something like this. Pardon the half elaborated graphics

Image With large sliderImage With small slider

Upvotes: 1

Related Questions