How to remove or overwrite bezierpath at touched point in iphone? - iphone

I am using following code to color the image using UIBezierPath. There is color picker from which user can select color. And with that color bezier path will be drawn over image. But when user fills color at some position in image.after that it selects color from color picker and again fills the color at same position. In this case previously drawn color is there. I want to remove that previously filled color and want to fill new color. This is only if user fills the color at same position. Here I am already getting the points where UIBezierPath is already drawn. There is one method of UIBezierPath removeAllPoints. But it's removing all points from path. I only want to remove only touched point from uibezierpath. How can I achieve this?
#import "MyLineDrawingView.h"
#implementation MyLineDrawingView
#synthesize selImage;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
arrBezierPaths=[[NSMutableArray alloc]init ];
globalPath=[[UIBezierPath alloc]init];
myPath=[[UIBezierPath alloc]init];
self.userInteractionEnabled = TRUE;
myPath.lineWidth=30;
brushPattern=[UIColor redColor];
NSLog(#"initWithFrame method called");
NSDictionary *dict=[NSDictionary dictionaryWithObjectsAndKeys:myPath,#"Path",brushPattern,#"Color", nil];
[arrBezierPaths addObject:dict];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
for (int i=0; i<[arrBezierPaths count]; i++)
{
NSDictionary *dict=[arrBezierPaths objectAtIndex:i];
UIColor *tempBrushpatter=[[UIColor alloc]init ];
tempBrushpatter=[dict valueForKey:#"Color"];
globalPath=[dict valueForKey:#"Path"];
[globalPath strokeWithBlendMode:kCGBlendModeOverlay alpha:1.0];
[tempBrushpatter setStroke];
}
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[globalPath moveToPoint:[mytouch locationInView:self]];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
CGPoint pointTouched = [mytouch locationInView:self];
for(int i=0;i<[arrBezierPaths count];i++)
{
NSDictionary *dictTemp=[arrBezierPaths objectAtIndex:0];
UIBezierPath *temppath=[dictTemp valueForKey:#"Path"];
if([temppath containsPoint:pointTouched])
{
// [tempPath removeAllPoints];
NSLog(#"This point already contain some path");
}
}
[globalPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void)changeColor:(UIColor *)color
{
UIBezierPath *temp=[[UIBezierPath alloc]init];
// self.userInteractionEnabled = TRUE;
temp.lineWidth=30;
UIColor *brushColor=color;
NSDictionary *dict=[NSDictionary dictionaryWithObjectsAndKeys:temp,#"Path",brushColor,#"Color", nil];
[temp release];
[arrBezierPaths addObject:dict];
brushPattern=[color retain];
[self setNeedsDisplay];
}

Need some more details. From my assumption you are drawing a line with desired color, But the next time you just wanted to replace the touch point with another color and not the whole line is it?

Related

UIBezierPath with multiple color? [duplicate]

This question already has answers here:
UIBezierPath Multiple Line Colors
(2 answers)
Closed 9 years ago.
I am working on project in which i am using UIBezierPath for drawing. My problem is that when i change the color of the path, whole UIBezierPath color changes. I want to ask is it possible to change the color of UIBezierPath with multiple lines.
Regards
For one single UIBezier path you can't AFAIK
You can do something like this
///// Add this in drawRect
for (NSMutableDictionary *dic in pathArray) {
UIBezierPath *_path = [dic valueForKey:#"path"];
[[dic valueForKey:#"fColor"] setFill];
[[dic valueForKey:#"sColor"] setStroke];
[_path stroke];
}
Populating array in touch events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.currentPath=[[UIBezierPath alloc]init];
self.currentPath.lineWidth=5;
self.currentPath.miterLimit=-10;
self.currentPath.lineCapStyle = kCGLineCapRound;
self.currentPath.flatness = 0.0;
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[self.currentPath moveToPoint:[mytouch locationInView:self]];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
[dic setObject:currentfColor forKey:#"fColor"];
[dic setObject:currentsColor forKey:#"sColor"];
[dic setObject:self.currentPath forKey:#"path"];
[pathArray addObject:dic];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.currentPath addLineToPoint:[touch locationInView:self.view]];
[self.view setNeedsDisplay];
}
PS: This is just an example. I havent checked this code, yet it should work may be some alteration needed.

Why there is a black ouline while using eraser?

Please see the attached image. I have created an app in which user can draw with multiple images but when I am using the Clear Color in order to erase the drawing it is showing the black border around the erased path. I have used UIBezierPath for drawing. Is this an issue with UIBezierPath or it can be resolved by any other way? Please let me know if you want code snippet! I will post that here.
Edit: Code has been added! Please ignore the irrelevant code.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if(isFirstTapp)
{
isFirstTapp=NO;
[self.spooleteView removeHandView];
}
isdraw=YES;
mouseSwapped=NO;
UITouch *touch = [touches anyObject];
lastPoint=[touch locationInView:self];
//UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[currentPath moveToPoint:p];
currentPath.flatness = 10.0;
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
UIBezierPath *myPath=[[UIBezierPath alloc]init];
myPath.lineCapStyle=kCGLineJoinRound;
[dict setObject:myPath forKey:#"Path"];
colorTag= [[AppHelper userDefaultsForKey:#"ColorTag"]intValue];
self.selectedColor = [brushColor objectAtIndex:colorTag];
if(isErase)
{
myPath.lineWidth=30.0;
self.selectedColor = [UIColor whiteColor];
}
else
{
if([mode isEqualToString:#"morsecode"])
myPath.lineWidth=10.0;
else
myPath.lineWidth=5.0;
}
//[dict setObject:[brushColor objectAtIndex:colorTag] forKey:#"Colors"];
[dict setObject:self.selectedColor forKey:#"Colors"];
[myArr addObject:dict];
currentPath=myPath;
currentPath.flatness = 0.1;
currentPath.lineJoinStyle = kCGLineJoinRound;
currentDict=dict;
[myPath moveToPoint:lastPoint];
[myPath release];
[dict release];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(!istapped)
{
if([mode isEqualToString:#"morsecode"])
{
mouseSwapped=YES;
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
currentPoint=[mytouch locationInView:self];
[currentPath addLineToPoint:currentPoint];
[self setNeedsDisplay];
}
}
// UITouch *touch = [touches anyObject];
// CGPoint p = [touch locationInView:self];
// [currentPath addLineToPoint:p];
// [self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(!istapped)
{
mouseSwapped=YES;
UITouch *objTouch=[[touches allObjects] objectAtIndex:0];
if (!mouseSwapped&&(objTouch.tapCount==1))
{
lastPoint=currentPoint;
}
}
if(isErase)
{
if ([myArr count]>50)
{
[myArr removeAllObjects];
}
}
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[currentPath addLineToPoint:p];
[self drawBitmap]; // (3)
[self setNeedsDisplay];
[currentPath removeAllPoints]; //(4)
}
- (void)drawRect:(CGRect)rect
{
[self.incrementalImage drawInRect:rect]; // (3)
[currentPath stroke];
//[self.incrementalImage drawInRect:rect];
for (NSMutableDictionary *dictionary in myArr)
{
UIBezierPath *_path = [dictionary objectForKey:#"Path"];
self.selectedColor = [dictionary objectForKey:#"Colors"];
[self.selectedColor setStroke];
[_path stroke];
[_path strokeWithBlendMode:kCGBlendModeCopy alpha:1.0];
_path.lineCapStyle = kCGLineJoinRound;
if([mode isEqualToString:#"morsecode"])
{
if (!isErase)
{
const float p[2] = {1,15.9};
[_path setLineDash:p count:2 phase:0.9];
}
else
{
self.selectedColor = [UIColor whiteColor];
}
}
}
}
- (void)drawBitmap // (3)
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
[self.selectedColor setStroke];
if (!self.incrementalImage) // first draw; paint background white by ...
{
UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object
[[UIColor clearColor] setFill];
[rectpath fill]; // filling it with white
}
[self.incrementalImage drawAtPoint:CGPointZero];
[currentPath stroke];
self.incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
I have found the reason of that issue. It was because of the second line of the following function.
- (void)drawRect:(CGRect)rect
{
[self.incrementalImage drawInRect:rect]; // (3)
[currentPath stroke];
i.e., [currentPath stroke];
I have commented that and now there is no black border around the path.
I hope this will help other.

UIBezierPath Smooth Curve for finger touch drawing

i want to smooth curve on finger touch draw line and i want solution in UIBezierPath only my code not smoothing line completely.my code here's
#implementation MyLineDrawingView
#synthesize undoSteps;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[super setBackgroundColor:[UIColor whiteColor]];
pathArray=[[NSMutableArray alloc]init];
bufferArray=[[NSMutableArray alloc]init];
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
[[UIColor blackColor] setStroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[bufferArray removeAllObjects];
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth=5;
myPath.miterLimit=-10;
myPath.lineCapStyle = kCGLineCapRound;
myPath.flatness = 0.0;
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[pathArray addObject:myPath];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
-(void)undoButtonClicked
{
if([pathArray count]>0)
{
UIBezierPath *_path=[pathArray lastObject];
[bufferArray addObject:_path];
[pathArray removeLastObject];
[self setNeedsDisplay];
}
}
-(void)redoButtonClicked
{
if([bufferArray count]>0){
UIBezierPath *_path=[bufferArray lastObject];
[pathArray addObject:_path];
[bufferArray removeLastObject];
[self setNeedsDisplay];
}
}
- (void)dealloc
{
[pathArray release];
[bufferArray release];
[super dealloc];
}
#end
and i am getting output using my code like below screen shot:
i want smooth curve output like below screen shot:
can any one help me greatly appreciated!
Thanks in Advance!
The problem is that you're only adding points to the path using addLineToPoint:. That's the equivalent of creating a series of straight lines. You really need to add control points, like the handles you might drag while drawing curved paths in Illustrator or Sketch.
You can use addCurveToPoint:controlPoint1:controlPoint2: to add those; the trick is working out where to put the control points, relative to the points you actually get back from the touches* events.
For a good discussion of possible techniques, I recommend the following question: Drawing Smooth Curves - Methods Needed.

Multiple coloured bezier paths

Here is my code for free hand drawing. But when i draw the path, previous path is disappeared. I am not able to figure it out why is it happening so. Can any body help me. Here is my code.
- (void)drawRect:(CGRect)rect
{
for (NSMutableDictionary *dictionary in pathArray) {
UIBezierPath *_path = [dict objectForKey:#"Path"];
UIColor *_colors = [dict objectForKey:#"Colors"];
[_colors setStroke];
_path.lineCapStyle = kCGLineCapRound;
[_path stroke];
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
isEdited=YES;
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth=lineWidths;
CGPoint touchPoint = [[touches anyObject] locationInView:self];
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[myPath addLineToPoint:CGPointMake(touchPoint.x+1, touchPoint.y+1)];
[dict setObject:myPath forKey:#"Path"];
[dict setObject:brushPattern forKey:#"Colors"];
[pathArray addObject:dict];
[self setNeedsDisplay];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
You should create myPath and dict localy in touchesBegan: each time it's fired. Ditch their class-wide definitions.
For simpler (faster) performance you can still have class-wide currentPath and currentDict
ivars for usage in touchesMoved:
EDIT: code would look something like this:
//currentPath declared as an iVar of UIBezierPath* type
//currentDict declared as an iVar of NSMutableDictionary* type
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
isEdited=YES;
UIBezierPath *myPath=[[UIBezierPath alloc]init]; //locally created
myPath.lineWidth=lineWidths;
CGPoint touchPoint = [[touches anyObject] locationInView:self];
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[myPath addLineToPoint:CGPointMake(touchPoint.x+1, touchPoint.y+1)];
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init]; //locally created
[dict setObject:myPath forKey:#"Path"];
[dict setObject:brushPattern forKey:#"Colors"];
[pathArray addObject:dict];
[self setNeedsDisplay];
currentPath = myPath;
currentDict = dict;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[currentPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
1) Create a UIImage *currentImage instance variable in your drawing view.
2) in drawRect method of your view put the following line:
[currentImage drawInRect:self.bounds];
3) In touchesEnded method put the following code:
CGRect rect = self.bounds;
UIGraphicsBeginImageContext(rect.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *tempImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
currentImage = tempImage;

How to smooth marker stroke for iPhone?

Hi I am working on an application where i have to draw something. When I draw with marker stroke it makes some edges, how i can avoid these edges?
Code for marker stroke
- (void)drawRect:(CGRect)rect
{
// KidsPhotoBookAppDelegate *appDelegate = (KidsPhotoBookAppDelegate*)[[UIApplication sharedApplication]delegate];
// brushPattern = (UIColor*)appDelegate.kidsSelectedColor;
DBManager *dbMgr = [DBManager sharedManager];
[dbMgr.c setStroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
KidsPhotoBookAppDelegate *appDelegate = (KidsPhotoBookAppDelegate*)[[UIApplication sharedApplication]delegate];
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth = appDelegate.kidsBrushSize;
myPath.lineCapStyle = kCGLineCapRound;
brushPattern=appDelegate.kidsSelectedColor;
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[pathArray addObject:myPath];
appDelegate.viewContainsDrawing = YES;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
You should set line join to kCGLineJoinRound using CGContextSetLineJoin function. See the Quartz 2D Guide for more.
UPDATE
Since you are using UIBezierPath, you should try setting the lineJoinStyle of UIBezierPath to kCGLineJoinRound.
How are you drawing those curves? If you're drawing a sequence of short straight line segments, that's the problem. You should be drawing these sorts of curves with a bezier path. If you're using a bezier path already, you may need to tweak the flatness property.
I achieved this smoothness with the help of this code https://github.com/levinunnink/Smooth-Line-View