So erhalten Sie Text in einem CATextLayer, um klar zu sein

92

Ich habe eine CALayermit einem hinzugefügt CATextLayerund der Text kommt verschwommen heraus. In den Dokumenten wird von "Subpixel-Antialiasing" gesprochen, aber das bedeutet mir nicht viel. Hat jemand ein Code-Snippet, das CATextLayermit ein bisschen Text ein klares macht?

Hier ist der Text aus Apples Dokumentation:

Hinweis: CATextLayer deaktiviert das Subpixel-Antialiasing beim Rendern von Text. Text kann nur mit Subpixel-Antialiasing gezeichnet werden, wenn er gleichzeitig mit dem Raster in einen vorhandenen undurchsichtigen Hintergrund eingefügt wird. Es gibt keine Möglichkeit, Text mit Subpixel-Antialiasing selbst in ein Bild oder eine Ebene zu zeichnen, bevor die Hintergrundpixel zum Weben der Textpixel vorhanden sind. Durch Festlegen der Deckkrafteigenschaft der Ebene auf JA wird der Rendermodus nicht geändert.

Der zweite Satz impliziert, dass man gut aussehenden Text erhalten kann, wenn man compositesihn in einen existing opaque background at the same time that it's rasterized. großen Text umwandelt. Aber wie kann ich ihn zusammensetzen und wie gibt man ihm einen undurchsichtigen Hintergrund und wie rastert man ihn?

Der Code, den sie in ihrem Beispiel für ein Kiosk-Menü verwenden, lautet wie folgt: (Es ist OS X, nicht iOS, aber ich gehe davon aus, dass es funktioniert!)

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 

Vielen Dank!


BEARBEITEN: Das Hinzufügen des Codes, den ich tatsächlich verwendet habe, führte zu verschwommenem Text. Es ist aus einer verwandten Frage , die ich über schrieb einen Zusatz und UILabelnicht als CATextLayeraber eine Black - Box stattdessen bekommen. 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: Siehe meine Antwort unten, wie dies gelöst wurde. sbg.

Steve
quelle
Dies wird Ihre Frage nicht beantworten, kann aber für jemanden wie mich relevant sein, der nur zugeschriebenen Text zeichnen möchte, ähnlich wie bei der Verwendung von UILabel: stackoverflow.com/questions/3786528/…
DenNukem

Antworten:

228

Kurze Antwort - Sie müssen die Inhaltsskalierung festlegen:

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

Vor einiger Zeit habe ich erfahren, dass Sie bei benutzerdefiniertem Zeichnungscode nach der Retina-Anzeige suchen und Ihre Grafiken entsprechend skalieren müssen. UIKitkümmert sich um das meiste, einschließlich der Skalierung von Schriftarten.

Nicht so bei CATextLayer.

Meine Unschärfe kam von einem Wert .zPosition, der nicht Null war, dh ich hatte eine Transformation auf meine übergeordnete Ebene angewendet. Durch Setzen auf Null wurde die Unschärfe beseitigt und durch eine ernsthafte Pixelung ersetzt.

Nach der Suche hoch und niedrig, fand ich , dass Sie festlegen können , .contentsScalefür ein CATextLayerund man kann es auf [[UIScreen mainScreen] scale]die Bildschirmauflösung anzupassen. (Ich gehe davon aus, dass dies bei Nicht-Netzhaut funktioniert, aber ich habe es nicht überprüft - zu müde)

Nachdem ich dies für mich aufgenommen hatte, wurde CATextLayerder Text klar. Hinweis - Für die übergeordnete Ebene ist dies nicht erforderlich.

Und die Unschärfe? Es kommt zurück, wenn Sie in 3D drehen, aber Sie bemerken es nicht, weil der Text klar beginnt und während er in Bewegung ist, können Sie es nicht sagen.

Problem gelöst!

Steve
quelle
37
Dies ist die kurze Antwort: textLayer.contentScale = [[UIScreen mainScreen] scale]; Übrigens, ich mag auch lange Antworten :)
nacho4d
Dies gilt für alle CALayer, die programmgesteuert erstellt werden. Wenn Sie beispielsweise feststellen, dass in Ihren CALayer gezeichnete Bilder auf dem Retina-Display nicht scharf sind, ist dies wahrscheinlich das Problem und die Lösung.
Jeff Argast
17
Korrektur _textLayer.contentsScale = [[UIScreen mainScreen] scale]; Sie vermissen ein "s";)
Ralphleon
1
Das funktioniert bei mir nicht. Ich füge einem Video (AVFoundation / AVMutableComposition) von AVVideoCompositionCoreAnimationTool einen CATextLayer hinzu. Der Text hat noch Aliasing.
Vietnam
Es gibt keine Skalierungsoption in Mac OSX
Sangram Shivankar
35

Schnell

Stellen Sie die Textebene so ein, dass sie den gleichen Maßstab wie der Bildschirm verwendet.

textLayer.contentsScale = UIScreen.main.scale

Vor:

Geben Sie hier die Bildbeschreibung ein

Nach dem:

Geben Sie hier die Bildbeschreibung ein

Suragch
quelle
macOS swift 4.2 version: (NSScreen.main? .backingScaleFactor)!
Roberto
17

Zunächst wollte ich darauf hinweisen, dass Sie Ihre Frage mit iOS markiert haben, Constraint-Manager jedoch nur unter OSX verfügbar sind. Daher bin ich mir nicht sicher, wie Sie dies zum Laufen bringen können, es sei denn, Sie konnten einen Link dazu erstellen irgendwie im Simulator. Auf dem Gerät ist diese Funktionalität nicht verfügbar.

Als nächstes möchte ich nur darauf hinweisen, dass ich CATextLayers häufig erstelle und nie das Unschärfeproblem habe, auf das Sie sich beziehen, damit ich weiß, dass dies möglich ist. Kurz gesagt, diese Unschärfe tritt auf, weil Sie Ihre Ebene nicht auf dem gesamten Pixel positionieren. Denken Sie daran, dass Sie beim Festlegen der Position einer Ebene Gleitkommawerte für x und y verwenden. Wenn diese Werte Zahlen nach der Dezimalstelle haben, wird die Ebene nicht auf dem gesamten Pixel positioniert und führt daher zu diesem Unschärfeeffekt, dessen Grad von den tatsächlichen Werten abhängt. Um dies zu testen, erstellen Sie einfach einen CATextLayer und fügen Sie ihn explizit zum Ebenenbaum hinzu, um sicherzustellen, dass sich Ihr Positionsparameter auf einem ganzen Pixel befindet. Beispielsweise:

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

Wenn Ihr Text immer noch verschwommen ist, stimmt etwas anderes nicht. Verschwommener Text auf Ihrer Textebene ist ein Artefakt von falsch geschriebenem Code und keine beabsichtigte Fähigkeit der Ebene. Wenn Sie Ihre Ebenen zu einer übergeordneten Ebene hinzufügen, können Sie die x- und y-Werte einfach auf das nächste ganze Pixel zwingen. Dies sollte Ihr Unschärfeproblem lösen.

Matt Long
quelle
15

Bevor Sie shouldRasterize einstellen, sollten Sie:

  1. Legen Sie die Rasterisierungsskala der Basisebene fest, die Sie rastern möchten
  2. Legen Sie die contentScale-Eigenschaft von CATextLayers und möglicherweise anderen Arten von Ebenen fest (es tut nie weh, dies zu tun).

Wenn Sie # 1 nicht ausführen, sieht die Retina-Version der Unterschichten selbst bei normalen CALayern verschwommen aus.

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

Sie sollten zwei Dinge tun, die erste wurde oben erwähnt:

Erweitern Sie CATextLayer und legen Sie die Eigenschaften opaque und contentScale so fest, dass die Retina-Anzeige ordnungsgemäß unterstützt wird. Rendern Sie dann mit aktiviertem Anti-Aliasing für Text.

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

Wenn Sie hier nach einem ähnlichen Problem für einen CATextLayer in OSX gesucht haben, habe ich nach vielem Kopfschlag den scharfen Klartext erhalten, indem ich Folgendes getan habe:

text_layer.contentsScale = self.window!.backingScaleFactor

(Ich habe auch den Inhalt der Hintergrundebene für Ansichten gleich eingestellt).

james_alvarez
quelle
0

Dies ist schneller und einfacher: Sie müssen nur contentScale festlegen

    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];
Alejandro Luengo
quelle