CALayer and CGGradientRef anti-aliasing?

I have a strange problem with a CALayer pattern for iPhone. I have a root layer that adds a bunch of sublayers representing "bubbles". The end result should look something like this:

http://www.expensivedna.com/IMG_0018.PNG http://www.expensivedna.com/IMG_0018.PNG

The problem is that I cannot make the layer smooth (note the jaggies on the bubbles). My drawInContext rewrite code for the CALayer bubble is as follows:

- (void)drawInContext:(CGContextRef)theContext{ CGContextSetAllowsAntialiasing(theContext, true); CGContextSetShouldAntialias(theContext, true); size_t num_locations = 2; CGFloat locations[2] = { 0.0, 1.0 }; CGFloat components[8] = { 1.0, 1.0, 1.0, 0.5, // Start color 1.0, 1.0, 1.0, 0.0 }; // End color CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB(); CGGradientRef glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations); CGPoint topCenter = CGPointMake(25, 20); CGPoint midCenter = CGPointMake(25, 25); CGContextDrawRadialGradient(theContext, glossGradient, midCenter, 20, topCenter, 10, kCGGradientDrawsAfterEndLocation); 

}

Now it’s really strange that if I slightly changed the drawing code to draw regular red circles as follows:

 - (void)drawInContext:(CGContextRef)theContext{ CGContextSetAllowsAntialiasing(theContext, true); CGContextSetShouldAntialias(theContext, true); CGContextSetFillColorWithColor(theContext, [UIColor redColor].CGColor); CGContextFillEllipseInRect(theContext, CGRectMake(0, 0, 40,40)); } 

Everything looks like antialiases OK:

http://www.expensivedna.com/IMG_0017.PNG http://www.expensivedna.com/IMG_0017.PNG

I can't seem to understand this strange behavior. Is there any difference between smoothing gradients and normal circles?

Thanks guys.

+4
source share
3 answers

Thanks guys. It turns out that the answer is a combination of your two answers (coob and Alex). Basically, it seems that the CGDrawRadialGradient function has only aliases in the start circle, and not at the end. Since I want to smooth out the "edges" on both, I first set up a function for drawing from the inside, which takes care of the first "edge", but creates the following:

Step 1

Then I clamp the image, as coob suggested, and it gives a nice smoothing around the last edge of the bubble:

Step 2

Looks good enough for me!

 - (void)drawInContext:(CGContextRef)theContext{ CGContextSetAllowsAntialiasing(theContext, true); CGContextSetShouldAntialias(theContext, true); size_t num_locations = 2; CGFloat locations[2] = { 0.0, 1.0 }; CGFloat components[8] = { 1.0, 1.0, 1.0, 0.0, // Start color 1.0, 1.0, 1.0, 0.5 }; // End color CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB(); CGGradientRef glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations); CGContextAddEllipseInRect(theContext, CGRectMake(5, 5, 40, 40)); CGContextClip(theContext); CGPoint topCenter = CGPointMake(25, 20); CGPoint midCenter = CGPointMake(25, 25); CGContextDrawRadialGradient(theContext, glossGradient, topCenter, 10, midCenter, 20, kCGGradientDrawsAfterEndLocation); 

}

+4
source

Jeff - make topCenter a little further and use the CGContextClipToMask with a circular mask.

Edit: In fact, a much better way to do this is to use the vector cropping path using CGContextClip.

Edit 2: Code Example:

 CGContextAddEllipseInRect(theContext, CGRectMake(20, 20, 10, 10)); CGContextClip(theContext); 

Add this before you draw your gradient and draw it a little.

+2
source

maybe try throwing kCGGradientDrawsAfterEndLocation? Maybe something strange with alpha

0
source

All Articles