傾斜轉換
查看扭曲轉換如何在 SkiaSharp 中建立傾斜的圖形物件
在 SkiaSharp 中,扭曲轉換會傾斜圖形物件,例如此影像中的陰影:
扭曲會將矩形變成平行投影,但扭曲的橢圓形仍然是橢圓形。
雖然 Xamarin.Forms 會定義翻譯、縮放和旋轉的屬性,但在扭曲中 Xamarin.Forms 沒有對應的屬性。
Skew
的 方法SKCanvas
會接受兩個自變數進行水準扭曲和垂直扭曲:
public void Skew (Single xSkew, Single ySkew)
第二 Skew
種方法會將這些自變數結合在單 SKPoint
一值中:
public void Skew (SKPoint skew)
不過,您不太可能隔離地使用這兩種方法之一。
[ 扭曲實驗 ] 頁面可讓您實驗介於 –10 到 10 之間的扭曲值。 文字字串位於頁面左上角,並具有從兩 Slider
個元素取得的扭曲值。 以下是 PaintSurface
類別中的 SkewExperimentPage
處理程式:
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
{
Style = SKPaintStyle.Fill,
Color = SKColors.Blue,
TextSize = 200
})
{
string text = "SKEW";
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
canvas.Skew((float)xSkewSlider.Value, (float)ySkewSlider.Value);
canvas.DrawText(text, 0, -textBounds.Top, textPaint);
}
}
xSkew
自變數的值會針對正值向右移位文字底部,或為負值向左移。 ySkew
針對正值或負值,將文字右邊的值向下移位:
xSkew
如果值是值的負值ySkew
,則結果會輪替,但也會稍微縮放。
轉換公式如下所示:
x' = x + xSkew ·Y
y' = ySkew ·x + y
例如,對於正 xSkew
值,轉換 x'
的值會隨著 y
增加而增加。 這就是造成傾斜的原因。
如果三角形寬 200 像素且高 100 像素,其左上角位於點 (0, 0), 並以 1.5 的值轉譯 xSkew
,則下列平行投影結果:
下邊緣的座標值為 y
100,因此會向右移動 150 圖元。
若為 或ySkew
的非零值xSkew
,則只有點 (0, 0) 會維持不變。 該點可以視為扭曲的中心。 如果您需要扭曲的中心做為別的東西(通常是這種情況),則沒有 Skew
提供該方法。 您必須明確地結合 Translate
呼叫與 Skew
呼叫。 若要將 扭曲置中 於 px
和 py
,請進行下列呼叫:
canvas.Translate(px, py);
canvas.Skew(xSkew, ySkew);
canvas.Translate(-px, -py);
複合轉換公式如下:
x' = x + xSkew ·(y – py)
y' = ySkew ·(x – px) + y
如果 ySkew
為零, px
則不會使用值。 值無關緊要,而且與 ySkew
和 py
類似。
您可能會覺得更舒適地將扭曲指定為傾斜角度,例如此圖表中的角度α:
150 像素向 100 像素垂直移位的比例是該角度的正切值,在此範例中為 56.3 度。
[扭曲角度實驗] 頁面的 XAML 檔案類似於 [扭曲角度] 頁面,不同之處在於Slider
元素的範圍從 –90 度到 90 度。 程序代碼後置檔案會將 SkewAngleExperiment
頁面上的文字置中,並使用 Translate
將扭曲的中心設定為頁面中心。 程式代碼底部的簡短 SkewDegrees
方法會將角度轉換成扭曲值:
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
{
Style = SKPaintStyle.Fill,
Color = SKColors.Blue,
TextSize = 200
})
{
float xCenter = info.Width / 2;
float yCenter = info.Height / 2;
string text = "SKEW";
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
float xText = xCenter - textBounds.MidX;
float yText = yCenter - textBounds.MidY;
canvas.Translate(xCenter, yCenter);
SkewDegrees(canvas, xSkewSlider.Value, ySkewSlider.Value);
canvas.Translate(-xCenter, -yCenter);
canvas.DrawText(text, xText, yText, textPaint);
}
}
void SkewDegrees(SKCanvas canvas, double xDegrees, double yDegrees)
{
canvas.Skew((float)Math.Tan(Math.PI * xDegrees / 180),
(float)Math.Tan(Math.PI * yDegrees / 180));
}
當角度接近正數或負數 90 度時,正切值會接近無限大,但最多 80 度左右的角度是可使用的:
斜體文字頁面所示範的小型負水準扭曲可以模仿斜體或斜體文字。 類別 ObliqueTextPage
會顯示其完成方式:
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()
{
Style = SKPaintStyle.Fill,
Color = SKColors.Maroon,
TextAlign = SKTextAlign.Center,
TextSize = info.Width / 8 // empirically determined
})
{
canvas.Translate(info.Width / 2, info.Height / 2);
SkewDegrees(canvas, -20, 0);
canvas.DrawText(Title, 0, 0, textPaint);
}
}
void SkewDegrees(SKCanvas canvas, double xDegrees, double yDegrees)
{
canvas.Skew((float)Math.Tan(Math.PI * xDegrees / 180),
(float)Math.Tan(Math.PI * yDegrees / 180));
}
屬性 TextAlign
SKPaint
設定為 Center
。 如果沒有任何轉換, DrawText
具有座標 (0, 0) 的呼叫會將文字置於左上角基準的水準中心。 會將 SkewDegrees
文字水平傾斜 20 度,相對於基準。 呼叫會將 Translate
文字基準的水準中心移至畫布的中心:
扭曲 陰影文字 頁面示範如何使用 45 度扭曲和垂直縮放的組合,讓文字陰影偏離文字。 以下是處理程序的相關部分 PaintSurface
:
using (SKPaint textPaint = new SKPaint())
{
textPaint.Style = SKPaintStyle.Fill;
textPaint.TextSize = info.Width / 6; // empirically determined
// Common to shadow and text
string text = "Shadow";
float xText = 20;
float yText = info.Height / 2;
// Shadow
textPaint.Color = SKColors.LightGray;
canvas.Save();
canvas.Translate(xText, yText);
canvas.Skew((float)Math.Tan(-Math.PI / 4), 0);
canvas.Scale(1, 3);
canvas.Translate(-xText, -yText);
canvas.DrawText(text, xText, yText, textPaint);
canvas.Restore();
// Text
textPaint.Color = SKColors.Blue;
canvas.DrawText(text, xText, yText, textPaint);
}
陰影會先顯示,然後顯示文字:
傳遞至 方法的 DrawText
垂直座標會指出相對於基準的文字位置。 這是用於扭曲中心的相同垂直座標。 如果文字字串包含子系,這項技術將無法運作。 例如,將 「quirky」 一詞取代為 「Shadow」,以下是結果:
陰影和文字仍然對齊基準,但效果看起來錯誤。 若要修正此問題,您需要取得文字界限:
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
呼叫 Translate
需要由子系的高度調整:
canvas.Translate(xText, yText + textBounds.Bottom);
canvas.Skew((float)Math.Tan(-Math.PI / 4), 0);
canvas.Scale(1, 3);
canvas.Translate(-xText, -yText - textBounds.Bottom);
現在陰影會從這些子系的底部延伸: