4

I'm trying to add a feature in my iPhone app that allows users to record the screen. To do this, I used an open source class called ScreenCaptureView that compiles a series of screenshots of the main view through the renderInContext: method. However, this method ignores masked CALayers, which is key to my app.

EDIT: I need a way to record the screen so that the masks are included. Although this question specifically asks for a way to create the illusion of an image mask, I'm open to any other modifications I can make to record the screen successfully.

APP DESCRIPTION

In the app, I take a picture and create the effect of a moving mouth by animating the position of the jaw region, as shown below.

enter image description here enter image description here

Currently, I have the entire face as one CALayer, and the chin region as a separate CALayer. To make the chin layer, I mask the chin region from the complete face using a CGPath. (This path is an irregular shape and must be dynamic).

enter image description here

- (CALayer *)getChinLayerFromPic:(UIImage *)pic frame:(CGRect)frame {


    CGMutablePathRef mPath = CGPathCreateMutable();
    CGPathMoveToPoint(mPath, NULL, p0.x, p0.y);
    CGPoint midpt = CGPointMake( (p2.x + p0.x)/2, (p2.y+ p0.y)/2);
    CGPoint c1 = CGPointMake(2*v1.x - midpt.x, 2*v1.y - midpt.y); //control points
    CGPoint c2 = CGPointMake(2*v2.x - midpt.x, 2*v2.y - midpt.y);

    CGPathAddQuadCurveToPoint(mPath, NULL, c1.x, c1.y, p2.x, p2.y);
    CGPathAddQuadCurveToPoint(mPath, NULL, c2.x, c2.y, p0.x, p0.y);

    CALayer *chin = [CALayer layer];
    CAShapeLayer *chinMask = [CAShapeLayer layer];
    chin.frame = frame;
    chin.contents = (id)[pic CGImageWithProperOrientation];
    chinMask.path = mPath;
    chin.mask = chinMask;
    CGPathRelease(mPath);
    return chin;

}

I then animate the chin layer with a path animation.

As mentioned before, the renderInContext: method ignores the mask, and returns an image of the entire face instead of just the chin. Is there any way I can create an illusion of masking the chin? I would like to use CALayers if possible, since it would be most convenient for animations. However, I'm open to any ideas, including other ways to capture the video. Thanks.

EDIT: I'm turning the cropped chin into a UIImage, and then setting that new image as the layers contents, instead of directly masking the layer. However, the cropped region is the reverse of the specified path.

 CALayer *chin = [CALayer layer];
 chin.frame = frame;   
 CGImageRef imageRef = [pic CGImage];
 CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
 int targetWidth = frame.size.width;
 int targetHeight = frame.size.height;
 CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

 CGContextRef bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
    CGContextAddPath(bitmap, mPath);
    CGContextClip(bitmap);
    CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage *chinPic = [UIImage imageWithCGImage:ref];
    chin.contents = (id)[chinPic CGImageWithProperOrientation];
Mahir
  • 1,684
  • 5
  • 31
  • 59

4 Answers4

0

I suggest that you draw each part alone(you don't need masks), the face without a chin, and the chin, both with alpha pixels around, then just draw the chin over and move it on your path ..

Please inform me if this wasn't helpful to you, regards

CME64
  • 1,673
  • 13
  • 24
  • I originally had a "face without chin" layer and a "chin" layer, but I was experiencing some problems, so I decided to do it my current way. – Mahir Jun 14 '13 at 03:03
  • I'm a little inexperienced with image drawing. Could you elaborate more on what you mean by drawing with the alpha pixels around? – Mahir Jun 14 '13 at 03:03
  • Well you can use the paint function to draw everything you want on an object, let's say you are using a jpanel and you are drawing your images on it, you have to make regard to the alpha pixels since they can be lost in the process as they have no rgb values. you will have to draw them with argb (Sorry I'm not home right now and I can't refer to my old project files), I hope this link this would help you in drawing images with alpha maps : http://docs.oracle.com/javase/tutorial/2d/images/drawimage.html – CME64 Jun 14 '13 at 03:21
  • I noticed the link was for java. I'm working with objective-c – Mahir Jun 14 '13 at 03:50
  • oh I thought u r using java, I think I'm sleep drunk or something. I'll check that for you but the same concept should apply. – CME64 Jun 14 '13 at 04:06
0

If you just need this in order to capture the screen, it is much easier to use a programme such as

http://www.airsquirrels.com/reflector/

that connects your device to the computer via AirPlay, and then record the stream on the computer. This particular programme has screen recording built in, extremely convenient. I think there is a trial version you can use for recordings of up to 10 minutes.

Gusutafu
  • 745
  • 6
  • 17
0

Why don't you draw the CALayer of the chin into a seperate CGImage and make a new UIImage with that? Then you can add this CGImage to a seperate UIImageView, which you can just move around with a PanGestureRecognizer for example?

Bersaelor
  • 2,517
  • 34
  • 58
  • I'm able to make an image from a normal calayer, but not when there is a mask, since the approach involves the `renderInContext` method. Is there a different way of drawing the layer that accounts for the mask? – Mahir Jun 28 '13 at 14:39
  • Couldn't you mask in your CGContext without using CALayers? Like in the answer to the following: http://stackoverflow.com/questions/9502737/masking-cgcontext-with-a-cgpathref – Bersaelor Jun 28 '13 at 16:55
  • I was able to get a cropped image, but I think I'm disregarding a change in coordinate systems because the cropped path is flipped vertically and on the opposite side of the screen. I added my code above – Mahir Jul 01 '13 at 18:00
  • Image orientation in these things is a b*** ;) Try using code from the answer to: http://stackoverflow.com/questions/1260249/resizing-uiimages-pulled-from-the-camera-also-rotates-the-uiimage – Bersaelor Jul 02 '13 at 07:44
0

Have you tried taking a look at layer.renderInContext doesn't take layer.mask into account? ?

In particular (notice the coordinate flip):

//Make the drawing right with coordinate switch
CGContextTranslateCTM(context, 0, cHeight);
CGContextScaleCTM(context, 1.0, -1.0);

CGContextClipToMask(context, CGRectMake(maskLayer.frame.origin.x * mod, maskLayer.frame.origin.y * modTwo, maskLayer.frame.size.width * mod,maskLayer.frame.size.height * modTwo), maskLayer.image.CGImage);

//Reverse the coordinate switch
CGAffineTransform ctm = CGContextGetCTM(context);
ctm = CGAffineTransformInvert(ctm);
CGContextConcatCTM(context, ctm);
Community
  • 1
  • 1
EsbenB
  • 3,356
  • 25
  • 44