Как получить текст в CATextLayer, чтобы быть понятным - PullRequest
91 голосов
/ 28 сентября 2010

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

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

Примечание: CATextLayer отключает субпиксельное сглаживаниепри рендеринге текста.Текст может быть нарисован только с использованием субпиксельного сглаживания, когда он скомпонован в существующий непрозрачный фон одновременно с растеризацией.Нет никакого способа нарисовать текст с сглаживанием субпикселей сам по себе, будь то изображение или слой, отдельно до появления фоновых пикселей, в которые будут вплетаться пиксели текста.Если для свойства opacity слоя задано значение 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 

Спасибо!


РЕДАКТИРОВАТЬ: Добавление кода, который я на самом деле использовал, что привело к размытым текстом.Это из родственного вопроса, который я написал о добавлении 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);

РЕДАКТИРОВАТЬ 2: Смотрите мой ответ ниже, как это было решено.SBG.

Ответы [ 7 ]

220 голосов
/ 05 октября 2010

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

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

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

Не так с CATextLayer.

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

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

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

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

Проблема решена!

31 голосов
/ 01 января 2016

Swift

Установите для текстового слоя тот же масштаб, что и для экрана.

textLayer.contentsScale = UIScreen.main.scale

До:

enter image description here

После того, как:

enter image description here

17 голосов
/ 30 сентября 2010

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

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

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 к ближайшему целому пикселю, и это должно решить вашу проблему размытия.

14 голосов
/ 22 ноября 2010

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

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

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

- (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];
}
4 голосов
/ 20 августа 2011

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

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

+ (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];
}
2 голосов
/ 05 февраля 2015

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

text_layer.contentsScale = self.window!.backingScaleFactor

(я также установил тот же уровень содержимого фона фона представлений).

0 голосов
/ 14 ноября 2015

Это быстрее и проще: вам просто нужно установить 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];
...