tags:

views:

1876

answers:

6

I have a small app that allows the user to draw on the screen with the finger. Yes, nothing original, but it's part of something larger :) I have a UIImageView where the user draws, by creating a CGContextRef and the various CG draw functions. I primarily draw strokes/lines with the function CGContextAddLineToPoint

Now the problem is this: the user can draw lines of various colors. I want to give him the ability to use a "rubber" tool to delete some part of the image drawn so far, with the finger. I initially did this by using a white color for the stroke (set with the CGContextSetRGBStrokeColor function) but it did't work out...because I discovered later that the UIImage on the UIImageView was actually with transparent background, not white...so I would end up with a transparent image with white lines on it!

Is there anyway to set a "transparent" stroke color...or is there any other way to clear the content of the CGContextRef under the user's finger, when he moves it? Thanks

A: 
UIColor *clearColor = [UIColor clearColor];
August
A: 

Well...thanks...I knew that....but if you read my question I said I need to pass the color components (red, gree, blue) to CGContextSetRGBStrokeColor. What do I do with the clearColor? How can I extract the components?

Even if I can extract the components...are you sure I'll be able to draw a transparent stroke over the rest of the image then? Or should I follow a different technique...that was my actual question...

devguy
A: 

I've tried using:

CGContextSetStrokeColorWithColor (myContext, [[UIColor clearColor] CGColor]);

but that doesn't work, because it seems to be "drawing" on top of the context with an invisible color (and invisible color + whatever color it is drawing on = the color it's drawing on).

The only solution I've found (which isn't optimal) is:

CGContextClearRect (myContext, CGRectMake(x, y, width, height));

Unfortunately, that means you have to trace a series of rects and generate the line yourself...

Jeffrey Berthiaume
+4  A: 

I ended up using Bresenham's line algorithm (harkening back to the days of yore when I had to write my own graphics routines)...

- (void) contextEraseLine:(CGContextRef) ctx from:(CGPoint)startPoint to:(CGPoint) endPoint withThickness:(int)thickness {
    int x, cx, deltax, xstep,
    y, cy, deltay, ystep,
    error, st, dupe;

    int x0, y0, x1, y1;

    x0 = startPoint.x;
    y0 = startPoint.y;
    x1 = endPoint.x;
    y1 = endPoint.y;

    // find largest delta for pixel steps
    st = (abs(y1 - y0) > abs(x1 - x0));

    // if deltay > deltax then swap x,y
    if (st) {
        (x0 ^= y0); (y0 ^= x0); (x0 ^= y0); // swap(x0, y0);
        (x1 ^= y1); (y1 ^= x1); (x1 ^= y1); // swap(x1, y1);
    }

    deltax = abs(x1 - x0);
    deltay = abs(y1 - y0);
    error  = (deltax / 2);
    y = y0;

    if (x0 > x1) { xstep = -1; }
    else         { xstep =  1; }

    if (y0 > y1) { ystep = -1; }
    else         { ystep =  1; }

    for ((x = x0); (x != (x1 + xstep)); (x += xstep))
    {
        (cx = x); (cy = y); // copy of x, copy of y

        // if x,y swapped above, swap them back now
        if (st) { (cx ^= cy); (cy ^= cx); (cx ^= cy); }

        (dupe = 0); // initialize no dupe

        if(!dupe) { // if not a dupe, write it out
      //NSLog(@"(%2d, %2d)", cx, cy);

      CGContextClearRect(ctx, CGRectMake(cx, cy, thickness, thickness));

    }

        (error -= deltay); // converge toward end of line

        if (error < 0) { // not done yet
            (y += ystep);
            (error += deltax);
        }
    }
}

Phew! That's a long way to go to create a (somewhat) clunky eraser line.

To use it, do something like:

- (void)eraseStart {
    // erase lines
    UIGraphicsBeginImageContext(drawingBoard.size);
    ctx = UIGraphicsGetCurrentContext();
    CGContextDrawImage(ctx,CGRectMake(0,0,drawingBoard.size.width, drawingBoard.size.height),[drawingBoard CGImage]); 
}

- (void)eraseEnd {
    drawingBoard = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    [drawingView removeFromSuperview];
    [drawingView release];

    drawingView = [[UIImageView alloc] initWithImage:drawingBoard];
    drawingView.frame = CGRectMake(intEtchX, intEtchY, intEtchWidth, intEtchHeight);

    [self.view addSubview:drawingView];
}

This assumes you have already created a drawingView (UIImageView) and drawingBoard (UIImage).

Then, to erase a line, simply do something like:

CGContextRef ctx = UIGraphicsGetCurrentContext();
[self eraseStart];
[self contextEraseLine:ctx from:CGPointMake (x1, y1) to:CGPointMake (x2, y2) withThickness:10];
[self eraseEnd];

(replace x1, y1, x2, and y2 with appropriate values)...

Jeffrey Berthiaume
A: 

hello,

How to unerase select the part of the image,

Since you did the erase the select the part of the image,if you find the solution of unerase,

can you help me ?

Thank you,

milanjansari
+6  A: 

CGContextSetBlendMode(context, kCGBlendModeClear) will do the trick.

Northorn
Thanks a million for this!
Peter Hajas
I searched the internet for weeks trying to figure out how to add erasing to my drawing app. This one line of code is a godsend - I just used it with my existing painting code and DONE!Simply awesome.
aloo