Partager via


Chemins et texte dans SkiaSharp

Explorer l’intersection des chemins d’accès et du texte

Dans les systèmes graphiques modernes, les polices de texte sont des collections de contours de caractères, généralement définies par des courbes de Bézier quadratique. Par conséquent, de nombreux systèmes graphiques modernes incluent une fonctionnalité permettant de convertir des caractères de texte en chemin d’accès graphique.

Vous avez déjà vu que vous pouvez traiter les contours des caractères de texte, ainsi que les remplir. Cela vous permet d’afficher ces contours de caractères avec une largeur de trait particulière et même un effet de chemin comme décrit dans l’article Effets du chemin d’accès. Mais il est également possible de convertir une chaîne de caractères en objet SKPath . Cela signifie que les contours de texte peuvent être utilisés pour la capture avec des techniques décrites dans l’article Clipping with Paths and Regions .

Outre l’utilisation d’un effet de chemin d’accès pour traiter un contour de caractère, vous pouvez également créer des effets de chemin d’accès basés sur un chemin dérivé d’une chaîne de caractères, et vous pouvez même combiner les deux effets :

Effet de chemin d’accès au texte

Dans l’article précédent sur les effets de chemin d’accès, vous avez vu comment la GetFillPath méthode de SKPaint peut obtenir un contour d’un chemin tracé. Vous pouvez également utiliser cette méthode avec des chemins dérivés de contours de caractères.

Enfin, cet article illustre une autre intersection de chemins d’accès et de texte : la DrawTextOnPath méthode de vous permet d’afficher une chaîne de SKCanvas texte afin que la ligne de base du texte suit un chemin courbé.

Conversion de texte en chemin

La GetTextPath méthode de conversion d’une chaîne de SKPaint caractères en objet SKPath :

public SKPath GetTextPath (String text, Single x, Single y)

Les x arguments et y les arguments indiquent le point de départ de la ligne de base du côté gauche du texte. Ils jouent ici le même rôle que dans la DrawText méthode de SKCanvas. Dans le chemin, la ligne de base du côté gauche du texte aura les coordonnées (x, y).

La GetTextPath méthode est excessive si vous souhaitez simplement remplir ou traiter le chemin résultant. La méthode normale DrawText vous permet de le faire. La GetTextPath méthode est plus utile pour d’autres tâches impliquant des chemins d’accès.

L’une de ces tâches consiste à découper. La page Texte de découpage crée un chemin de découpage en fonction des contours de caractères du mot « CODE ». Ce chemin d’accès est étendu à la taille de la page pour découper une bitmap qui contient une image du code source du texte de découpage :

Capture d’écran triple de la page Texte de découpage

Le ClippingTextPage constructeur de classe charge la bitmap stockée en tant que ressource incorporée dans le dossier Media de la solution :

public class ClippingTextPage : ContentPage
{
    SKBitmap bitmap;

    public ClippingTextPage()
    {
        Title = "Clipping Text";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;

        string resourceID = "SkiaSharpFormsDemos.Media.PageOfCode.png";
        Assembly assembly = GetType().GetTypeInfo().Assembly;

        using (Stream stream = assembly.GetManifestResourceStream(resourceID))
        {
            bitmap = SKBitmap.Decode(stream);
        }
    }
    ...
}

Le PaintSurface gestionnaire commence par créer un SKPaint objet adapté au texte. La Typeface propriété est définie ainsi que le TextSize, bien que pour cette application particulière, la TextSize propriété soit purement arbitraire. Notez également qu’il n’existe aucun Style paramètre.

Les TextSize paramètres de propriété ne Style sont pas nécessaires, car cet SKPaint objet est utilisé uniquement pour l’appel à l’aide GetTextPath de la chaîne de texte « CODE ». Le gestionnaire mesure ensuite l’objet résultant SKPath et applique trois transformations pour le centrer et l’adapter à la taille de la page. Le chemin d’accès peut ensuite être défini comme chemin d’accès de découpage :

public class ClippingTextPage : ContentPage
{
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear(SKColors.Blue);

        using (SKPaint paint = new SKPaint())
        {
            paint.Typeface = SKTypeface.FromFamilyName(null, SKTypefaceStyle.Bold);
            paint.TextSize = 10;

            using (SKPath textPath = paint.GetTextPath("CODE", 0, 0))
            {
                // Set transform to center and enlarge clip path to window height
                SKRect bounds;
                textPath.GetTightBounds(out bounds);

                canvas.Translate(info.Width / 2, info.Height / 2);
                canvas.Scale(info.Width / bounds.Width, info.Height / bounds.Height);
                canvas.Translate(-bounds.MidX, -bounds.MidY);

                // Set the clip path
                canvas.ClipPath(textPath);
            }
        }

        // Reset transforms
        canvas.ResetMatrix();

        // Display bitmap to fill window but maintain aspect ratio
        SKRect rect = new SKRect(0, 0, info.Width, info.Height);
        canvas.DrawBitmap(bitmap,
            rect.AspectFill(new SKSize(bitmap.Width, bitmap.Height)));
    }
}

Une fois le chemin d’accès de découpage défini, l’image bitmap peut être affichée, et elle est découpée dans les contours des caractères. Notez l’utilisation de la AspectFill méthode de SKRect calcul d’un rectangle pour remplir la page tout en conservant le rapport d’aspect.

La page Effet de chemin de texte convertit un caractère d’ampersand unique en un chemin d’accès pour créer un effet de chemin d’accès 1D. Un objet de peinture avec cet effet de chemin d’accès est ensuite utilisé pour traiter le contour d’une version plus grande de ce même caractère :

Capture d’écran triple de la page Effet du chemin de texte

Une grande partie du travail de la TextPathEffectPath classe se produit dans les champs et le constructeur. Les deux SKPaint objets définis en tant que champs sont utilisés à deux fins différentes : le premier (nommé textPathPaint) est utilisé pour convertir l’ampersand avec un TextSize chemin d’accès de 50 en chemin d’accès 1D. Le deuxième (textPaint) est utilisé pour afficher la version plus grande de l’ampersand avec cet effet de chemin d’accès. Pour cette raison, le Style deuxième objet de peinture est défini Strokesur , mais la StrokeWidth propriété n’est pas définie, car cette propriété n’est pas nécessaire lors de l’utilisation d’un effet de chemin d’accès 1D :

public class TextPathEffectPage : ContentPage
{
    const string character = "@";
    const float littleSize = 50;

    SKPathEffect pathEffect;

    SKPaint textPathPaint = new SKPaint
    {
        TextSize = littleSize
    };

    SKPaint textPaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Black
    };

    public TextPathEffectPage()
    {
        Title = "Text Path Effect";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;

        // Get the bounds of textPathPaint
        SKRect textPathPaintBounds = new SKRect();
        textPathPaint.MeasureText(character, ref textPathPaintBounds);

        // Create textPath centered around (0, 0)
        SKPath textPath = textPathPaint.GetTextPath(character,
                                                    -textPathPaintBounds.MidX,
                                                    -textPathPaintBounds.MidY);
        // Create the path effect
        pathEffect = SKPathEffect.Create1DPath(textPath, littleSize, 0,
                                               SKPath1DPathEffectStyle.Translate);
    }
    ...
}

Le constructeur utilise d’abord l’objet textPathPaint pour mesurer l’ampersand avec une TextSize valeur de 50. Les négatifs des coordonnées centrale de ce rectangle sont ensuite passés à la GetTextPath méthode pour convertir le texte en chemin d’accès. Le chemin résultant a le point (0, 0) au centre du caractère, qui est idéal pour un effet de chemin 1D.

Vous pensez peut-être que l’objet SKPathEffect créé à la fin du constructeur peut être défini sur la PathEffect propriété du lieu d’être textPaint enregistré en tant que champ. Mais cela s’est avéré ne pas fonctionner très bien parce qu’il a déformé les résultats de l’appel MeasureText dans le PaintSurface gestionnaire :

public class TextPathEffectPage : ContentPage
{
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Set textPaint TextSize based on screen size
        textPaint.TextSize = Math.Min(info.Width, info.Height);

        // Do not measure the text with PathEffect set!
        SKRect textBounds = new SKRect();
        textPaint.MeasureText(character, ref textBounds);

        // Coordinates to center text on screen
        float xText = info.Width / 2 - textBounds.MidX;
        float yText = info.Height / 2 - textBounds.MidY;

        // Set the PathEffect property and display text
        textPaint.PathEffect = pathEffect;
        canvas.DrawText(character, xText, yText, textPaint);
    }
}

Cet MeasureText appel est utilisé pour centrer le caractère sur la page. Pour éviter les problèmes, la PathEffect propriété est définie sur l’objet de peinture une fois que le texte a été mesuré, mais avant son affichage.

Contours des contours de caractères

Normalement, la GetFillPath méthode de conversion d’un chemin à un autre en appliquant des propriétés de SKPaint peinture, notamment la largeur et l’effet de tracé. Lorsqu’il est utilisé sans effets de chemin d’accès, GetFillPath crée efficacement un chemin qui décrit un autre chemin. Cela a été illustré dans la page Appuyer pour décrire le chemin d’accès dans l’article Effets du chemin d’accès.

Vous pouvez également appeler GetFillPath le chemin d’accès retourné, GetTextPath mais au début, vous ne serez peut-être pas entièrement sûr de ce qui ressemblerait.

La page Contours du contour des caractères illustre la technique. Tout le code approprié se trouve dans le PaintSurface gestionnaire de la CharacterOutlineOutlinesPage classe.

Le constructeur commence par créer un SKPaint objet nommé textPaint avec une TextSize propriété en fonction de la taille de la page. Cette opération est convertie en chemin d’accès à l’aide de la GetTextPath méthode. Arguments de coordonnées pour GetTextPath centrer efficacement le chemin d’accès à l’écran :

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    using (SKPaint textPaint = new SKPaint())
    {
        // Set Style for the character outlines
        textPaint.Style = SKPaintStyle.Stroke;

        // Set TextSize based on screen size
        textPaint.TextSize = Math.Min(info.Width, info.Height);

        // Measure the text
        SKRect textBounds = new SKRect();
        textPaint.MeasureText("@", ref textBounds);

        // Coordinates to center text on screen
        float xText = info.Width / 2 - textBounds.MidX;
        float yText = info.Height / 2 - textBounds.MidY;

        // Get the path for the character outlines
        using (SKPath textPath = textPaint.GetTextPath("@", xText, yText))
        {
            // Create a new path for the outlines of the path
            using (SKPath outlinePath = new SKPath())
            {
                // Convert the path to the outlines of the stroked path
                textPaint.StrokeWidth = 25;
                textPaint.GetFillPath(textPath, outlinePath);

                // Stroke that new path
                using (SKPaint outlinePaint = new SKPaint())
                {
                    outlinePaint.Style = SKPaintStyle.Stroke;
                    outlinePaint.StrokeWidth = 5;
                    outlinePaint.Color = SKColors.Red;

                    canvas.DrawPath(outlinePath, outlinePaint);
                }
            }
        }
    }
}

Le PaintSurface gestionnaire crée ensuite un chemin nommé outlinePath. Il devient le chemin d’accès de destination dans l’appel à GetFillPath. La StrokeWidth propriété 25 provoque outlinePath la description du contour d’un chemin d’accès de 25 pixels qui a trait aux caractères de texte. Ce chemin s’affiche ensuite en rouge avec une largeur de trait de 5 :

Capture d’écran triple de la page Contours du contour du caractère

Regardez attentivement et vous verrez des chevauchements où le contour du chemin fait un coin aigu. Il s’agit d’artefacts normaux de ce processus.

Texte le long d’un chemin

Le texte est normalement affiché sur une ligne de base horizontale. Le texte peut être pivoté pour s’exécuter verticalement ou en diagonale, mais la ligne de base est toujours une ligne droite.

Toutefois, il y a des moments où vous souhaitez que le texte s’exécute le long d’une courbe. Il s’agit de l’objectif de la DrawTextOnPath méthode de SKCanvas:

public Void DrawTextOnPath (String text, SKPath path, Single hOffset, Single vOffset, SKPaint paint)

Le texte spécifié dans le premier argument est effectué pour s’exécuter le long du chemin spécifié comme deuxième argument. Vous pouvez commencer le texte à un décalage à partir du début du chemin d’accès avec l’argument hOffset . Normalement, le chemin forme la ligne de base du texte : les croissants de texte se trouvent sur un côté du chemin, et les descendeurs de texte se trouvent sur l’autre. Toutefois, vous pouvez décaler la ligne de base de texte du chemin d’accès avec l’argument vOffset .

Cette méthode n’a pas la possibilité de fournir des conseils sur la définition de la TextSize propriété de SKPaint façon à ce que le texte soit parfaitement dimensionné pour s’exécuter du début du chemin jusqu’à la fin. Parfois, vous pouvez déterminer cette taille de texte par vous-même. D’autres fois, vous devez utiliser les fonctions de mesure du chemin d’accès pour être décrites dans l’article suivant sur les informations de chemin d’accès et l’énumération.

Le programme Texte circulaire encapsule le texte autour d’un cercle. Il est facile de déterminer la circonférence d’un cercle, de sorte qu’il est facile de dimensionner le texte pour s’adapter exactement. Le PaintSurface gestionnaire de la CircularTextPage classe calcule un rayon d’un cercle en fonction de la taille de la page. Ce cercle devient circularPath:

public class CircularTextPage : ContentPage
{
    const string text = "xt in a circle that shapes the te";
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPath circularPath = new SKPath())
        {
            float radius = 0.35f * Math.Min(info.Width, info.Height);
            circularPath.AddCircle(info.Width / 2, info.Height / 2, radius);

            using (SKPaint textPaint = new SKPaint())
            {
                textPaint.TextSize = 100;
                float textWidth = textPaint.MeasureText(text);
                textPaint.TextSize *= 2 * 3.14f * radius / textWidth;

                canvas.DrawTextOnPath(text, circularPath, 0, 0, textPaint);
            }
        }
    }
}

La TextSize propriété de textPaint l’objet est ensuite ajustée afin que la largeur du texte corresponde à la circonférence du cercle :

Capture d’écran triple de la page Texte circulaire

Le texte lui-même a été choisi pour être un peu circulaire : le mot « cercle » est à la fois le sujet de la phrase et l’objet d’une expression prépositionnelle.