CATextLayer subpixel antialiasing

2019-05-11 05:04发布

My app draws layer-backed labels over a NSImageView.
The image view displays an image, and a tint color over that image.

This ensures that the contrast between the labels and the background image works.

enter image description here

As you can see, subpixel antialiasing is enabled and works correctly.

When you hover over those labels, they animate the frame property (Actually the view containing them).
While animating, the subpixel antialiasing is disabled, and when done enabled again.

enter image description here

This looks incredibly weird.

The layer is never redrawn, and the subpixel antialiasing doesn't have to change.
So I don't see a good reason why it shouldn't be displayed when animating.

I've tried everything I can think of.

  • Making the NSTextField opaque
  • Making the CATextLayer opaque
  • Giving the NSTextField a background-color
  • Giving the CATextLayer a background-color

Always the same result.

Disabling subpixel antialiasing for the labels is not an option, since it's not well readable on non-retina devices.


EDIT

I forgot that the layer is replaced with a presentationLayer while animating.
This layer probably does not support subpixel antialiasing, which is why it's disabled.

Now the question is if I can replace this presentationLayer with a CATextLayer.

What I also noticed is that setting shouldRasterize to YES enabled subpixel antialiasing also for animation, but only against the background color. So no background-color will bring no subpixel antialiasing.

2条回答
一夜七次
2楼-- · 2019-05-11 05:27

The problem is with positioning of the text layer. Let's presume you use left alignment. The text will look good if x and y coordinates of the layer's frame origin are rounded numbers. For example:

CGFloat x = 10.6;
CGFloat y = 10.3;

textLayer.frame = CGRectMake(x, y, width, height); // the text will be blur.
textLayer.frame = CGRectMake(round(x), round(y), width, height); // the text will not be blur.

So, the first problem may be that the coordinates you assign to the layer's frame are not rounded. The tricky part is that the edge of the layer may still be not aligned with pixels even if you think you passed rounded coordinates. This may happen if the anchorPoint of your layer is (0.5, 0.5), which is the default value. If you set:

textLayer.position = CGPointMake(10.0, 10.0);

you may think it should draw the text sharp. However, position point is in the center of the layer here, and depending on the layer's width and height the left and top edge's coordinates may be fractional numbers.

If you want to make a quick test do this.

  1. Use textLayer.frame = frame instead of using position and anchor point, it will assign the coordinates directly to the frame.
  2. Make sure the numbers you use in the frame are rounded.
  3. Do not mess with rendering mechanism, remove the code that changes shouldRasterize, antialiasing, etc.

If this makes the text sharp, you can start using the anchor point and position and to see how the result changes.

查看更多
劳资没心,怎么记你
3楼-- · 2019-05-11 05:45

Is there any way that you can post a piece of sample code? I quickly mocked up an NSWindow, added an NSImageView, added a background-less NSTextField with setWantsLayer: set to YES. In my applicationDidFinishLaunching: I set a new rect on the NSTextField's Animator frame, but I didn't see any pixelation.

查看更多
登录 后发表回答