Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Antialiased drawing in a CALayer

Greetings! I'm trying to draw a series of circles in a CALayer that resides in a zoomable UISCrollView. This is the layer that zooms on pinch. If i draw the circles using CAShapeLayer, then they zoom beautifully:

CAShapeLayer plotLayer = [CAShapeLayer layer];
plotLayer.bounds = self.bounds;
plotLayer.anchorPoint = CGPointZero;
plotLayer.position = CGPointZero;

CGMutablePathRef path = CGPathCreateMutable();
for (id one in many) {
    CGRect ellipseRect = [one circleRect];
    CGPathAddEllipseInRect(path, NULL, ellipseRect);
}
plotLayer.path = path
CFRelease(path);
[self.layer addSublayer:plotLayer];
[plotLayer setNeedsDisplay];

However, when i try to draw them with vanilla core graphics in my drawLayer:inContext: method, the circles get very jaggy (downright pro-aliased!) No amount of antialias jiggery-pokery seems to help:

-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
    CGContextSetAllowsAntialiasing(context, true);
    CGContextSetShouldAntialias(context, true);
    CGContextClip(context);

    for (id one in many) {
        CGRect ellipseRect = [one circleRect];
        CGContextStrokeEllipseInRect(context, ellipseRect);
    }
}

I'm trying to figure out what CAShapeLayer is doing to get such nice antialiasing so that (aside from my own edification) i can take full advantage of core graphics in my drawing rather than just the stroke/fill that i can get with CAShapeLayer. Am i just missing a transform somewhere?

Many thanks!

like image 349
kalperin Avatar asked Nov 05 '22 21:11

kalperin


1 Answers

Short answer: contentsScale

Longer answer: (taken almost verbatim from pe8ter at Vector like drawing for zoomable UIScrollView):

You can get a better rendering by setting the contentScale property on the layer in question after zooming:

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView
                       withView:(UIView *)view
                        atScale:(float)scale
{
    [CATransaction begin];
    [CATransaction setValue:[NSNumber numberWithBool:YES] 
                     forKey:kCATransactionDisableActions];
    uglyBlurryTextLayer.contentsScale = scale;
    [CATransaction commit];
}

There's a (typically excellent) description by Brad Larson of when the actual drawing occurs (spoiler, it usually only occurs once despite how many transforms are applied) at So a CALayer does not contain a content bitmap of a view?. Based on this, i can only assume that setting contentsScale causes the layer to render again.

like image 183
kalperin Avatar answered Nov 11 '22 03:11

kalperin