Как получить текст в CATextLayer, чтобы быть ясным

я CALayer С CATextLayer и текст выходит размытым. В документах они говорят о" субпиксельном сглаживании", но для меня это мало что значит. У любого есть фрагмент кода, который делает CATextLayer немного текста, что понятно?

вот текст из документации Apple:

Примечание: CATextLayer отключает субпиксельное сглаживание при рендеринге текста. Текст можно рисовать только с помощью субпиксельного сглаживания, когда он комбинируется в существующий непрозрачный фон, в то же время, что он растеризован. Невозможно нарисовать субпиксельно-сглаженный текст с помощью сам по себе, будь то изображение или слой, отдельно заранее наличие фоновых пикселей для переплетения текстовых пикселей. Установочный свойство непрозрачности слоя YES не изменяет отрисовку режим.

второе предложение подразумевает, что можно получить красивый текст, если один composites на existing opaque background at the same time that it's rasterized. вот отлично, но как я его составлю, и как вы дадите ему непрозрачный фон, и как вы его растеризуете?

код, который они используют в своем примере меню киоска, таков: (это OS X, а не iOS, но я предполагаю, что он работает!)

NSInteger i;
for (i=0;i<[names count];i++) {
    CATextLayer *menuItemLayer=[CATextLayer layer];
    menuItemLayer.string=[self.names objectAtIndex:i];
    menuItemLayer.font=@"Lucida-Grande";
    menuItemLayer.fontSize=fontSize;
    menuItemLayer.foregroundColor=whiteColor;
    [menuItemLayer addConstraint:[CAConstraint
         constraintWithAttribute:kCAConstraintMaxY
                      relativeTo:@"superlayer"
                       attribute:kCAConstraintMaxY
                          offset:-(i*height+spacing+initialOffset)]];
    [menuItemLayer addConstraint:[CAConstraint
         constraintWithAttribute:kCAConstraintMidX
                      relativeTo:@"superlayer"
                       attribute:kCAConstraintMidX]];
    [self.menuLayer addSublayer:menuItemLayer];
} // end of for loop 

спасибо!


EDIT: добавление кода, который я фактически использовал, что привело к размытому тексту. Это из связанного вопроса, который я опубликовал о добавлении UILabel, а не CATextLayer но вместо этого получить черный ящик. http://stackoverflow.com/questions/3818676/adding-a-uilabels-layer-to-a-calayer-and-it-just-shows-black-box

CATextLayer* upperOperator = [[CATextLayer alloc] init];
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGFloat components1[4] = {1.0, 1.0, 1.0, 1.0};
CGColorRef almostWhite = CGColorCreate(space,components1);
CGFloat components2[4] = {0.0, 0.0, 0.0, 1.0};
CGColorRef almostBlack = CGColorCreate(space,components2);
CGColorSpaceRelease(space);
upperOperator.string = [NSString stringWithFormat:@"13"];
upperOperator.bounds = CGRectMake(0, 0, 100, 50);
upperOperator.foregroundColor = almostBlack;
upperOperator.backgroundColor = almostWhite;
upperOperator.position = CGPointMake(50.0, 25.0);
upperOperator.font = @"Helvetica-Bold";
upperOperator.fontSize = 48.0f;
upperOperator.borderColor = [UIColor redColor].CGColor;
upperOperator.borderWidth = 1;
upperOperator.alignmentMode = kCAAlignmentCenter;
[card addSublayer:upperOperator];
[upperOperator release];
CGColorRelease(almostWhite);
CGColorRelease(almostBlack);

EDIT 2: см. мой ответ ниже о том, как это было решено. sbg.

7 ответов


короткий ответ-вам нужно установить масштабирование содержимого:

textLayer.contentsScale = [[UIScreen mainScreen] scale];

некоторое время назад я узнал, что когда у вас есть пользовательский код рисования, вы должны проверить дисплей retina и соответствующим образом масштабировать графику. UIKit позаботится о большей части этого, включая масштабирование шрифта.

не так CATextLayer.

мой размытость пришли от .zPosition это не было нулем, то есть у меня было преобразование, примененное к моему родительскому слою. Установив это ноль, размытость исчезла и сменилась серьезной пикселизацией.

после поиска повсюду, я обнаружил, что вы можете установить .contentsScale на CATextLayer и вы можете установить его, чтобы [[UIScreen mainScreen] scale] чтобы соответствовать разрешению экрана. (Я предполагаю, что это работает для не-сетчатки, но я не проверял-слишком устал)

после этого для меня CATextLayer текст стал четким. Примечание - это не обязательно для родительского слоя.

и размытость? Он возвращается, когда ты вращаешься. в 3D, но вы не замечаете этого, потому что текст начинается ясно, и пока он находится в движении, вы не можете сказать.

решена!

Swift

установите текстовый слой в том же масштабе, что и экран.

textLayer.contentsScale = UIScreen.main.scale

перед:

enter image description here

после:

enter image description here


во-первых, я хотел отметить, что вы пометили свой вопрос с iOS, но менеджеры ограничений доступны только на OSX, поэтому я не уверен, как вы получаете это, чтобы работать, если вы не смогли связать с ним в симуляторе как-то. На устройстве, эта функция недоступна.

далее, я просто отмечу, что я часто создаю CATextLayers и никогда не имею проблемы размытия, о которой вы говорите, поэтому я знаю, что это можно сделать. В двух словах это размытие происходит потому что вы не располагаете свой слой на весь пиксель. Помните, что когда вы устанавливаете положение слоя, вы используете значения float для x и y. Если эти значения имеют числа после десятичной дроби, слой не будет расположен на весь пиксель и, следовательно, даст этот эффект размытия-степень которого зависит от фактических значений. Чтобы проверить это, просто создайте CATextLayer и явно добавьте его в дерево слоев, гарантируя, что ваш параметр position находится на всем пикселе. Для пример:

CATextLayer *textLayer = [CATextLayer layer];
[textLayer setBounds:CGRectMake(0.0f, 0.0f, 200.0f, 30.0f)];
[textLayer setPosition:CGPointMake(200.0f, 100.0f)];
[textLayer setString:@"Hello World!"];

[[self menuLayer] addSublayer:textLayer];

Если вы текст все еще размыты, то есть что-то еще не так. Размытый текст на текстовом слое является следствием неправильно написанного кода, а не предполагаемой возможности слоя. При добавлении слоев в родительский слой вы можете просто принудить значения x и y к ближайшему целому пикселю, и это должно решить вашу проблему размытия.


перед установкой shouldRasterize, вы должны:

  1. установите rasterizationScale базового слоя, который вы собираетесь растеризировать
  2. установите свойство contentsScale любых CATextLayers и, возможно, других типов слоев (это никогда не повредит)

Если вы не сделаете #1, то версия сетчатки подслоев будет выглядеть размытой, даже для нормальных CALayers.

- (void)viewDidLoad {
  [super viewDidLoad];

  CALayer *mainLayer = [[self view] layer];
  [mainLayer setRasterizationScale:[[UIScreen mainScreen] scale]];

  CATextLayer *messageLayer = [CATextLayer layer];
  [messageLayer setForegroundColor:[[UIColor blackColor] CGColor]];
  [messageLayer setContentsScale:[[UIScreen mainScreen] scale]];
  [messageLayer setFrame:CGRectMake(50, 170, 250, 50)];
  [messageLayer setString:(id)@"asdfasd"];

  [mainLayer addSublayer:messageLayer];

  [mainLayer setShouldRasterize:YES];
}

вы должны сделать 2 вещи, первое было упомянуто выше:

расширьте CATextLayer и установите свойства opaque и contentsScale для правильной поддержки retina display, затем визуализируйте с включенным сглаживанием для текста.

+ (TextActionLayer*) layer
{
  TextActionLayer *layer = [[TextActionLayer alloc] init];
  layer.opaque = TRUE;
  CGFloat scale = [[UIScreen mainScreen] scale];
  layer.contentsScale = scale;
  return [layer autorelease];
}

// Render after enabling with anti aliasing for text

- (void)drawInContext:(CGContextRef)ctx
{
    CGRect bounds = self.bounds;
    CGContextSetFillColorWithColor(ctx, self.backgroundColor);
    CGContextFillRect(ctx, bounds);
    CGContextSetShouldSmoothFonts(ctx, TRUE);
    [super drawInContext:ctx];
}

Если вы пришли искать здесь аналогичную проблему для CATextLayer в OSX, после того, как много стучать головой стены, я получил четкий текст, сделав:

text_layer.contentsScale = self.window!.backingScaleFactor

(Я также установил, что вид фонового слоя contentsScale должен быть одинаковым).


это быстрее и проще: вам просто нужно установить contentsScale

    CATextLayer *label = [[CATextLayer alloc] init];
    [label setFontSize:15];
    [label setContentsScale:[[UIScreen mainScreen] scale]];
    [label setFrame:CGRectMake(0, 0, 50, 50)];
    [label setString:@"test"];
    [label setAlignmentMode:kCAAlignmentCenter];
    [label setBackgroundColor:[[UIColor clearColor] CGColor]];
    [label setForegroundColor:[[UIColor blackColor] CGColor]];
    [self addSublayer:label];