Dzeremix
Dzeremix

Reputation: 478

How to scale CALayer to fit on the video layer

I have a problem with CALayer. The point is that I want to save few UIViews on the movie. Basically I am trying to do it by CALayer. Everything is okay, the app export movie with layers but the layers with views are smaller than video frame.

I tried to scale layer manually but at all it is not look like on the screen. If I move UIView higher on movie it is going much higher.

Video has FullHd frame and layers of UIView depends of it how user place it on the screen.

The questions are: - How to render UIView Context with better retina quality?

There is the code:

VideoSaver.saveVideo(videoAsset!) { (composition, size) in
        ////////////////
        //Parent Layer//
        ////////////////

        let parentLayer = CALayer()
        parentLayer.frame = CGRectMake(0, 0, size.width, size.height)

        /////////
        //Sizes//
        /////////
        let xScaleValue = CGRectGetWidth(parentLayer.frame)/CGRectGetWidth(self.view.frame)
        let yScaleValue = CGRectGetHeight(parentLayer.frame)/CGRectGetHeight(self.view.frame)

        ///////////////
        //Video Layer//
        ///////////////
        let videoLayer = CALayer()
        videoLayer.frame = CGRectMake(0, 0, size.width, size.height)

        //////////////////
        //Captions Layer//
        //////////////////

        //Creating UIImage from Captions
        UIGraphicsBeginImageContext(CGSizeMake(self.captionsTextView.bounds.size.width, self.captionsTextView.bounds.size.height+20))
        let currentContext = UIGraphicsGetCurrentContext()

        CGContextTranslateCTM(currentContext, 0, 16)

        self.captionsTextView.layer.renderInContext(currentContext!)
        let captionTextViewImage = UIGraphicsGetImageFromCurrentImageContext()

        UIGraphicsEndImageContext()

        let captionsOverlayLayer = CALayer()
        captionsOverlayLayer.contents = captionTextViewImage.CGImage
        captionsOverlayLayer.frame = CGRectMake(self.captionsTextView.frame.origin.x * xScaleValue,
                                            (size.height - ((self.captionsTextView.frame.origin.y - 20) * yScaleValue)),
                                            CGRectGetWidth(self.captionsTextView.frame) * xScaleValue,
                                            (CGRectGetHeight(self.captionsTextView.frame)+20) * yScaleValue)

        captionsOverlayLayer.masksToBounds = true

        ///////////////////
        //TagFilter Layer//
        ///////////////////
        UIGraphicsBeginImageContext(self.tagView.bounds.size)
        self.tagView.layer.renderInContext(UIGraphicsGetCurrentContext()!)

        let tagViewImage = UIGraphicsGetImageFromCurrentImageContext()

        UIGraphicsEndImageContext()

        let tagOverlayLayer = CALayer()
        tagOverlayLayer.contents = tagViewImage.CGImage
        tagOverlayLayer.frame = CGRectMake(self.tagView.frame.origin.x * xScaleValue,
                                           (size.height - ((self.tagView.frame.origin.y) * yScaleValue)),
                                           CGRectGetWidth(self.tagView.frame) * xScaleValue,
                                           (CGRectGetHeight(self.tagView.frame)) * yScaleValue)
        ///////////////////////////////////////////////

        parentLayer.addSublayer(videoLayer)
        parentLayer.addSublayer(captionsOverlayLayer)
        parentLayer.addSublayer(tagOverlayLayer)

        ///////////////
        //Composition//
        ///////////////
        composition.animationTool = AVVideoCompositionCoreAnimationTool.init(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer)
    }

I will be glad for help :)

Upvotes: 3

Views: 2764

Answers (2)

Dzeremix
Dzeremix

Reputation: 478

At the end all UIViews that I want to have on the video I put to one UIView. From that UIView I am creating the layer and scaling it to video size. There is a code if someone will have the same problem:

VideoSaver.saveVideo(videoAsset!) 
{ 
    (composition, size) in
    ////////////////
    //Parent Layer//
    ////////////////

    let parentLayer = CALayer()
    parentLayer.frame = CGRectMake(0, 0, size.width, size.height)

    ///////////////
    //Video Layer//
    ///////////////
    let videoLayer = CALayer()
    videoLayer.frame = CGRectMake(0, 0, size.width, size.height)

    ///////////////////////
    //Effect Layout Layer//
    ///////////////////////
    UIGraphicsBeginImageContextWithOptions(self.effectLayoutView.bounds.size, false, 0.0)
    self.effectLayoutView.layer.renderInContext(UIGraphicsGetCurrentContext()!)

    let effectLayoutViewImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    let effectOverlayLayer = CALayer()
    effectOverlayLayer.contents = effectLayoutViewImage.CGImage

    effectOverlayLayer.frame = CGRectMake(0, 0, size.width, size.height)
    effectOverlayLayer.masksToBounds = true

    ///////////////////////////////////////////////

    parentLayer.addSublayer(videoLayer)
    parentLayer.addSublayer(effectOverlayLayer)

    ///////////////
    //Composition//
    ///////////////
    composition.animationTool = AVVideoCompositionCoreAnimationTool.init(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer)
}

Upvotes: 1

matt
matt

Reputation: 535138

If the problem is the resolution of the image as displayed by the layer, then:

  • This is your first mistake: UIGraphicsBeginImageContext. Always call UIGraphicsBeginImageContextWithOptions and a third argument of 0, or an explicit resolution.

  • Your second mistake is that you never set the CALayer's contentsScale.

Upvotes: 1

Related Questions