如何解决由CALayer支持的文本中的较差文本呈现问题 [英] How to work around poor text rendering in text backed by a CALayer

查看:94
本文介绍了如何解决由CALayer支持的文本中的较差文本呈现问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在CALayer背景视图上呈现的NSTextField中有一些可变文本.由于CALayer不支持在其上方的任何文本的文本呈现中使用亚像素别名,因此该文本看起来很垃圾.

I have some variable text in an NSTextField that renders on a CALayer background view. As a CALayer does not support sub-pixel aliasing for text rendering of any text on top of it, this text looks rubbish.

一些谷歌搜索揭示了这样做的原因,并且必须将文本渲染到不透明的背景上才能启用SPA.在这种情况下,我想避免渲染到不透明的背景上.有更好的解决方法吗?

A bit of googling reveals the reasons why this is, and that text must be rendered onto an opaque background to have SPA enabled. Rendering onto an opaque background is something I'd like to avoid if at all possible in this case. Is there a better workaround?

如果可以,我完全可以将文本自己呈现为NSImage,但是我找不到任何确认的报告.

I am completely amenable to rendering the text myself into an NSImage, if that will help, but I can't find any confirmed reports that it will.

在Interface Builder中看起来绝对不错,所以我知道这个秘密就在这台计算机的某个地方,它正竭力逃脱.

It looks absolutely fine in Interface Builder so I know the secret is somewhere inside this computer just straining to get out.

推荐答案

找到了解决方法.看起来,Quartz中的任何内容都无法使用子像素混叠"来呈现文本.但是,您可以将文本渲染到屏幕外的位图缓冲区,前提是已经以正确的方式创建了屏幕外的位图缓冲区.该缓冲区的背景必须不透明.

Workaround found. Nothing in Quartz can render text with Sub-Pixel Aliasing on top of a transparent background, seemingly. However, you CAN render text to an offscreen bitmap buffer, providing that offscreen bitmap buffer has been created in the correct fashion. The background of this buffer must be opaque.

我的视图以前具有略微透明的PNG背景.我本可以简单地使该背景不透明并毫无问题地对其进行渲染,但是由于此视图需要淡入和淡出,因此需要CALayer支持,因此该文本可以正确渲染一次,然后随后无需进行子像素混叠即可进行渲染.

My view previously had a PNG background that was slightly transparent. I could have simply made this background opaque and rendered to it without problem, but as this view needs to fade in and out, it needed to be CALayer-backed, so the text renders once properly, and then subsequently renders without Sub-Pixel Aliasing.

这是我的代码.似乎太冗长了,如果有人可以帮助我降低成本,我会喜欢的.假定您有一个名为_title的NSImageView和一个名为title的NSString.

Here's my code. It seems incredibly verbose, I'd love it if anyone could help me whittle it down. It assumes you have an NSImageView called _title and an NSString called title.

// Create the attributed string
NSMutableAttributedString *attStr = [[[NSMutableAttributedString alloc] initWithString: title] autorelease];

NSRange strRange = NSMakeRange(0, [attStr length]);
NSFont *font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize: NSSmallControlSize]];

[attStr addAttribute: NSForegroundColorAttributeName value: [NSColor whiteColor] range: strRange];
[attStr addAttribute: NSFontAttributeName value: font range: strRange];

NSMutableParagraphStyle *paraStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
[paraStyle setAlignment: NSCenterTextAlignment];
[paraStyle setLineBreakMode: NSLineBreakByTruncatingMiddle];
[attStr addAttribute: NSParagraphStyleAttributeName value: paraStyle range: strRange];

// Set up the image context
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * [_title frame].size.width;
NSUInteger bitsPerComponent = 8;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// These constants are necessary to enable sub-pixel aliasing.
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;

// Create the memory buffer to be used as the context's workspace
unsigned char *contextBuffer = malloc([_title frame].size.height * [_title frame].size.width * 4);

CGContextRef context = CGBitmapContextCreate(contextBuffer, 
                                             [_title frame].size.width, 
                                             [_title frame].size.height, 
                                             bitsPerComponent, 
                                             bytesPerRow, 
                                             colorSpace, 
                                             bitmapInfo);


[NSGraphicsContext saveGraphicsState];

[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]];


CGContextSetFillColorWithColor(context, CGColorGetConstantColor(kCGColorBlack));
CGRect rectangle = CGRectMake(0, 0, [_title frame].size.width,[_title frame].size.height);
CGContextAddRect(context, rectangle);
CGContextFillPath(context);

CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attStr);

CGContextSetTextPosition(context, 10.0, 10.0);
CTLineDraw(line, context);
CFRelease(line);

// Create a data provider from the context buffer in memory
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, contextBuffer, bytesPerRow * [_title frame].size.height, NULL);

// Create an image from the data provider
CGImageRef imageRef = CGImageCreate ([_title frame].size.width,
                                     [_title frame].size.height,
                                     bitsPerComponent,
                                     bytesPerPixel * 8,
                                     bytesPerRow,
                                     colorSpace,
                                     bitmapInfo,
                                     dataProvider,
                                     NULL,
                                     false,
                                     kCGRenderingIntentDefault
                                     );

// Turn it into an NSImage
NSImage *newImage = [[[NSImage alloc] initWithCGImage:imageRef size: NSZeroSize] autorelease];

CGDataProviderRelease(dataProvider);
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
CGImageRelease(imageRef);

free(contextBuffer);

[NSGraphicsContext restoreGraphicsState];

[_title setImage: newImage];

这篇关于如何解决由CALayer支持的文本中的较差文本呈现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆