在iOS的绘画应用中制作一个橡皮擦工具

8
我正在创建一个绘画应用程序,想知道如何实现橡皮擦工具。我不希望我的橡皮擦工具涂上白色,因为我想允许用户更改背景颜色。另外,是否可以设置画笔的硬度?如果可以,请告诉我如何设置。
谢谢。
以下是我目前所做的:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    lastPoint = [touch locationInView:self.view];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint currentPoint = [touch locationInView:self.view];
    UIGraphicsBeginImageContext(self.view.frame.size);
    [drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 10);
    CGContextBeginPath(UIGraphicsGetCurrentContext());
    CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
    CGContextStrokePath(UIGraphicsGetCurrentContext());
    drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    lastPoint = currentPoint;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 10);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

lastPoint = currentPoint;
}
- (IBAction)clear:(id)sender {
drawImage.image = nil;
}

这是一个有趣的问题,但我认为你可以让它更清晰明了。告诉我们你目前为止做了什么;也许包括一些代码。 - jtbandes
请查看以下链接并观看我的回答: http://stackoverflow.com/questions/3863931/want-to-add-manual-erasing-option-in-ipad-painting-application-by-quartz/12797513#12797513 - Waseem Shah
3个回答

17
好的,这是我为橡皮擦工具所做的事情: 我添加了这行代码: CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear); 所以代码会是这样的:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

// I add this
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);

CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), sizeSlider.value);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);

CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}

3
非常感谢,它非常好用。我已经很长时间在寻找这个。 - Pavan

3

我制作了一款涂鸦应用程序,它可以在iTunes上下载,名为“Easy Doodle”应用。橡皮擦没有特殊逻辑,只需获取背景图像的RGB值并传递即可。

CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(),R value,G value,B value, 1.0);

根据所选的背景图片进行调整。

@mat 你好..如果我们为绘制创建自定义UIView,那么我们能否在不使用drawrect方法的情况下进行绘制? - Hitarth
也许你想问Rock,但我不这么认为。如果你有一个自定义的UIView,每次想要修改它时都需要调用setNeedsDisplay来绘制视图本身。否则,请查看我的旧类似回答 - Mat
1
这不是正确的答案。正确的答案是下面那个赞更多的答案。苹果有一个内置的橡皮擦功能,只需一行代码即可实现。这个答案甚至并没有真正地擦除,它只是向图像中添加更多的“颜料”,与其下方的像素(背景图像)相同的颜色。这并不是真正的擦除(特别是如果背景图像发生变化),而且数据量更大。 - Albert Renshaw
非常感谢 @Mat! - gunjot singh

1

好的,我已经寻找了一个星期的解决方案,以创建一个橡皮擦。我必须改变我的看法,因为无论我尝试多少次擦除某些内容,它都会抹去背景图像。

然而,最终我找到了一个适合我的解决方案(我可以擦除涂料,同时仍然感觉背景图像没有被触碰或擦除),希望这能帮助其他人。下面是方法:

1)在UIView中创建两个imageviews。 2)设置两个imageviews的背景图像。 3)我创建了一个分段控件来确定用户是否想要擦除。 4)当选择分段控件时,添加以下功能...

  func drawLineForRubber(fromPoint: CGPoint, toPoint: CGPoint) {

    // 1
    UIGraphicsBeginImageContext(view.frame.size)
    let context = UIGraphicsGetCurrentContext()
    mainImageView.image?.drawInRect(CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height))

    // 2
    CGContextMoveToPoint(context, fromPoint.x, fromPoint.y)
    CGContextAddLineToPoint(context, toPoint.x, toPoint.y)

    // 3
    CGContextSetBlendMode(context, CGBlendMode.Clear)
    CGContextSetLineCap(context, CGLineCap.Round)
    CGContextSetLineWidth(context, 10.0)
    //this line is very important as it paints the screen clear
    CGContextSetRGBStrokeColor(context, red, green, blue, 0.0)
    CGContextSetBlendMode(context, CGBlendMode.Clear)

    // 4
    CGContextStrokePath(context)

    // 5
    mainImageView.image = UIGraphicsGetImageFromCurrentImageContext()
    mainImageView.alpha = opacity
    UIGraphicsEndImageContext()

}

如您所见,这里有一行代码设置了CGContextSetRGBStrokeColor的值为0.0,这很重要,因为当用户擦除绘画时,他会同时擦掉顶部imageview中的绘画和透明颜色的绘画。但是,由于您还有另一个imageview在其下面,因此看起来好像它被擦掉了,而不影响背景图像。
相反,它确实被擦掉了,但是后面的imageview使得它看起来好像没有被擦掉。当您想要导出图像时(您可以用多种方式实现,但我选择了以下方式),只需将带有背景图像的绘画与原始背景图像组合在一起即可:
第一个imageview将具有您绘制的绘画,第二个imageview将具有您想要的原始背景图像。
    func share() {

    let layer = UIApplication.sharedApplication().keyWindow!.layer
    let scale = UIScreen.mainScreen().scale
    UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale); // reconsider size property for your screenshot

    layer.renderInContext(UIGraphicsGetCurrentContext()!)
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()


    UIGraphicsBeginImageContext(mainImageView.bounds.size)
    mainImageView.image?.drawInRect(CGRect(x: 0, y: 0,
        width: mainImageView.frame.size.width, height: mainImageView.frame.size.height))

    UIGraphicsEndImageContext()

    let activity = UIActivityViewController(activityItems: [screenshot], applicationActivities: nil)
    presentViewController(activity, animated: true, completion: nil)
}

希望这能帮助其他人顺利进行......天啊,我花了很长时间才理解它 =)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接