How can I draw a line with gradually change edge using CoreGraphics?

251 Views Asked by At

I want to accomplish a function just like a Brush. The area where finger swipes changes to trasparent with gradually changed border.

enter image description here
I can only change the color to crystal clear now with following codes:

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.eraser) return;

CGFloat scale = self.transform.a;
if (scale < 1) scale = 1;

CGPoint p = [[touches anyObject] locationInView: self];
CGPoint q = [[touches anyObject] previousLocationInView: self];

UIImage* image;
image = self.image;
CGSize  size = self.frame.size;
UIGraphicsBeginImageContext(size);
CGRect  rect;
rect.origin = CGPointZero;
rect.size = size;
[image drawInRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);

CGContextBeginPath(context);
CGContextSaveGState( context );
CGContextSetLineWidth(context, (10.0 / scale) + 1);
CGContextSetBlendMode(context, kCGBlendModeClear);

CGContextMoveToPoint(context, q.x, q.y);
CGContextAddLineToPoint(context, p.x, p.y);
CGContextStrokePath(context);
CGContextRestoreGState( context );

UIImage* editedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setBounds:rect];
[self setImage:editedImage];

}

How can I get the edge with gradually change? Thanks in advance.

1

There are 1 best solutions below

0
On BEST ANSWER

You can achieve this effect by drawing a radial gradient with a variable alpha in the kCGBlendModeDestinationIn mode in each spot the user passes.

This blend mode has the effect of only applying the layer's alpha to layers below. With the variable alpha of our gradient, we can achieve this effect.

const CGFloat kBrushSize = 10.f;

CGContextSaveGState(context);

// Make a radial gradient that goes from transparent black on the inside
// to opaque back on the outside.
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.0,
                          1.0, 1.0, 1.0, 1.0 };

CGColorSpaceRef myColorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGGradientRef myGradient = CGGradientCreateWithColorComponents (myColorspace, components,
                                                                locations, num_locations);
CGColorSpaceRelease(myColorspace);

// Draw the gradient at the point using kCGBlendModeDestinationIn
// This mode only applies the new layer's alpha to the lower layer.
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawRadialGradient(context, myGradient, p, 0.f, p, (kBrushSize / scale) + 1, kCGGradientDrawsAfterEndLocation);

CGGradientRelease(myGradient);

CGContextRestoreGState(context);

Here is a screenshot of this code in action:

CGBrush Scribble

Note: Using this technique, if the user is moving his/her finger very fast, you may see a spacing effect where discrete brush dots are visible. This is a feature of some graphics software, but if this is undesirable for you, you can add code to interpolate the points between the current and last to draw more brush points, creating a more continuous stroke.

Also, you should be able to adjust the gradient color stops to achieve any kind of brush softness you like.

Source: https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadings/dq_shadings.html