Question

I need to render uiview with transparent rectangle. As a result, that uiview is set mask and rendered it. The below code is okay for ios 7. However, it doesn't work on ios 6. I can't get image with transparent/blank box. How shall I do?

CAShapeLayer *mask = [[CAShapeLayer alloc] init];
mask.frame = self.view1.layer.bounds;
CGRect biggerRect = CGRectMake(mask.frame.origin.x, mask.frame.origin.y, mask.frame.size.width, mask.frame.size.height);


CGRect smallerRect = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);

UIBezierPath *maskPath = [UIBezierPath bezierPath];
[maskPath moveToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMaxY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMaxY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMinY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))];

[maskPath moveToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMaxY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMaxY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMinY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))];

mask.path = maskPath.CGPath;
[mask setFillRule:kCAFillRuleEvenOdd];
mask.fillColor = [[UIColor blackColor] CGColor];

// Set the mask of the view.
_view1.layer.mask = mask;





UIGraphicsBeginImageContextWithOptions(_view1.bounds.size, NO, 0.0);
[_view1.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage * img = UIGraphicsGetImageFromCurrentImageContext();

NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);

NSString *documentsDirectory = [path objectAtIndex:0];

NSString *myDBnew = [documentsDirectory stringByAppendingPathComponent:@"renderImg.png" ];

if ([[NSFileManager defaultManager] fileExistsAtPath:myDBnew]) {
    [[NSFileManager defaultManager] removeItemAtPath:myDBnew error:nil];
}


NSArray *paths1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory1 = [paths1 objectAtIndex:0];
NSString *savedImagePath1 = [documentsDirectory1 stringByAppendingPathComponent:[NSString stringWithFormat:@"renderImg.png"]];
NSData *imageDatatest = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
[imageDatatest writeToFile:savedImagePath1 atomically:NO];




UIGraphicsEndImageContext();

_imgView.image = img;

http://i58.tinypic.com/33ti8v5.png

Modification
The reason of masking view or wiping out that area with transparent rectangle is described below. I need to render those 2 uiview together as shown in the second image but I can't receive like desired one. It look like transparent view cannot be rendered on another view that has color. As a result, I am thinking like wiping out those area first and render it with second view. How shall I do? enter image description here

Was it helpful?

Solution

I tried out the code and can confirm it is correct but doesn't work on ion and below.

I read the docs for renderInContext: and noticed it even tells you:
" WARNING: currently this method does not implement the full CoreAnimation composition model, use with caution."

I cross referenced the OSX docs and the are more explicit:
" Important The OS X v10.5 implementation of this method does not support the entire Core Animation composition model. QCCompositionLayer, CAOpenGLLayer, and QTMovieLayer layers are not rendered. Additionally, layers that use 3D transforms are not rendered, nor are layers that specify backgroundFilters, filters, compositingFilter, or a mask values. Future versions of OS X may add support for rendering these layers and properties."

=> so thats why it works on ios7 but not ios6.


a workaround is to apply the mask not only to the layer but again to the ImageContext

//mask layer to image
UIGraphicsBeginImageContextWithOptions(_view1.bounds.size, NO, 0.0);
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0, _view1.bounds.size.height);
CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1, -1);
[_view1.layer.mask renderInContext:UIGraphicsGetCurrentContext()];
UIImage * maskImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

//draw img
UIGraphicsBeginImageContextWithOptions(_view1.bounds.size, NO, 0.0);
CGContextClipToMask(UIGraphicsGetCurrentContext(), _view1.bounds, maskImage .CGImage);
[_view1.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top