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);
        }
Example #2
0
        /// <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));
Example #4
0
        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);
            }
        }
Example #5
0
        /// <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);
        }
Example #6
0
        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);
        }
Example #7
0
        /// <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);
        }