Cesty a text v SkiaSharpu
Prozkoumání průniku cest a textu
V moderních grafických systémech jsou textová písma kolekce obrysů znaků, obvykle definované kvadratickými Bézierovými křivkami. V důsledku toho mnoho moderních grafických systémů zahrnuje zařízení pro převod textových znaků na grafickou cestu.
Už jste viděli, že můžete tahat obrysy textových znaků a vyplnit je. Díky tomu můžete tyto obrysy znaků zobrazit s konkrétní šířkou tahu a dokonce i efektem cesty, jak je popsáno v článku Efekty cesty. Je ale také možné převést řetězec znaků na SKPath
objekt. To znamená, že osnovy textu se dají použít k výřezu pomocí technik popsaných v článku Výřez s cestami a oblastmi.
Kromě použití efektu cesty k tahu obrysu znaku můžete také vytvořit efekty cesty založené na cestě odvozené z řetězce znaků a můžete dokonce zkombinovat tyto dva efekty:
V předchozím článku o efektech cesty jste viděli, jak GetFillPath
metoda SKPaint
může získat osnovu tahové cesty. Tuto metodu můžete použít také s cestami odvozenými z obrysů znaků.
Nakonec tento článek ukazuje další průnik cest a textu: DrawTextOnPath
Metoda SKCanvas
umožňuje zobrazit textový řetězec tak, aby směrný plán textu následuje zakřivenou cestou.
Převod textu na cestu
GetTextPath
Metoda SKPaint
převede řetězec znaků na SKPath
objekt:
public SKPath GetTextPath (String text, Single x, Single y)
y
Argumenty x
označují výchozí bod účaří levé strany textu. Hrají zde stejnou roli jako v DrawText
metodě SKCanvas
. V cestě bude mít účaří levé strany textu souřadnice (x, y).
Metoda GetTextPath
je nadměrná, pokud chcete pouze vyplnit nebo tahnout výslednou cestu. DrawText
Normální metoda vám to umožní. Metoda GetTextPath
je užitečnější pro jiné úlohy zahrnující cesty.
Jedním z těchto úkolů je výřez. Stránka Výřez textu vytvoří cestu výřezu na základě obrysů znaků slova "KÓD". Tato cesta se roztáhne na velikost stránky a vystřihuje rastrový obrázek, který obsahuje obrázek zdrojového kódu Oříznutí textu :
Konstruktor ClippingTextPage
třídy načte rastrový obrázek, který je uložen jako vložený prostředek ve složce Media řešení:
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);
}
}
...
}
Obslužná rutina PaintSurface
začíná vytvořením objektu vhodného SKPaint
pro text. Vlastnost Typeface
je nastavena i TextSize
, i když pro tuto konkrétní aplikaci TextSize
je vlastnost čistě libovolná. Všimněte si také, že neexistuje žádné Style
nastavení.
Nastavení TextSize
a Style
vlastnosti nejsou nutné, protože tento SKPaint
objekt se používá výhradně pro GetTextPath
volání pomocí textového řetězce "CODE". Obslužná rutina pak změruje výsledný SKPath
objekt a použije tři transformace na střed a škáluje ho na velikost stránky. Tuto cestu pak můžete nastavit jako cestu výřezu:
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 nastavení cesty výřezu se dá rastrový obrázek zobrazit a vystřihuje se na obrysy znaků. Všimněte si použití AspectFill
metody SKRect
, která vypočítá obdélník pro vyplnění stránky při zachování poměru stran.
Stránka Efektu textové cesty převede jeden ampersand znak na cestu a vytvoří 1D efekt cesty. Malování objektu s tímto efektem cesty se pak použije k tahu obrysu větší verze stejného znaku:
Velká část práce ve TextPathEffectPath
třídě se vyskytuje v polích a konstruktoru. Dva SKPaint
objekty definované jako pole se používají pro dva různé účely: První (pojmenovaný textPathPaint
) slouží k převodu ampersandu TextSize
s hodnotou 50 na cestu pro efekt 1D cesty. Druhá (textPaint
) slouží k zobrazení větší verze ampersandu s tímto efektem cesty. Z tohoto důvodu Style
je druhý objekt malování nastaven na Stroke
, ale StrokeWidth
vlastnost není nastavena, protože tato vlastnost není nutná při použití efektu cesty 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 nejprve použije textPathPaint
objekt k měření ampersandu TextSize
s 50. Zápory středových souřadnic tohoto obdélníku se pak předají GetTextPath
metodě pro převod textu na cestu. Výsledná cesta má bod (0, 0) uprostřed znaku, který je ideální pro efekt 1D cesty.
Můžete si myslet, že SKPathEffect
objekt vytvořený na konci konstruktoru může být nastaven na PathEffect
vlastnost textPaint
namísto uložení jako pole. Ale ukázalo se, že to nefunguje velmi dobře, protože zkresloval výsledky MeasureText
volání v obslužné rutině PaintSurface
:
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);
}
}
Toto MeasureText
volání slouží ke středu znaku na stránce. Aby nedocházelo k problémům, PathEffect
vlastnost je nastavena na objekt malování po měření textu, ale před zobrazením.
Obrysy obrysů znaků
GetFillPath
SKPaint
Metoda obvykle převede jednu cestu na jinou použitím vlastností barvy, zejména šířky tahu a efekt cesty. Při použití bez efektů cesty efektivně vytvoří cestu, GetFillPath
která nastíní jinou cestu. To jsme si ukázali v článku Efekty cesty v části Klepnutím na osnovu stránky Cesta.
Můžete také volat GetFillPath
cestu vrácenou z GetTextPath
cesty, ale zpočátku si nejste úplně jistí, jak by to vypadalo.
Stránka Osnovy obrysů znaků ukazuje techniku. Veškerý relevantní kód je v PaintSurface
obslužné rutině CharacterOutlineOutlinesPage
třídy.
Konstruktor začíná vytvořením objektu SKPaint
pojmenovaného textPaint
vlastností TextSize
na základě velikosti stránky. To je převedeno na cestu pomocí GetTextPath
metody. Argumenty souřadnic, které efektivně zacentrují GetTextPath
cestu na obrazovce:
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);
}
}
}
}
}
Obslužná rutina PaintSurface
pak vytvoří novou cestu s názvem outlinePath
. Tím se stane cílová cesta v volání GetFillPath
. Vlastnost StrokeWidth
25 způsobí outlinePath
popis obrysu cesty s šířkou 25 pixelů s textem. Tato cesta se pak zobrazí červeně s šířkou tahu 5:
Podívejte se pozorně a uvidíte, že se překrývají, kde obrys cesty dělá ostrý roh. Jedná se o běžné artefakty tohoto procesu.
Text podél cesty
Text se obvykle zobrazuje na vodorovném účaří. Text lze otočit tak, aby běžel svisle nebo diagonálně, ale směrný plán je stále přímkou.
Někdy ale platí, že když chcete, aby text běžel podél křivky. Jedná se o účel DrawTextOnPath
metody SKCanvas
:
public Void DrawTextOnPath (String text, SKPath path, Single hOffset, Single vOffset, SKPaint paint)
Text zadaný v prvním argumentu se provede tak, aby běžel podél cesty zadané jako druhý argument. Text můžete zahájit od začátku cesty argumentem hOffset
. Cesta obvykle tvoří směrný plán textu: Vzestupné texty jsou na jedné straně cesty a sestupné texty jsou na druhé. Směrný plán textu ale můžete odsazením cesty odsazením argumentu vOffset
.
Tato metoda nemá žádné možnosti, jak poskytnout pokyny k nastavení TextSize
vlastnosti SKPaint
, aby text byl dokonale nastaven tak, aby běžel od začátku cesty na konec. Někdy můžete zjistit, že velikost textu je sama o sobě. Jindy budete muset použít funkce měření cesty, které jsou popsány v dalším článku o informacích o cestě a výčtu.
Program Kruhový text zalamuje text kolem kruhu. Je snadné určit obvod kruhu, takže je snadné upravit velikost textu tak, aby se přesně vešel. Obslužná PaintSurface
rutina CircularTextPage
třídy vypočítá poloměr kruhu na základě velikosti stránky. Tento kruh se stane 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);
}
}
}
}
Vlastnost TextSize
textPaint
se pak upraví tak, aby šířka textu odpovídala obvodu kruhu:
Samotný text byl zvolen tak, aby byl poněkud kruhový: Slovo "kruh" je předmětem věty i objektu předložkové fráze.