iOS - How to draw a shaped line with CGContextRef - ios

How can I draw a shaped line? For example a heart, diamond or star line with CGContextRef?
Heart line example:
Diamond line example:
Triangle line example:
Star line example:
This is what I currently have:
- (void)draw
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, path);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextSetAlpha(context, self.lineAlpha);
CGContextStrokePath(context);
}
The above code only draws a normal pen line.
Can I draw the shaped lines with an a .png image made from photoshop? Please guide me on how to do this.

I have create dummy app for you please look at idea how we can achieve custom line drawing.
Let me know if you need some more help.
https://github.com/tikamsingh/ShapeDrawing

Related

Drawing in UIView on touch points gives blurr drawing effect on boundaries

To sort out my last problem : Draw/Paint like sketch color inside a bezier path in UIView, I took an exact Image (of path) filled with selected color. Then, to draw that in UIView, for context color I took:
lineColor=[UIColor colorWithPatternImage:img];
in drawrect :
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
[curImage drawInRect:CGRectZero];
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);
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context,lineColor.CGColor);
CGContextSetShouldAntialias(context, YES);
CGContextSetAllowsAntialiasing(context, YES);
CGContextSetFlatness(context,0.5);
CGContextSetAlpha(context, 1.0);
CGContextStrokePath(context);
It draws exactly in the path of view but on boundaries the color goes out like melting effect.
Source Image in which color has to be filled :
image to be used as colorWithPatternImage (img)
After drawing on touches ,resultimg Image :
What am I missing here to fill it perfectly?
Any help with core graphics is most welcomed!
Thank You!
To mask the image I also did :
-(void)clipView :(MyUIBezierPath*)path drawingView:(DrawingView*)myView
{
MyUIBezierPath *myClippingPath =path;
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = myClippingPath.CGPath;
myView.layer.mask = mask;
}
But colorWithPatternImage and this masking does the same trick i.e lets me draw only inside the path , the problem I am facing now is : It gives a bad effect on drawing on touch points around the boundaries of path !
Well its working with my own masking method via colorWithPatternImage , though masking it by clipping is the same thing.Drawing issue was because of the image being drawn at touch point in the method "calculateMinImageArea: CGPoint1 :CGPoint2 :CGPoint3". Changing its dimensions (height-width according to line width) sorts it out.
You can create a path points out of this image. Then make a CGPathRef or CGMutablePathRef and then use it as a mask to your CGContextRef.

Proper use of eraser tool above the image while drawing?

I have one UIView in that I have draw image. On this View I am drawing pen tool, rectangle tool and update the new image and draw. Just Like the ACEDrawingView
I am facing one issue with the eraser tool. when I use the eraser the background image color is also gone. Please check the screenshot.
In the above image the black portion is pen drawing and white portion is my eraser drawing. what I want when user do the eraser drawing not to clear the background image. just the drawing.
Redraw Image code
- (void)updateCacheImage:(BOOL)redraw
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
if (redraw) {
// erase the previous image
self.image = nil;
// load previous image (if returning to screen)
[[self.prev_image copy] drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
// I need to redraw all the lines
for (id<ACEDrawingTool> tool in self.pathArray) {
[tool draw];
}
} else {
// set the draw point
[self.image drawAtPoint:CGPointZero];
[self.currentTool draw];
}
// store the image
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
Eraser tool drawing
- (void)draw
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, self.path);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextSetAlpha(context, self.lineAlpha);
CGContextStrokePath(context);
}
This is because you are using self.lineColor.CGColor which i guess is the last chosen color, which is white in this case. Try replacing the current color with [UIColor clearColor] and add this line of code CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
I have faced this now ...Just found the solutions like following.Your eraser colour should be like your background view background colour.
example:
CGContextSetStrokeColorWithColor(context, yourviewBackgroundColor);

how to draw a blur line with finger touches on iPhone?

How do I draw a blur line with a finger slide/touch motion on the iPhone? I have the following code but it is not worked. It do it wit core-graphics.some sample code?
Thanks!!
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSaveGState(context);
{
CGContextSetShadowWithColor(context, CGSizeMake(-2.0f, 2.0f), 7.0f, BLACK.CGColor);
CGContextBeginPath(context);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextAddPath(context, path);
CGContextStrokePath(context);
}
CGContextRestoreGState(context);
CGPathRelease(path);
Here is the code for simple drawing method. Hope this will help you to implement your code.

Generate a CGPath from another path's line width outline

I might not be explaining this in the best way possible, so please bear with me.
What I have is a drawn CGPath on top of a MKMapView object:
The way I was able to achieve this is to create a CGPath for the darker blue line, then create a copy of that path, and then stroke a thicker version of it with a semi-transparent blue color. Here's the code that I'm currently using for this:
// set the shadow around the path line
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetRGBStrokeColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
CGContextSetRGBFillColor(context, 0.0f, 0.0f, 1.0f, 0.4f);
CGPathRef shadowPath = CGPathCreateCopyByStrokingPath(self.path.CGPath, NULL, 80.0f, kCGLineCapRound, kCGLineJoinRound, 0.0f);
CGContextBeginPath(context);
CGContextAddPath(context, shadowPath);
CGContextDrawPath(context, kCGPathFillStroke);
CGContextRestoreGState(context);
CGPathRelease(shadowPath);
Works pretty well, nothing wrong so far.
However, what I would like to do though is to get a CGPathRef of the outline of that thicker semi-transparent blue area. Here's another screenshot showing the pseudo-path that I want out of this (hand drawn in red):
How is this possible?
Simple: just use CGPathCreateCopyByStrokingPath. Pass in a wide line width, and a cap of kCGLineCapRound.
You can draw two stokes.
one stroke with width n (which n is the outline width) and black color.
another stroke is then drawn on top of the first one, with eraser mode:
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);

iOS: Long Touch Gesture

I have these sizes of circles that changes using a UISlider and draws on touch.
Now, i am trying give it a new style on how it will draw on the screen on touch, and it's like this, when the user holds the touch (for example he's on the middle size circle) it'll start form the smallest size and stops on its current size but when the user just tap the screen very quick it'll just draw the smallest size no matter what's the size is...
how will i able to that??
here's my current code:
On touchesBegan:
if(!touchSwiped) {
UIGraphicsBeginImageContext(self.view.frame.size);
[drawView.image drawInRect:CGRectMake(0, 0, 768, 1024)];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, lineWidth);
CGContextSetRGBStrokeColor(context, color1, color2, color3, alpha);
CGContextSetBlendMode(context, blendMode);
CGContextMoveToPoint(context, endingPoint.x, endingPoint.y);
CGContextAddLineToPoint(context, endingPoint.x, endingPoint.y);
CGContextStrokePath(context);
CGContextFlush(context);
drawView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
Thanks!
UILongPressGestureRecognizer may be what you're looking for.

Resources