cocoatextcore-animationblurrycatextlayer

Blurry CATextLayer with scale transform


I'm at my wits end. I've tried what I think is everything to get rid of CATextLayer blurriness to no avail. Admittedly, some things help, but text is still far too blurry when zoomed in 2x and nowhere near the crispness of non-CATextLayer text.

Here's my situation. I've got a layer-hosted view which can contain many sublayers, including CATextLayers (inside a custom CALayer container). Now, the user can zoom the main content layer (which contains all the sublayer content) and this is done by applying a scale transform to the content layer.

Here are the things I'm currently doing. Most make a difference, though not a huge difference. If I zoom in all the way (which is 2x scale factor) I get seriously blurry text.

Code fragment:

- (void) drawInContext:(CGContextRef)context
{
    // Allow font smoothing.
    CGContextSetAllowsAntialiasing(context, YES);
    CGContextSetAllowsFontSmoothing(context, YES);
    CGContextSetAllowsFontSubpixelPositioning(context, YES);
    CGContextSetAllowsFontSubpixelQuantization(context, YES);

    // Set drawing attributes.
    CGContextSetStrokeColorWithColor(context, self.foregroundColor);
    CGContextSetFillColorWithColor(context, self.backgroundColor);
    CGContextFillRect(context, self.bounds);

    // Font smoothing.
    CGContextSetShouldAntialias(context, YES);
    CGContextSetShouldSmoothFonts(context, YES);
    CGContextSetShouldSubpixelPositionFonts(context, YES);
    CGContextSetShouldSubpixelQuantizeFonts(context, YES);

    [super drawInContext:context];
}

What am I missing?


Solution

  • For the sharpest possible text, in addition to everything mentioned in the original question, the solution that had the biggest impact is to double the contentsScale value for text layers to twice the window backing scale factor - if you want to support crisp text at 2x zoom.

    If you want to support crisp text at higher zoom values then use the max zoom factor for your application as an adjusted contentsScale. For example, you can do this by overriding -setContentsScale: for a custom CATextLayer subclass:

    - (void) setContentsScale:(CGFloat)contentsScale
    {
        [super setContentsScale:contentsScale * kMaxZoomFactor];
    }
    

    Note, be sure that changes to view backing properties (e.g., change to screen with higher resolution) are propagated to your layer-hosted hierarchy by overriding -viewDidChangeBackingProperties for your layer-hosted view:

    - (void) viewDidChangeBackingProperties
    {
        // Propagate self.window.backingScaleFactor change to layer hierarchy.
    }