Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mask does not work when capturing a uiview to a uiimage

I have a UIView which I want to save as a UIImage. I do this using UIGraphicsBeginImageContext, and it works OK. But when I apply mask to the images in the (view/layer.mask), the image that I capture through UIGraphicsBeginImageContext is wrong (the masking is working when running the app but not when trying to get a UIImage from a UIView). Anyone encountered similar problem?

like image 516
Thanassis Bantios Avatar asked Dec 17 '12 08:12

Thanassis Bantios


1 Answers

If I understand correctly, you wish to create a UIImage from a UIView layer, while that layer is masked. I assume that you want the target UIImage to have transparent background.

I encountered no problems implementing this and I have a demo project you can take a look at:

https://bitbucket.org/reydan/so_imagemask

You first need to press the Mask button. It will load a mask image (black and white) from the bundle and set it as the layer mask for the UIView container above.

Then, you can press the Copy Image button which renders the UIView container into an UIImage, and then set it to the destination image view below to see the result.

I will also post the 2 methods here:

- (IBAction)onMask:(id)sender {

    UIImage* maskImage = [UIImage imageNamed:@"star.png"];
    UIImageView* maskImageView = [[UIImageView alloc] initWithImage:maskImage];
    maskImageView.contentMode = UIViewContentModeScaleAspectFit;
    maskImageView.frame = _mainContainerView.bounds;

    _mainContainerView.layer.mask = maskImageView.layer;
}

- (IBAction)onCopyImage:(id)sender {

    UIGraphicsBeginImageContextWithOptions(_mainContainerView.bounds.size, FALSE, [[UIScreen mainScreen] scale]);
    [_mainContainerView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    _destImageView.image = img;
}

EDIT

Apparently renderInContext: on IOS6 does not use the mask (as it is also said here on SO). My solution was to manually apply mask to the image. The mask is taken from the mask property of the layer and rendered in a context too so we don't have any problems with transformations/contentModes/etc.

Here is the updated source code (it is also available on bitbucket):

- (IBAction)onCopyImage:(id)sender {

    // Get the image from the mainImageView
    UIGraphicsBeginImageContextWithOptions(_mainContainerView.bounds.size, FALSE, [[UIScreen mainScreen] scale]);
    [_mainContainerView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();


    // Use the next block if targeting IOS6
    {
        // Manually create a mask image (taken from the mask layer)
        UIGraphicsBeginImageContextWithOptions(_mainContainerView.bounds.size, TRUE, [[UIScreen mainScreen] scale]);

        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor);
        CGContextFillRect(ctx, _mainContainerView.bounds);

        [_mainContainerView.layer.mask renderInContext:ctx];
        UIImage * maskimg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();


        // Create a image mask from the UIImage
        CGImageRef maskRef = maskimg.CGImage;
        CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                            CGImageGetHeight(maskRef),
                                            CGImageGetBitsPerComponent(maskRef),
                                            CGImageGetBitsPerPixel(maskRef),
                                            CGImageGetBytesPerRow(maskRef),
                                            CGImageGetDataProvider(maskRef), NULL, false);

        // Apply the mask to our source image
        CGImageRef maskedimg= CGImageCreateWithMask(img.CGImage, mask);

        // Convert to UIImage so we can easily display it in a UIImageView
        img = [UIImage imageWithCGImage:maskedimg scale:img.scale orientation:img.imageOrientation];

        CGImageRelease(mask);
        CGImageRelease(maskedimg);
    }



    _destImageView.image = img;

}

EDIT Please check the latest project on bitbucket as it contains the latest version.

like image 133
Andrei Stanescu Avatar answered Oct 19 '22 16:10

Andrei Stanescu