コード例 #1
0
 public static SKPoint GradientBrushPointToSkiaPoint(Point point, IGradientBrush gradientBrush, IUIElement uiElement)
 {
     if (gradientBrush.MappingMode == BrushMappingMode.RelativeToBoundingBox)
     {
         return(new SKPoint(
                    (float)(point.X * uiElement.Width),
                    (float)(point.Y * uiElement.Height)));
     }
     else
     {
         return(new SKPoint((float)point.X, (float)point.Y));
     }
 }
コード例 #2
0
        public static SKShader ToSkiaShader(IGradientBrush gradientBrush, IShape shape)
        {
            SKShaderTileMode tileMode = gradientBrush.SpreadMethod switch
            {
                GradientSpreadMethod.Pad => SKShaderTileMode.Clamp,
                GradientSpreadMethod.Reflect => SKShaderTileMode.Mirror,
                GradientSpreadMethod.Repeat => SKShaderTileMode.Repeat,
                _ => throw new InvalidOperationException($"Unknown GradientSpreadmethod value {gradientBrush.SpreadMethod}")
            };

            List <SKColor> skiaColors         = new List <SKColor>();
            List <float>   skiaColorPositions = new List <float>();

            foreach (IGradientStop gradientStop in gradientBrush.GradientStops)
            {
                skiaColors.Add(ToSkiaColor(gradientStop.Color));
                skiaColorPositions.Add((float)gradientStop.Offset);
            }

            if (gradientBrush is ILinearGradientBrush linearGradientBrush)
            {
                SKPoint skiaStartPoint = new SKPoint(
                    (float)(shape.Left + linearGradientBrush.StartPoint.X * shape.Width),
                    (float)(shape.Top + linearGradientBrush.StartPoint.Y * shape.Height));
                SKPoint skiaEndPoint = new SKPoint(
                    (float)(shape.Left + linearGradientBrush.EndPoint.X * shape.Width),
                    (float)(shape.Top + linearGradientBrush.EndPoint.Y * shape.Height));

                return(SKShader.CreateLinearGradient(skiaStartPoint, skiaEndPoint, skiaColors.ToArray(), skiaColorPositions.ToArray(), tileMode));
            }
            else if (gradientBrush is IRadialGradientBrush radialGradientBrush)
            {
                SKPoint skiaCenterPoint = new SKPoint(
                    (float)(shape.Left + radialGradientBrush.Center.X * shape.Width),
                    (float)(shape.Top + radialGradientBrush.Center.Y * shape.Height));

                float radius = (float)(radialGradientBrush.RadiusX * shape.Width);
                return(SKShader.CreateRadialGradient(skiaCenterPoint, radius, skiaColors.ToArray(), skiaColorPositions.ToArray(), tileMode));
            }
            else
            {
                throw new InvalidOperationException($"GradientBrush type {gradientBrush.GetType()} is unknown");
            }
        }
コード例 #3
0
        internal static IGradientBrush ConvertSolidColorBrushToGradient(IGradientBrush gradientBrush, ISolidColorBrush solidColorBrush)
        {
            switch (gradientBrush)
            {
            case IRadialGradientBrush oldRadial:
                return(new ImmutableRadialGradientBrush(
                           CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity,
                           oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius));

            case IConicGradientBrush oldConic:
                return(new ImmutableConicGradientBrush(
                           CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity,
                           oldConic.SpreadMethod, oldConic.Center, oldConic.Angle));

            case ILinearGradientBrush oldLinear:
                return(new ImmutableLinearGradientBrush(
                           CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity,
                           oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint));

            default:
                throw new NotSupportedException($"Gradient of type {gradientBrush?.GetType()} is not supported");
            }
コード例 #4
0
        /// <summary>
        /// Configure paint wrapper for using gradient brush.
        /// </summary>
        /// <param name="paintWrapper">Paint wrapper.</param>
        /// <param name="targetSize">Target size.</param>
        /// <param name="gradientBrush">Gradient brush.</param>
        private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Size targetSize, IGradientBrush gradientBrush)
        {
            var tileMode    = gradientBrush.SpreadMethod.ToSKShaderTileMode();
            var stopColors  = gradientBrush.GradientStops.Select(s => s.Color.ToSKColor()).ToArray();
            var stopOffsets = gradientBrush.GradientStops.Select(s => (float)s.Offset).ToArray();

            switch (gradientBrush)
            {
            case ILinearGradientBrush linearGradient:
            {
                var start = linearGradient.StartPoint.ToPixels(targetSize).ToSKPoint();
                var end   = linearGradient.EndPoint.ToPixels(targetSize).ToSKPoint();

                // would be nice to cache these shaders possibly?
                using (var shader =
                           SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode))
                {
                    paintWrapper.Paint.Shader = shader;
                }

                break;
            }

            case IRadialGradientBrush radialGradient:
            {
                var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint();
                var radius = (float)(radialGradient.Radius * targetSize.Width);

                // TODO: There is no SetAlpha in SkiaSharp
                //paint.setAlpha(128);

                // would be nice to cache these shaders possibly?
                using (var shader =
                           SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode))
                {
                    paintWrapper.Paint.Shader = shader;
                }

                break;
            }
            }
        }
コード例 #5
0
        /// <summary>
        /// Configure paint wrapper for using gradient brush.
        /// </summary>
        /// <param name="paintWrapper">Paint wrapper.</param>
        /// <param name="targetSize">Target size.</param>
        /// <param name="gradientBrush">Gradient brush.</param>
        private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Size targetSize, IGradientBrush gradientBrush)
        {
            var tileMode    = gradientBrush.SpreadMethod.ToSKShaderTileMode();
            var stopColors  = gradientBrush.GradientStops.Select(s => s.Color.ToSKColor()).ToArray();
            var stopOffsets = gradientBrush.GradientStops.Select(s => (float)s.Offset).ToArray();

            switch (gradientBrush)
            {
            case ILinearGradientBrush linearGradient:
            {
                var start = linearGradient.StartPoint.ToPixels(targetSize).ToSKPoint();
                var end   = linearGradient.EndPoint.ToPixels(targetSize).ToSKPoint();

                // would be nice to cache these shaders possibly?
                using (var shader =
                           SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode))
                {
                    paintWrapper.Paint.Shader = shader;
                }

                break;
            }

            case IRadialGradientBrush radialGradient:
            {
                var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint();
                var radius = (float)(radialGradient.Radius * targetSize.Width);

                var origin = radialGradient.GradientOrigin.ToPixels(targetSize).ToSKPoint();

                if (origin.Equals(center))
                {
                    // when the origin is the same as the center the Skia RadialGradient acts the same as D2D
                    using (var shader =
                               SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode))
                    {
                        paintWrapper.Paint.Shader = shader;
                    }
                }
                else
                {
                    // when the origin is different to the center use a two point ConicalGradient to match the behaviour of D2D

                    // reverse the order of the stops to match D2D
                    var reversedColors = new SKColor[stopColors.Length];
                    Array.Copy(stopColors, reversedColors, stopColors.Length);
                    Array.Reverse(reversedColors);

                    // and then reverse the reference point of the stops
                    var reversedStops = new float[stopOffsets.Length];
                    for (var i = 0; i < stopOffsets.Length; i++)
                    {
                        reversedStops[i] = stopOffsets[i];
                        if (reversedStops[i] > 0 && reversedStops[i] < 1)
                        {
                            reversedStops[i] = Math.Abs(1 - stopOffsets[i]);
                        }
                    }

                    // compose with a background colour of the final stop to match D2D's behaviour of filling with the final color
                    using (var shader = SKShader.CreateCompose(
                               SKShader.CreateColor(reversedColors[0]),
                               SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode)
                               ))
                    {
                        paintWrapper.Paint.Shader = shader;
                    }
                }

                break;
            }

            case IConicGradientBrush conicGradient:
            {
                var center = conicGradient.Center.ToPixels(targetSize).ToSKPoint();

                // Skia's default is that angle 0 is from the right hand side of the center point
                // but we are matching CSS where the vertical point above the center is 0.
                var angle    = (float)(conicGradient.Angle - 90);
                var rotation = SKMatrix.CreateRotationDegrees(angle, center.X, center.Y);

                using (var shader =
                           SKShader.CreateSweepGradient(center, stopColors, stopOffsets, rotation))
                {
                    paintWrapper.Paint.Shader = shader;
                }

                break;
            }
            }
        }
コード例 #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ImmutableGradientBrush"/> class.
 /// </summary>
 /// <param name="source">The brush from which this brush's properties should be copied.</param>
 protected ImmutableGradientBrush(IGradientBrush source)
     : this(source.GradientStops.ToList(), source.Opacity, source.SpreadMethod)
 {
 }
コード例 #7
0
 public static IGradientBrush CreateRef(this IGradientBrush objectRef) =>
 ((IGradientBrush)objectRef.CreateRef(typeof(IGradientBrush)));