CGContextSetShadow - how to apply to 'compound' shape? - ios

I'm using CoreGraphics to draw a line with circular endpoints and a drop shadow using the code below:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetShadowWithColor(UIGraphicsGetCurrentContext(), CGSizeMake(0, 0), 4.0, [UIColor blackColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillEllipseInRect(context, CGRectMake(_startPoint.x - 5, _startPoint.y - 5, 10, 10));
CGContextFillEllipseInRect(context, CGRectMake(_endPoint.x - 5, _endPoint.y - 5, 10, 10));
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 3.0);
CGContextMoveToPoint(context, _startPoint.x, _startPoint.y);
CGContextAddLineToPoint(context, _endPoint.x, _endPoint.y);
CGContextDrawPath(context, kCGPathStroke);
However, this results in something like this:
The shadow is being applied to the line and circles individually. Instead, what I want is for the shadow to be applied to the 'compound' shape created by all three (i.e. only use the compound alpha channel as the basis for the shadow), like so:
Any idea how I might achieve this effect instead? (note that I cannot use the layer.shadow property of my UIView as this line is rendered in response to touch drag events and that method is not performant enough).

This is exactly what Transparency Layers are for.
I think you'll find that the examples look familiar.

Related

cgcontext drawing - first set of shape is shown, the second exact same set, shifted slightly right is not shown

I have the following code:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// Left frame.
CGContextAddRect(context, CGRectMake(0, 0,
frameWidth,
self.frameHeight));
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:frameBorderColorRed
green:frameBorderColorGreen
blue:frameBorderColorBlue
alpha:frameBorderColorAlpha].CGColor);
CGContextFillPath(context);
CGContextAddRect(context, CGRectMake(frameBorderWidth,
frameBorderWidth,
frameWidth - (2*frameBorderWidth),
self.frameHeight - (2*frameBorderWidth)));
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextFillPath(context);
// Right frame.
CGContextAddRect(context, CGRectMake(frameWidth + distanceBetweenFrames,
0,
frameWidth,
self.frameHeight));
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:frameBorderColorRed
green:frameBorderColorGreen
blue:frameBorderColorBlue
alpha:frameBorderColorAlpha].CGColor);
CGContextFillPath(context);
CGContextAddRect(context, CGRectMake(frameWidth + distanceBetweenFrames + frameBorderWidth,
frameBorderWidth,
frameWidth - (2*frameBorderWidth),
self.frameHeight - (2*frameBorderWidth)));
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextFillPath(context);
}
The left frame is showing but the right frame isn't. However, if I were to comment out the left frame, the right frame shows. I have also tried drawing the lines themselves as in the docs:
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGContext/index.html#//apple_ref/c/func/CGContextAddRect
To no avail.
I would consider using CoreAnimation since it uses GPU.
Besides the problem is that you close current path by:
CGContextFillPath(context);
and then try to use:
CGContextAddRect
As documentation says: "Adds a rectangular path to the current path."
You need to use method below to add another path:
CGContextMoveToPoint
More detailed information you can read there:
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGContext/index.html

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.

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

UIBezierPath Shadow effect

Currently I am working on a paint app for iOS. I am stuck with applying shadow effect to a particular drawn path. I have use UIBezierpath to draw paths. Is there any way to apply shadow effect on UIBezierpath?
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor] CGColor]);
CGContextSetShadowWithColor(context, CGSizeMake(0, 5), 5.0, [[UIColor blackColor]CGColor]);
CGContextDrawPath(context, kCGPathFill);
Something like this may help u..
CGContextSetShadowWithColor(context, CGSizeZero, 20, [path.color CGColor])
I think this may help you to show shadow effect

Core Graphics Color Context

So ... I have this app that draws shapes and then the user can color them. I made a tabbar that has 4 shapes and when one is clicked the respective shape is drawn. I took the drawing idea from the quartzDemo. So I have a shape general class and then shape_name subclasses of shape. Here is the code for the Square.
#implementation Square
- (void)drawInContext:(CGContextRef)context {
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 1.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1, 1);
CGContextAddLineToPoint(context, 1, 79);
CGContextAddLineToPoint(context, 79, 79);
CGContextAddLineToPoint(context, 79, 1);
CGContextAddLineToPoint(context, 1, 1);
CGContextClosePath(context);
CGContextStrokePath(context);
}
#end
When a shape is tapped a color menu appears and I want to change the color when a button from the menu is tapped. How can I do this.
Ty in advance.
I suggest adding a property to your base shape class like this:
#property(nonatomic,retain) UIColor* fillColor;
In your menu implementation set the value of the property to a UIColor object of your user's choice and send the shape setNeedsDisplay. Then modify your drawInContext: method as follows:
CGContextSetFillColorWithColor(context, self.fillColor.CGColor);
// ... your current drawing code goes here
// replace the last line, with CGContextStrokePath(), with this:
CGContextDrawPath(context, kCGPathFillStroke);

Resources