Drawing a line between the previous end point to next start point - iphone

i'm stuck at this problem. I need to draw a line between the previous end point to next start point. My code for drawing a line between 2 points is
- (void)drawRect:(CGRect)rect
{
CGContextRef c=UIGraphicsGetCurrentContext();
CGContextSetLineWidth(c, 4.0);
CGFloat red[4]={0.0f, 0.0f, 0.0f, 1.0f};
CGContextSetStrokeColor(c, red);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 50.0f, 50.0f);
CGContextAddLineToPoint(c, 100.0f, 100.0f);
CGContextStrokePath(c) ;
}
How can i give multiple points, so that i can it shows like a graph.
Thanks in advance

On a side note, Apple prefers that you use the higher UIKit methods instead of the Core Graphics calls for simple stuff like drawing lines and curves, so you could rewrite your method like this:
[[UIColor redColor] setStroke];
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:CGPointMake(50.0, 50.0)];
[linePath addLineToPoint:CGPointMake(100.0, 100.0)];
[linePath setLineWidth:4.0];
[linePath stroke];

Just add more CGContextAddLineToPoint calls
- (void)drawRect:(CGRect)rect
{
CGContextRef c=UIGraphicsGetCurrentContext();
CGContextSetLineWidth(c, 4.0);
CGFloat red[4]={0.0f, 0.0f, 0.0f, 1.0f};
CGContextSetStrokeColor(c, red);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 50.0f, 50.0f);
CGContextAddLineToPoint(c, 100.0f, 100.0f);
CGContextAddLineToPoint(c, 120.0f, 80.0f);
CGContextAddLineToPoint(c, 140.0f, 120.0f);
CGContextAddLineToPoint(c, 160.0f, 80.0f);
...
CGContextStrokePath(c) ;
}

Jus a little correction to your code:
-(void)drawLineFromPoint:(CGPoint)startPoint toPoint:(CGPoint)endPoint{
UIGraphicsBeginImageContext(YOUR_IMAGEVIEW.image.size);
[YOUR_IMAGEVIEW.image drawInRect:CGRectMake(0, 0, YOUR_IMAGEVIEW.image.size.width, YOUR_IMAGEVIEW.image.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), startPoint.x, startPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), endPoint.x, endPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
[YOUR_IMAGEVIEW setImage:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
}
YOUR_IMAGEVIEW is an outlet to your imageview you are drawing on.
As you can see - you just have to send to this method your start point and the end one! Easy as 1-2-3.
EDIT 1
How to use it? Declare a global CGPoint "startPoint";
Then say:
//___________________________________________________
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startPoint = [touch locationInView:YOUR_IMAGEVIEW];
}
//___________________________________________________
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint nextPoint = [touch locationInView:YOUR_IMAGEVIEW];
[self drawLineFromPoint:startPoint toPoint:nextPoint];
startPoint = nextPoint;
}
EDIT 2
Here is another way to draw your points:
- (void)drawGraphMethod{
NSMutableArray *pointsArr = [[[NSMutableArray alloc]init]autorelease];
//now you should add the needed points to your array
//I have no idea what graph do you have, so I just
//put there some random points that will look like a graph
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(30.0, 10.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(40.0, 26.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(70.0, 55.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(80.0, 88.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(90.0, 33.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(130.0, 100.0)]];
//well, you can store only objects, that's why I used NSValue.
//it's not hard to cenvert it back
//now parse the array
for (int i = 0; i < pointsArr.count-1; i++) {
CGPoint startPoint = [[pointsArr objectAtIndex:i] CGPointValue];
CGPoint nextPoint = [[pointsArr objectAtIndex:i+1] CGPointValue];
[self drawLineFromPoint:startPoint toPoint:nextPoint];
}
}

Related

How to draw a straight line on an iOS map without moving the map using MKmapkit

I want to draw a straight line on an iOS map using MKmapkit without the map moving around.
For example, if the user draws a straight line between two places on the map without removing the finger off the map, I don't want the map view to move around while the user is drawing the line.
I've searched on google, but didn't find an answer/solution.
Please can somebody help me?
Disable the mapkit scroll
_mapView.scrollEnabled=NO;
And then draw line with the help of core graphics
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (drawImage==nil) {
drawImage=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:drawImage];
}
lastPoint = [touch locationInView:self.view];
lastPoint.y -= 20;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:drawImage];
currentPoint.y -= 20;
UIGraphicsBeginImageContext(drawImage.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width,drawImage.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.5, 0.6, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
You can draw poly line between two or more points/ coordinates.
Here is a question which is answered. Source: Draw a polyline between two coordinates in Xcode
You have to use MKOverlayView like below :
In Interface file
MKPolyline* _routeLine;
MKPolylineView* _routeLineView;
In Implementation file
Store all the coordinates in
NSMutablrArray *routeLatitudes
then
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * [routeLatitudes count]);
for(int idx = 0; idx < [routeLatitudes count]; idx++)
{
CLLocationCoordinate2D workingCoordinate;
workingCoordinate.latitude=[[routeLatitudes objectAtIndex:idx] doubleValue];
workingCoordinate.longitude=[[routeLongitudes objectAtIndex:idx] doubleValue];
MKMapPoint point = MKMapPointForCoordinate(workingCoordinate);
pointArr[idx] = point;
}
// create the polyline based on the array of points.
routeLine = [MKPolyline polylineWithPoints:pointArr count:[routeLatitudes count]];
[mapViewHome addOverlay:self.routeLine];
free(pointArr);
and Overlay delegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKOverlayView* overlayView = nil;
if(overlay == routeLine)
{
routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];
routeLineView.fillColor = [UIColor colorWithRed:0.945 green:0.027 blue:0.957 alpha:1];
routeLineView.strokeColor = [UIColor colorWithRed:0.945 green:0.027 blue:0.957 alpha:1];
routeLineView.lineWidth = 4;
overlayView = routeLineView;
}
return overlayView;
}

How to create embossed or shadow effects using Core Graphics (for finger paint)

I have issue to implement "Emboss/Shadow effects" in my drawing. Finger paint functionality is currently working fine with my custom UIView and below is my drawRect method code:
Edit code with all methods :
- (void)drawRect:(CGRect)rect
{
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextSaveGState(context);
// for shadow effects
CGContextSetShadowWithColor(context, CGSizeMake(0, 2),3, self.lineColor.CGColor);
CGContextStrokePath(context);
[super drawRect:rect];
}
CGPoint midPoint(CGPoint p1, CGPoint p2)
{
return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
previousPoint1 = [touch previousLocationInView:self];
previousPoint2 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
[self touchesMoved:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
previousPoint2 = previousPoint1;
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
// calculate mid point
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, mid1.x, mid1.y);
CGPathAddQuadCurveToPoint(path, NULL, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGRect bounds = CGPathGetBoundingBox(path);
CGPathRelease(path);
CGRect drawBox = bounds;
//Pad our values so the bounding box respects our line width
drawBox.origin.x -= self.lineWidth * 2;
drawBox.origin.y -= self.lineWidth * 2;
drawBox.size.width += self.lineWidth * 4;
drawBox.size.height += self.lineWidth * 4;
UIGraphicsBeginImageContext(drawBox.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
curImage = UIGraphicsGetImageFromCurrentImageContext();
[curImage retain];
UIGraphicsEndImageContext();
[self setNeedsDisplayInRect:drawBox];
}
when i have implemented this i am getting paint effects with dot dot dot ...
See below image (which does not have any shadow or embossed effects). If you have any idea of how to add these effects, please give me some suggestion. How can i resolve this?
It appears that you're creating hundreds, maybe even thousands of separate paths, one on each drawRect. You do flatten these out using [self.layer renderInContext] but I don't think that's a good way to go about it. Instead, I think what you want to do is create one UIBezierPath to track the finger, append paths to that and draw the UIBezierPath to the screen. If you create two layers (or views) you can set the top one (transparent) to "draw" on. When the user lifts their finger, you then render the entire UIBezierPath to the second layer (along with previously drawn data) and create a new UIBezierPath to draw the next finger-tracking. This way you're only updating one layer (the top one) when you're tracking someone's finger. This will help prevent the device from slowing down drawing too many paths.
Although, I will say, your current method does produce a cool looking "3D" effect.
I'm not sure about embossing, but if what you want is to apply a drop shadow to a drawing that is updated progressively, then a nice approach would be to use CALayers (link to a tutorial). Basically, your progressive drawing would update a transparent image (without attempting to draw any shadows in this image) and this image would be configured to be displayed with a drop shadow through its CALayer.
Shadow is created on borders and you are drawing small segments of lines and this creates this effect. You need to create a path and then stroke it once. This code might help you :)
for (int i=0; i<[currentPath count]; i++)
{
CGPoint mid1 = [[self midPoint:[currentPath objectAtIndex:i+1] :[currentPath objectAtIndex:i]] CGPointValue];
CGPoint mid2 = [[self midPoint:[currentPath objectAtIndex:i+2] :[currentPath objectAtIndex:i+1]] CGPointValue];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context, [[currentPath objectAtIndex:i+1] CGPointValue].x, [[currentPath objectAtIndex:i+1] CGPointValue].y, mid2.x, mid2.y);
CGContextSetShadow(context, CGSizeMake(-2, -2), 3);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetStrokeColorWithColor(context,[color CGColor]);
CGContextSetLineWidth(context, linewidth);
i+=2;
}
CGContextStrokePath(context);
Try this way.. This solved might solve your issue.. First create ur path and after it is fully created, stroke it. This happens since at every small line you stroke and hence shadow created make a dot on its bounds, so you get this effect.

How to erase finger paint on Custom UIView in iPhone

I have created a custom UIView (without .xib) for a finger paint application.
Paint is working fine with custom UIView but my problem is that when I try to erase the painted path I am getting:
Error : Invalid context
Below is my class:
.h file
#interface draw2D : UIView
{
CGPoint previousPoint;
CGPoint lastPoint;
CGMutablePathRef path;
UIButton *btnClose;
UIButton *btnErase;
BOOL IsErase;
}
- (IBAction)btnClose:(id)sender;
- (IBAction)btnErase:(id)sender;
#end
#implementation draw2D
- (void)awakeFromNib
{
path = CGPathCreateMutable();
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
btnClose = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnClose addTarget:self action:#selector(btnClose:)
forControlEvents:UIControlEventTouchDown];
[btnClose setTitle:#"close" forState:UIControlStateNormal];
btnClose.frame = CGRectMake(10, 10, 100, 40.0);
btnErase = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnErase addTarget:self action:#selector(btnErase:)
forControlEvents:UIControlEventTouchDown];
[btnErase setTitle:#"Erase" forState:UIControlStateNormal];
btnErase.frame = CGRectMake(150, 10, 100, 40.0);
[self addSubview:btnClose];
[self addSubview:btnErase];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
NSLog(#"Touch Began :%d",[touch tapCount]);
if ([touch tapCount] > 1)
{
NSLog(#"::::: Paint Start :::::");
path = CGPathCreateMutable();
previousPoint = lastPoint;
[self setNeedsDisplay];
}
self.backgroundColor = [UIColor clearColor];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"::::: touchesMoved :::::");
lastPoint = [[touches anyObject] locationInView:self];
previousPoint = [[touches anyObject] previousLocationInView:self];
if(IsErase)
{
NSLog(#"erase");
UITouch *erasetouch = [touches anyObject];
CGPoint erasecurrentPoint = [erasetouch locationInView:self];
CGContextRef erasecontext = UIGraphicsGetCurrentContext();
CGContextSetLineCap(erasecontext, kCGLineCapRound);
CGContextSetLineWidth(erasecontext,10);
CGContextSetBlendMode(erasecontext, kCGBlendModeClear);
CGContextSetStrokeColorWithColor(erasecontext, [[UIColor clearColor] CGColor]);
CGContextBeginPath(erasecontext);
CGContextMoveToPoint(erasecontext, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(erasecontext, erasecurrentPoint.x, erasecurrentPoint.y);
CGContextStrokePath(erasecontext);
CGContextFlush(erasecontext);
}
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"::::: drawRect :::::");
CGContextRef context = UIGraphicsGetCurrentContext();
CGPathMoveToPoint(path, NULL, previousPoint.x, previousPoint.y);
CGPathAddLineToPoint(path, NULL, lastPoint.x, lastPoint.y);
CGContextAddPath(context, path);
CGContextSetLineWidth(context, 5);
[[UIColor blueColor] setStroke];
CGContextDrawPath(context, kCGPathFillStroke);
}
- (IBAction)btnClose:(id)sender
{
[self removeFromSuperview];
}
- (IBAction)btnErase:(id)sender
{
IsErase = YES;
}
#end
I have set erase button with functionality but not working.
The problem you have is that you are not supposed to call UIGraphicGetContext() outside of drawRect:
In your touchesBegan:withEvent: and touchesMoved:withEvent: you should simply store the points you want to draw and call [self setNeedsDisplay] as you are doing now.
In your drawRect: implementation you would then draw the points you have stored.
You can take a look at this github repo that provides an implementation for a smooth drawing:https://github.com/levinunnink/Smooth-Line-View
finally i have find the solution . my mistake was i m implement erase code intouchMove method with new context . i dont have to need new context . implement erase code in drawrect method and now its working fine . see the below code.
- (void)drawRect:(CGRect)rect
{
[curImage drawAtPoint:CGPointMake(0, 0)];
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
if(IsErase)
{
CGContextSetLineWidth(context,self.lineWidth);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextBeginPath(context);
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddLineToPoint(context, previousPoint1.x, previousPoint1.y);
CGContextStrokePath(context);
CGContextFlush(context);
}
else
{
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextSaveGState(context);
CGContextStrokePath(context);
}
[super drawRect:rect];
[curImage release];
}
i hope it will helps to someone in erase functionality .

How to get rid of this "points" between my lines when I am drawing?

is there an easy way to not draw this points in my lines?
I don't know why this points are there because i never release my finger from screen during drawing of a line.
I got the code from a drawing example.
// draw a line
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
currentPoint.y -= 0; // 20 only for 'kCGLineCapRound'
UIGraphicsBeginImageContext(self.view.frame.size);
//Albert Renshaw - Apps4Life
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushSize); // for size
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), r, g, b, alpha); //values for R, G, B, and Alpha
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
mouseMoved++;
if (mouseMoved == 10) {
mouseMoved = 0;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
//Draw a dot
if(!mouseSwiped) {
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushSize);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), r, g, b, alpha);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
This is the final version with unique alpha, color, brushSize for every line:
- (void) updateDrawingBoard
{
UIGraphicsBeginImageContext(self.drawImage.bounds.size);
for ( NSDictionary *dict in paths ) {
UIBezierPath *p = (UIBezierPath*)[dict objectForKey:#"path"];
p.lineWidth = [[dict objectForKey:#"size"]floatValue];
[[UIColor colorWithRed:[[dict objectForKey:#"red"]floatValue]
green:[[dict objectForKey:#"green"]floatValue]
blue:[[dict objectForKey:#"blue"]floatValue]
alpha:[[dict objectForKey:#"alpha"]floatValue]] setStroke];
[p stroke];
}
[[UIColor colorWithRed:r green:g blue:b alpha:alpha] setStroke];
[path stroke];
self.drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInView:self.drawImage];
path = [[UIBezierPath bezierPath] retain];
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineJoinBevel;
path.lineWidth = brushSize;
[path moveToPoint:touchPoint];
[self updateDrawingBoard];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInView:self.drawImage];
[path addLineToPoint:touchPoint];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
path,#"path",
[NSNumber numberWithFloat:r], #"red",
[NSNumber numberWithFloat:g], #"green",
[NSNumber numberWithFloat:b], #"blue",
[NSNumber numberWithFloat:alpha], #"alpha",
[NSNumber numberWithFloat:brushSize], #"size", nil];
[paths addObject:dict];
[path release];
path = nil;
[self updateDrawingBoard];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInView:self.drawImage];
[path addLineToPoint:touchPoint];
[self updateDrawingBoard];
}
The problem is that you are gradually accumulating the line by drawing into an image. Where the old line and the new line overlap, you see "dots" from the overdraw.
The solution is to accumulate your points in a path and draw the image afresh each time using that path. Since you will be drawing a single path, not multiple overlapping paths, you shouldn't see the dots.
Outline of code:
Some time before drawing begins, create a CGMutablePathRef.
When you get a new point you want to add to your line, use CGPathAddLineToPoint.
When it's time to draw the path, use CGContextAddPath to add the line to the context, then fill or stroke as desired. You could also use CGContextDrawPath.
Alternatively, you can use UIBezierPath instead of CGMutablePathRef, in which case the steps are:
Create a UIBezierPath.
Use -addLineToPoint: to add lines to the path.
Use -stroke, -fill, and similar to draw the path into the context.
This is likely to be simpler if you are not accustomed to working with CoreGraphics directly.
I would drop the intermediate image and move this code into a view class (LineDrawView or CanvasView or something) rather than leaving the code in a view controller. Instead of updating an image, the view can just draw itself directly to the screene. The view would have methods to clear the path, undo strokes, and create an image of the path. The view controller would then use these to clear the canvas, undo lines, and save the drawing. You could enrich this later with functionality to configure the line style.
I have been trying to beat this problem for a few days, trying out Jeremy W. Sherman's answer that is probably a very good idea but was not feasable for my implementation.
In my drawing app, I could not get the alpha curves to blend into each other by constantly render the path, though the dots disappeared. If you just want a clean, alpha-colored path this is probably the way to go.
But I found a solution to this that was much simpler; these adjustments create a perfect, alpha-colored path in realtime with blending (think of it as a felt tip pen kind of style):
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapButt);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeMultiply);
Hope this helps anyone who's doing some simple CG painting in iOS.

how to draw airbrush on UIImageView?

I am a beginner working on paint application on iphone.
adding new tool for my iphone App called airbrush...
which will spray on UIImageView. can any one help me out how to work with it.
Logic for air brush.........
- (UIBezierPath *)pathFromPoint:(CGPoint)start toPoint:(CGPoint)end {
CGFloat lineWidth=10;
redrawRect = CGRectMake(end.x-lineWidth,end.y-lineWidth,lineWidth*2,lineWidth*2);
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
UIBezierPath *circle = [UIBezierPath bezierPathWithOvalInRect:redrawRect];
NSInteger i, x, y;
NSInteger modNumber =4*(int)lineWidth;
for (i = 0; i < (lineWidth*lineWidth)/2; i++) {
do {
x = (random() % modNumber)+end.x - 2*lineWidth;
y = (random() % modNumber)+end.y - 2*lineWidth;
} while (![circle containsPoint:CGPointMake(x,y)]);
[bezierPath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(x,y,0.5,0.5)]];
}
return bezierPath;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
currentPoint = [touch locationInView:self.view];
currentPoint.y -=20;
[self drawCircle];
}
-(void)drawCircle{
UIGraphicsBeginImageContext(self.drawImage.frame.size);
[drawImage.image drawInRect:CGRectMake(0,0, drawImage.frame.size.width, drawImage.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
CGContextSetLineWidth(UIGraphicsGetCurrentContext(),10);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
UIBezierPath *path=[self pathFromPoint:currentPoint
toPoint:currentPoint];
[path stroke];
lastPoint = currentPoint;
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
I think you might be looking for CGContextBeginPath and its related functions. I am not quite sure how to define a new stroke but I imagine it can be handled with something like [UIColor colorFromImage:myImage]. You should look into Quartz 2D, try looking here.
/Thomas