Net olmak için CATextLayer'da metin nasıl alınır


94

Bir yaptık CALayereklenen bir ile CATextLayerve metin bulanık çıkar. Dokümanlarda "alt piksel yumuşatma" dan bahsediyorlar ama bu benim için pek bir şey ifade etmiyor. CATextLayerNet olan bir metinle bir kod parçacığı yapan var mı?

Apple'ın belgelerinden metin şu şekildedir:

Not: CATextLayer, metni işlerken alt piksel yumuşatmayı devre dışı bırakır. Metin, yalnızca rasterleştirilmesiyle aynı zamanda mevcut opak bir arka planda birleştirildiğinde alt piksel yumuşatma kullanılarak çizilebilir. Metin piksellerini örmek için arka plan piksellerine sahip olmadan önce, bir görüntü veya bir katman içine, alt piksel-anti-yalınlaştırılmış metni kendi başına ayrı ayrı çizmenin bir yolu yoktur. Katmanın opaklık özelliğinin EVET olarak ayarlanması, oluşturma modunu değiştirmez.

İkinci cümle, birinin güzel görünen bir metni compositesbir existing opaque background at the same time that it's rasterized. Bu harika haline getirebileceğini ima eder , ancak onu nasıl birleştiririm ve ona opak bir arka plan verir ve onu nasıl rasterleştirirsiniz?

Kiosk Menüsü örneğinde kullandıkları kod şu şekildedir: (OS X, iOS değil, ancak çalıştığını varsayıyorum!)

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 

Teşekkürler!


DÜZENLEME: Aslında kullandığım kodu eklemek bulanık metinle sonuçlandı. Bu, a UILabelyerine CATextLayerbir kara kutu eklemekle ilgili yayınladığım ilgili bir sorudan . 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);

DÜZENLEME 2: Bunun nasıl çözüldüğünü öğrenmek için aşağıdaki cevabıma bakın. sbg.


Bu, sorunuzu yanıtlamaz, ancak UILabel kullanmaya çok benzer bir şekilde yalnızca atıfta
bulunulan

Yanıtlar:


231

Kısa cevap - İçerik ölçeklemesini ayarlamanız gerekir:

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

Bir süre önce, özel çizim kodunuz olduğunda retina ekranını kontrol etmeniz ve grafiklerinizi buna göre ölçeklendirmeniz gerektiğini öğrendim. UIKityazı tipi ölçekleme de dahil olmak üzere bunun çoğunu halleder.

Öyle değil CATextLayer.

Bulanıklığım .zPositionsıfır olmayan bir a sahip olmaktan geldi , yani üst katmanıma uygulanan bir dönüşüm vardı. Bunu sıfıra ayarlayarak, bulanıklık ortadan kalktı ve yerini ciddi pikselleşme aldı.

Arama en yüksek ve en düşük sonra ayarlayabileceğiniz bulundu .contentsScalebir için CATextLayerve bunu ayarlayabilirsiniz [[UIScreen mainScreen] scale]ekran çözünürlüğü maç. (Bunun retina dışı için işe yaradığını varsayıyorum, ancak kontrol etmedim - çok yorgun)

Bunu metnime ekledikten CATextLayersonra netleşti. Not - ana katman için gerekli değildir.

Ve bulanıklık? 3B'de döndüğünüzde geri gelir, ancak fark etmezsiniz çünkü metin net olarak başlar ve hareket halindeyken söyleyemezsiniz.

Sorun çözüldü!


37
Kısa cevap bu: textLayer.contentScale = [[UIScreen mainScreen] scale]; BTW, ben de uzun cevapları seviyorum :)
nacho4d

Bu, programlı olarak oluşturulan tüm CALayer'lar için geçerlidir. Örneğin, CALayer'ınıza çizilen görüntülerin retina ekranında net olmadığını fark ederseniz, büyük olasılıkla sorun ve çözüm budur.
Jeff Argast

17
Düzeltme _textLayer.contentsScale = [[UIScreen mainScreen] scale]; Bir "s" eksik;)
Ralphleon

1
Bu benim için çalışmıyor. AVVideoCompositionCoreAnimationTool tarafından bir videoya (AVFoundation / AVMutableComposition) CATextLayer ekliyorum. Metnin hala takma adı var.
vietstone

mac
osx'te

36

Swift

Metin katmanını ekranla aynı ölçeği kullanacak şekilde ayarlayın.

textLayer.contentsScale = UIScreen.main.scale

Önce:

görüntü açıklamasını buraya girin

Sonra:

görüntü açıklamasını buraya girin


macOS swift 4.2 sürümü: (NSScreen.main? .backingScaleFactor)!
roberto

16

Öncelikle sorunuzu iOS ile etiketlediğinizi belirtmek istedim, ancak kısıtlama yöneticileri yalnızca OSX'te mevcut, bu yüzden ona karşı bağlantı kuramadığınız sürece bunu nasıl çalıştıracağınızdan emin değilim simülatörde bir şekilde. Cihazda bu işlev mevcut değildir.

Daha sonra, CATextLayers'ı sık sık oluşturduğumu ve bahsettiğiniz bulanık sorunu asla yaşamadığımı, bu yüzden yapılabileceğini biliyorum. Özetle, bu bulanıklaşma, katmanınızı tüm piksel üzerinde konumlandırmadığınız için oluşur. Bir katmanın konumunu belirlediğinizde, x ve y için bir float değerleri kullandığınızı unutmayın. Bu değerlerin ondalık sayıdan sonra sayıları varsa, katman pikselin tamamına yerleştirilmeyecek ve bu nedenle, derecesi gerçek değerlere bağlı olan bu bulanıklaştırma etkisini verecektir. Bunu test etmek için, sadece bir CATextLayer oluşturun ve bunu, konum parametrenizin tam bir pikselde olduğundan emin olarak katman ağacına açıkça ekleyin. Örneğin:

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

Metniniz hala bulanıksa, başka bir sorun var demektir. Metin katmanınızdaki bulanık metin, yanlış yazılmış kodun bir ürünüdür ve katmanın amaçlanan bir yeteneği değildir. Katmanlarınızı bir ana katmana eklerken, x ve y değerlerini en yakın tam piksele zorlayabilirsiniz ve bu, bulanıklaştırma sorununuzu çözmelidir.


15

ShouldRasterize ayarlamadan önce şunları yapmalısınız:

  1. Rasterleştireceğiniz temel katmanın piksel ölçeğini ayarlayın
  2. Herhangi bir CATextLayers ve muhtemelen diğer katman türlerinin ContentScale özelliğini ayarlayın (bunu yapmak asla zarar vermez)

# 1 yapmazsanız, alt katmanların retina versiyonu normal CALayer'lar için bile bulanık görünecektir.

- (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

2 şey yapmalısınız, ilki yukarıda belirtilmişti:

CATextLayer'ı genişletin ve opaque ve contentScale özelliklerini retina görüntülemeyi düzgün şekilde destekleyecek şekilde ayarlayın, ardından metin için kenar yumuşatma etkinleştirilmiş olarak oluşturun.

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

3

Buraya OSX'te bir CATextLayer için benzer bir sorun aramaya geldiyseniz, çok fazla duvar başını vurduktan sonra, keskin ve net metni şu şekilde elde ettim:

text_layer.contentsScale = self.window!.backingScaleFactor

(Ayrıca görünümler arka plan katmanı contentScale'i aynı olacak şekilde ayarladım).


0

Bu daha hızlı ve daha kolaydır: sadece içeriği ayarlamanız gerekir

    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];
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.