Generate a CGPath from another path's line width outline - ios

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]);

Related

iOS - How to draw a shaped line with CGContextRef

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

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.

CGContextDrawPath for two inner and outer Rect of different colors

I am using the below code in drawRect
CGContextSaveGState(context);
CGMutablePathRef outerPath=[self createPath:rect];
CGMutablePathRef innnerPath=[self createPath:UIEdgeInsetsInsetRect(rect, UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0)];
CGPathCloseSubpath(outerPath);
CGContextAddPath(context, outerPath);
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:249.0/255.0 green:38.0/255.0 blue:1.0/255.0 alpha:1.0].CGColor);
CGContextEOFillPath(context);
CGContextDrawPath(context, kCGPathFill);
CGContextAddPath(context, innnerPath);
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:50.0/255.0 green:213.0/255.0 blue:1.0 alpha:0.4].CGColor);
CGContextDrawPath(context, kCGPathFill);
CGContextRestoreGState(context);
But, since I am using 0.4 alpha for the inner colour , the inner colour becomes brown.
How can I have something like this as show in below?
I would just make a single rectangle, fill it with a cyan color, and stroke it with a red color. Make sure you set the stroke width to the size you need.

Fill the remainder of a CGContext, keeping one rectangle transparent

I want to fill the remaining part of a CGCntext after drawing a rect? How can I do that? Thank you!
But the thing is, I set the blend mode of the cgcontext kCGBlendModeClear. I want to make the little rect in the context to transparent. If a draw the background first, can I still see the image in the rect?
If you want to fill the context (whose frame is bigRect), except for a rectangle inside it (whose frame is smallRect):
CGContextBeginPath(context);
CGContextAddRect(context, bigRect);
CGContextAddRect(context, smallRect);
CGContextSetFillColorWithColor(context, color);
CGContextEOFillPath(context, bigRect);
Do the background first...
CGRect bounds = [self bounds];
[[UIColor blackColor] set];
UIBezierPath* backgroundPath = [UIBezierPath bezierPathWithRect:bounds];
[backgroundPath fill];
CGRect innerRect = CGRectMake(self.bounds-10,
self.bounds-10,
self.bounds.width-20
self.bounds.height-20);
[[UIColor redColor] set];
UIBezierPath* foregroundPath = [UIBezierPath bezierPathWithRect:innerRect];
[foregroundPath fill];
Draw your background and then use CGContextClearRect to clear the area you want to be transparent.
arbitrary shape:
// do your foreground drawing
CGPathRef arbitraryShape; // asign your arbitrary shape
CGContextBeginPath(ctx);
CGContextAddRect(ctx, bounds); // rect in full size of the context
CGContextAddPath(ctx, arbitraryShape); // set the area you dont want to be drawn on
CGContextClip(ctx);
// do your background drawing

IOS: drawRect display 1px on corners

i'm using drawRect inside a custom UIButton to draw a bordered button with an image inside. The code is the following:
- (void) drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
//Draw a rectangle
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextSetStrokeColorWithColor(context, [[UIColor grayColor] CGColor]);
//Define a rectangle
CGRect drawrect = CGRectMake(CGRectGetMinX(rect),CGRectGetMinY(rect),rect.size.width,rect.size.height);
CGContextStrokeRect(context,drawrect);}
The problem is that on corners i got an extra pixel (see the attached image). What am i doing wrong?
thanks
You are drawing your rectangle along the edges of pixels, instead of drawing it along the centers of pixels. So your rectangle only covers half of most pixels. On the corners it covers three-quarters of the pixels.
To draw along the pixel centers, you have to use half-integer coordinates. Try this:
CGContextStrokeRect(context, CGRectInset(rect, 0.5, 0.5));

Resources