Ścieżki i tekst w skiaSharp
Eksplorowanie przecięć ścieżek i tekstu
W nowoczesnych systemach graficznych czcionki tekstowe to kolekcje konturów znaków, zwykle definiowane przez krzywe kwadratowe Béziera. W związku z tym wiele nowoczesnych systemów graficznych obejmuje obiekt umożliwiający konwertowanie znaków tekstowych na ścieżkę graficzną.
Wiesz już, że można pociągnić kontury znaków tekstowych, a także je wypełnić. Dzięki temu można wyświetlić te kontury znaków o określonej szerokości pociągnięcia, a nawet efekt ścieżki, jak opisano w artykule Path Effects. Można jednak również przekonwertować ciąg znaków na SKPath
obiekt. Oznacza to, że kontury tekstowe mogą służyć do tworzenia wycinków za pomocą technik opisanych w artykule Tworzenie wycinków ze ścieżkami i regionami .
Oprócz użycia efektu ścieżki do pociągnięcia konturu znaku, można również utworzyć efekty ścieżki oparte na ścieżce pochodzącej z ciągu znaku, a nawet połączyć dwa efekty:
W poprzednim artykule dotyczącym funkcji Path Effects pokazano, jak GetFillPath
metoda SKPaint
umożliwia uzyskanie konspektu ścieżki pociągniętej. Można również użyć tej metody ze ścieżkami pochodzącymi z konspektów znaków.
Na koniec w tym artykule przedstawiono kolejne przecięcie ścieżek i tekstu: DrawTextOnPath
Metoda SKCanvas
umożliwia wyświetlenie ciągu tekstowego tak, aby punkt odniesienia tekstu był zgodny ze ścieżką zakrzywioną.
Konwersja tekstu na ścieżkę
Metoda GetTextPath
konwertowania SKPaint
ciągu znaków na SKPath
obiekt:
public SKPath GetTextPath (String text, Single x, Single y)
Argumenty x
i y
wskazują punkt początkowy punktu odniesienia po lewej stronie tekstu. Odgrywają tu tę samą rolę co w DrawText
metodzie SKCanvas
. W ścieżce linia bazowa po lewej stronie tekstu będzie miała współrzędne (x, y).
Metoda GetTextPath
jest nadmierna, jeśli chcesz tylko wypełnić lub pociągnić wynikową ścieżkę. DrawText
Normalna metoda pozwala to zrobić. Metoda jest bardziej przydatna GetTextPath
w przypadku innych zadań obejmujących ścieżki.
Jednym z tych zadań jest wycinkowanie. Strona Clipping Text tworzy ścieżkę do wycinków na podstawie konspektu znaku "CODE". Ta ścieżka jest rozciągnięta do rozmiaru strony, aby wyciąć mapę bitową zawierającą obraz kodu źródłowego Clipping Text :
Konstruktor ClippingTextPage
klasy ładuje mapę bitową przechowywaną jako zasób osadzony w folderze Media rozwiązania:
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);
}
}
...
}
Procedura PaintSurface
obsługi rozpoczyna się od utworzenia obiektu odpowiedniego SKPaint
dla tekstu. Właściwość Typeface
jest ustawiona, a także TextSize
właściwość , chociaż dla tej konkretnej aplikacji TextSize
właściwość jest czysto arbitralna. Zwróć również uwagę, że nie Style
ma żadnego ustawienia.
TextSize
Ustawienia właściwości i Style
nie są niezbędne, ponieważ ten SKPaint
obiekt jest używany wyłącznie dla GetTextPath
wywołania przy użyciu ciągu tekstowego "CODE". Następnie procedura obsługi mierzy wynikowy SKPath
obiekt i stosuje trzy przekształcenia, aby go wyśrodkować i skalować do rozmiaru strony. Następnie ścieżkę można ustawić jako ścieżkę wycinkową:
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)));
}
}
Po ustawieniu ścieżki wycinków można wyświetlić mapę bitową i zostanie obcięta do obramowania znaków. Zwróć uwagę na użycie AspectFill
metody SKRect
, która oblicza prostokąt do wypełniania strony przy zachowaniu współczynnika proporcji.
Strona Efekt ścieżki tekstowej konwertuje pojedynczy znak ampersand na ścieżkę w celu utworzenia efektu ścieżki 1D. Obiekt farby z tym efektem ścieżki jest następnie używany do pociągnięcia konturu większej wersji tego samego znaku:
Większość pracy w TextPathEffectPath
klasie odbywa się w polach i konstruktorze. Dwa SKPaint
obiekty zdefiniowane jako pola są używane do dwóch różnych celów: pierwszy (nazwany textPathPaint
) służy do konwertowania znaku ampersand z wartością TextSize
50 na ścieżkę dla efektu ścieżki 1D. Drugi (textPaint
) służy do wyświetlania większej wersji znaku ampersand z tym efektem ścieżki. Z tego powodu drugi obiekt farby jest ustawiony na Stroke
, ale StrokeWidth
właściwość nie jest ustawiona, Style
ponieważ ta właściwość nie jest konieczna w przypadku używania efektu ścieżki 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);
}
...
}
Konstruktor najpierw używa textPathPaint
obiektu do mierzenia ampersand z wartością TextSize
50. Wartości ujemne współrzędnych środkowych tego prostokąta są następnie przekazywane do GetTextPath
metody w celu przekonwertowania tekstu na ścieżkę. Wynikowa ścieżka ma punkt (0, 0) w środku znaku, który jest idealny dla efektu ścieżki 1D.
Można pomyśleć, że SKPathEffect
obiekt utworzony na końcu konstruktora może być ustawiony na właściwość textPaint
zamiast zapisywać PathEffect
jako pole. Okazało się jednak, że nie działa to bardzo dobrze, ponieważ zniekształciło wyniki MeasureText
wywołania w procedurze PaintSurface
obsługi:
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);
}
}
To MeasureText
wywołanie służy do wyśrodkowania znaku na stronie. Aby uniknąć problemów, PathEffect
właściwość jest ustawiona na obiekt farby po zmierzeniu tekstu, ale przed jego wyświetleniem.
Kontury konspektów znaków
GetFillPath
Zwykle metoda konwersji SKPaint
jednej ścieżki na inną przez zastosowanie właściwości farby, zwłaszcza efektu szerokości pociągnięcia i ścieżki. W przypadku użycia bez efektów GetFillPath
ścieżki skutecznie tworzy ścieżkę, która przedstawia inną ścieżkę. Zostało to pokazane na stronie Naciśnij, aby nakreślić ścieżkę w artykule Path Effects (Efekty ścieżki).
Możesz również wywołać GetFillPath
ścieżkę zwróconą z GetTextPath
, ale na początku może nie być całkowicie pewien, jak to wygląda.
Na stronie Konspektu znaku przedstawiono technikę. Cały odpowiedni kod znajduje się w procedurze PaintSurface
CharacterOutlineOutlinesPage
obsługi klasy .
Konstruktor rozpoczyna się od utworzenia SKPaint
obiektu o nazwie textPaint
z właściwością TextSize
na podstawie rozmiaru strony. Jest on konwertowany na ścieżkę przy użyciu GetTextPath
metody . Argumenty współrzędnych, aby GetTextPath
skutecznie wyśrodkować ścieżkę na ekranie:
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);
}
}
}
}
}
Następnie PaintSurface
program obsługi tworzy nową ścieżkę o nazwie outlinePath
. Staje się to ścieżką docelową w wywołaniu metody GetFillPath
. Właściwość StrokeWidth
25 powoduje outlinePath
opisanie konturu ścieżki o szerokości 25 pikseli, która nabija znaki tekstowe. Ta ścieżka jest następnie wyświetlana na czerwono z szerokością pociągnięcia 5:
Przyjrzyj się bliżej i zobaczysz nakładające się na siebie krawędzie ścieżki. Są to normalne artefakty tego procesu.
Tekst wzdłuż ścieżki
Tekst jest zwykle wyświetlany w poziomie linii bazowej. Tekst można obracać w pionie lub po przekątnej, ale linia bazowa jest nadal prostą linią.
Czasami jednak tekst ma być uruchamiany wzdłuż krzywej. Jest to cel DrawTextOnPath
metody :SKCanvas
public Void DrawTextOnPath (String text, SKPath path, Single hOffset, Single vOffset, SKPaint paint)
Tekst określony w pierwszym argumencie jest uruchamiany wzdłuż ścieżki określonej jako drugi argument. Tekst można rozpocząć od przesunięcia od początku ścieżki z argumentem hOffset
. Zwykle ścieżka tworzy punkt odniesienia tekstu: Rosnąco tekst znajdują się po jednej stronie ścieżki, a malejąco tekstu znajdują się na drugiej. Można jednak zrównoważyć linię bazową tekstu ze ścieżki argumentem vOffset
.
Ta metoda nie ma możliwości zapewnienia wskazówek dotyczących ustawiania TextSize
właściwości SKPaint
, aby rozmiar tekstu był idealnie uruchamiany od początku ścieżki do końca. Czasami można samodzielnie ustalić ten rozmiar tekstu. Innym razem należy użyć funkcji pomiaru ścieżki, które mają być opisane w następnym artykule w temacie Informacje o ścieżce i wyliczenie.
Program Okrągły tekst owija tekst wokół okręgu. Łatwo jest określić obwód okręgu, dzięki czemu można łatwo dopasować tekst do dokładnego dopasowania. Procedura PaintSurface
obsługi CircularTextPage
klasy oblicza promień okręgu na podstawie rozmiaru strony. Ten okrąg staje się :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);
}
}
}
}
TextSize
Właściwość textPaint
elementu jest następnie dopasowywana tak, aby szerokość tekstu odpowiadała obwodowi okręgu:
Sam tekst został wybrany jako nieco okrągły, jak również: Słowo "circle" jest zarówno przedmiotem zdania, jak i obiektem frazy przyimkowej.