是否可以在Swift中使用CAShapeLayer.compositingFilters来合成蒙版?

问题描述 投票:3回答:1

我正在为iPad应用程序实现绘图功能。我在CAShapeLayers上使用UIBezierPaths进行绘图。通过为每个TouchesBegan事件创建一个新的CAShapeLayer,我将构建一个“堆叠的” CAShapeLayers数组,使我可以通过在数组中上下移动层来轻松实现撤消和重做。我还通过使用一些CAShapeLayer.compositingFilters做一些有趣的图层混合技术。一切都很好。我的挑战正在消除。

我正在尝试创建第二个CAShapeLayers数组,并使用它们来掩盖第一组。在使用不透明颜色进行绘制时,我可以使用与上面相同的方法将其添加到蒙版组中,但是我无法从蒙版组中删除不透明区域。

我以为我可以使用不透明的基础层(黑色,白色或其他)开始蒙版技术。然后,我曾希望使用UIColor.clear.cgColor绘制UIBezierPaths,并将绘制的清晰路径与基础不透明基本蒙版组合或合成。实际上,这应该“擦除”蒙版的该区域,并隐藏我绘制到的堆叠的CAShapeLayers。我不想将遮罩层组合成图像,因为我会失去通过弹出并推动遮罩阵列轻松撤消和重做的功能。

我在下面包括了一些伪代码。任何指示,帮助或解决方案的策略将不胜感激!我已经为此工作了几个星期,我真的很沮丧。我找不到有关该策略的任何信息。另外,如果我从一开始就不正确地使用绘图功能,并且在保持简单的撤消/重做和添加擦除的同时,还有一种更简便的绘制方法,请告诉我。我完全愿意调整自己的方法!在此先感谢您的协助。

// setup the layer hierarchy for drawing    
private func setupView() {
        self.mainDrawLayer = CAShapeLayer()
        self.mainDrawLayer.backgroundColor = UIColor.clear.cgColor
        self.layer.addSublayer(self.mainDrawLayer)

        // set up the mask. add an opaque background so everything shows through to start
        self.maskLayer = CALayer()
        let p = UIBezierPath.init(rect: self.bounds)
        self.maskShapeLayer = CAShapeLayer()
        self.maskShapeLayer?.fillColor = UIColor.black.cgColor
        self.maskShapeLayer?.path = p.cgPath
        self.maskLayer?.addSublayer(self.maskShapeLayer!)

        // apply the mask
        self.layer.mask = self.maskLayer
    }

override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)

        guard let touch = touches.first else {
            return
        }

        var erasing = false


        // setup the currentDrawLayer which captures the bezier path
        self.currentDrawLayer = CAShapeLayer()
        self.currentDrawLayer?.lineCap = CAShapeLayerLineCap.round
        self.currentDrawLayer?.fillColor = nil

        // set the ink color to use for drawing
        if let ink = UserDefaults.standard.string(forKey: "ink") {
            self.currentDrawLayer?.strokeColor = UIColor(hex: ink)?.cgColor
        } else {
            self.currentDrawLayer?.strokeColor = UIColor(hex: Constants.inkBlack3)?.cgColor
        }

        if UserDefaults.standard.string(forKey: "ink") == Constants.inkBlack5 {
            // removing the filter makes white overlay other colors
            // this is essentially erasing with a white background
            self.currentDrawLayer?.compositingFilter = nil
        } else {
            // this blend mode ads a whole different feeling to the drawing!
            self.currentDrawLayer?.compositingFilter = "darkenBlendMode"
        }

        // THIS IS THE ERASER COLOR!
        if UserDefaults.standard.string(forKey: "ink") == Constants.inkBlack4 {
            // trying erasing via drawing with clear
            self.currentDrawLayer?.strokeColor = UIColor.clear.cgColor
            // is there a compositingFilter available to 'combine' my clear color with the black opaque mask layer created above?
            self.currentDrawLayer?.compositingFilter = "iDontHaveADamnClueIfTheresOneThatWillWorkIveTriedThemAllItSeems:)"

            erasing = true

        }

        self.currentDrawLayer?.path = self.mainDrawPath.cgPath

        if erasing {
            // add the layer to the masks
            self.maskLayer!.addSublayer(self.currentDrawLayer!)
        } else {
            // add the layer to the drawings
            self.layer.addSublayer(self.currentDrawLayer!)
        }

        let location = touch.location(in: self)

        self.ctr = 0
        self.pts[0] = location
    }
ios swift drawing mask cashapelayer
1个回答
0
投票

我只能通过附加到蒙版的形状层的路径来完成类似的事情。

        CALayer *penStroke = ... the layer that has all the pen strokes ...;

        UIBezierPath *eraserStroke = [[UIBezierPath bezierPathWithRect:[self bounds]] bezierPathByReversingPath];
        [eraserStroke appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(110, 110, 200, 30)]];

        CAShapeLayer *maskFill = [CAShapeLayer layer];
        maskFill.path = [eraserStroke CGPath];
        maskFill.fillRule = kCAFillRuleEvenOdd;
        maskFill.fillColor = [[UIColor blackColor] CGColor];
        maskFill.backgroundColor = [[UIColor clearColor] CGColor];

        penStroke.mask = maskFill;

上面将用所有橡皮擦笔迹遮盖所有笔笔画。但是绘图应用程序希望能够绘制以前的橡皮擦笔划。我认为,这需要通过将现有的penStroke层连续包装到另一个新的penStroke层,并始终将penStrokes添加到最外层来解决。

这会给类似:

 - Layer C: most recent pen strokes
   - mask: no mask, so that all strokes are pen strokes
   - Layer B: sublayer of layer C, contains some previous pen strokes
     - Layer B's mask: most recent eraser strokes
     - Layer A: sublayer on Layer B, contains pen strokes before the most recent eraser strokes
       - Layer A's mask: eraser strokes before layer B's pen strokes

希望这很有道理。基本上,它将是嵌套层/蒙版。每次用户从笔->橡皮擦或橡皮擦->笔切换时,都会在所有现有的笔/橡皮擦笔划层周围包裹一个新层。

© www.soinside.com 2019 - 2024. All rights reserved.