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.
Ensure integral coordinates - works and makes an appreciable difference, but still far too blurry at 2x scale
Turn off shadows on CATextLayer
container layers - makes a difference though not at 2x scale
Ensure background color of text layer is fully opaque - seems to make a difference though not at 2x scale
Set the contentsScale
property to the window backing scale factor for all layers - seems to make a difference though not at 2x scale
Override -drawInContext:
of this custom CATextLayer
subclass to smooth, anti-alias, and sub-pixel quantize the hell out of everything - fonts render much truer, but still blurry at 2x scale
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?
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.
}