issue with drawing two CGMutablePathRef - iphone

So I can't seem to be able to draw 2 CGMutablePathRef. Here's the code:
CGRect mainRect = CGRectMake(2, 2, rect.size.width-4, 210);
CGMutablePathRef mainPathRef = createRoundedRectForRect(mainRect, 4);
if (self.imageExists_){
[[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0] set];
CGContextAddPath(context, mainPathRef);
CGContextClip(context);
UIGraphicsBeginImageContext(mainRect.size);
//need to flip the images to that it is drawn appropriately as CALayer uses a different coordinate system
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, 210);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, mainRect, self.highlightItem_.highlightStoryImage.CGImage);
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[scaledImage drawAtPoint:CGPointMake(0, 0)];
CGContextRestoreGState(context);
this draws the image just fine on the path I specified, clipped. But then I want to draw another rounded rect below it, so I did:
[[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0] set];
CGFloat colors [] = {
0.20, 0.20, 0.20, 1.0,
0.17, 0.17, 0.17, 1.0
};
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2);
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
CGContextSaveGState(context);
CGRect commentRect = CGRectMake(2, 215, rect.size.width-4, rect.size.height - 215);
CGMutablePathRef pathRef = createRoundedRectForRect(commentRect, 3);
CGContextAddPath(context, pathRef);
CGContextClip(context);
CGPoint startPoint = CGPointMake(CGRectGetMidX(commentRect), CGRectGetMinY(commentRect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(commentRect), CGRectGetMaxY(commentRect));
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient), gradient = NULL;
CGContextRestoreGState(context);
CGContextAddPath(context, pathRef);
CGContextDrawPath(context, kCGPathStroke);
Any idea why this doesn't work?

You've clipped the drawing to the first rect, but haven't reset the clipping path before drawing the second time. You need to save the graphics state before the first clipping path is invoked, I believe.
Your first snippet should look something like this:
CGContextSaveGState(...);
CGContextAddPath(...);
CGContextClip(...);
UIGraphicsBeginImageContext(...);
... rest of your drawing code...
CGContextRestoreGState(...);
and then the second code snippet.

Related

Drawing pattern with UIImage not like pattern but it is filled UIImage in UIView

My line of code:
UIColor *brushPattern=[[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"Frame-1#2x.png"]];
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(),brushPattern.CGColor);
Image pattern
url
Which does not draw like brush pattern whereas it fill pattern in UIView
I have used the following code for the same
At ViewDidLoad or Where ever your going to start the assign this
patternColor = [UIColor colorWithPatternImage:image]
This will resolve your memory issues and below code willhelp you
UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
[view.image drawInRect:CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)];
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 10);
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(), patternColor.CGColor);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextStrokePath(context);
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Drawing an entire image in triangle in iPhone?

I am drawing triangle portion of the image using
UIImage *image = [UIImage imageNamed:#"sampleImage.png"];
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,NULL,10.0f, 200.0f);
CGPathAddLineToPoint(path,NULL,200.0f,10.0f);
CGPathAddLineToPoint(path,NULL,200.0f,200.0f);
CGPathAddLineToPoint(path,NULL,200.0f,200.0f);
CGPathCloseSubpath(path);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ctx, [UIColor blueColor].CGColor);
CGContextAddPath(ctx, path);
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, image.size.height);
CGContextConcatCTM(ctx, flipVertical);
CGContextClip(ctx);
CGContextDrawImage(ctx, CGRectMake(10, 10.0f, 200.0f, 200.0f), image.CGImage);
CGContextFillPath(ctx);
But i need entire image to be mapped into the triangle region. Is it possible to achieve this using core graphics?

CoreGraphics taking a while to show on a large view - can i get it to repeat pixels?

This is my coregraphics code:
void drawTopPaperBackground(CGContextRef context, CGRect rect) {
CGRect paper3 = CGRectMake(10, 14, 300, rect.size.height - 14);
CGRect paper2 = CGRectMake(13, 12, 294, rect.size.height - 12);
CGRect paper1 = CGRectMake(16, 10, 288, rect.size.height - 10);
//Shadow
CGContextSetShadowWithColor(context, CGSizeMake(0,0), 10, [[UIColor colorWithWhite:0 alpha:0.5]CGColor]);
CGPathRef path = createRoundedRectForRect(paper3, 0);
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextAddPath(context, path);
CGContextFillPath(context);
//Layers of paper
CGContextSaveGState(context);
drawPaper(context, paper3);
drawPaper(context, paper2);
drawPaper(context, paper1);
CGContextRestoreGState(context);
}
void drawPaper(CGContextRef context, CGRect rect) {
//Shadow
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0,0), 1, [[UIColor colorWithWhite:0 alpha:0.5]CGColor]);
CGPathRef path = createRoundedRectForRect(rect, 0);
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextAddPath(context, path);
CGContextFillPath(context);
CGContextRestoreGState(context);
//Gradient
CGContextSaveGState(context);
CGColorRef startColor = [UIColor colorWithWhite:0.92 alpha:1.0].CGColor;
CGColorRef endColor = [UIColor colorWithWhite:0.94 alpha:1.0].CGColor;
CGRect firstHalf = CGRectMake(rect.origin.x,
rect.origin.y, rect.size.width / 2, rect.size.height);
CGRect secondHalf = CGRectMake(rect.origin.x + (rect.size.width / 2),
rect.origin.y, rect.size.width / 2, rect.size.height);
drawVerticalGradient(context, firstHalf, startColor, endColor);
drawVerticalGradient(context, secondHalf, endColor, startColor);
CGContextRestoreGState(context);
CGContextSaveGState(context);
CGRect redRect = rectForRectWithInset(rect, -1);
CGMutablePathRef redPath = createRoundedRectForRect(redRect, 0);
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextAddPath(context, path);
CGContextClip(context);
CGContextAddPath(context, redPath);
CGContextSetShadowWithColor(context, CGSizeMake(0, 0), 15.0, [[UIColor colorWithWhite:0 alpha:0.1] CGColor]);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
The view is a UIScrollView, which contains a textview. Every time the user types something and goes onto a new line, I call [self setNeedsDisplay]; and it redraws the code. But when the view starts to get long - around 1000 height, it has very noticeable lag. How can i make this code more efficient? Can i take a line of pixels and make it just repeat that, or stretch it, all the way down?
You can draw your repeating background once, into an offscreen context, pull out the image from it, then create a UIColor with the pattern image and set that as your background colour. The image will then be tiled for you.
You start an image context with UIGraphicsBeginImageContextWithOptions(). The options include the size of your expected image - I assume this is the width of your scrollview and x pixels high, the opacity, and scale. Send 0 for the scale for automatic retina support.
You can then act as if you were within a drawRect method - so your functions above can be called as normal.
Then, extract the image:
UIImage *background = UIGraphicsGetImageFromCurrentImageContext();
End the image context:
UIGraphicsEndImageContext();
Then create the colour:
UIColor *backgroundColor = [UIColor colorWithPatternImage:background];
And set that as the background for your scrollview. Typed on a phone, so apologies for ... everything.

CGContextSetShadowWithColor not working

This code should be showing a shadow, but it isn't:
CGContextRef context = UIGraphicsGetCurrentContext();
//Border
CGMutablePathRef outerPath = createRoundedRectForRect(self.bounds, MENU_BUTTON_OUTER_RADIUS);
CGContextSetFillColorWithColor(context, [[UIColor colorWithWhite:0 alpha:0.18] CGColor]);
CGContextAddPath(context, outerPath);
CGContextFillPath(context);
//Button
UIColor *buttonColor;
if (self.type == JMenuButtonTypeBlack) {
buttonColor = [UIColor colorWithWhite:0 alpha:1.0];
}
else if (self.type == JMenuButtonTypeWhite) {
buttonColor = [UIColor colorWithWhite:0.72 alpha:1.0];
}
CGRect insideRect = rectForRectWithInset(self.bounds, 3);
CGMutablePathRef innerPath = createRoundedRectForRect(insideRect, MENU_BUTTON_INNER_RADIUS);
CGPoint gradientTop = CGPointMake(0, insideRect.origin.y);
CGPoint gradientBottom = CGPointMake(0, insideRect.origin.y + insideRect.size.height);
//Base color
CGContextSaveGState(context);
CGContextSetFillColorWithColor(context, [buttonColor CGColor]);
CGContextAddPath(context, innerPath);
CGContextFillPath(context);
CGContextRestoreGState(context);
//Gradient 1
CGContextSaveGState(context);
CGFloat colors [] = {
1.0, 1.0, 1.0, 0.16,
0.0, 0.0, 0.0, 0.11
};
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2);
CGContextAddPath(context, innerPath);
CGContextClip(context);
CGContextDrawLinearGradient(context, gradient, gradientTop, gradientBottom, 0);
CGGradientRelease(gradient), gradient = NULL;
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
CGContextRestoreGState(context);
//Shadow
CGContextSaveGState(context);
CGContextAddPath(context, innerPath);
CGContextSetShadowWithColor(context, CGSizeMake(0, 2), 3.0, [[UIColor blackColor] CGColor]);
CGContextRestoreGState(context);
This is what it looks like so far. The shadow code doesn't make a difference:
You're not drawing anything after you set the shadow. You need to either stroke or fill (CGContextStrokePath() or CGContextFillPath()) the path in order for it to be drawn into the context and thus appear on screen.

How to fill a path with gradient in drawRect:?

filling a path with a solid color is easy enough:
CGPoint aPoint;
for (id pointValue in points)
{
aPoint = [pointValue CGPointValue];
CGContextAddLineToPoint(context, aPoint.x, aPoint.y);
}
[[UIColor redColor] setFill];
[[UIColor blackColor] setStroke];
CGContextDrawPath(context, kCGPathFillStroke);
I'd like to draw a gradient instead of solid red, but I am having trouble.
I've tried the code listed in the Question/Answer: Gradients on UIView and UILabels On iPhone
which is:
CAGradientLayer *gradient = [CAGradientLayer layer];
[gradient setFrame:rect];
[gradient setColors:[NSArray arrayWithObjects:(id)[[UIColor blueColor] CGColor],
(id)[[UIColor whiteColor] CGColor], nil]];
[[self layer] setMasksToBounds:YES];
[[self layer] insertSublayer:gradient atIndex:0];
However, this paints the entire view that this is in with the gradient, covering up my original path.
I would clip to the path you want to fill, and use CGContextDrawLinearGradient. Here is a simple implementation of drawRect: as an example:
- (void) drawRect:(CGRect)rect
{
// Create a gradient from white to red
CGFloat colors [] = {
1.0, 1.0, 1.0, 1.0,
1.0, 0.0, 0.0, 1.0
};
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2);
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextAddEllipseInRect(context, rect);
CGContextClip(context);
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient), gradient = NULL;
CGContextRestoreGState(context);
CGContextAddEllipseInRect(context, rect);
CGContextDrawPath(context, kCGPathStroke);
}