void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) { SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); TaperSide taperSide = (TaperSide)taperSidePicker.SelectedIndex; TaperCorner taperCorner = (TaperCorner)taperCornerPicker.SelectedIndex; float taperFraction = (float)taperFractionSlider.Value; SKMatrix taperMatrix = TaperTransform.Make(new SKSize(bitmap.Width, bitmap.Height), taperSide, taperCorner, taperFraction); // Display the matrix in the lower-right corner SKSize matrixSize = matrixDisplay.Measure(taperMatrix); matrixDisplay.Paint(canvas, taperMatrix, new SKPoint(info.Width - matrixSize.Width, info.Height - matrixSize.Height)); // Center bitmap on canvas float x = (info.Width - bitmap.Width) / 2; float y = (info.Height - bitmap.Height) / 2; SKMatrix matrix = SKMatrix.MakeTranslation(-x, -y); SKMatrix.PostConcat(ref matrix, taperMatrix); SKMatrix.PostConcat(ref matrix, SKMatrix.MakeTranslation(x, y)); canvas.SetMatrix(matrix); canvas.DrawBitmap(bitmap, x, y); }
/// <summary> /// Creates a matrix that performs a tapering projective transform. /// <see href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/non-affine"/> /// </summary> /// <param name="size">The rectangular size of the image being transformed.</param> /// <param name="side">An enumeration that indicates the side of the rectangle that tapers.</param> /// <param name="corner">An enumeration that indicates on which corners to taper the rectangle.</param> /// <param name="fraction">The amount to taper.</param> /// <returns>The <see cref="Matrix4x4"/></returns> public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner corner, float fraction) { Matrix4x4 matrix = Matrix4x4.Identity; /* * SkMatrix is laid out in the following manner: * * [ ScaleX SkewY Persp0 ] * [ SkewX ScaleY Persp1 ] * [ TransX TransY Persp2 ] * * When converting from Matrix4x4 to SkMatrix, the third row and * column is dropped. When converting from SkMatrix to Matrix4x4 * the third row and column remain as identity: * * [ a b c ] [ a b 0 c ] * [ d e f ] -> [ d e 0 f ] * [ g h i ] [ 0 0 1 0 ] * [ g h 0 i ] */ switch (side) { case TaperSide.Left: matrix.M11 = fraction; matrix.M22 = fraction; matrix.M14 = (fraction - 1) / size.Width; switch (corner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M12 = size.Height * matrix.M14; matrix.M42 = size.Height * (1 - fraction); break; case TaperCorner.Both: matrix.M12 = size.Height * .5F * matrix.M14; matrix.M42 = size.Height * (1 - fraction) / 2; break; } break; case TaperSide.Top: matrix.M11 = fraction; matrix.M22 = fraction; matrix.M24 = (fraction - 1) / size.Height; switch (corner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M21 = size.Width * matrix.M24; matrix.M41 = size.Width * (1 - fraction); break; case TaperCorner.Both: matrix.M21 = size.Width * .5F * matrix.M24; matrix.M41 = size.Width * (1 - fraction) * .5F; break; } break; case TaperSide.Right: matrix.M11 = 1 / fraction; matrix.M14 = (1 - fraction) / (size.Width * fraction); switch (corner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M12 = size.Height * matrix.M14; break; case TaperCorner.Both: matrix.M12 = size.Height * .5F * matrix.M14; break; } break; case TaperSide.Bottom: matrix.M22 = 1 / fraction; matrix.M24 = (1 - fraction) / (size.Height * fraction); switch (corner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M21 = size.Width * matrix.M24; break; case TaperCorner.Both: matrix.M21 = size.Width * .5F * matrix.M24; break; } break; } return(matrix); }
/// <summary> /// Appends a matrix that performs a tapering projective transform. /// </summary> /// <param name="side">An enumeration that indicates the side of the rectangle that tapers.</param> /// <param name="corner">An enumeration that indicates on which corners to taper the rectangle.</param> /// <param name="fraction">The amount to taper.</param> /// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns> public ProjectiveTransformBuilder AppendTaper(TaperSide side, TaperCorner corner, float fraction) => this.Append(size => TransformUtilities.CreateTaperMatrix(size, side, corner, fraction));
public void Transform_WithTaperMatrix <TPixel>(TestImageProvider <TPixel> provider, TaperSide taperSide, TaperCorner taperCorner) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) { Matrix4x4 m = ProjectiveTransformHelper.CreateTaperMatrix(image.Size(), taperSide, taperCorner, .5F); image.Mutate(i => { i.Transform(m); }); FormattableString testOutputDetails = $"{taperSide}-{taperCorner}"; image.DebugSave(provider, testOutputDetails); image.CompareFirstFrameToReferenceOutput(TolerantComparer, provider, testOutputDetails); } }
/// <summary> /// Creates a matrix that performs a tapering projective transform. /// <see href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/non-affine"/> /// </summary> /// <param name="size">The rectangular size of the image being transformed.</param> /// <param name="side">An enumeration that indicates the side of the rectangle that tapers.</param> /// <param name="corner">An enumeration that indicates on which corners to taper the rectangle.</param> /// <param name="fraction">The amount to taper.</param> /// <returns>The <see cref="Matrix4x4"/></returns> public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner corner, float fraction) { Matrix4x4 matrix = Matrix4x4.Identity; switch (side) { case TaperSide.Left: matrix.M11 = fraction; matrix.M22 = fraction; matrix.M13 = (fraction - 1) / size.Width; switch (corner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M12 = size.Height * matrix.M13; matrix.M32 = size.Height * (1 - fraction); break; case TaperCorner.Both: matrix.M12 = size.Height * .5F * matrix.M13; matrix.M32 = size.Height * (1 - fraction) / 2; break; } break; case TaperSide.Top: matrix.M11 = fraction; matrix.M22 = fraction; matrix.M23 = (fraction - 1) / size.Height; switch (corner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M21 = size.Width * matrix.M23; matrix.M31 = size.Width * (1 - fraction); break; case TaperCorner.Both: matrix.M21 = size.Width * .5F * matrix.M23; matrix.M31 = size.Width * (1 - fraction) / 2; break; } break; case TaperSide.Right: matrix.M11 = 1 / fraction; matrix.M13 = (1 - fraction) / (size.Width * fraction); switch (corner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M12 = size.Height * matrix.M13; break; case TaperCorner.Both: matrix.M12 = size.Height * .5F * matrix.M13; break; } break; case TaperSide.Bottom: matrix.M22 = 1 / fraction; matrix.M23 = (1 - fraction) / (size.Height * fraction); switch (corner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M21 = size.Width * matrix.M23; break; case TaperCorner.Both: matrix.M21 = size.Width * .5F * matrix.M23; break; } break; } return(matrix); }
public static SKMatrix Make(SKSize size, TaperSide taperSide, TaperCorner taperCorner, float taperFraction) { var matrix = SKMatrix.MakeIdentity(); switch (taperSide) { case TaperSide.Left: matrix.ScaleX = taperFraction; matrix.ScaleY = taperFraction; matrix.Persp0 = (taperFraction - 1) / size.Width; switch (taperCorner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.SkewY = size.Height * matrix.Persp0; matrix.TransY = size.Height * (1 - taperFraction); break; case TaperCorner.Both: matrix.SkewY = (size.Height / 2) * matrix.Persp0; matrix.TransY = size.Height * (1 - taperFraction) / 2; break; } break; case TaperSide.Top: matrix.ScaleX = taperFraction; matrix.ScaleY = taperFraction; matrix.Persp1 = (taperFraction - 1) / size.Height; switch (taperCorner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.SkewX = size.Width * matrix.Persp1; matrix.TransX = size.Width * (1 - taperFraction); break; case TaperCorner.Both: matrix.SkewX = (size.Width / 2) * matrix.Persp1; matrix.TransX = size.Width * (1 - taperFraction) / 2; break; } break; case TaperSide.Right: matrix.ScaleX = 1 / taperFraction; matrix.Persp0 = (1 - taperFraction) / (size.Width * taperFraction); switch (taperCorner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.SkewY = size.Height * matrix.Persp0; break; case TaperCorner.Both: matrix.SkewY = (size.Height / 2) * matrix.Persp0; break; } break; case TaperSide.Bottom: matrix.ScaleY = 1 / taperFraction; matrix.Persp1 = (1 - taperFraction) / (size.Height * taperFraction); switch (taperCorner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.SkewX = size.Width * matrix.Persp1; break; case TaperCorner.Both: matrix.SkewX = (size.Width / 2) * matrix.Persp1; break; } break; } return(matrix); }
/// <summary> /// Creates a matrix that performs a tapering projective transform. /// <see href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/non-affine"/> /// </summary> /// <param name="size">The rectangular size of the image being transformed.</param> /// <param name="taperSide">An enumeration that indicates the side of the rectangle that tapers.</param> /// <param name="taperCorner">An enumeration that indicates on which corners to taper the rectangle.</param> /// <param name="taperFraction">The amount to taper.</param> /// <returns>The <see cref="Matrix4x4"/></returns> public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide taperSide, TaperCorner taperCorner, float taperFraction) { Matrix4x4 matrix = Matrix4x4.Identity; switch (taperSide) { case TaperSide.Left: matrix.M11 = taperFraction; matrix.M22 = taperFraction; matrix.M13 = (taperFraction - 1) / size.Width; switch (taperCorner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M12 = size.Height * matrix.M13; matrix.M32 = size.Height * (1 - taperFraction); break; case TaperCorner.Both: matrix.M12 = (size.Height * 0.5f) * matrix.M13; matrix.M32 = size.Height * (1 - taperFraction) / 2; break; } break; case TaperSide.Top: matrix.M11 = taperFraction; matrix.M22 = taperFraction; matrix.M23 = (taperFraction - 1) / size.Height; switch (taperCorner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M21 = size.Width * matrix.M23; matrix.M31 = size.Width * (1 - taperFraction); break; case TaperCorner.Both: matrix.M21 = (size.Width * 0.5f) * matrix.M23; matrix.M31 = size.Width * (1 - taperFraction) / 2; break; } break; case TaperSide.Right: matrix.M11 = 1 / taperFraction; matrix.M13 = (1 - taperFraction) / (size.Width * taperFraction); switch (taperCorner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M12 = size.Height * matrix.M13; break; case TaperCorner.Both: matrix.M12 = (size.Height * 0.5f) * matrix.M13; break; } break; case TaperSide.Bottom: matrix.M22 = 1 / taperFraction; matrix.M23 = (1 - taperFraction) / (size.Height * taperFraction); switch (taperCorner) { case TaperCorner.RightOrBottom: break; case TaperCorner.LeftOrTop: matrix.M21 = size.Width * matrix.M23; break; case TaperCorner.Both: matrix.M21 = (size.Width * 0.5f) * matrix.M23; break; } break; } return(matrix); }