我在NSTextField
中有一些可变文本在CALayer
背景视图中呈现。由于CALayer
不支持对其上方任何文本进行文本呈现的子像素别名,因此该文字看起来很垃圾。
一些谷歌搜索揭示了原因,并且必须将文本渲染到不透明的背景上才能启用SPA。在这种情况下,如果可能的话,我想避免渲染到不透明的背景上。有更好的解决方法吗?
我完全可以将自己的文字呈现为NSImage
,如果这会有所帮助,但我找不到任何已确认的报告。
它在Interface Builder中看起来非常好,所以我知道这台计算机内部的秘密只是紧张而已。
答案 0 :(得分:3)
找到了解决方法。 Quartz中的任何内容都无法在透明背景上呈现带有Sub-Pixel Aliasing的文本。但是,您可以将文本渲染到屏幕外位图缓冲区,前提是已经以正确的方式创建了屏幕外位图缓冲区。此缓冲区的背景必须是不透明的。
我之前的视图有一个稍微透明的PNG背景。我可以简单地使这个背景不透明并且没有问题地渲染它,但是由于这个视图需要淡入淡出,它需要被CALayer支持,所以文本渲染一次,然后渲染没有子像素别名
这是我的代码。它似乎令人难以置信的冗长,如果有人能帮助我减少它,我会喜欢它。它假设您有一个名为_title
的NSImageView和一个名为title
的NSString。
// 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];
答案 1 :(得分:0)
我不太确定你的限制是什么,或者为什么你必须绘制到一个图层,但os4.1中的新内容,Core Text从桌面移植到iOS。您可以利用它的高级类型设置功能来沿着线条甚至弧形渲染字形,并让它为您完成大部分繁重的工作。它是一个相对较低级别的API,但速度非常快。
- (void)drawLayer:(CALayer *)theLayer
inContext:(CGContextRef)context
{
CFStringRef string; CTFontRef font; // assuming these exist
// Initialize string, font, and context
CFStringRef keys[] = { kCTFontAttributeName };
CFTypeRef values[] = { font };
CFDictionaryRef attributes =
CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
(const void**)&values, sizeof(keys) / sizeof(keys[0]),
&kCFTypeDictionaryCallBacks,
&kCFTypeDictionaryValueCallbacks);
CFAttributedStringRef attrString =
CFAttributedStringCreate(kCFAllocatorDefault, string, attributes);
CFRelease(string);
CFRelease(attributes);
CTLineRef line = CTLineCreateWithAttributedString(attrString);
// Set text position and draw the line into the graphics context
CGContextSetTextPosition(context, 10.0, 10.0);
CTLineDraw(line, context);
CFRelease(line);
}
其他示例包括CoreTextArcCocoa和CoreTextTest
答案 2 :(得分:0)
以下是原版海报不想这样做的原因,但我可以选择不透明的背景......
制作图层时:
layer.opaque = YES;
然后在
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
[NSGraphicsContext saveGraphicsState];
NSGraphicsContext *nscg = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO];
[NSGraphicsContext setCurrentContext:nscg];
NSRect ourframe = self.frame;
// white background enables antialiasing
[[NSColor whiteColor] setFill];
NSRect ourNSFrame = ourframe;
ourNSFrame.origin = NSZeroPoint;
NSRectFill(ourNSFrame);
[sometext drawInRect:ourNSFrame withAttributes:someattrs];
[NSGraphicsContext restoreGraphicsState];
答案 3 :(得分:-1)
文本的X,Y位置一旦得到它的变量字符串就填充了什么?我对UILabel
有类似的问题,这是由文本的XY位置浮动引起的。 (它试图将可变数据居中,而XY值是半像素)
我截断了值并修复了模糊文本。