How to have CATextLayer smooth its text?


Question or issue on macOS:

According to the documentation, it is possible to enable font smoothing inside CATextLayer:

Text can only be drawn using sub-pixel antialiasing when it is composited into an existing opaque background at the same time that it’s rasterized.

Here is how I understand this sentence:

@implementation CATextLayerWithFontSmoothing
-(id)init {
    self=[super init];
    if (self) {
    CALayer * whiteBackground = [CALayer layer];
    CATextLayer * blackText = [CATextLayer layer];

    [whiteBackground setBounds:NSMakeRect(0, 0, 300, 300)];
    [blackText setBounds:NSMakeRect(0, 0, 300, 300)];

    [whiteBackground setBackgroundColor:[NSColor whiteColor].CGColor];
    [blackText setForegroundColor:[NSColor blackColor].CGColor];
    [blackText setString:@"CATextLayer"];

    [blackText setShouldRasterize:YES];

    [self addSublayer:whiteBackground];
    [self addSublayer: blackText];

    return self;

which doesn’t work. Text is not drawn using subpixel anti-aliasing.

How to solve this problem?

Solution no. 1:

The method described here works:

Case 2: If you’re using a CATextLayer directly, you’ll need to
subclass CATextLayer and do something like the following in your
drawing code:

- (void)drawInContext:(CGContextRef)ctx
CGContextSetRGBFillColor (ctx, r, g, b, a);
CGContextFillRect (ctx, [self bounds]);
CGContextSetShouldSmoothFonts (ctx, true);
[super drawInContext:ctx];

Here is a comparison of smoothed vs non-smoothed:

text on a regular CATextLayer

text with sub-pixel-aa

800% zoom of both layers

PS: Don’t look at this answer on a CRT.

Solution no. 2:

May be late. But I see that this question has a perfect solution, as Steve’s answer, and nacho4d’s comment:

How to get text in a CATextLayer to be clear

Solution no. 3:

The way I understand this documentation, it says that CATextLayer always disables sub-pixel antialiasing. The sentence you quoted is just given as an explanation for this, not as instructions on how to enable it – it’s followed by:

Setting the opacity property of the layer to YES does not change the rendering mode.

…which implies that even if you use an opaque background for the layer, this won’t change the fact that CATextLayer doesn’t use sub-pixel-aa.

Solution no. 4:

If you came searching for an issue where CATextLayer is rendering slightly blurry text in OSX, after much wall head banging, I got the sharp clear text by doing:

text_layer.contentsScale = self.window!.backingScaleFactor text_layer.zPosition = 0 

(I also set the views background layer contentsScale to be the same).

Solution no. 5:

Accepted answer do not work for my.

I found working solution on Ignacio Nieto blog

textLayer.contentsScale = UIScreen.mainScreen().scale 

Solution no. 6:

the most common case is to have clear sharp visible fonts,
so in Objective-C it would look like…

CATextLayer *text = [CATextLayer layer]; text.allowsEdgeAntialiasing = NO; text.allowsFontSubpixelQuantization = YES; // the following is a CGFloat, so can even be scaled down, to make it pixelish text.contentsScale = [UIScreen mainScreen].scale; text.frame = CGRectInset(self.frame, 0, 5); text.foregroundColor = UIColor.orangeColor.CGColor; text.fontSize = 36.0; text.font = (__bridge CFTypeRef _Nullable)([UIFont fontWithName:@"HelveticaNeue-UltraLight" size:text.fontSize]); [self.layer addSublayer:text]; 

text.fontSize is ignored when setting .font property but before setting the font with bridging it can be used to store the fonts size when creating the font

Hope this helps!