I am trying to create image animation on Video with the help of CAScrollLayer I am able to add images on CAScrollLayer but it's not scrolling when video is played any help will be appreciable below is my code i have tried so far.
CALayer *layer;
// self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
scrollLayer = [CAScrollLayer layer];
scrollLayer.backgroundColor = [[UIColor blackColor] CGColor];
scrollLayer.bounds = parentLayer.bounds;
scrollLayer.contentsRect = CGRectMake(0, 0, scrollLayer.bounds.size.width*images.count, scrollLayer.bounds.size.height);
scrollLayer.borderWidth = 2.5;
scrollLayer.borderColor = [[UIColor redColor] CGColor];
scrollLayer.position = CGPointMake(self.view.center.x, self.view.center.y - 20);
scrollLayer.scrollMode = kCAScrollHorizontally;
scrollLayer.speed = 2.0;
// [self.view.layer addSublayer:scrollLayer];
[parentLayer insertSublayer:scrollLayer atIndex:0];
for(int i=0; i<[images count]; i++) {
UIImage *image = [images objectAtIndex:i];
layer = [CALayer layer];
layer.backgroundColor = [[UIColor blackColor] CGColor];
layer.bounds = CGRectMake(0, 0, 300, 300);
layer.contents = (id)[image CGImage];
layer.position = CGPointMake(layer.bounds.size.width * i, self.view.center.y);
// scrollLayer.speed = 2.0;
[scrollLayer addSublayer:layer];
}
[parentLayer addSublayer:scrollLayer];
[self performSelector:#selector(scrollPoint) withObject:nil afterDelay:2.0];
compostion.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
Thank you.
Related
I have an image above which I delimitate a transparent rectangle using layer and mask.
I would like this transparent rectangle to be red bordered. But I could find a way to achieve this :
Here is what I have done :
My ViewController has a darkenedView property.
- (void)loadView {
UIView *const rootView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
rootView.backgroundColor = [UIColor whiteColor];
self.view = rootView;
[self addContentSubviews];
}
- (void)addContentSubviews {
UIImageView *const imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"DSC_0823.jpg"]];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.frame = self.view.bounds;
imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:imageView];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self addDarkenedSubview];
}
- (void)viewDidLayoutSubviews {
CGRect const bounds = self.view.bounds;
darkenedView.center = CGPointMake(CGRectGetMidX(bounds), 0);
}
- (void)addDarkenedSubview {
darkenedView = [[UIView alloc] initWithFrame:CGRectMake(10, 30, 400, 1200)];
darkenedView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.6];
darkenedView.autoresizingMask = 0;
[self.view addSubview:darkenedView];
[self addMaskToDarkenedView];
}
- (void)addMaskToDarkenedView {
CGRect bounds = darkenedView.bounds;
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
CGRect const myRect = CGRectMake(CGRectGetMidX(bounds) - 100,
CGRectGetMidY(bounds) + 100,
200, 200);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:myRect];
[path appendPath:[UIBezierPath bezierPathWithRect:bounds]];
maskLayer.path = path.CGPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
darkenedView.layer.mask = maskLayer;
}
I've tried without success :
maskLayer.strokeColor = [UIColor redColor].CGColor;
maskLayer.lineWidth = 3.0f;
Instead of giving stroke to maskLayer object create CAShapeLayer and addSublayer to darkenedView view below is sample code Hope it help
CAShapeLayer *shape = [CAShapeLayer layer];
shape.frame = darkenedView.bounds;
shape.path = path.CGPath;
shape.lineWidth = 3.0f;
shape.strokeColor = [UIColor redColor].CGColor;
shape.fillColor = [UIColor clearColor].CGColor;
[darkenedView.layer addSublayer:shape];
How can i add circular, triangle, square image overlay to UIImagepickercontroller as per above pic
and when user presses camera button then only image inside circular or triangular or square must be captured.
I have used below code but its not giving proper result. kindly see below pic.
Which is totally reverse what i want to achieve.
-(void)openCamera {
self.pickerController = [[UIImagePickerController alloc] init];
self.pickerController.delegate = self;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
[self.pickerController setSourceType:UIImagePickerControllerSourceTypeCamera];
} else {
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Tatoo App" message:#"No Camera Available" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alertView show];
}
self.pickerController.allowsEditing = NO;
self.pickerController.showsCameraControls = NO;
// creating overlayView
self.overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.pickerController.view.frame.size.width-20, self.pickerController.view.frame.size.height)];
// letting png transparency be
self.overlayView .backgroundColor = [UIColor colorWithRed:0/255 green:0/255 blue:0/255 alpha:0.5];
[self.overlayView .layer setOpaque:NO];
self.overlayView .opaque = NO;
/*
UIView *circleView = [[UIView alloc]initWithFrame:CGRectMake(self.pickerController.view.frame.size.width/4, self.pickerController.view.frame.size.width/4, self.pickerController.view.frame.size.width/2, self.pickerController.view.frame.size.height/4)];
circleView.backgroundColor = [UIColor greenColor];
circleView.layer.cornerRadius = circleView.frame.size.width / 2;
circleView.clipsToBounds = YES;
[self.overlayView addSubview:circleView];
[self.overlayView bringSubviewToFront:circleView];
*/
CAShapeLayer *maskLayer = [CAShapeLayer layer];
self.overlayView.layer.mask = maskLayer;
self.maskLayer = maskLayer;
// create shape layer for circle we'll draw on top of image (the boundary of the circle)
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.lineWidth = 3.0;
circleLayer.fillColor = [[UIColor clearColor] CGColor];
circleLayer.strokeColor = [[UIColor blackColor] CGColor];
[self.overlayView.layer addSublayer:circleLayer];
self.circleLayer = circleLayer;
// create circle path
[self updateCirclePathAtLocation:CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0) radius:self.view.bounds.size.width * 0.30];
CGFloat scale = [[self.overlayView.window screen] scale];
CGFloat radius = self.circleRadius * scale;
CGPoint center = CGPointMake(self.circleCenter.x * scale, self.circleCenter.y * scale);
CGRect frame = CGRectMake(center.x - radius,
center.y - radius,
radius * 2.0,
radius * 2.0);
// temporarily remove the circleLayer
// CALayer *circleLayer = self.circleLayer;
// [self.circleLayer removeFromSuperlayer];
// render the clipped image
UIGraphicsBeginImageContextWithOptions(self.imageOverlay.frame.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
if ([self.overlayView respondsToSelector:#selector(drawViewHierarchyInRect:afterScreenUpdates:)])
{
// if iOS 7, just draw it
[self.overlayView drawViewHierarchyInRect:self.overlayView.bounds afterScreenUpdates:YES];
}
else
{
// if pre iOS 7, manually clip it
CGContextAddArc(context, self.circleCenter.x, self.circleCenter.y, self.circleRadius, 0, M_PI * 2.0, YES);
CGContextClip(context);
[self.overlayView.layer renderInContext:context];
}
// capture the image and close the context
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// add the circleLayer back
[self.overlayView.layer addSublayer:circleLayer];
// crop the image
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], frame);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
self.takePicture = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.takePicture.frame = CGRectMake(80.0, self.pickerController.view.frame.size.height-100, 150.0, 30.0);
self.takePicture.tag = 0;
[ self.takePicture setTitle:#"Take" forState:UIControlStateNormal];
[ self.takePicture addTarget:self action:#selector(takeSnapShot:) forControlEvents:UIControlEventTouchUpInside];
[self.overlayView addSubview: self.takePicture];
self.pickerController.cameraOverlayView = self.overlayView;
[self presentViewController:self.pickerController animated:YES completion:nil];
}
Before the thought of posting this question came into my mind I had already spent a few hours on this small snippet of code... So I wrote two different pieces of code in two different classes, and both were used to cut out a specific shape. But for some reason only one of them worked!?!? I have ABSOLUTELY no idea why this happened, for they have the exact same structure.
Below is the snippet that WORKS.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor blackColor];
UIBezierPath *arrowPath = [UIBezierPath bezierPath];
CGPoint start = CGPointMake(self.frame.size.width - 2, self.frame.size.height / 2);
[arrowPath moveToPoint:start];
[arrowPath addLineToPoint:CGPointMake(7, 7)];
[arrowPath addLineToPoint:CGPointMake(2, 7)];
[arrowPath addLineToPoint:CGPointMake(self.frame.size.width - 7, self.frame.size.height/2)];
[arrowPath addLineToPoint:CGPointMake( 2, self.frame.size.height - 7)];
[arrowPath addLineToPoint:CGPointMake(7, self.frame.size.height - 7)];
[arrowPath addLineToPoint:start];
[arrowPath closePath];
UIView *arrow = [[UIView alloc]initWithFrame:self.frame];
arrow.backgroundColor = [UIColor whiteColor];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.frame = self.frame;
mask.backgroundColor = (__bridge CGColorRef)([UIColor clearColor]);
mask.path = arrowPath.CGPath;
arrow.layer.mask = mask;
[self addSubview:arrow];
}
return self;
}
And here is the piece of code that only works PARTIALLY.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIView *roundedRectView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height - 20)];
roundedRectView.backgroundColor = [UIColor clearColor];
[self addSubview:roundedRectView];
UIBezierPath *roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:roundedRectView.frame cornerRadius:10];
UIView *rectangle = [[UIView alloc]initWithFrame:roundedRectView.frame];
rectangle.backgroundColor = [UIColor blackColor];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.frame = rectangle.frame;
mask.path = roundedRectPath.CGPath;
mask.backgroundColor = (__bridge CGColorRef)([UIColor clearColor]);
rectangle.layer.mask = mask;
rectangle.alpha = 0.8;
[roundedRectView addSubview:rectangle];
UIView *rectangleTwo = [[UIView alloc]initWithFrame:CGRectMake(0, self.frame.size.height - 20, self.frame.size.width, 20)];
rectangleTwo.backgroundColor = [UIColor redColor];
UIBezierPath *trianglePath = [UIBezierPath bezierPath];
CGPoint start = CGPointMake(rectangleTwo.frame.size.width / 2 - 15, 0);
[trianglePath moveToPoint:start];
[trianglePath addLineToPoint:CGPointMake(start.x + 20, start.y)];
[trianglePath addLineToPoint:CGPointMake(start.x + 10, start.y + 20)];
[trianglePath addLineToPoint:start];
[trianglePath closePath];
CAShapeLayer *triangleMask = [CAShapeLayer layer];
triangleMask.frame = rectangleTwo.frame;
triangleMask.path = trianglePath.CGPath;
rectangleTwo.layer.mask = triangleMask;
[self addSubview:rectangleTwo];
}
return self;
}
Allocating this speech bubble using CGRectMake(0,0,80,60), only the rounded rectangle showed up on the screen, but the triangle was no where to be seen.
Can anyone point out what's wrong with this code? Any help is appreciated, thanks!!
Problem solved!
Turned out that my triangleMask.frame wasn't defined properly. Instead of triangleMask.path = rectangleTwo.frame I should've used triangleMask.frame = CGRectMake(0, 0, rectangleTwo.frame.size.width, rectangleTwo.frame.size.height); instead! CAShapeLayer's origin is relative to that of the shape on which you want to place it!
I have the following code:
- (void)setupLayer {
self.faucetShape = [CAShapeLayer layer];
self.faucetShape.strokeColor = [[UIColor blackColor] CGColor];
self.faucetShape.lineWidth = 2;
self.faucetShape.fillColor = nil;
self.faucetShape.path = [self faucetPath].CGPath; // faucetPath returns a 4 point diamond shaped UIBezierPath*
self.faucet = [CAGradientLayer layer];
self.faucet.mask = self.faucetShape;
self.faucet.colors = #[(id)[UIColor redColor].CGColor, (id)[UIColor redColor].CGColor];
[self.layer addSublayer: self.faucet];
}
But it shows nothing. Not sure what I'm missing (other than my graphic).
(faucet and faucetPath are both properties)
UPDATE
OK, I guess a CAGradientLayer has to have a meaningful frame. I assume a CAShapeLayer's frame isn't as meaningful, since the path can go outside the frame. Adding the following line made it show up:
self.faucet.frame = CGRectMake(0, 0, 64, 64);
So NOW my question is, is there a way to avoid having to do that? I'd just like the frame of the layer to implicitly be that of the containing View/Layer.
You need to set the frame of the layers. The following code will draw a red circle:
- (void)setupLayer
{
CAShapeLayer *faucetShape = [CAShapeLayer layer];
faucetShape.frame = CGRectMake(0, 0, 100, 100);
faucetShape.strokeColor = [[UIColor blackColor] CGColor];
faucetShape.lineWidth = 2;
faucetShape.fillColor = nil;
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, nil, CGRectMake(0, 0, 100, 100));
faucetShape.path = path;
CGPathRelease(path);
CAGradientLayer *faucet = [CAGradientLayer layer];
faucet.frame = CGRectMake(10, 10, 100, 100);
faucet.mask = faucetShape;
faucet.colors = #[(id)[UIColor redColor].CGColor, (id)[UIColor redColor].CGColor];
[self.view.layer addSublayer: faucet];
}
I am using MKNetwrkKit. I have an imageView, I have added it as a subView to a UIView. I download an image using "UIImageView+MKNetworkKitAdditions.h". I add a mask to the ImageView and remove it from superView, before the download is completed, and I get a crash!
- (void) testUIImageViewDownloadCrash {
UIImageView *imageView = [[UIImageView alloc] init];
[imageView mk_setImageAtURL:[NSURL URLWithString:#"http://www.gravatar.com/avatar/a717291747c76567bb0f086e15ae6e43?s=32&d=identicon&r=PG"] onCompletion:^(BOOL success, BOOL fromCache) {
//
}];
UIView *view = [[UIView alloc] init];
[view addSubview:imageView];
[self addMaskToImageView:imageView];
[imageView removeFromSuperview];
}
Now, the weird thing is, this crash occurs only when I add the mask... here is the function that adds the mask.
- (CAGradientLayer*) addMaskToImageView:(UIImageView *) inImageView
{
CALayer *imageLayer = inImageView.layer;
CGRect imageBounds = imageLayer.bounds;
CGRect ellipseRect = CGRectInset(imageBounds, 4, 4);
CGPathRef maskPath = CGPathCreateWithEllipseInRect(ellipseRect, NULL);
if (maskPath)
{
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.bounds = imageBounds;
maskLayer.position = (CGPoint){CGRectGetMidX(imageBounds), CGRectGetMidY(imageBounds)};
maskLayer.path = maskPath;
maskLayer.fillColor = [UIColor blackColor].CGColor;
imageLayer.mask = maskLayer;
CFRelease(maskPath);
}
CAGradientLayer *gradientRingLayer = [self createGradientRing:imageBounds];
CALayer *containerLayer = [CALayer layer];
[imageLayer.superlayer addSublayer:containerLayer];
// Move container layer to the image position
containerLayer.position = imageLayer.position;
// Image is now at 0,0 in the container
imageLayer.position = CGPointZero;
[containerLayer addSublayer:gradientRingLayer];
[containerLayer addSublayer:imageLayer];
layer.shouldRasterize = YES;
layer.rasterizationScale = [[UIScreen mainScreen] scale];
layer.contentsScale = [[UIScreen mainScreen] scale];
containerLayer.shadowColor = [UIColor blackColor].CGColor;
containerLayer.shadowOpacity = 1.0f;
containerLayer.shadowOffset = CGSizeMake(2.0f, 5.0f);
containerLayer.shadowRadius = 7.5f;
// Create shadow at the righ place around the image
CGPathRef containerShadowPath = CGPathCreateWithEllipseInRect(imageLayer.frame, NULL);
containerLayer.shadowPath = containerShadowPath;
CFRelease(containerShadowPath);
return gradientRingLayer;
}
- (CAGradientLayer*)createGradientRing:(CGRect)inBounds {
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.anchorPoint = CGPointMake(0.5f, 0.5f);
gradient.position = CGPointMake(0.0f, 0.0f);
// gradient.startPoint = CGPointMake(0.0,0.0);
// gradient.endPoint = CGPointMake(0.0,0.0);
gradient.bounds = inBounds;
gradient.cornerRadius = 0.0;
gradient.colors = [NSArray arrayWithObjects:
(id)[UIColor ringLight].CGColor,
(id)[UIColor ringLight].CGColor,
nil];
CAShapeLayer *frameLayer = [CAShapeLayer layer];
CGPathRef framePath = CGPathCreateWithEllipseInRect(CGRectInset(inBounds, 0, 0), NULL);
if (framePath)
{
frameLayer.bounds = inBounds;
frameLayer.position = (CGPoint){CGRectGetMidX(inBounds), CGRectGetMidY(inBounds)};
frameLayer.path = framePath;
frameLayer.fillColor = [UIColor blackColor].CGColor;
CFRelease(framePath);
}
gradient.mask = frameLayer;
return gradient;
}
If I comment out adding the mask, it won't crash. Another thing that I don't understand is, after adding the mask, if do this:
NSLog(#"subviews count : %i",[view.subviews count]);
then I get 0! Where did the imageView go?
I observed that the addMask function is making a superView of the imageView null. I found out that the line [containerLayer addSublayer:imageLayer]; is the culprit. This is making the superView of the imageView null. But why? And how can I fix it?
Sometimes I get this exception too, and I don't know why.
-[__NSCFString sublayers]: unrecognized selector sent to instance
I tried on iOS 5 and iOS 6.