【问题标题】:iOS Core Graphics How to erase a drawingiOS Core Graphics 如何擦除绘图
【发布时间】:2014-04-03 14:46:34
【问题描述】:

我正在为我的涂鸦应用程序学习本教程。

http://www.raywenderlich.com/18840/how-to-make-a-simple-drawing-app-with-uikit

他的擦除功能是使用白色绘图。但是我正在使用图像背景,当我擦除时,我真的需要擦除。

我试过了

CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);

但它不起作用。这是我的代码:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    _mouseSwiped = NO;
    UITouch *touch = [touches anyObject];
    _lastPoint = [touch locationInView:self.tempImageView];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    _mouseSwiped = YES;
    UITouch *touch = [touches anyObject];
    CGPoint currentPoint = [touch locationInView:self.tempImageView];

    UIGraphicsBeginImageContext(self.tempImageView.frame.size);
    [self.tempImageView.image drawInRect:CGRectMake(0, 0, self.tempImageView.frame.size.width, self.tempImageView.frame.size.height)];
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _width );


    CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), _red, _green, _blue, 1.0);

    if (_isErasing) {
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
    }
    else {
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
    }

    CGContextStrokePath(UIGraphicsGetCurrentContext());
    self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
    [self.tempImageView setAlpha:_alpha];
    UIGraphicsEndImageContext();

    _lastPoint = currentPoint;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

    CGSize size = self.tempImageView.frame.size;

    if(!_mouseSwiped) {
        UIGraphicsBeginImageContext(self.tempImageView.frame.size);
        [self.tempImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height)];
        CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _width);


        CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), _red, _green, _blue, _alpha);
        CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
        CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
        CGContextStrokePath(UIGraphicsGetCurrentContext());
        CGContextFlush(UIGraphicsGetCurrentContext());
        self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }




    UIGraphicsBeginImageContext(self.drawImageView.frame.size);
    [self.drawImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height) blendMode:kCGBlendModeNormal alpha:1.0];

    if (_isErasing) {
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
    }

    [self.tempImageView.image drawInRect:CGRectMake(0, 0, self.tempImageView.frame.size.width, self.tempImageView.frame.size.height) blendMode:kCGBlendModeNormal alpha:_alpha];


    self.drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
    self.tempImageView.image = nil;
    UIGraphicsEndImageContext();
}

【问题讨论】:

    标签: ios uikit core-graphics


    【解决方案1】:

    通过在触摸开始时交换 tempImageView 和 drawImageView(如果它正在擦除)解决了这个问题

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        _mouseSwiped = NO;
        UITouch *touch = [touches anyObject];
        _lastPoint = [touch locationInView:self.tempImageView];
    
        if (_isErasing) {
            self.tempImageView.image = self.drawImageView.image;
            self.drawImageView.image = nil;
        }
    
    }
    
    
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    
        _mouseSwiped = YES;
        UITouch *touch = [touches anyObject];
        CGPoint currentPoint = [touch locationInView:self.tempImageView];
    
        UIGraphicsBeginImageContext(self.tempImageView.frame.size);
        [self.tempImageView.image drawInRect:CGRectMake(0, 0, self.tempImageView.frame.size.width, self.tempImageView.frame.size.height)];
        CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
        CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
        CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _width );
    
    
        if (_isErasing) {
            CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
        }
        else {
            CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), _red, _green, _blue, 1.0);
            CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
        }
    
        CGContextStrokePath(UIGraphicsGetCurrentContext());
        self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
        [self.tempImageView setAlpha:_alpha];
        UIGraphicsEndImageContext();
    
        _lastPoint = currentPoint;
    }
    
    
    
    
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    
        CGSize size = self.tempImageView.frame.size;
    
        if(!_mouseSwiped) {
            UIGraphicsBeginImageContext(self.tempImageView.frame.size);
            [self.tempImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height)];
            CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
            CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _width);
    
    
            if (_isErasing) {
                CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
            }
            else {
                CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), _red, _green, _blue, _alpha);
                CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
            }
    
            CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
            CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
            CGContextStrokePath(UIGraphicsGetCurrentContext());
            CGContextFlush(UIGraphicsGetCurrentContext());
            self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
        }
    
    
    
    
        UIGraphicsBeginImageContext(self.drawImageView.frame.size);
        [self.drawImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height) blendMode:kCGBlendModeNormal alpha:1.0];
        [self.tempImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height) blendMode:kCGBlendModeNormal alpha:_alpha];
        self.drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
        self.tempImageView.image = nil;
        UIGraphicsEndImageContext();
    }
    

    【讨论】:

    • 为什么要交换 tempImage 和 drawingImage ?只是好奇?
    • 不是交换图像视图,而是将清除绘制到“主图像视图”上。这就是我解决同样问题的方法。
    【解决方案2】:

    如果有人仍然感兴趣,这就是我在 Swift 3 中的工作方式。感谢 OMGPOP 的帮助

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        swiped = false
        hideAllButtons()
        if let touch = touches.first {
            lastPoint = touch.location(in: self.view)
        }
    
        if isErasing {
            self.tempImageView.image = self.mainImageView.image
            self.mainImageView.image = nil
        }
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        swiped = true
        if let touch = touches.first {
            let currentPoint = touch.location(in: view)
            drawLineFrom(fromPoint: lastPoint, toPoint: currentPoint)
    
            lastPoint = currentPoint
        }
    
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        showAllButtons()
        if !swiped {
            drawLineFrom(fromPoint: lastPoint, toPoint: lastPoint)
        }
    
        UIGraphicsBeginImageContext(mainImageView.frame.size)
        mainImageView.image?.draw(in: CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height), blendMode: .normal, alpha: 1.0)
        tempImageView.image?.draw(in:  CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height), blendMode: .normal, alpha: opacity)
        mainImageView.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    
        tempImageView.image = nil
    }
    
    // Draws a line between two points on the view
    func drawLineFrom(fromPoint: CGPoint, toPoint: CGPoint) {
        UIGraphicsBeginImageContext(view.frame.size)
        let context = UIGraphicsGetCurrentContext()
        tempImageView.image?.draw(in: CGRect(x:0, y:0, width: view.frame.size.width, height: view.frame.size.height))
    
        context?.move(to: fromPoint)
        context?.addLine(to: toPoint)
    
        context?.setLineCap(.round)
        context?.setLineWidth(brushWidth)
    
        if isErasing {
            context?.setBlendMode(.clear)
        } else {
            context?.setStrokeColor(red: red, green: green, blue: blue, alpha: 1.0)
            context?.setBlendMode(.normal)
        }
        context?.strokePath()
    
        tempImageView.image = UIGraphicsGetImageFromCurrentImageContext()
        tempImageView.alpha = opacity
        UIGraphicsEndImageContext()
    
    }
    

    【讨论】:

    【解决方案3】:

    这就是我让橡皮擦工作的方法。 在 touchesEnded 函数中,我使用以下代码绘制上下文:

    //draw the main image on the context
    self.mainImage.image?.draw(in: CGRect(x:0, y:0, width:self.view.frame.size.width, height:self.view.frame.size.height), blendMode: .normal, alpha: 1.0)
        if(erasing == false) {
            //draw the current stroke normally since we're not erasing
            self.tempDrawImage.image?.draw(in: CGRect(x:0, y:0, width:self.view.frame.size.width, height:self.view.frame.size.height), blendMode: .normal, alpha: opacity!)
        } else {
            //let's create a mask of what we would like to erase by using the destinationIn function which according to the docs is the following
            //R = D*Sa
            //Destination * Source_Alpha
            self.tempDrawImage.image?.draw(in: CGRect(x:0, y:0, width:self.view.frame.size.width, height:self.view.frame.size.height), blendMode: .destinationIn, alpha: 1.0)
            //Let's apply this mask to the current drawing using XOR blending which removes any drawing underneath our mask but leaves everything else alone
            self.mainImage.image?.draw(in: CGRect(x:0, y:0, width:self.view.frame.size.width, height:self.view.frame.size.height), blendMode: .xor, alpha: 1.0)
        }
        //let's apply the changes we've made to our mainImage
        self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
        self.tempDrawImage.image = nil;
    

    要更好地了解它的工作原理,您可以单独注释掉绘图调用以查看它们的外观。

    您可能会发现一些锯齿问题,即您在笔画边缘留下了一点点。要在擦除模式下绘制时删除它,请为上下文启用别名:

    let ctx = UIGraphicsGetCurrentContext()
        ctx?.setShouldAntialias(false)
    

    【讨论】:

      【解决方案4】:

      我正在使用一个“画布”视图和以下功能来实现“擦除效果”。我的画布是透明的,在它下面,我有背景 UIImageView,上面有一张我画线的照片。 在我在画布上完成绘图并且用户想要最终绘图后,我将画布和背景合并。这完成了擦除先前绘制的线条的工作:

      private func drawStroke(context: CGContext?, touch: UITouch, width: CGFloat, color: UIColor) {
              guard let context = context else { return }
              let previousLocation = touch.previousLocation(in: self)
              let location = touch.location(in: self)
      
              context.setBlendMode(color == .clear ? .clear : .normal)
              context.setLineWidth(width)
              context.setStrokeColor(color.cgColor)
              context.setLineCap(.round)
      
              context.move(to: previousLocation)
              context.addLine(to: location)
              context.strokePath()
          }
      

      【讨论】:

        【解决方案5】:

        为什么不在单独的视图上绘画/绘图?

        TopView = 绘画 + 手势 ....,BottomView = 背景图像。

        擦除颜色 = ClearColor(透明)

        最后,如果你想保存你的构图,由你来组合两张图片。

        【讨论】:

        • 正如教程指出的那样,拥有 2 个视图来处理不透明度要简单得多
        • "可以,但是双 UIImageViews 用于保持不透明度。当您在 tempDrawImage 上绘图时,不透明度设置为 1.0(完全不透明)。但是,当您将 tempDrawImage 与 mainImage 合并时, tempDrawImage 的不透明度设置为配置值,从而为笔触提供我们想要的不透明度。如果您要直接在 mainImage 上绘制,那么绘制具有不同不透明度值的笔触将非常困难。"
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-15
        • 1970-01-01
        • 1970-01-01
        • 2010-09-23
        相关资源
        最近更新 更多