Search code examples
iosobjective-cmacoscore-graphics

Harsh colour banding in radial CGGradient


CGContextDrawRadialGradient produces a very visible ‘cross’ at the centre of the gradient:

A visible radial cross at the gradient centre

Code (reduced):

- (void)drawRect:(NSRect)dirtyRect {
    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];

    size_t numberOfGradientLocations = 2;
    CGFloat startRadius = 0.0f;
    CGFloat endRadius = 30.0f;
    CGPoint centre = CGPointMake(floorf(self.bounds.size.width / 2), floorf(self.bounds.size.height / 2));
    CGFloat gradientColours[8] = {0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f};
    CGFloat gradientLocations[2] = {0.0f, 1.0f};

    CGColorSpaceRef colourspace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colourspace, gradientColours, gradientLocations, numberOfGradientLocations);
    CGContextDrawRadialGradient(context, gradient, centre, startRadius, centre, endRadius, kCGGradientDrawsBeforeStartLocation);
}

This happens on both macOS and iOS. Meanwhile, the same kind of gradient renders perfectly in WebKit with CSS (so it’s not some ‘bad display’ issue).

What am I doing wrong? Is there a known way around this?


Solution

  • Here's what I get on iOS; I used the iPhone 7 Plus simulator at 100% so as to make every pixel visible, and it seems completely smooth:

    enter image description here

    EDIT After some experimentation, I suspect you're seeing a moiré effect caused by misalignment between points and pixels.