Làm thế nào để văn bản trong CATextLayer trở nên rõ ràng


92

Tôi đã thực hiện một CALayervới một được thêm vào CATextLayervà văn bản bị mờ. Trong tài liệu, họ nói về "khử răng cưa điểm ảnh phụ", nhưng điều đó không có nhiều ý nghĩa với tôi. Có ai có đoạn mã tạo ra một đoạn CATextLayervăn bản rõ ràng không?

Đây là nội dung từ tài liệu của Apple:

Lưu ý: CATextLayer vô hiệu hóa khử răng cưa pixel phụ khi hiển thị văn bản. Văn bản chỉ có thể được vẽ bằng cách sử dụng khử răng cưa pixel phụ khi nó được kết hợp vào một nền mờ hiện có cùng thời điểm nó được tạo ra. Không có cách nào để tự vẽ văn bản subpixel-antialiased, cho dù vào một hình ảnh hay một lớp, trước khi có các pixel nền để đan các pixel văn bản vào. Đặt thuộc tính độ mờ đục của lớp thành CÓ không thay đổi chế độ hiển thị.

Câu thứ hai ngụ ý rằng người ta có thể có được văn bản đẹp nếu một văn bản compositesđó thành Một cái existing opaque background at the same time that it's rasterized. đó thật tuyệt, nhưng làm cách nào để kết hợp nó và làm thế nào để bạn tạo cho nó một nền mờ và làm thế nào để bạn phân loại nó?

Mã họ sử dụng trong ví dụ về Menu Kiosk như sau: (Đó là OS X, không phải iOS, nhưng tôi cho rằng nó hoạt động!)

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 

Cảm ơn!


CHỈNH SỬA: Thêm mã mà tôi thực sự đã sử dụng dẫn đến văn bản bị mờ. Đó là từ một câu hỏi liên quan mà tôi đã đăng về việc thêm một UILabelchứ không phải một CATextLayernhưng thay vào đó nhận được một hộp đen. 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);

CHỈNH SỬA 2: Xem câu trả lời của tôi bên dưới để biết cách giải quyết vấn đề này. sbg.


Điều này sẽ không trả lời câu hỏi của bạn, nhưng có thể phù hợp với một người như tôi, người chỉ tìm cách vẽ văn bản được quy, theo cách gần giống với việc sử dụng UILabel: stackoverflow.com/questions/3786528/…
DenNukem

Câu trả lời:


228

Câu trả lời ngắn gọn - Bạn cần đặt tỷ lệ nội dung:

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

Một thời gian trước, tôi đã biết rằng khi bạn có mã vẽ tùy chỉnh, bạn phải kiểm tra màn hình hiển thị võng mạc và chia tỷ lệ đồ họa của bạn cho phù hợp. UIKitchăm sóc hầu hết điều này, bao gồm cả việc chia tỷ lệ phông chữ.

Không phải như vậy với CATextLayer.

Độ mờ của tôi đến từ việc có một .zPositionđiểm khác không, tức là tôi đã áp dụng một phép biến đổi cho lớp cha của mình. Bằng cách đặt điều này thành 0, độ mờ biến mất và được thay thế bằng hiện tượng pixel hóa nghiêm trọng.

Sau khi tìm kiếm cao và thấp, tôi thấy rằng bạn có thể đặt .contentsScalecho a CATextLayervà bạn có thể đặt thành [[UIScreen mainScreen] scale]để phù hợp với độ phân giải màn hình. (Tôi cho rằng điều này hoạt động đối với những người không có võng mạc, nhưng tôi chưa kiểm tra - quá mệt mỏi)

Sau khi bao gồm điều này cho CATextLayervăn bản của tôi trở nên sắc nét. Lưu ý - nó không cần thiết cho lớp cha.

Và độ mờ? Nó quay lại khi bạn đang xoay ở chế độ 3D, nhưng bạn không nhận thấy nó vì văn bản bắt đầu rõ ràng và trong khi nó đang chuyển động, bạn không thể biết được.

Vấn đề đã được giải quyết!


37
Đây là câu trả lời ngắn: textLayer.contentScale = [[UIScreen mainScreen] scale]; BTW, tôi giống như câu trả lời dài quá :)
nacho4d

Điều này áp dụng cho bất kỳ CALayer nào được tạo theo chương trình. Ví dụ: nếu bạn nhận thấy hình ảnh được vẽ vào CALayer của bạn không sắc nét trên màn hình võng mạc, có thể đây là vấn đề và giải pháp.
Jeff Argast

17
Sửa lại _textLayer.contentsScale = [[UIScreen mainScreen] scale]; Bạn đang thiếu một "s";)
Ralphleon

1
Điều này không hiệu quả với tôi. Tôi thêm CATextLayer vào video (AVFoundation / AVMutableComposition) bằng AVVideoCompositionCoreAnimationTool. Văn bản vẫn có răng cưa.
vietstone

không có tùy chọn tỷ lệ trong mac osx
Sangram Shivankar

35

Nhanh

Đặt lớp văn bản sử dụng cùng tỷ lệ với màn hình.

textLayer.contentsScale = UIScreen.main.scale

Trước:

nhập mô tả hình ảnh ở đây

Sau:

nhập mô tả hình ảnh ở đây


Phiên bản macOS swift 4.2: (NSScreen.main? .backingScaleFactor)!
roberto

17

Trước hết, tôi muốn chỉ ra rằng bạn đã gắn thẻ câu hỏi của mình với iOS, nhưng trình quản lý ràng buộc chỉ có sẵn trên OSX, vì vậy tôi không chắc bạn làm cách nào để điều này hoạt động trừ khi bạn có thể liên kết với nó trong trình mô phỏng bằng cách nào đó. Trên thiết bị, chức năng này không khả dụng.

Tiếp theo, tôi sẽ chỉ ra rằng tôi tạo CATextLayers thường xuyên và không bao giờ gặp vấn đề làm mờ mà bạn đang đề cập đến vì vậy tôi biết nó có thể được thực hiện. Tóm lại, hiện tượng mờ này xảy ra do bạn không định vị lớp của mình trên toàn bộ pixel. Hãy nhớ rằng khi bạn đặt vị trí của một lớp, bạn sử dụng các giá trị float cho x và y. Nếu các giá trị đó có số sau số thập phân, lớp sẽ không được định vị trên toàn bộ pixel và do đó sẽ tạo ra hiệu ứng làm mờ này - mức độ tùy thuộc vào giá trị thực tế. Để kiểm tra điều này, chỉ cần tạo CATextLayer và thêm rõ ràng nó vào cây lớp đảm bảo rằng thông số vị trí của bạn nằm trên toàn bộ pixel. Ví dụ:

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

Nếu văn bản của bạn vẫn bị mờ, thì có điều gì đó sai khác. Văn bản bị mờ trên lớp văn bản của bạn là tạo tác của mã được viết không chính xác và không phải là khả năng dự kiến ​​của lớp. Khi thêm các lớp của bạn vào một lớp mẹ, bạn chỉ có thể ép các giá trị x và y đến toàn bộ pixel gần nhất và nó sẽ giải quyết được vấn đề làm mờ của bạn.


15

Trước khi thiết lập shouldRasterize, bạn nên:

  1. đặt rasterizationScale của lớp cơ sở mà bạn sẽ phân loại
  2. thiết lập thuộc tính ContentScale của bất kỳ CATextLayers nào và có thể là các loại lớp khác (không bao giờ có hại khi làm điều đó)

Nếu bạn không làm số 1, thì phiên bản võng mạc của các lớp phụ sẽ trông mờ, ngay cả đối với những CALayers bình thường.

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

Bạn nên làm 2 điều, điều đầu tiên đã được đề cập ở trên:

Mở rộng CATextLayer và đặt các thuộc tính đục và nội dungScale để hỗ trợ đúng cách hiển thị võng mạc, sau đó hiển thị với tính năng khử răng cưa cho văn bản.

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

Nếu bạn đến đây tìm kiếm vấn đề tương tự cho CATextLayer trong OSX, sau nhiều lần va chạm mạnh vào tường, tôi đã nhận được văn bản rõ ràng sắc nét bằng cách:

text_layer.contentsScale = self.window!.backingScaleFactor

(Tôi cũng đặt các chế độ xem background layer contentScale giống nhau).


0

Điều này nhanh hơn và dễ dàng hơn: bạn chỉ cần đặt nội dung

    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];
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.