使用 Core Animation 渲染文本效果不佳
首先,我知道这个话题之前已经被提出过好几次了,但我发布这个问题是因为我过去使用过的“解决方案”都没有在这个特定的情况下起作用。我正在将一些文本绘制到由 NSToolbar 内的视图托管的 CALayer 中。文本如下所示:
我尝试使用 此 StackOverflow 帖子,即调用CGContextSetShouldSmoothFonts(ctx, false)
在绘制到上下文之前关闭子像素抗锯齿。这个解决方案在过去给了我可接受的结果,但在这种情况下,它似乎使文本看起来更糟:
该帖子中提到的另一个解决方案是在绘制之前用不透明的背景颜色填充矩形,在这种情况下这是不可能的,因为工具栏背景是渐变的。我可以做些什么来使该文本看起来像绘制到普通 NSView
中的文本一样漂亮吗?
First of all, I know this topic has been brought up several times before but I'm posting this question because none of the "solutions" I've used in the past have worked in this specific case. I'm drawing some text to a CALayer
that is hosted by a view inside my NSToolbar. Here's what the text look likes:
I tried using a suggestion from this StackOverflow post, which is to call CGContextSetShouldSmoothFonts(ctx, false)
to turn off subpixel antialiasing before drawing into the context. This is a solution that has given me acceptable results in the past, but in this case it seems to have made the text look even worse:
The other solution mentioned in that post is to fill the rect with an opaque background color before drawing, which simply isn't possible in this case because the toolbar background is a gradient. Is there anything I can do to make this text look as nice as text drawn into a plain NSView
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
子像素抗锯齿不可能实现的原因是,在幕后,
CALayers
本质上只是 OpenGL 纹理。这意味着它们是由 GPU 直接处理和渲染的位图。 GPU 对文本一无所知,因此无法应用子像素抗锯齿。
为了处理子像素抗锯齿,每次修改图层时都必须重新计算图层内容的像素值,这将非常昂贵,并且消除了在 GPU 上托管图层的全部意义,即合成和渲染速度极快。
不透明背景上的文本可以使用 SPAA 的原因是,在将图层纹理存储到 GPU 上之前,文本会使用子像素抗锯齿进行预渲染。如果文本背景是透明的,则这是不可能的。
您将不得不忍受这个限制。值得庆幸的是,当我们最终都拥有 HiDPI 显示器时,这将不再是问题……看看 iPhone,它根本不支持子像素抗锯齿功能。在 iPhone 上,由于屏幕分辨率高,文本看起来很好。
The reason sub-pixel antialiasing is not possible is that behind the scenes,
CALayers
are essentially just OpenGL textures.This means they are bitmaps handled and rendered directly by the GPU. The GPU knows nothing about text and so can't apply sub-pixel antialiasing.
In order to handle sub-pixel antialiasing, it would have to recalculate the pixel values of the layer content each time the layer was modified, which would be prohibitively expensive and remove the whole point of hosting the layer on the GPU, which is to make compositing and rendering extremely fast.
The reason that text on opaque backgrounds can use SPAA is that the text is pre-rendered with sub-pixel anti-aliasing before the layer texture is stored on the GPU. This is not possible if the background of the text is transparent.
You will have to live with this limitation. Thankfully, it will no longer be an issue when we eventually all get HiDPI displays… have a look at the iPhone, which does not do sub-pixel antialiasing at all. On the iPhone, text looks just fine thanks to the high screen resolution.
不幸的是没有神奇的修复方法。最终,文本必须绘制在不透明的背景上才能获得 SPAA。这很糟糕,但考虑到图层的工作方式,它很有意义。老实说,我看不到苹果会“解决”这个问题。我认为这就是他们长期坚持使用旧的软件合成模型的原因。这是一个难题,他们希望通过提高 DPI 来忽略它。
但无论如何,根据您的具体情况,有几种方法可以获得 SPAA。
您可以尝试重新创建渐变并在绘制文本时自己绘制它。但显然,如果工具栏渐变在操作系统更新中发生变化,那就很脆弱,并且可能很难让渐变完全正确匹配。
或者,您实际上可以尝试在运行时或提前抓取工具栏背景的图像,并将其绘制为背景。
Unfortunately there's no magic fix. At the end of the day, the text must be drawn on to an opaque background to get SPAA. It sucks, but it makes a lot of sense given how layers work. And honestly, I can't see Apple ever "fixing" this. I think this is the reason they've stuck with the old software compositing model for so long. It's a hard problem and they're hoping to ignore it by going high-DPI.
But anyways, there are a few ways to get SPAA in your specific case.
You could try to re-create the gradient and draw it yourself when you draw your text. But obviously that's brittle if the toolbar gradient changes in an OS update, and it could be hard to get the gradient to match exactly right.
Or you could actually try to grab an image of the toolbar background, either at runtime or ahead of time, and draw that as your background.
我在 OpenGL、动画、实时滚动文本、使用多重采样 AA 在纹理上渲染文本方面有很好的经验。带有 Alpha 的 4 字节纹理不关心背景是否透明。 OpenGL 实时渲染透明纹理。在字形发生任何微小变化时重新制作纹理,都是微秒的问题。苹果可以解决这个问题。
I have a good experience in OpenGL, animation, real-time scrolling text, rendering text on textures using multisample AA. A 4 bytes texture, with alpha, doesn't care about the background is or isn't transparent. OpenGL renders that transparent texture in real time. And remaking a texture at any small change of the glyphs, is a question of microseconds. Apple could fix that.