Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smoothing a rounded stroke in Core Graphics

I am creating my own UITableViewCells with a gradient background. I have all the logic and drawing worked out, but one thing I want to fix is the "chunkiness" around the corners of my custom cell:

alt text http://grab.by/27SM

If you zoom in on the corners, you can see what I am talking about. Here is the code I a using to generate the cell:

CGContextRef c = UIGraphicsGetCurrentContext();
CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef myGradient = nil;
CGFloat components[8] = TABLE_CELL_BACKGROUND;
CGContextSetStrokeColorWithColor(c, [[UAColor colorWithWhite:0.7 alpha:1] CGColor]);
CGContextSetLineWidth(c, 2);
CGContextSetAllowsAntialiasing(c, YES);
CGContextSetShouldAntialias(c, YES);
CGFloat minx = CGRectGetMinX(rect) , midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect) , maxy = CGRectGetMaxY(rect) ;

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, minx, miny);
CGPathAddArcToPoint(path, NULL, minx, maxy, midx, maxy, kDefaultMargin);
CGPathAddArcToPoint(path, NULL, maxx, maxy, maxx, miny, kDefaultMargin);
CGPathAddLineToPoint(path, NULL, maxx, miny);
CGPathAddLineToPoint(path, NULL, minx, miny);
CGPathCloseSubpath(path);

// Fill and stroke the path
CGContextSaveGState(c);
CGContextAddPath(c, path);
CGContextClip(c);

CGFloat locations[2] = { 0.0, 1.0 };
CGFloat mycomponents[8] = TABLE_CELL_BACKGROUND;
CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
myGradient = CGGradientCreateWithColorComponents(myColorspace, mycomponents, locations, 2);
CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

CGContextRestoreGState(c);  
CGContextAddPath(c, path);
CGContextStrokePath(c);

What can I do to smooth the edges while keeping a consistent edge thickness across all cells?

like image 939
coneybeare Avatar asked Feb 28 '23 16:02

coneybeare


2 Answers

Your line width is set to 2 points. What's happening is that your code is calculating your bounding rect without understanding the width of the line. The result is that for every straight segment of your shape, only half of the stroke's width is visible. On the arc, the full stroke width is visible.

Here's the relevant segment of code from my app, Funversation, to draw the playing cards with rounded corners similar to what you have.

CGRect rect = [self bounds];
rect.size.width -= lineWidth;
rect.size.height -= lineWidth;
rect.origin.x += lineWidth / 2.0;
rect.origin.y += lineWidth / 2.0;

Add that before your calculation for minx, midx, maxx, etc. and the strokes for your shape should be uniform.

like image 155
Giao Avatar answered Mar 02 '23 08:03

Giao


The other way to make the stroke consistent would be to move the AddPath and StrokePath calls up above the RestoreGState call—that is, stroke while clipped.

For a truly 2-pt-wide stroke with this solution, simply double the line width you put in the graphics state (i.e., set it to 4 pt), since half of it will be clipped out.

like image 20
Peter Hosey Avatar answered Mar 02 '23 06:03

Peter Hosey