A transformação de distorção
Veja como a transformação de inclinação pode criar objetos gráficos inclinados no SkiaSharp
No SkiaSharp, a transformação de inclinação inclina objetos gráficos, como a sombra nesta imagem:
A inclinação transforma um retângulo em um paralelogramo, mas uma elipse enviesada ainda é uma elipse.
Embora Xamarin.Forms defina propriedades para translação, dimensionamento e rotações, não há nenhuma propriedade correspondente em Xamarin.Forms para inclinação.
O Skew
método de SKCanvas
aceita dois argumentos para inclinação horizontal e inclinação vertical:
public void Skew (Single xSkew, Single ySkew)
Um segundo Skew
método combina esses argumentos em um único SKPoint
valor:
public void Skew (SKPoint skew)
No entanto, é improvável que você use qualquer um desses dois métodos isoladamente.
A página Experimento de inclinação permite que você experimente valores de inclinação que variam entre –10 e 10. Uma cadeia de texto é posicionada no canto superior esquerdo da página, com valores de inclinação obtidos de dois Slider
elementos. Aqui está o PaintSurface
manipulador na SkewExperimentPage
classe:
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);
}
}
Os valores do xSkew
argumento deslocam a parte inferior do texto para a direita para valores positivos ou para a esquerda para valores negativos. Valores de ySkew
deslocar a direita do texto para baixo para valores positivos ou para cima para valores negativos:
Se o xSkew
valor for o negativo do valor, o resultado é rotação, mas também dimensionado ySkew
um pouco.
As fórmulas de transformação são as seguintes:
x' = x + xSkew · y
y' = ySkew · x + y
Por exemplo, para um valor positivo xSkew
, o valor transformado x'
aumenta à medida y
que aumenta. É isso que causa a inclinação.
Se um triângulo de 200 pixels de largura e 100 pixels de altura for posicionado com seu canto superior esquerdo no ponto (0, 0) e for renderizado com um xSkew
valor de 1,5, o seguinte paralelogramo resultará:
As coordenadas da borda inferior têm y
valores de 100, portanto, ela é deslocada 150 pixels para a direita.
Para valores diferentes de zero de xSkew
ou ySkew
, apenas o ponto (0, 0) permanece o mesmo. Esse ponto pode ser considerado o centro da inclinação. Se você precisa que o centro de inclinação seja outra coisa (o que geralmente é o caso), não há nenhum Skew
método que forneça isso. Você precisará combinar Translate
explicitamente as chamadas com a Skew
chamada. Para centralizar a inclinação em px
e py
, faça as seguintes chamadas:
canvas.Translate(px, py);
canvas.Skew(xSkew, ySkew);
canvas.Translate(-px, -py);
As fórmulas de transformação composta são:
x' = x + xSkew · (y – py)
y' = ySkew · (x – px) + y
Se ySkew
for zero, o px
valor não será usado. O valor é irrelevante, e da mesma forma para ySkew
e py
.
Você pode se sentir mais confortável em especificar a inclinação como um ângulo de inclinação, como o ângulo α neste diagrama:
A proporção do deslocamento de 150 pixels para a vertical de 100 pixels é a tangente desse ângulo, neste exemplo de 56,3 graus.
O arquivo XAML da página Skew Angle Experiment é semelhante à página Skew Angle , exceto que os Slider
elementos variam de –90 graus a 90 graus. O SkewAngleExperiment
arquivo code-behind centraliza o texto na página e usa Translate
para definir um centro de inclinação para o centro da página. Um método curto SkewDegrees
na parte inferior do código converte ângulos em valores de inclinação:
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));
}
À medida que um ângulo se aproxima de 90 graus positivos ou negativos, a tangente se aproxima do infinito, mas ângulos de até cerca de 80 graus ou mais são utilizáveis:
Uma pequena inclinação horizontal negativa pode imitar texto oblíquo ou itálico, como demonstra a página Texto oblíquo. A ObliqueTextPage
aula mostra como é feito:
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));
}
A TextAlign
propriedade de SKPaint
é definida como Center
. Sem transformações, a DrawText
chamada com coordenadas de (0, 0) posicionaria o texto com o centro horizontal da linha de base no canto superior esquerdo. O SkewDegrees
distorce o texto horizontalmente 20 graus em relação à linha de base. A Translate
chamada move o centro horizontal da linha de base do texto para o centro da tela:
A página Texto de sombra de inclinação demonstra como usar uma combinação de inclinação de 45 graus e escala vertical para criar uma sombra de texto que se inclina para longe do texto. Aqui está a parte pertinente do PaintSurface
manipulador:
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);
}
A sombra é exibida primeiro e, em seguida, o texto:
A coordenada vertical passada para o DrawText
método indica a posição do texto em relação à linha de base. Essa é a mesma coordenada vertical usada para o centro de inclinação. Essa técnica não funcionará se a cadeia de caracteres de texto contiver descendentes. Por exemplo, substitua a palavra "peculiar" por "Sombra" e aqui está o resultado:
A sombra e o texto ainda estão alinhados na linha de base, mas o efeito parece errado. Para corrigi-lo, você precisa obter os limites de texto:
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
As Translate
chamadas precisam ser ajustadas pela altura dos descendentes:
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);
Agora a sombra se estende do fundo daqueles descendentes: