31 votes

Faux antialiasing sous-pixel sur du texte avec animation de base

Pour toute personne qui travaille sur un projet avec Core Animation couche adossés à des points de vue, il est malheureusement évident que les sous-pixel de l'anticrénelage (lissage de texte) est désactivé pour des textes qui ne sont pas rendus sur un arrière-plan opaque. Maintenant, pour les personnes qui sont en mesure de définir opaque horizons pour leur texte (avec un setBackgroundColor: appel ou le paramètre équivalent dans Interface Builder), cette question n'est pas trop un problème. Pour d'autres, cependant, qui n'ont absolument aucun moyen de le contourner, ce n'est pas quelque chose que l'on peut ignorer.

J'ai été à la recherche en ligne pour bien plus de deux jours pour trouver une solution, et rien d'utilisable a venir. Tout ce que je veux faire est de créer une étiquette de texte (pas modifiable par l'utilisateur) qui est prévue sur une feuille de fenêtre (fenêtre feuille de milieux transparents, de sorte d'avoir la feuille de contenu de vue déclarer wantsLayer comme vrai désactive le lissage de texte pour toutes les étiquettes de la fenêtre); quelque chose de très simple. J'ai vu beaucoup de contestés solutions (une rapide recherche sur Google va mettre ce sujet dans de nombreux autres endroits), mais jusqu'à présent, toutes ces solutions s'appuient sur des personnes capables et disposés à faire des compromis avec un arrière-plan opaque (vous ne pouvez pas l'utiliser sur une feuille).

Jusqu'à présent, la meilleure direction que je peux imaginer de prendre ce est pré-rendu du texte avec le lissage de texte sur une image, puis l'affichage de l'image, comme d'habitude sur une couche adossés à vue. Cependant, cela ne semble pas être possible. "Normal", je ne l'assume on pourrait faire est d'essayer cela:

NSAttributedString *string = [[self cell] attributedStringValue];
NSImage *textImage = [[NSImage alloc] initWithSize:[string size]];
[textImage lockFocus];
[string drawAtPoint:NSZeroPoint];
[textImage unlockFocus];

Mais cela ne semble pas fonctionner (le plus probable parce que, lorsqu'il est appelé à partir d' drawRect:, le contexte graphique mis en place a déjà lissage de texte handicapés - sous-pixel de l'anticrénelage est éteint et régulière de l'antialiasing est utilisé à la place), mais aucun n'a plus de solution à cette question (où vous créez votre propre contexte graphique).

Alors, comment est en train de faire quelque chose comme cela possible? Pouvez-vous en quelque sorte de "faux" l'effet de lissage de texte? Sont là, même hack-ish solutions qui permettront d'obtenir quelque chose à configurer? Je ne veux vraiment pas avoir à abandonner Core Animation, juste à cause de cette stupide question; il y a beaucoup d'avantages à ce que d'économiser beaucoup de temps et de code.


Edit: Après beaucoup de recherche, j'ai trouvé quelque chose. Bien que le fil lui-même seulement réaffirme mes soupçons, je pense que j'ai peut-être trouvé une solution à ce problème: la coutume CALayer dessin. Timothy Bois, dans une de ses réponses, ci-joint un exemple de projet qui montre le lissage des polices à l'aide de plusieurs techniques, plusieurs travaux. Je vais regarder dans l'intégrer dans mon projet.

Edit #2: s'avère, le lien ci-dessus est un buste ainsi. Bien que les méthodes liées donner de sous-pixel de l'antialiasing, ils ne réussissent pas aussi bien sur des arrière-plans transparents.

9voto

LaC Points 7191

Si vous utilisez une feuille transparente, vous ne savez pas à l'avance ce que les pixels au-dessous de il sera. Ils peuvent changer. Rappelez-vous que vous avez un seul canal alpha pour trois couleurs: si vous la rendre transparente, vous ne verrez pas de sous-pixel en effet, mais si vous le faites opaque, tous trois sous-éléments vont montage est effectué avec l'arrière-plan. Si vous donner un avantage de la bonne couleur pour le montage sur un fond blanc, il ne sera pas regarder à droite, si l'arrière-plan des modifications à certaines autres couleurs.

Par exemple, disons que vous êtes le dessin du texte noir sur un fond blanc, et le sous-élément de commande est en mode RVB. Un bord droit peut être un bleu pâle: haute valeur B (plein de luminosité sur le côté, loin de la glyphe), légèrement plus faible, mais toujours de haute R et de G des valeurs (luminosité plus faible sur le côté le plus proche de la glyphe). Maintenant, si vous le compositing de pixel sur un fond gris foncé, vous allez le rendre plus léger qu'il ne l'aurait été si vous aviez rendu du texte noir sur fond gris foncé directement.

Fondamentalement, vous n'êtes pas face à une limitation arbitraire de CoreAnimation: il fait tout simplement pas de sens pour l'utilisation de sous-pixel rendering sur une couche transparente qui peut être combiné à un arrière-plan arbitraire. Vous auriez besoin d'un alpha par canal de couleur, mais depuis que le format de pixel de votre tampon est RGBA (ou ARGB ou quoi que ce soit), vous ne pouvez pas l'avoir.

Mais cela nous amène à la solution. Si vous savez que le fond restera le même (par exemple, la feuille s'affiche sur une fenêtre dont le contenu vous de contrôle), alors vous pouvez simplement faire de votre couche d'opaque, de le remplir avec une copie de la région de l'arrière-plan de la fenêtre, et le rendu de sous-pixel-crénelage du texte. Fondamentalement, vous seriez precompositing votre calque avec le fond. Si le fond reste le même, ce sera identique à ce que l'normale composition alpha ferait, sauf que vous pouvez maintenant faire des sous-pixel de l'affichage de texte; si le décor change, alors que vous auriez à renoncer à faire des sous-pixel de l'affichage de texte, de toute façon (même si je suppose que vous pourriez garder copie de l'arrière-plan et de redessiner votre couche opaque à chaque changement).

2voto

Dietrich Epp Points 72865

En tant que simple hack, si l'anti-aliasing de texte fonctionne (mais pas en sous-pixels), vous pouvez le simuler en le rendant dans une vue qui est 3x plus large, puis en le réduisant. Ce n'est pas portable car je ne connais aucun moyen d'interroger l'ordre des éléments sur votre affichage, mais cela devrait fonctionner.

Par exemple,

 RGB RGB RGB -> RGB
|    |    |    |||  
|    |    +----++^
|    +---------+^
+--------------^
 

2voto

Chris Burt-Brown Points 2423

Je ne suis pas vraiment sûr, j'ai saisi la question, donc c'est une vraie barque à fond plat.

Mais j'ai remarqué LaC de la réponse dépend des pixels d'être écrites sur le dessus les uns des autres dans la façon normale. De la manière que vous le feriez dans Photoshop appeler le "Mode de Fusion Normal".

Vous pouvez fusionner les deux calques dans beaucoup de façons, y compris la "Multipliez-vous":

enter image description here

Cette multiplie les de R, G et B de chaque pixel. Donc, si vous aviez le texte sur un fond blanc, vous pourriez obtenir une plus-couche arrière de montrer à travers par la définition de la couche supérieure "Multiplier" qui fait que les deux couches de brûler les uns les autres comme si.

Cela devrait fonctionner pour votre cas d'utilisation de trop:

enter image description here

Les deux couches de texte dans cette photo ont un arrière-plan blanc opaque, mais celui de droite est le mode de fusion sur "Multiplier".

Avec "Multipliez-Vous":

  • les pixels blancs dans la couche supérieure, de multiplier les couches inférieures de 1, en laissant inchangés
  • les pixels noirs dans la couche supérieure, de multiplier les couches inférieures par 0, en les réduisant à noir
  • les nuances entre les deux assombrir les couches inférieures proportionnellement

En d'autres termes, le même résultat que vous avez obtenu juste la pose du texte directement sur le fond.

Je n'ai pas de sous-pixel antialiased le texte dans cette capture d'écran, mais ça marcherait aussi bien avec les différentes R, G, B et valeurs.


Je ne suis pas à distance familier avec Mac API, mais d'après ce lien, Core Animation n'ont cette capacité, que vous pouvez obtenir par écrit:

myLayer.compositingFilter = [CIFilter filterWithName:@"CIMultiplyBlendMode"];

ou

myLayer.compositingFilter = [CIFilter filterWithName:@"CIMultiplyCompositing"];

(Je n'ai aucune idée de ce "Mode de Fusion" vs "Compositing" se rapporte au Mac le langage de sorte que vous aurez à essayer les deux!)


EDIT: je ne suis pas sûr que vous avez déjà défini votre texte était Noir. Si elle est Blanche, vous pouvez utiliser un blanc-sur-noir de la couche de définir un Mode de Fusion "Écran".

-3voto

Nathan Day Points 3672

Je ne sais pas si cette solution fonctionnera pour vous, mais pouvez-vous dessiner le texte dans une image avec un fond transparent en utilisant UIGraphicsBeginImageContext (), je suis presque sûr que vous pouvez configurer un alias pour cela, sinon vous dessinez votre texte deux fois ou 4 fois la taille, puis réduisez l'échelle lorsque vous dessinez l'image dans votre vue.

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