ios: Screenshot doesn't display mask Layer - objective-c

I have a view with a certain background color. I am masking this view with the following code:
UIView *colorableView = [[UIView* alloc] init];
colorableView.backgroundColor = someColor;
CALayer *maskLayer = [CALayer layer];
maskLayer.contents = (id)[UIImage imageNamed:maskImageName].CGImage;
colorableView.layer.mask = maskLayer;
Ok everything works fine there. The view gets masked, so some parts are transparent. Now I make a screenshot of this view:
CGRect frame = colorableView.frame;
UIGraphicsBeginImageContext(frame.size);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(someUninterestingCodeToGetACorrectPosition);
[self.view.layer renderInContext:c];
UIImage *screenShotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenShotImage;
Taking a screenshot works (actually I display some other stuff above the view too and that gets displayed in the screenshot as well), but somehow, the mask is not recognized. Meaning what I get is a screenshot of a fully colored view (a rectangle) without the mask hiding some parts of it.
I guess ´UIGraphicsGetImageFromCurrentImageContext()`doesn't work with mask layers, so what can I do about it? I need to have a UIImage to display the screenshot in a mail.
Thanks a lot in advance

One way to fix this can be to use Quartz functions to clip the view (CGContextClip, I don't remember exactly, you'll have to dig a little bit into the documentation).
Hope this will help

Related

CAMetalLayer with texture rendered by CARenderer is not visible?

I'm using a CARenderer to render another CALayer tree into a CAMetalLayer, which I hope to use as the mask of yet another layer. For testing purposes, I've tried adding the CAMetalLayer as a normal sublayer instead of a mask.
The layer object below is not visible after adding it to a superlayer that is definitely visible. I've confirmed the frame of the layer is not a problem. Here's how I'm making the CAMetalLayer and its CARenderer.
CAMetalLayer *layer = [CAMetalLayer layer];
layer.frame = bounds;
layer.device = MTLCreateSystemDefaultDevice();
//layer.opaque = NO;
//layer.framebufferOnly = NO;
id<CAMetalDrawable> drawable = layer.nextDrawable;
_lastDrawable = drawable;
_renderer = [CARenderer rendererWithMTLTexture:drawable.texture options:nil];
_renderer.layer = self.superview.layer;
_renderer.bounds = bounds;
👇 By creating a CIImage and inspecting it with the debugger, I've confirmed the CARenderer is updating the Metal texture.
CIImage *img = [CIImage imageWithMTLTexture:_lastDrawable.texture options:nil];
But when I set the superlayer of the CAMetalLayer, it's nowhere to be seen.
[self.layer addSublayer:layer];
Here's how I'm using the CARenderer:
[_renderer beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
[_renderer addUpdateRect:bounds];
[_renderer render];
[_renderer endFrame];
That last snippet runs frequently.
edit 1
I've added a backgroundColor and now the layer is visible, but its texture is not being rendered inside it.
layer.backgroundColor = NSColor.yellowColor.CGColor;
I would recommend just setting the original layer as a mask rather than trying to render it to a texture first; you’re sort of duplicating the work that CA would be doing anyway.
If you really need control over when the mask layer tree gets rendered—and again you should definitely try the standard method first—the right way to do this would be to create an IOSurface-backed MTLTexture rather than using a CAMetalLayer’s drawable, draw into the texture with your CARenderer, set the IOSurface as the contents of a regular CALayer, and use that layer as the mask.

why is the screenshot taken in objective c blank white image?

I want to take screenshot of the actual screen as viewed by the user on the iphone/ipad then present option for the user to share/save it
I have code and tried several but each time all i get is either a blank white or black image. The image is the same size of the screen.
The screen actual background is plain white and has white buttons on it, i can never capture the buttons.
NSLog(#"Taking The Screenshot");
CALayer *layer = [[UIApplication sharedApplication].delegate.window.rootViewController.layer;
CGFloat scale = [UIScreen mainScreen].scale;
UIGraphicsBeginImageContextWithOptions(layer.frame.size, NO, scale);
[layer renderInContext:UIGraphicsGetCurrentContext()];
screengrab = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//new code for sharing...
UIActivityViewController *shareVC = [[UIActivityViewController alloc] initWithActivityItems:#[screengrab] applicationActivities:nil];
It is because you now have scenes and the app delegate window no longer works.
One way to fix this, if self is a VC, is to change your layer line to
CALayer * layer = self.view.window.rootViewController.view.layer;

Get UIImage from UIImageView with masked subviews

Through Face Detection, I want to blur eyes and mouth of a person. So I have a imageView that contains 3 subviews (2 per eye and the mouth). Each one of these subviews were masked with a PNG shape (with background clear) for avoiding to show rectangle.
My imageView in screen remain so: http://screencast.com/t/ak4SkNXM0I
And I want to obtain the image for storing in another place, so I've tried this:
CGSize size = [imageView bounds].size;
UIGraphicsBeginImageContext(size);
[[imageView layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
But finalImage is an image like this:
http://screencast.com/t/eDlvGqqY
My subViews (eyes and mouth) are not masked as above.
Any idea?
Thanks.
Edit:
I have to use library compatible with ios6
You can check the new API added to iOS7. Try one of the following methods:
snapshotViewAfterScreenUpdates:
resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets: for resizable image
drawViewHierarchyInRect:afterScreenUpdates:

Can't get a screenshot of UIView to be displayed inside UIImageView

Here's my code to get the screenshot of the view:
if (NULL != UIGraphicsBeginImageContextWithOptions){
UIGraphicsBeginImageContextWithOptions(pagedScrollView.frame.size, NO, [[UIScreen mainScreen] scale]);
}else{
UIGraphicsBeginImageContext(pagedScrollView.frame.size);
}
[pagedScrollView.layer renderInContext:UIGraphicsGetCurrentContext()];
screenshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView = [[UIImageView alloc] initWithImage:screenshotImage];
imageView.frame = CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y, imageView.frame.size.width, imageView.frame.size.height);
imageView.backgroundColor = [UIColor greenColor];
[self.view addSubview:imageView];
I'm 100% sure I have the right frame and the right view - the size of UIImageView say about it - but the thing is I can't get my UIImage to be displayed on the UIImageView.
The UIImageView is added on the view and I see a green region on it - but no image inside it, what can be wrong?
I'm using iOS 6 and ARC.
Well, I just tested your code running on my view controller's view and the capture and display worked fine. This leads me to believe that pagedScrollView is probably nil, or has a zero frame.
Either way, you'll be creating an image from a blank context and then passing it to your image view resulting in there not being any visible image.
It turns out I've been taking a screenshot of a long UIScrollView and I was always taking its first page - it had a lot of pages in it and sometimes the layer had nothing in it. It also turns out that UIImage was never released and the memory can effectively store dozens of them.

CALayer Audio Indicator with Mask

Ok, What I want to do is create an audio indicator, basically overlay a mask or layer onto an image with a background color and opacity... so it looks like a red level indicator is bouncing up and down overtop of a microphone image, I got this to work in a very poor way updating the image each time with a UIImage mask but this was very inefficient.
Im trying to get it to work now with a CALayer which it does and better than the first trial and error way I tried. The problem now is Im only showing a rectangle and the corresponding level with it. I want it to be bounded by the microphone image, so it looks half full for instance, when I mask to bounds the rectangle takes the shape of the microphone and jumps up and down in that shape instead of "filling" the image.
Hopefully this isn't too confusing, I hope you can understand the premise and help!! Here is some code I have working now, in the wrong way:
self.image = [UIImage imageNamed:#"img_icon_microphone.png"];
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(0.f, 0.f, 200.f, 200.f);
maskLayer.contents = (id) [UIImage imageNamed:#"img_icon_microphone.png"].CGImage;
micUpdateLayer = [CALayer layer];
micUpdateLayer.frame = CGRectMake(0.f, 200.f, 200.f, -5.f);
micUpdateLayer.backgroundColor = [UIColor redColor].CGColor;
micUpdateLayer.opacity = 0.5f;
[self.layer addSublayer:micUpdateLayer];
Im then just using a NSTimer and a call to a function which simply updates the micUpdateLayer.frame y to make it appear to be moving with the audio input.
Thank you for any suggestions!