rFlex / SCRecorder

iOS camera engine with Vine-like tap to record, animatable filters, slow motion, segments editing
Apache License 2.0
3.06k stars 583 forks source link

Using CIGaussianBlur or any blur filter creates black border #350

Closed dondreytaylor closed 7 years ago

dondreytaylor commented 7 years ago

It appears that when you use any blur filter such as CIGaussianBlur, a black border appears around the surrounding frame.

   let blur = SCFilter(CIFilterName: "CIGaussianBlur")
   blur.CIFilter?.setValue(10, forKey: "inputRadius")

   let filters = SCFilter.emptyFilter()
   filters.addSubFilter(blur)

   let filterImageView = SCFilterImageView(frame: CGRectMake(0,0,frame.width, frame.height))
   filterImageView.filter = filters

   recorderVideoConfiguration.filter = blur

img_1560

My understanding is that prior to adding the blur theCIAffineClamp filter needs to be applied and then the CIImage output of that needs to be passed to the CIGaussianBlur filter. However, I'm a little unsure how I could go about doing that.

Any help is greatly appreciated.

dondreytaylor commented 7 years ago

YAY!!! Okay, I was able to figure out how to remove the black border surrounding the frame. Since filters added using SCFilter are done in parallel. You will need subclass SCImageView and then override the - (CIImage *)renderedCIImageInRect:(CGRect)rect. The below class is a subclass of SCImageView and will apply the CIAffineClamp filter prior to all other filters.

class SCClampedFilterImageView: SCImageView {

    // Stores reference to passed filter
    var filter:SCFilter?

    // Where we will override the rendering of each CIImage to apply the CIAffineClamp first
    override func renderedCIImageInRect(rect: CGRect) -> CoreImage.CIImage? {

       // Get the rendered CIImage from SCImageView first
        var image:CoreImage.CIImage? = super.renderedCIImageInRect(rect) 

       // Reference to current context
        var context:CIContext? = nil;

       // Load the context accordingly
        if (!self.loadContextIfNeeded()) {
            context = CIContext(options: [kCIContextUseSoftwareRenderer:false])
        }
        else {
            context = super.context!.CIContext;
        }

        // Applies CIAffineClamp filter to CIImage
        let clampFilter:CIFilter = CIFilter(name: "CIAffineClamp")!
        clampFilter.setDefaults()
        clampFilter.setValue(image, forKey: kCIInputImageKey)

        // Cache the size of the CIImage. This is because CAAffineClamp sets the extent
        // of the CIImage to infinity
        let inputImageExtent:CGRect? = image?.extent

       // If we have a CIImage and a filter apply all other filters and recreate the CIImage
        if (image != nil) {
            if (filter != nil) {
                image = filter?.imageByProcessingImage(clampFilter.outputImage, atTime: self.CIImageTime)
                let cgImage = context?.createCGImage(image!, fromRect: inputImageExtent!)
                if (cgImage != nil) {
                    image = CoreImage.CIImage(CGImage: cgImage!)
                }
            }
        }

        return image;
    }
}

Once you've subclassed the SCImageView you can use it like the following

        let blur = SCFilter(CIFilterName: "CIGaussianBlur")
        blur.CIFilter?.setValue(10, forKey: "inputRadius")

        let filters = SCFilter.emptyFilter()
        filters.addSubFilter(blur)

        let filterImageView = SCClampedFilterImageView(frame: CGRectMake(0,0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height))
        filterImageView.filter = filters

        recorderVideoConfiguration.filter = blur

The resulting video output will show no border around the frames.

img_1561