Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mask problem with renderInContext of CALayer #12

Open
hk007 opened this issue Mar 2, 2013 · 4 comments
Open

Mask problem with renderInContext of CALayer #12

hk007 opened this issue Mar 2, 2013 · 4 comments

Comments

@hk007
Copy link

hk007 commented Mar 2, 2013

When using renderInContext method of CALayer the mask layers are not rendered. The result looks ugly, the entire track image is show in the UIImage.
I know the real problem is that renderInContext does not support mask layer -- but is there something that can be done in TTSwitch to address this? My app requires screenshot of UIView which contains the Switch. I just finished replacing all the Swtiches in the app with TTSwitch... would hate to revert back to UISwitch.

Test code to reproduce the issue (modified the example project):


#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>

@interface TTXibViewController : UIViewController <MFMailComposeViewControllerDelegate>

@end





#import "TTXibViewController.h"
#import "TTSwitch.h"
#import <QuartzCore/QuartzCore.h>

@interface TTXibViewController ()

@property (weak, nonatomic) IBOutlet TTSwitch *defaultSwitch;

@end

@implementation TTXibViewController
- (IBAction)sendEmail:(id)sender {

    UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0);

    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    NSData * data = UIImagePNGRepresentation(screenshot);
    [self emailImageWithImageData:data];
}

- (void)emailImageWithImageData:(NSData *)data
{
    MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
    mailController.mailComposeDelegate = self;
    [mailController setSubject:@"Test Email"];
    [mailController setMessageBody:nil isHTML:NO];
    [mailController addAttachmentData:data mimeType:@"image/png" fileName:@"test.png"];
    [self.navigationController presentModalViewController:mailController animated:YES];
}

- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
    [self dismissModalViewControllerAnimated:YES];

}

@end

;
@spenrose
Copy link
Contributor

spenrose commented Mar 9, 2013

I am not sure how to solve this problem without rewriting the switch to draw with core graphics. I am open to any ideas on how to change the way the masking currently works to fix it.

@hackiftekhar
Copy link

I wasted two days, but finally i had to create my own logic.

I have solved this problem by a tricky logic.

I created following code to get UIImage from UIView.subviews.
Actually i am having Subviews. And my subView's layer is masked by CAShapeLayer.
modify this code according to your requirement.

-(UIImage*) imageFromView:(UIView*)originalView
{
    //Creating a fakeView which is initialized as our original view.
    //Actually i render images on a fakeView and take screenshot of this fakeView.
    UIView *fakeView = [[UIView alloc] initWithFrame:originalView.frame];
            [fakeView setBackgroundColor:originalView.backgroundColor];
            [fakeView.layer setMasksToBounds:originalView.layer.masksToBounds];
            [fakeView.layer setCornerRadius:originalView.layer.cornerRadius];
            [fakeView.layer setBorderColor:originalView.layer.borderColor];
            [fakeView.layer setBorderWidth:originalView.layer.borderWidth];

            //Getting subviews of originalView.
            for (UIView *view in originalView.subviews)
            {
                //Getting screenshot of layer of view.
                UIGraphicsBeginImageContext(view.bounds.size);
                [view.layer renderInContext:UIGraphicsGetCurrentContext()];
                UIImage *imageLayer = UIGraphicsGetImageFromCurrentImageContext();
                UIGraphicsEndImageContext();

                //If it is masked view, then get masked image.
                if (view.layer.mask)
                {
                    //getting screenshot of masked layer.
                    UIGraphicsBeginImageContext(view.bounds.size);
                    [view.layer.mask renderInContext:UIGraphicsGetCurrentContext()];

                    //PNG Representation is most important. otherwise this masked image will not work.
                    UIImage *maskedLayerImage=[UIImage imageWithData:UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext())];
                    UIGraphicsEndImageContext();

                    //getting image by masking original image.
                    imageLayer = [self maskImage:imageLayer withMask:maskedLayerImage];
                }

                //If imageLayer is pointing to a valid object, then setting this image to UIImageView, our UIImageView frame having exactly as view.frame.
                if (imageLayer)
                {
                    UIImageView *imageView = [[UIImageView alloc] initWithFrame:view.frame];
                    [imageView setImage:imageLayer];
                    [fakeView addSubview:imageView];
                }
            }

            //At the end, taking screenshot of fakeView. This will get your Original Image.
            UIGraphicsBeginImageContext(fakeView.bounds.size);
            [fakeView.layer renderInContext:UIGraphicsGetCurrentContext()];
            UIImage *previewCapturedImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            return previewCapturedImage;
        }
}

//Method is used to get masked 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];
}

@hk007
Copy link
Author

hk007 commented Jun 9, 2013

Thanks hackiftekhar! Your tricky solution worked. Just had to modify a little according to my view setup.

@hackiftekhar
Copy link

most welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants