94 votes

Comment faire en sorte que le texte d'un CATextLayer soit clair ?

J'ai fait un CALayer avec un ajout CATextLayer et le texte est flou. Dans la documentation, ils parlent d'un "anticrénelage sous-pixel", mais cela ne veut pas dire grand chose pour moi. Quelqu'un a t-il un extrait de code qui fait un CATextLayer avec un bout de texte qui est clair ?

Voici le texte de la documentation d'Apple :

Remarque : CATextLayer désactive l'anticrénelage sous-pixel lors du rendu du texte. Le texte ne peut être dessiné en utilisant l'anticrénelage sous-pixel que lorsqu'il est lorsqu'il est composé dans un arrière-plan opaque existant en même temps que le texte. qu'il est rastérisé. Il n'y a aucun moyen de dessiner du texte avec anticrénelage sous-pixel par lui-même, que ce soit dans une image ou dans un tableau. par lui-même, que ce soit dans une image ou un calque, séparément avant le avant de disposer des pixels d'arrière-plan dans lesquels tisser les pixels du texte. Le réglage de la propriété d'opacité du calque sur OUI ne change pas le mode de rendu. de rendu.

La deuxième phrase implique que l'on peut obtenir un texte de bonne qualité si l'on composites dans un existing opaque background at the same time that it's rasterized. C'est génial, mais comment le composer, comment lui donner un fond opaque et comment le rastériser ?

Le code qu'ils utilisent dans leur exemple de menu kiosque est le suivant : (C'est OS X, pas iOS, mais je suppose que cela fonctionne !)

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 

Gracias.


EDIT : Ajout du code que j'ai effectivement utilisé et qui a donné lieu à un texte flou. Il provient d'une question connexe que j'ai postée au sujet de l'ajout d'une balise UILabel plutôt qu'un CATextLayer mais en obtenant une boîte noire à la place. 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 : Voir ma réponse ci-dessous pour savoir comment cela a été résolu. sbg.

0 votes

Cela ne répondra pas à votre question, mais peut être pertinent pour quelqu'un comme moi qui cherche seulement à dessiner du texte attribué, d'une manière très similaire à l'utilisation de UILabel : stackoverflow.com/questions/3786528/

234voto

Steve Points 2692

Réponse courte - Vous devez définir la mise à l'échelle du contenu :

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

Il y a quelque temps, j'ai appris que lorsque vous disposez d'un code de dessin personnalisé, vous devez tenir compte de l'affichage de la rétine et adapter vos graphiques en conséquence. UIKit s'occupe de la plupart de ces tâches, y compris la mise à l'échelle des polices.

Ce n'est pas le cas avec CATextLayer.

Mon flou vient du fait que j'ai un .zPosition qui n'était pas zéro, c'est-à-dire que j'avais une transformation appliquée à mon calque parent. En mettant cette transformation à zéro, le flou a disparu et a été remplacé par une pixellisation importante.

Après avoir cherché partout, j'ai découvert qu'il était possible de définir .contentsScale pour un CATextLayer et vous pouvez le régler sur [[UIScreen mainScreen] scale] pour correspondre à la résolution de l'écran. (Je suppose que cela fonctionne pour les écrans non-rétina, mais je n'ai pas vérifié - trop fatigué).

Après avoir inclus ceci pour mon CATextLayer le texte est devenu net. Note - ce n'est pas nécessaire pour le calque parent.

Et le flou ? Il réapparaît lorsque vous effectuez une rotation en 3D, mais vous ne le remarquez pas parce que le texte est clair au départ et que vous ne pouvez pas le voir lorsqu'il est en mouvement.

Problème résolu !

37 votes

Voici la réponse courte : textLayer.contentScale = [[UIScreen mainScreen] scale]; BTW, j'aime aussi les réponses longues :)

0 votes

Cela s'applique à tout CALayer créé de manière programmatique. Par exemple, si vous remarquez que les images dessinées dans votre CALayer ne sont pas nettes sur l'écran de la rétine, il est probable que le problème et la solution soient là.

17 votes

Correction _textLayer.contentsScale = [[UIScreen mainScreen] scale]; Il vous manque un "s" ;)

40voto

Suragch Points 197

Swift

Configurez le calque de texte pour qu'il utilise la même échelle que l'écran.

textLayer.contentsScale = UIScreen.main.scale

Avant :

enter image description here

Après :

enter image description here

15voto

Matt Long Points 16701

Tout d'abord, je voulais souligner que vous avez étiqueté votre question avec iOS, mais les gestionnaires de contraintes ne sont disponibles que sur OSX, donc je ne suis pas sûr de savoir comment vous arrivez à faire fonctionner cela, à moins que vous ayez été en mesure de le lier dans le simulateur en quelque sorte. Sur l'appareil, cette fonctionnalité n'est pas disponible.

Ensuite, je tiens à préciser que je crée souvent des CATextLayers et que je n'ai jamais eu le problème de flou auquel vous faites référence, donc je sais que c'est possible. En bref, ce flou se produit parce que vous ne positionnez pas votre calque sur l'ensemble du pixel. Rappelez-vous que lorsque vous définissez la position d'un calque, vous utilisez des valeurs flottantes pour les x et y. Si ces valeurs comportent des chiffres après la virgule, le calque ne sera pas positionné sur l'ensemble du pixel et donnera donc cet effet de flou - dont le degré dépend des valeurs réelles. Pour tester cela, il suffit de créer un CATextLayer et de l'ajouter explicitement à l'arbre des calques en veillant à ce que votre paramètre de position soit sur un pixel entier. Par exemple :

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];

Si votre texte est toujours flou, il y a un autre problème. Le texte flou sur votre calque de texte est un artefact de code mal écrit et non une capacité prévue du calque. Lorsque vous ajoutez vos calques à un calque parent, vous pouvez simplement contraindre les valeurs x et y au pixel entier le plus proche et cela devrait résoudre votre problème de flou.

15voto

Gabe Points 1563

Avant de définir shouldRasterize, vous devez :

  1. Définissez l'échelle de rastérisation de la couche de base que vous allez rastériser.
  2. définir la propriété contentsScale de tout CATextLayers et éventuellement d'autres types de couches (cela ne fait jamais de mal de le faire).

Si vous ne faites pas la première étape, la version rétine des sous-couches sera floue, même pour les CALayers normaux.

- (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];
}

4voto

MoDJ Points 1343

Vous devez faire deux choses, la première a été mentionnée ci-dessus :

Étendez CATextLayer et définissez les propriétés opaque et contentsScale pour prendre en charge correctement l'affichage rétina, puis effectuez le rendu avec l'anticrénelage activé pour le texte.

+ (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];
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X