Example #1
0
 public static SKMatrix Scale(this SKMatrix m, float sx, float sy)
 {
     return(m.Concat(SKMatrix.MakeScale(sx, sy)));
 }
        public override void Resize(string sourceFile, string destinationFile, ImageAsset asset, OutputConfig outputConfig)
        {
            int    sourceNominalWidth  = asset.Width;
            int    sourceNominalHeight = asset.Height;
            double resizeRatio         = outputConfig.Ratio;

            var fillColor = asset.FillColor;

            if (string.IsNullOrEmpty(fillColor))
            {
                fillColor = outputConfig.FillColor;
            }

            // For SVG's we can optionally change the fill color on all paths
            if (!string.IsNullOrEmpty(fillColor))
            {
                var svgText = File.ReadAllText(sourceFile);

                foreach (var rxPattern in rxFillPatterns)
                {
                    var matches = Regex.Matches(svgText, rxPattern);

                    foreach (Match match in matches)
                    {
                        var fillGroup = match.Groups?["fill"];

                        if (fillGroup != null)
                        {
                            // Replace the matched rx group with our override fill color
                            var a = svgText.Substring(0, fillGroup.Index);
                            var b = svgText.Substring(fillGroup.Index + fillGroup.Length);
                            svgText = a + outputConfig.FillColor.TrimEnd(';') + ";" + b;
                        }
                    }
                }

                // Write our changes out to a temp file so we don't alter the original
                var tempFile = Path.GetTempFileName();
                File.WriteAllText(tempFile, svgText);
                sourceFile = tempFile;
            }

            var svg = new SKSvg();

            svg.Load(sourceFile);

            // Find the actual size of the SVG
            var sourceActualWidth  = svg.Picture.CullRect.Width;
            var sourceActualHeight = svg.Picture.CullRect.Height;

            // Figure out what the ratio to convert the actual image size to the nominal size is
            var nominalRatio = Math.Max((double)sourceNominalWidth / (double)sourceActualWidth, (double)sourceNominalHeight / (double)sourceActualHeight);

            // Multiply nominal ratio by the resize ratio to get our final ratio we actually adjust by
            var adjustRatio = nominalRatio * resizeRatio;

            // Figure out our scaled width and height to make a new canvas for
            var scaledWidth  = sourceActualWidth * adjustRatio;
            var scaledHeight = sourceActualHeight * adjustRatio;

            // Make a canvas of the target size to draw the svg onto
            var bmp    = new SKBitmap((int)scaledWidth, (int)scaledHeight);
            var canvas = new SKCanvas(bmp);

            // Make a matrix to scale the SVG
            var matrix = SKMatrix.MakeScale((float)adjustRatio, (float)adjustRatio);

            canvas.Clear(SKColors.Transparent);

            // Draw the svg onto the canvas with our scaled matrix
            canvas.DrawPicture(svg.Picture, ref matrix);

            // Save the op
            canvas.Save();

            // Export the canvas
            var img  = SKImage.FromBitmap(bmp);
            var data = img.Encode(SKImageEncodeFormat.Png, 100);

            using (var fs = File.Open(destinationFile, FileMode.Create)) {
                data.SaveTo(fs);
            }
        }
Example #3
0
        private SKMatrix ReadTransform(string raw)
        {
            var t = SKMatrix.MakeIdentity();

            if (string.IsNullOrWhiteSpace(raw))
            {
                return(t);
            }

            var calls = raw.Trim().Split(new[] { ')' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var c in calls)
            {
                var args = c.Split(new[] { '(', ',', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                var nt   = SKMatrix.MakeIdentity();
                switch (args[0])
                {
                case "matrix":
                    if (args.Length == 7)
                    {
                        nt.Values = new float[]
                        {
                            ReadNumber(args[1]), ReadNumber(args[3]), ReadNumber(args[5]),
                            ReadNumber(args[2]), ReadNumber(args[4]), ReadNumber(args[6]),
                            0, 0, 1
                        };
                    }
                    else
                    {
                        LogOrThrow($"Matrices are expected to have 6 elements, this one has {args.Length - 1}");
                    }
                    break;

                case "translate":
                    if (args.Length >= 3)
                    {
                        nt = SKMatrix.MakeTranslation(ReadNumber(args[1]), ReadNumber(args[2]));
                    }
                    else if (args.Length >= 2)
                    {
                        nt = SKMatrix.MakeTranslation(ReadNumber(args[1]), 0);
                    }
                    break;

                case "scale":
                    if (args.Length >= 3)
                    {
                        nt = SKMatrix.MakeScale(ReadNumber(args[1]), ReadNumber(args[2]));
                    }
                    else if (args.Length >= 2)
                    {
                        var sx = ReadNumber(args[1]);
                        nt = SKMatrix.MakeScale(sx, sx);
                    }
                    break;

                case "rotate":
                    var a = ReadNumber(args[1]);
                    if (args.Length >= 4)
                    {
                        var x  = ReadNumber(args[2]);
                        var y  = ReadNumber(args[3]);
                        var t1 = SKMatrix.MakeTranslation(x, y);
                        var t2 = SKMatrix.MakeRotationDegrees(a);
                        var t3 = SKMatrix.MakeTranslation(-x, -y);
                        SKMatrix.Concat(ref nt, ref t1, ref t2);
                        SKMatrix.Concat(ref nt, ref nt, ref t3);
                    }
                    else
                    {
                        nt = SKMatrix.MakeRotationDegrees(a);
                    }
                    break;

                default:
                    LogOrThrow($"Can't transform {args[0]}");
                    break;
                }
                SKMatrix.Concat(ref t, ref t, ref nt);
            }

            return(t);
        }
Example #4
0
        public static SKMatrix ToSKMatrix(this SvgTransformCollection svgTransformCollection)
        {
            var skMatrixTotal = SKMatrix.MakeIdentity();

            if (svgTransformCollection == null)
            {
                return(skMatrixTotal);
            }

            foreach (var svgTransform in svgTransformCollection)
            {
                switch (svgTransform)
                {
                case SvgMatrix svgMatrix:
                {
                    var skMatrix = svgMatrix.ToSKMatrix();
                    SKMatrix.PreConcat(ref skMatrixTotal, ref skMatrix);
                }
                break;

                case SvgRotate svgRotate:
                {
                    var skMatrixRotate = SKMatrix.MakeRotationDegrees(svgRotate.Angle, svgRotate.CenterX, svgRotate.CenterY);
                    SKMatrix.PreConcat(ref skMatrixTotal, ref skMatrixRotate);
                }
                break;

                case SvgScale svgScale:
                {
                    var skMatrixScale = SKMatrix.MakeScale(svgScale.X, svgScale.Y);
                    SKMatrix.PreConcat(ref skMatrixTotal, ref skMatrixScale);
                }
                break;

                case SvgShear svgShear:
                {
                    // Not in the svg specification.
                }
                break;

                case SvgSkew svgSkew:
                {
                    float sx           = (float)Math.Tan(Math.PI * svgSkew.AngleX / 180);
                    float sy           = (float)Math.Tan(Math.PI * svgSkew.AngleY / 180);
                    var   skMatrixSkew = SKMatrix.MakeSkew(sx, sy);
                    SKMatrix.PreConcat(ref skMatrixTotal, ref skMatrixSkew);
                }
                break;

                case SvgTranslate svgTranslate:
                {
                    var skMatrixTranslate = SKMatrix.MakeTranslation(svgTranslate.X, svgTranslate.Y);
                    SKMatrix.PreConcat(ref skMatrixTotal, ref skMatrixTranslate);
                }
                break;

                default:
                    break;
                }
            }

            return(skMatrixTotal);
        }
Example #5
0
        public ImageDrawable(SvgImage svgImage, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgImage, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgImage, IgnoreAttributes) && HasFeatures(svgImage, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            float width    = svgImage.Width.ToDeviceValue(UnitRenderingType.Horizontal, svgImage, skOwnerBounds);
            float height   = svgImage.Height.ToDeviceValue(UnitRenderingType.Vertical, svgImage, skOwnerBounds);
            float x        = svgImage.Location.X.ToDeviceValue(UnitRenderingType.Horizontal, svgImage, skOwnerBounds);
            float y        = svgImage.Location.Y.ToDeviceValue(UnitRenderingType.Vertical, svgImage, skOwnerBounds);
            var   location = new SKPoint(x, y);

            if (width <= 0f || height <= 0f || svgImage.Href == null)
            {
                IsDrawable = false;
                return;
            }

            // TODO: Check for image recursive references.
            //if (SkiaUtil.HasRecursiveReference(svgImage, (e) => e.Href))
            //{
            //    _canDraw = false;
            //    return;
            //}

            var image       = SvgImageExtensions.GetImage(svgImage.Href, svgImage.OwnerDocument);
            var skImage     = image as SKImage;
            var svgFragment = image as SvgFragment;

            if (skImage == null && svgFragment == null)
            {
                IsDrawable = false;
                return;
            }

            if (skImage != null)
            {
                _disposable.Add(skImage);
            }

            SrcRect = default;

            if (skImage != null)
            {
                SrcRect = SKRect.Create(0f, 0f, skImage.Width, skImage.Height);
            }

            if (svgFragment != null)
            {
                var skSize = SvgExtensions.GetDimensions(svgFragment);
                SrcRect = SKRect.Create(0f, 0f, skSize.Width, skSize.Height);
            }

            var destClip = SKRect.Create(location.X, location.Y, width, height);

            var aspectRatio = svgImage.AspectRatio;

            if (aspectRatio.Align != SvgPreserveAspectRatio.none)
            {
                var fScaleX = destClip.Width / SrcRect.Width;
                var fScaleY = destClip.Height / SrcRect.Height;
                var xOffset = 0f;
                var yOffset = 0f;

                if (aspectRatio.Slice)
                {
                    fScaleX = Math.Max(fScaleX, fScaleY);
                    fScaleY = Math.Max(fScaleX, fScaleY);
                }
                else
                {
                    fScaleX = Math.Min(fScaleX, fScaleY);
                    fScaleY = Math.Min(fScaleX, fScaleY);
                }

                switch (aspectRatio.Align)
                {
                case SvgPreserveAspectRatio.xMinYMin:
                    break;

                case SvgPreserveAspectRatio.xMidYMin:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX) / 2;
                    break;

                case SvgPreserveAspectRatio.xMaxYMin:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX);
                    break;

                case SvgPreserveAspectRatio.xMinYMid:
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMidYMid:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX) / 2;
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMaxYMid:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX);
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMinYMax:
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY);
                    break;

                case SvgPreserveAspectRatio.xMidYMax:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX) / 2;
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY);
                    break;

                case SvgPreserveAspectRatio.xMaxYMax:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX);
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY);
                    break;
                }

                DestRect = SKRect.Create(
                    destClip.Left + xOffset,
                    destClip.Top + yOffset,
                    SrcRect.Width * fScaleX,
                    SrcRect.Height * fScaleY);
            }
            else
            {
                DestRect = destClip;
            }

            Clip = destClip;

            var skClipRect = SvgClippingExtensions.GetClipRect(svgImage, destClip);

            if (skClipRect != null)
            {
                Clip = skClipRect;
            }

            if (skImage != null)
            {
                Image = skImage;
            }

            if (svgFragment != null)
            {
                FragmentDrawable = new FragmentDrawable(svgFragment, skOwnerBounds, root, this, ignoreAttributes);
                _disposable.Add(FragmentDrawable);
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgImage);

            if (Image != null)
            {
                TransformedBounds = DestRect;
            }

            if (FragmentDrawable != null)
            {
                //_skBounds = _fragmentDrawable._skBounds;
                TransformedBounds = DestRect;
            }

            Transform         = SvgTransformsExtensions.ToSKMatrix(svgImage.Transforms);
            FragmentTransform = SKMatrix.MakeIdentity();
            if (FragmentDrawable != null)
            {
                float dx = DestRect.Left;
                float dy = DestRect.Top;
                float sx = DestRect.Width / SrcRect.Width;
                float sy = DestRect.Height / SrcRect.Height;
                var   skTranslationMatrix = SKMatrix.MakeTranslation(dx, dy);
                var   skScaleMatrix       = SKMatrix.MakeScale(sx, sy);
                FragmentTransform = FragmentTransform.PreConcat(skTranslationMatrix);
                FragmentTransform = FragmentTransform.PreConcat(skScaleMatrix);
            }

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            TransformedBounds = Transform.MapRect(TransformedBounds);
        }
Example #6
0
        public void DrawImage(SvgImage svgImage, bool ignoreDisplay)
        {
            if (!CanDraw(svgImage, ignoreDisplay))
            {
                return;
            }

            float width    = svgImage.Width.ToDeviceValue(null, UnitRenderingType.Horizontal, svgImage);
            float height   = svgImage.Height.ToDeviceValue(null, UnitRenderingType.Vertical, svgImage);
            var   location = svgImage.Location.ToDeviceValue(null, svgImage);

            if (width <= 0f || height <= 0f || svgImage.Href == null)
            {
                return;
            }

            var image       = SkiaUtil.GetImage(svgImage, svgImage.Href);
            var skImage     = image as SKImage;
            var svgFragment = image as SvgFragment;

            if (skImage == null && svgFragment == null)
            {
                return;
            }

            if (skImage != null)
            {
                _disposable.Add(skImage);
            }

            SKRect srcRect = default;

            if (skImage != null)
            {
                srcRect = SKRect.Create(0f, 0f, skImage.Width, skImage.Height);
            }

            if (svgFragment != null)
            {
                var skSize = SkiaUtil.GetDimensions(svgFragment);
                srcRect = SKRect.Create(0f, 0f, skSize.Width, skSize.Height);
            }

            var destClip = SKRect.Create(location.X, location.Y, width, height);
            var destRect = destClip;

            var aspectRatio = svgImage.AspectRatio;

            if (aspectRatio.Align != SvgPreserveAspectRatio.none)
            {
                var fScaleX = destClip.Width / srcRect.Width;
                var fScaleY = destClip.Height / srcRect.Height;
                var xOffset = 0f;
                var yOffset = 0f;

                if (aspectRatio.Slice)
                {
                    fScaleX = Math.Max(fScaleX, fScaleY);
                    fScaleY = Math.Max(fScaleX, fScaleY);
                }
                else
                {
                    fScaleX = Math.Min(fScaleX, fScaleY);
                    fScaleY = Math.Min(fScaleX, fScaleY);
                }

                switch (aspectRatio.Align)
                {
                case SvgPreserveAspectRatio.xMinYMin:
                    break;

                case SvgPreserveAspectRatio.xMidYMin:
                    xOffset = (destClip.Width - srcRect.Width * fScaleX) / 2;
                    break;

                case SvgPreserveAspectRatio.xMaxYMin:
                    xOffset = (destClip.Width - srcRect.Width * fScaleX);
                    break;

                case SvgPreserveAspectRatio.xMinYMid:
                    yOffset = (destClip.Height - srcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMidYMid:
                    xOffset = (destClip.Width - srcRect.Width * fScaleX) / 2;
                    yOffset = (destClip.Height - srcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMaxYMid:
                    xOffset = (destClip.Width - srcRect.Width * fScaleX);
                    yOffset = (destClip.Height - srcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMinYMax:
                    yOffset = (destClip.Height - srcRect.Height * fScaleY);
                    break;

                case SvgPreserveAspectRatio.xMidYMax:
                    xOffset = (destClip.Width - srcRect.Width * fScaleX) / 2;
                    yOffset = (destClip.Height - srcRect.Height * fScaleY);
                    break;

                case SvgPreserveAspectRatio.xMaxYMax:
                    xOffset = (destClip.Width - srcRect.Width * fScaleX);
                    yOffset = (destClip.Height - srcRect.Height * fScaleY);
                    break;
                }

                destRect = SKRect.Create(
                    destClip.Left + xOffset, destClip.Top + yOffset,
                    srcRect.Width * fScaleX, srcRect.Height * fScaleY);
            }

            _skCanvas.Save();

            var skMatrix = SkiaUtil.GetSKMatrix(svgImage.Transforms);

            SetTransform(skMatrix);
            SetClipPath(svgImage, _disposable);

            var skPaintOpacity = SetOpacity(svgImage, _disposable);

            var skPaintFilter = SetFilter(svgImage, _disposable);

            _skCanvas.ClipRect(destClip, SKClipOperation.Intersect);

            SetClip(svgImage, destClip);

            if (skImage != null)
            {
                _skCanvas.DrawImage(skImage, srcRect, destRect);
            }

            if (svgFragment != null)
            {
                _skCanvas.Save();

                float dx = destRect.Left;
                float dy = destRect.Top;
                float sx = destRect.Width / srcRect.Width;
                float sy = destRect.Height / srcRect.Height;
                var   skTranslationMatrix = SKMatrix.MakeTranslation(dx, dy);
                var   skScaleMatrix       = SKMatrix.MakeScale(sx, sy);
                SKMatrix.PreConcat(ref skTranslationMatrix, ref skScaleMatrix);
                SetTransform(skTranslationMatrix);

                DrawFragment(svgFragment, ignoreDisplay);

                _skCanvas.Restore();
            }

            if (skPaintFilter != null)
            {
                _skCanvas.Restore();
            }

            if (skPaintOpacity != null)
            {
                _skCanvas.Restore();
            }

            _skCanvas.Restore();
        }
        private static void ExtractImageFromStream(string url, Size desiredSize, Stream inputStream, Stream imageStream)
        {
            if (IsSvg(url))
            {
                using (var svg = new SKSvg())
                {
                    try
                    {
                        svg.Load(inputStream);
                    }
                    catch (Exception exception)
                    {
                        Logger.Warning(exception, $"Something is wrong with: \"{url}\".");
                    }

                    var skPicture = svg.Picture;
                    var imageInfo = new SKImageInfo((int)desiredSize.Width, (int)desiredSize.Height);
                    using (var surface = SKSurface.Create(imageInfo))
                    {
                        using (var canvas = surface.Canvas)
                        {
                            // calculate the scaling need to fit to desired size
                            var scaleX = desiredSize.Width / skPicture.CullRect.Width;
                            var scaleY = desiredSize.Height / skPicture.CullRect.Height;
                            var matrix = SKMatrix.MakeScale((float)scaleX, (float)scaleY);

                            // draw the svg
                            canvas.Clear(SKColors.Transparent);
                            canvas.DrawPicture(skPicture, ref matrix);
                            canvas.Flush();

                            using (var data = surface.Snapshot())
                            {
                                using (var pngImage = data.Encode(SKEncodedImageFormat.Png, 100))
                                {
                                    pngImage.SaveTo(imageStream);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                var bitmap = SKBitmap.Decode(inputStream);
                if (bitmap != null)
                {
                    var resizeInfo = GetResizeSkImageInfo(desiredSize, bitmap);
                    using (var resizedBitmap = bitmap.Resize(resizeInfo, SKFilterQuality.High))
                    {
                        bitmap.Dispose();

                        using (var image = SKImage.FromBitmap(resizedBitmap))
                        {
                            using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
                            {
                                data.SaveTo(imageStream);
                            }
                        }
                    }
                }
            }
        }
Example #8
0
        /// <summary>
        /// Constructor
        /// </summary>
        public RotaryEventPage()
        {
            // NOTICE: IRotaryEventReceiver object MUST set 'RotaryFocusObject' to get the event.
            RotaryFocusObject = this;

            // Initialize variables to set the state to rotating right
            currentState = ONGOING_EVENT_STATE.RIGHT_DIRECTION_ROTATE;
            instruction  = "Rotate the bezel to the right.";
            angle        = 0;

            // Initialize gradient to draw arrows
            // Create the main canvas new
            canvasView = new SKCanvasView();
            // Need to set heightRequest and WidthReques to SkiaSharp canvas
            canvasView.HeightRequest = 360;
            canvasView.WidthRequest  = 360;

            // Add tap gesture recognizer
            var tapGestureRecognizer = new TapGestureRecognizer();

            // Show a toast when tapped.
            tapGestureRecognizer.Tapped += (s, e) =>
            {
                Toast.DisplayText("Tapped !!!");
            };
            // Add to GestureRecognizers in canvas view
            canvasView.GestureRecognizers.Add(tapGestureRecognizer);
            // This event handler actually draws in SkiaSharp canvas
            canvasView.PaintSurface += (sender, e) =>
            {
                // Right arrow svg data
                SKPath rightDirectionArrow = SKPath.ParseSvgPathData("M2.5,4.375l1.5625,-1.25h-1.25a8,8,0,0,0,-6,-6.25a2,2,0,0,1,-0.625,3.125a4.6,4.6,0,0,1,5.875,3.125h-1.25Z");
                // Left arrow svg data
                SKPath leftDirectionArrow = SKPath.ParseSvgPathData("M-2.5,4.375L-4.0625,3.125H-2.8125A8,8,0,0,1,3.1875,-3.125A2,2,0,0,0,3.8125,0A4.6,4.6,0,0,0,-2.0625,3.125H-0.8125Z");
                // Get surface
                SKSurface canvasSurface = e.Surface;
                // Get canvas of surface
                SKCanvas canvas = canvasSurface.Canvas;
                // Save canvas here to later retrieve
                canvas.Save();
                // Initialize canvase before drawing
                canvas.Clear(SKColors.Black);
                // Handling for the right rotation state
                if (currentState == ONGOING_EVENT_STATE.RIGHT_DIRECTION_ROTATE)
                {
                    // To draw arrow for rotating direction, move canvas point
                    canvas.Translate(e.Info.Width * 3 / 4, e.Info.Height / 4);
                    // Set scale for the path
                    SKMatrix matrix = SKMatrix.MakeScale(15, 15);
                    // Adjust scale before drawing
                    rightDirectionArrow.Transform(matrix);
                    // Set a shader for gradient
                    var colors = new SKColor[] { SKColors.White, SKColors.Blue };
                    // Points needed for gradient
                    SKPoint startPoint = new SKPoint(0, 0);
                    SKPoint endPoint   = new SKPoint(20, 20);
                    var     shader     = SKShader.CreateLinearGradient(startPoint, endPoint, colors, null, SKShaderTileMode.Clamp);
                    // Add the shader to paint to present gradient effect
                    blackStrokePaint.Shader = shader;
                    // Draw SVG path for right rotate direction arrow
                    canvas.DrawPath(rightDirectionArrow, blackStrokePaint);
                }
                else if (currentState == ONGOING_EVENT_STATE.LEFT_DIRECTION_ROTATE)
                {
                    // Move the canvas translate point
                    canvas.Translate(e.Info.Width * 1 / 4, e.Info.Height / 4);
                    // Set scale for the path
                    SKMatrix matrix = SKMatrix.MakeScale(15, 15);
                    // Set a shader for gradient
                    leftDirectionArrow.Transform(matrix);
                    // Colors for gradient
                    var colors = new SKColor[] { SKColors.White, SKColors.Blue };
                    // Points for gradient
                    SKPoint startPoint = new SKPoint(20, 0);
                    SKPoint endPoint   = new SKPoint(0, 20);
                    // Define a shader for left rotate arrow
                    var shader = SKShader.CreateLinearGradient(startPoint, endPoint, colors, null, SKShaderTileMode.Clamp);
                    blackStrokePaint.Shader = shader;
                    // Draw SVG path for left rotate direction arrow
                    canvas.DrawPath(leftDirectionArrow, blackStrokePaint);
                }

                // Need to reset canvas which were changed by Translate
                canvas.Restore();
                // Text drawing
                SKPaint textPaint = new SKPaint
                {
                    // Text color white
                    Color = SKColors.White,
                    // Text size 10
                    TextSize = 10,
                    // Antialiasing true
                    IsAntialias = true
                };
                string str = instruction;
                // Before draw a text, need to calculate total width of a text to locate in the middle
                float textWidth = textPaint.MeasureText(str);
                textPaint.TextSize = 0.7f * e.Info.Width * textPaint.TextSize / textWidth;
                // Draw instruction
                SKRect textBounds = new SKRect();
                textPaint.MeasureText(str, ref textBounds);
                float xText = e.Info.Width / 2 - textBounds.MidX;
                float yText = e.Info.Height / 2 - textBounds.MidY;
                canvas.DrawText(str, xText, yText, textPaint);
            };

            Content = new StackLayout
            {
                Children =
                {
                    canvasView
                }
            };
        }
Example #9
0
        /// <summary>
        /// Delete folder and icons within
        /// </summary>
        /// <param name="currentIcon"></param>
        public async void ConfirmDeleteFolder(Icon currentIcon)
        {
            var response = await Acr.UserDialogs.UserDialogs.Instance.ConfirmAsync("Delete this folder and the icons within?");

            if (response && currentIcon != null)
            {
                new Xamarin.Forms.Animation((value) =>
                {
                    try
                    {
                        if (currentIcon != null)
                        {
                            currentIcon.Transformation = SKMatrix.MakeScale(1 - (float)value, 1 - (float)value);
                        }
                    }
                    catch (System.Exception e)
                    {
                        System.Diagnostics.Debug.WriteLineIf(App.OutputVerbose, e.ToString());
                    }
                }).Commit(Xamarin.Forms.Application.Current.MainPage, "Anim", length: Constants.DeviceLayout.AnimationShrinkMillis, finished: async(v2, c2) =>
                {
                    try
                    {
                        var containedIconColl = canvasRef.Icons.Where(elem => elem.IsStoredInAFolder &&
                                                                      elem.StoredFolderTag == currentIcon.Text);

                        if (containedIconColl != null && containedIconColl.Any() && containedIconColl.Count() > 0)
                        {
                            System.Collections.Generic.List <int> indicesToRemove = new System.Collections.Generic.List <int>();

                            // Build a list of items to remove
                            foreach (var storedIcon in containedIconColl)
                            {
                                indicesToRemove.Add(canvasRef.Icons.IndexOf(storedIcon));
                            }

                            indicesToRemove = indicesToRemove.Where(i => i != -1)
                                              .OrderByDescending(i => i)
                                              .ToList();

                            foreach (var index in indicesToRemove)
                            {
                                canvasRef.Icons.RemoveAt(index);
                            }
                        }

                        if (currentIcon != null)
                        {
                            canvasRef.Icons.Remove(currentIcon);
                            canvasRef.Controller.PromptResave();

#pragma warning disable CS0618 // Type or member is obsolete
                            await PopupNavigation.PopAsync();
#pragma warning restore CS0618 // Type or member is obsolete
                        }
                    }
                    catch (System.Exception e)
                    {
                        System.Diagnostics.Debug.WriteLineIf(App.OutputVerbose, e.ToString());
                    }
                });
            }
        }
Example #10
0
        public MainPage()
        {
            InitializeComponent();
            //AbsoluteLayout.SetLayoutFlags(CanvasView, AbsoluteLayoutFlags.All);
            //AbsoluteLayout.SetLayoutBounds(CanvasView, new Rectangle(0, 0, 1, 1));
            var bluetoothManager        = DependencyService.Get <IManagerManager>().BluetoothManager;
            var deviceInfomationService = new DeviceInfomationServiceBuilder(bluetoothManager).Build();

            bluetoothManager.GattSever.AddService(new DeviceInfomationServiceBuilder(bluetoothManager).Build());
            //bluetoothManager.GattSever.AddService(new BatteryServiceWrapper(bluetoothManager).GattServerService);
            bluetoothManager.GattSever.AddService(new RfcommServerServiceWrapper(bluetoothManager).GattServerService);
            KeyboardServiceWrapper = new KeyboardServiceWrapper(bluetoothManager);
            bluetoothManager.GattSever.AddService(KeyboardServiceWrapper.GattServerService);
            bluetoothManager.GattSever.StartAdvertising();

            var createServiceProviderTask = bluetoothManager.CreateRfcommServiceProviderAsync(GyroscopeRfcommServiceConnectionWrapper.RfcommServiceId);

            createServiceProviderTask.Wait();
            var gyroRfcommServiceProvider = createServiceProviderTask.Result;

            gyroRfcommServiceProvider.OnConnectionReceived += GyroRfcommServiceProvider_OnConnectionReceived;
            gyroRfcommServiceProvider.StartAdvertising();
            Sketch = new Sketch();
            Sketch.SkiaManager.Init(CanvasView.InvalidateSurface, SKMatrix.MakeScale(1, -1));


            Sketch.SketchEngine.Instantiate <GridRenderer>();

            Sketch.SketchEngine.Instantiate <PointerInfoBoard>();
            Sketch.SkiaManager.BeforePaint += SkiaManager_BeforePaint;
            ManagerManager     = DependencyService.Get <IManagerManager>();
            SketchInputManager = Sketch.SketchEngine.Instantiate <SketchInputManager>();
            Sketch.Start();
            SketchInputManager.Init(ManagerManager.InputManager);

            /*
             * var joystick = Sketch.SketchEngine.Instantiate<ColorJoystick>();
             * joystick.RectTransform.AnchorMax = new Vector2(1, 1);
             * joystick.RectTransform.AnchorMin = new Vector2(0, 0);
             * joystick.RectTransform.OffsetMax = new Vector2(-800, -800);
             * joystick.RectTransform.OffsetMin = new Vector2(10, 10);
             * joystick.Level = 2;
             */

            var joystick2 = Sketch.SketchEngine.Instantiate <LineAreaJoystick <byte> >();

            joystick2.RectTransform.AnchorMax = new Vector2(0, 0);
            joystick2.RectTransform.AnchorMin = new Vector2(0, 0);
            joystick2.RectTransform.OffsetMax = new Vector2(600, 600);
            joystick2.RectTransform.OffsetMin = new Vector2(500, 500);
            joystick2.Level = 3;

            joystick2.AddArea(AreaJoystick <byte> .Area <byte> .CreateFromAngle((byte)VirtualKeyCode.VK_D, -60, 60, 0, float.PositiveInfinity));
            joystick2.AddArea(AreaJoystick <byte> .Area <byte> .CreateFromAngle((byte)VirtualKeyCode.VK_W, 30, 150, 0, float.PositiveInfinity));
            joystick2.AddArea(AreaJoystick <byte> .Area <byte> .CreateFromAngle((byte)VirtualKeyCode.VK_A, 120, 240, 0, float.PositiveInfinity));
            joystick2.AddArea(AreaJoystick <byte> .Area <byte> .CreateFromAngle((byte)VirtualKeyCode.VK_S, 210, 330, 0, float.PositiveInfinity));
            joystick2.AddArea(AreaJoystick <byte> .Area <byte> .CreateFromAngle((byte)VirtualKeyCode.LSHIFT, 0, 360, 0.7f, float.PositiveInfinity));
            joystick2.OnAreaStatusChanged += Joystick2_OnAreaStatusChanged;

            var keyboardButton = Sketch.SketchEngine.Instantiate <KeyboardKeyButton>();

            keyboardButton.RectTransform.AnchorMax = new Vector2(0, 0);
            keyboardButton.RectTransform.AnchorMin = new Vector2(0, 0);
            keyboardButton.RectTransform.OffsetMin = new Vector2(50, 50);
            keyboardButton.RectTransform.OffsetMax = new Vector2(150, 150);
            keyboardButton.Level = 2;
            ExampleSketchObject  = Sketch.SketchEngine.Instantiate <ExampleSketchObject>();
            Sketch.SketchEngine.Instantiate <SketchBorderRenderer>();
            Sketch.SketchEngine.Instantiate <RectTransformFrameRenderer>();

            CanvasView.InvalidateSurface();
            ExampleSketchObject.Position = new SKPoint(Sketch.Width / 2, Sketch.Height / 2);
            SensorSpeed speed = SensorSpeed.Game;

            Gyroscope.ReadingChanged += Gyroscope_ReadingChanged;
            Gyroscope.Start(speed);

            Device.StartTimer(TimeSpan.FromSeconds(1 / 60f), () => { CanvasView.InvalidateSurface(); return(!true); });
        }
        public MainPage()
        {
            this.InitializeComponent();
            InputManager inputManager = new InputManager(InputLayerRect);

            Sketch = new Sketch();
            Sketch.SkiaManager.Init(SKCanvasView.Invalidate, SKMatrix.MakeScale(1, -1));
            System.Diagnostics.Debug.WriteLine("MainPageThread:" + Thread.CurrentThread.ManagedThreadId);

            BluetoothManager = new BluetoothManager();

            ExampleSketchObject = Sketch.SketchEngine.Instantiate <ExampleSketchObject>();
            Sketch.SketchEngine.Instantiate <GridRenderer>();
            Sketch.SketchEngine.Instantiate <PointerInfoBoard>();
            Sketch.SketchEngine.Instantiate <SketchBorderRenderer>();
            sketchInputManager = Sketch.SketchEngine.Instantiate <SketchInputManager>();
            sketchInputManager.Init(inputManager);

            Sketch.Start();

            var joystick = Sketch.SketchEngine.Instantiate <ColorJoystick>();

            joystick.RectTransform.AnchorMax = new Vector2(0, 0);
            joystick.RectTransform.AnchorMin = new Vector2(0, 0);
            joystick.RectTransform.OffsetMax = new Vector2(-100, -100);
            joystick.RectTransform.OffsetMin = new Vector2(100, 100);
            joystick.Level = 3;

            var joystick2 = Sketch.SketchEngine.Instantiate <LineAreaJoystick <byte> >();

            joystick2.RectTransform.AnchorMax = new Vector2(0, 0);
            joystick2.RectTransform.AnchorMin = new Vector2(0, 0);
            joystick2.RectTransform.OffsetMax = new Vector2(-10, -10);
            joystick2.RectTransform.OffsetMin = new Vector2(-2000, 2000);
            joystick2.Level = 2;
            //InputLayerRect.TransformMatrix;
            Matrix3x2 matrix = Matrix3x2.CreateScale(0.2f, -0.2f);

            sketchInputManager.InputSpaceToSketchSpaceMatrix = matrix;
            Sketch.SkiaManager.BeforePaint += SkiaManager_BeforePaint;


            /*
             * var characteristicDict = new Dictionary<Guid, List<CharacteristicProfile>>();
             * characteristicDict.Add(KeyboardServiceWrapper.Guid, new List<CharacteristicProfile>()
             * {
             *  new CharacteristicProfile
             *  {
             *      Notified = true,
             *      Guid = Constants.KeyActionCharacteristicWrapper
             *  }
             * });
             * var serviceId = new List<Guid>
             * {
             *  GyroscopeRfcommServiceConnectionWrapper.RfcommServiceId
             * };
             * ConnectionProfile profile = new ConnectionProfile()
             * {
             *  RequiredCharacteristicGuids = characteristicDict,
             *  RequiredServiceGuids = serviceId
             * };
             *
             * TestJitterFixer.DataEmited += TestJitterFixer_DataEmited;
             * var dialog = new BleDeviceSelectorDialog(BluetoothManager, profile);
             * dialog.Closed += Dialog_Closed;
             * dialog.ShowAsync();
             */
        }
        public async Task <Tuple <Stream, LoadingResult, ImageInformation> > Resolve(string identifier, TaskParameter parameters, CancellationToken token)
        {
            ImageSource source = parameters.Source;

            if (!string.IsNullOrWhiteSpace(parameters.LoadingPlaceholderPath) && parameters.LoadingPlaceholderPath == identifier)
            {
                source = parameters.LoadingPlaceholderSource;
            }
            else if (!string.IsNullOrWhiteSpace(parameters.ErrorPlaceholderPath) && parameters.ErrorPlaceholderPath == identifier)
            {
                source = parameters.ErrorPlaceholderSource;
            }

            var resolvedData = await(Configuration.DataResolverFactory ?? new DataResolverFactory())
                               .GetResolver(identifier, source, parameters, Configuration)
                               .Resolve(identifier, parameters, token).ConfigureAwait(false);

            if (resolvedData?.Item1 == null)
            {
                throw new FileNotFoundException(identifier);
            }

            var svg = new SKSvg()
            {
                ThrowOnUnsupportedElement = false,
            };
            SKPicture picture;

            using (var svgStream = resolvedData.Item1)
            {
                picture = svg.Load(resolvedData?.Item1);
            }

            float sizeX = 0;
            float sizeY = 0;

            if (VectorWidth == 0 && VectorHeight == 0)
            {
                if (picture.CullRect.Width > 0)
                {
                    sizeX = picture.CullRect.Width;
                }
                else
                {
                    sizeX = 300;
                }

                if (picture.CullRect.Height > 0)
                {
                    sizeY = picture.CullRect.Height;
                }
                else
                {
                    sizeY = 300;
                }
            }
            else if (VectorWidth > 0 && VectorHeight > 0)
            {
                sizeX = VectorWidth;
                sizeY = VectorHeight;
            }
            else if (VectorWidth > 0)
            {
                sizeX = VectorWidth;
                sizeY = (VectorWidth / picture.CullRect.Width) * picture.CullRect.Height;
            }
            else
            {
                sizeX = (VectorHeight / picture.CullRect.Height) * picture.CullRect.Width;
                sizeY = VectorHeight;
            }

            using (var bitmap = new SKBitmap((int)sizeX, (int)sizeY))
                using (var canvas = new SKCanvas(bitmap))
                    using (var paint = new SKPaint())
                    {
                        canvas.Clear(SKColors.Transparent);
                        float scaleX = sizeX / picture.CullRect.Width;
                        float scaleY = sizeY / picture.CullRect.Height;
                        var   matrix = SKMatrix.MakeScale(scaleX, scaleY);

                        canvas.DrawPicture(picture, ref matrix, paint);
                        canvas.Flush();

                        using (var image = SKImage.FromBitmap(bitmap))
                            using (var data = image.Encode(SKImageEncodeFormat.Png, 80))
                            {
                                var stream = new MemoryStream();
                                data.SaveTo(stream);
                                stream.Position = 0;
                                //var stream = data?.AsStream();
                                return(new Tuple <Stream, LoadingResult, ImageInformation>(stream, resolvedData.Item2, resolvedData.Item3));
                            }
                    }
        }
Example #13
0
        void OnTouchEffectAction(object sender, TouchActionEventArgs args)
        {
            // Convert Xamarin.Forms point to pixels
            var     pt    = args.Location;
            SKPoint point = new SKPoint((float)(canvasView.CanvasSize.Width * pt.X / canvasView.Width),
                                        (float)(canvasView.CanvasSize.Height * pt.Y / canvasView.Height));

            switch (args.Type)
            {
            case TouchActionType.Pressed:
                // Find transformed bitmap rectangle
                SKRect rect = new SKRect(0, 0, bitmap.Width, bitmap.Height);
                rect = matrix.MapRect(rect);

                // Determine if the touch was within that rectangle
                //if (rect.Contains(point))
                //{
                //    // touchId = args.Id;
                //    // previousPoint = point;
                //    touchDictionary.Add(args.Id, point);
                //}
                if (rect.Contains(point) && !touchDictionary.ContainsKey(args.Id))
                {
                    touchDictionary.Add(args.Id, point);
                }

                break;

            case TouchActionType.Moved:
                if (touchDictionary.ContainsKey(args.Id))
                {
                    //if (touchId == args.Id)
                    if (touchDictionary.Count == 1)
                    {
                        // Adjust the matrix for the new position
                        //matrix.TransX += point.X - previousPoint.X;
                        //matrix.TransY += point.Y - previousPoint.Y;
                        //previousPoint = point;
                        SKPoint prevPoint = touchDictionary[args.Id];
                        matrix.TransX += point.X - prevPoint.X;
                        matrix.TransY += point.Y - prevPoint.Y;
                        // Move within canvas limits
                        //if (matrix.TransX > 0) matrix.TransX = 0;
                        //if (matrix.TransX < - bitmap.Width + (int)canvasView.CanvasSize.Width) matrix.TransX = - bitmap.Width + (int)canvasView.CanvasSize.Width;
                        //if (matrix.TransY > 0) matrix.TransY = 0;
                        //if (matrix.TransY < -bitmap.Height + (int)canvasView.CanvasSize.Height) matrix.TransY = -bitmap.Height + (int)canvasView.CanvasSize.Height;
                        canvasView.InvalidateSurface();
                    }
                    else if (touchDictionary.Count >= 2)
                    {
                        // Copy two dictionary keys into array
                        long[] keys = new long[touchDictionary.Count];
                        touchDictionary.Keys.CopyTo(keys, 0);

                        // Find index of non-moving (pivot) finger
                        int pivotIndex = (keys[0] == args.Id) ? 1 : 0;

                        // Get the three points involved in the transform
                        SKPoint pivotPoint = touchDictionary[keys[pivotIndex]];
                        SKPoint prevPoint  = touchDictionary[args.Id];
                        SKPoint newPoint   = point;

                        // Calculate two vectors
                        SKPoint oldVector = prevPoint - pivotPoint;
                        SKPoint newVector = newPoint - pivotPoint;

                        // Scaling factors are ratios of those
                        scaleX = newVector.X / oldVector.X;
                        scaleY = newVector.Y / oldVector.Y;

                        //if (!float.IsNaN(scaleX) && !float.IsInfinity(scaleX) &&
                        //    !float.IsNaN(scaleY) && !float.IsInfinity(scaleY))
                        if (!float.IsNaN(scaleX) && !float.IsInfinity(scaleX))
                        {
                            // If something bad hasn't happened, calculate a scale and translation matrix
                            SKMatrix scaleMatrix =
                                SKMatrix.MakeScale(scaleX, scaleX, pivotPoint.X, pivotPoint.Y);

                            SKMatrix.PostConcat(ref matrix, scaleMatrix);
                            canvasView.InvalidateSurface();
                        }
                    }
                    // Store the new point in the dictionary
                    touchDictionary[args.Id] = point;
                }
                break;

            case TouchActionType.Released:
            case TouchActionType.Cancelled:
                // touchId = -1;
                if (touchDictionary.ContainsKey(args.Id))
                {
                    touchDictionary.Remove(args.Id);
                }
                break;
            }
        }
        private void FolderCanvas_PaintSurface(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
        {
            SKImageInfo info    = e.Info;
            SKSurface   surface = e.Surface;
            SKCanvas    canvas  = surface.Canvas;

            canvas.Clear();


            float scaleFactor = 0.67f;
            float density     = scaleFactor * info.Size.Height / (float)this.Height;


            canvas.Save();

            using (SKPath backPath = SKPath.ParseSvgPathData(
                       "M87.909,9.917V4.02A4.032,4.032,0,0,0,83.889,0H23.72A4.032,4.032,0,0,0,19.7,4.02v5.9H13.338a4.529,4.529,0,0,0-3.822,4.02l.27,112.7a3.954,3.954,0,0,0,3.951,4.024H167.344a3.963,3.963,0,0,0,3.97-4.011l-.6-112.71a4.092,4.092,0,0,0-4.07-4.02Z"))
            {
                backPath.Transform(SKMatrix.MakeScale(density, density));
                backPath.GetTightBounds(out var backPathTightBounds);
                var translateXBackPath = info.Width * 0.5f - backPathTightBounds.MidX;
                var translateYbackPath = info.Height - backPathTightBounds.Bottom - 20f;
                canvas.Translate(translateXBackPath, translateYbackPath);
                fillPaint.Shader = SKShader.CreateLinearGradient(
                    new SKPoint(info.Width * 0.5f, 0),
                    new SKPoint(info.Width * 0.5f, info.Height),
                    new SKColor[] { SKColor.Parse(Color1), SKColor.Parse(Color2), SKColor.Parse(Color2) },
                    new float[] { 0, 0.37f, 1 },
                    SKShaderTileMode.Clamp
                    );
                canvas.DrawPath(backPath, fillPaint);
            }

            canvas.Restore();

            canvas.Save();
            using (SKPath backFilePath = SKPath.ParseSvgPathData("M174.079,150.908H29.155l-.4-114.144H174.481Z"))
            {
                backFilePath.Transform(SKMatrix.MakeScale(density, density));
                backFilePath.GetTightBounds(out var backFilePathTightBounds);
                var translateXBackFilePath = info.Width * 0.5f - backFilePathTightBounds.MidX;
                var translateYbackFilePath = info.Height - backFilePathTightBounds.Bottom - 20f;
                canvas.Translate(translateXBackFilePath, translateYbackFilePath);
                fillPaint.Shader = SKShader.CreateLinearGradient(
                    new SKPoint(info.Width * 0.5f, 0),
                    new SKPoint(info.Width * 0.5f, info.Height),
                    new SKColor[] { SKColor.Parse("#e6e6e6"), SKColor.Parse("#e8e8e8"), SKColor.Parse("#f0f0f0"), SKColor.Parse("#f2f2f2") },
                    new float[] { 0, 0.633f, 0.949f, 1 },
                    SKShaderTileMode.Clamp
                    );
                canvas.DrawPath(backFilePath, fillPaint);
            }
            canvas.Restore();

            canvas.Save();
            using (SKPath frontFilePath = SKPath.ParseSvgPathData("M170.491,158.681H25.567L22.753,49.764H173.3Z"))
            {
                frontFilePath.Transform(SKMatrix.MakeScale(density, density));
                frontFilePath.GetTightBounds(out var frontFilePathTightBounds);
                var translateXFrontFilePath = info.Width * 0.5f - frontFilePathTightBounds.MidX;
                var translateYFrontFilePath = info.Height - frontFilePathTightBounds.Bottom - 20f;
                canvas.Translate(translateXFrontFilePath, translateYFrontFilePath);
                fillPaint.Shader = SKShader.CreateLinearGradient(
                    new SKPoint(info.Width * 0.5f, 0),
                    new SKPoint(info.Width * 0.5f, info.Height),
                    new SKColor[] { SKColor.Parse("#cccccc"), SKColor.Parse("#cecece"), SKColor.Parse("#d6d6d6"), SKColor.Parse("#e3e3e3"), SKColor.Parse("#f6f6f6"), SKColor.Parse("#ffffff") },
                    new float[] { 0, 0.427f, 0.64f, 0.806f, 0.947f, 1 },
                    SKShaderTileMode.Clamp
                    );
                canvas.DrawPath(frontFilePath, fillPaint);
            }
            canvas.Restore();

            canvas.Save();
            using (SKPath frontPath = SKPath.ParseSvgPathData("M165.433,164.917a4.106,4.106,0,0,1-4.089,4.011H7.735a4.578,4.578,0,0,1-4.325-4.292L0,68.019A3.948,3.948,0,0,1,3.95,64H164.895a3.948,3.948,0,0,1,3.95,4.02Z"))
            {
                frontPath.Transform(SKMatrix.MakeScale(density, density));
                frontPath.GetTightBounds(out var frontPathTightBounds);

                fillPaint.Shader = SKShader.CreateLinearGradient(
                    new SKPoint(info.Width * 0.5f, 0),
                    new SKPoint(info.Width * 0.5f, info.Height),
                    new SKColor[] { SKColor.Parse(Color3), SKColor.Parse(Color4), SKColor.Parse(Color5), SKColor.Parse(Color6) },
                    new float[] { 0, 0.595f, 0.957f, 1 },
                    SKShaderTileMode.Clamp
                    );

                SKMatrix   matrix   = SKMatrix.MakeTranslation(-frontPathTightBounds.Right, -frontPathTightBounds.Bottom);
                SKMatrix44 matrix44 = SKMatrix44.CreateIdentity();
                matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(1, 0, 0, -FrontPathDegree));
                matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 1, 0, -0.5f * FrontPathDegree));
                matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 0, 1, 0));
                SKMatrix.PostConcat(ref matrix, matrix44.Matrix);
                SKMatrix.PostConcat(ref matrix, SKMatrix.MakeTranslation(frontPathTightBounds.Right, frontPathTightBounds.Bottom));
                canvas.SetMatrix(matrix);

                var translateXFrontPath = info.Width * 0.5f - frontPathTightBounds.MidX;
                var translateYFrontPath = info.Height - frontPathTightBounds.Bottom - 20f;
                canvas.Translate(translateXFrontPath, translateYFrontPath);
                canvas.DrawPath(frontPath, fillPaint);
            }
            canvas.Restore();
        }
Example #15
0
        public static List <MGLPaint> ConvertFillLayer(JsonStyleLayer jsonStyleLayer, MGLSpriteAtlas spriteAtlas)
        {
            var layout = jsonStyleLayer?.Layout;
            var paint  = jsonStyleLayer?.Paint;

            var area = new MGLPaint();
            var line = new MGLPaint();

            // Set defaults
            area.SetFixColor(new SKColor(0, 0, 0, 0));
            area.SetFixOpacity(1);
            area.SetFixStyle(SKPaintStyle.Fill);
            line.SetFixColor(new SKColor(0, 0, 0, 0));
            line.SetFixOpacity(1);
            line.SetFixStyle(SKPaintStyle.Stroke);
            line.SetFixStrokeWidth(0);

            // If we don't have a paint, than there isn't anything that we could do
            if (paint == null)
            {
                return(new List <MGLPaint>()
                {
                    area, line
                });
            }

            // fill-color
            //   Optional color. Defaults to #000000. Disabled by fill-pattern. Exponential.
            //   The color of the filled part of this layer. This color can be specified as
            //   rgba with an alpha component and the color's opacity will not affect the
            //   opacity of the 1px stroke, if it is used.
            if (paint.FillColor != null)
            {
                if (paint.FillColor.Stops != null)
                {
                    area.SetVariableColor((context) => jsonStyleLayer.Paint.FillColor.Evaluate(context.Zoom));
                    line.SetVariableColor((context) => jsonStyleLayer.Paint.FillColor.Evaluate(context.Zoom));
                }
                else
                {
                    area.SetFixColor(jsonStyleLayer.Paint.FillColor.SingleVal);
                    line.SetFixColor(jsonStyleLayer.Paint.FillColor.SingleVal);
                }
            }

            // fill-outline-color
            //   Optional color. Disabled by fill-pattern. Requires fill-antialias = true. Exponential.
            //   The outline color of the fill. Matches the value of fill-color if unspecified.
            if (paint.FillOutlineColor != null && paint.FillAntialias != null)
            {
                if (paint.FillOutlineColor.Stops != null)
                {
                    line.SetVariableColor((context) => jsonStyleLayer.Paint.FillOutlineColor.Evaluate(context.Zoom));
                }
                else
                {
                    line.SetFixColor(jsonStyleLayer.Paint.FillOutlineColor.SingleVal);
                }
            }

            // fill-opacity
            //   Optional number. Defaults to 1. Exponential.
            //   The opacity of the entire fill layer. In contrast to the fill-color, this
            //   value will also affect the 1px stroke around the fill, if the stroke is used.
            if (paint.FillOpacity != null)
            {
                if (paint.FillOpacity.Stops != null)
                {
                    area.SetVariableOpacity((context) => jsonStyleLayer.Paint.FillOpacity.Evaluate(context.Zoom));
                    line.SetVariableOpacity((context) => jsonStyleLayer.Paint.FillOpacity.Evaluate(context.Zoom));
                }
                else
                {
                    area.SetFixOpacity(jsonStyleLayer.Paint.FillOpacity.SingleVal);
                    line.SetFixOpacity(jsonStyleLayer.Paint.FillOpacity.SingleVal);
                }
            }

            // fill-antialias
            //   Optional boolean. Defaults to true. Interval.
            //   Whether or not the fill should be antialiased.
            if (paint.FillAntialias != null)
            {
                if (paint.FillAntialias.Stops != null)
                {
                    area.SetVariableAntialias((context) => jsonStyleLayer.Paint.FillAntialias.Evaluate(context.Zoom));
                    line.SetVariableAntialias((context) => jsonStyleLayer.Paint.FillAntialias.Evaluate(context.Zoom));
                }
                else
                {
                    area.SetFixAntialias(jsonStyleLayer.Paint.FillAntialias.SingleVal == null ? false : (bool)jsonStyleLayer.Paint.FillAntialias.SingleVal);
                    line.SetFixAntialias(jsonStyleLayer.Paint.FillAntialias.SingleVal == null ? false : (bool)jsonStyleLayer.Paint.FillAntialias.SingleVal);
                }
            }

            // fill-translate
            //   Optional array. Units in pixels. Defaults to 0,0. Exponential.
            //   The geometry's offset. Values are [x, y] where negatives indicate left and up,
            //   respectively.

            // TODO: Use matrix of paint object for this

            // fill-translate-anchor
            //   Optional enum. One of map, viewport. Defaults to map. Requires fill-translate. Interval.
            //   Control whether the translation is relative to the map (north) or viewport (screen)

            // TODO: Use matrix of paint object for this

            // fill-pattern
            //   Optional string. Interval.
            //   Name of image in sprite to use for drawing image fills. For seamless patterns,
            //   image width and height must be a factor of two (2, 4, 8, …, 512).
            if (paint.FillPattern != null)
            {
                // FillPattern needs a color. Instead no pattern is drawn.
                area.SetFixColor(SKColors.Black);

                if (paint.FillPattern.Stops == null && !paint.FillPattern.SingleVal.Contains("{"))
                {
                    area.SetVariableShader((context) =>
                    {
                        var name = paint.FillPattern.SingleVal;

                        var sprite = spriteAtlas.GetSprite(name);
                        if (sprite != null && sprite.Image != null)
                        {
                            return(sprite.Image.ToShader(SKShaderTileMode.Repeat, SKShaderTileMode.Repeat, SKMatrix.MakeScale(context.Scale, context.Scale)));
                        }
                        else
                        {
                            // Log information, that no sprite is found
                            // TODO
                            // Logging.Logger.Log(Logging.LogLevel.Information, $"Fill pattern {name} not found");
                            return(null);
                        }
                    });
                }
                else
                {
                    area.SetVariableShader((context) =>
                    {
                        var name = ReplaceFields(jsonStyleLayer.Paint.FillPattern.Evaluate(context.Zoom), context.Tags);

                        var sprite = spriteAtlas.GetSprite(name);
                        if (sprite != null && sprite.Image != null)
                        {
                            return(sprite.Image.ToShader(SKShaderTileMode.Repeat, SKShaderTileMode.Repeat, SKMatrix.MakeScale(context.Scale, context.Scale)));
                        }
                        else
                        {
                            // Log information, that no sprite is found
                            // TODO
                            // Logging.Logger.Log(Logging.LogLevel.Information, $"Fill pattern {name} not found");
                            return(null);
                        }
                    });
                }
            }

            return(new List <MGLPaint>()
            {
                area, line
            });
        }
Example #16
0
        /// <summary>
        /// Insert an icon into a specific folder
        /// </summary>
        /// <param name="_currentIcon"></param>
        /// <param name="folderOfInterest"></param>
        public void InsertIntoFolder(Icon _currentIcon, System.Collections.Generic.IEnumerable <Icon> folderOfInterest)
        {
            if (folderOfInterest != null && _currentIcon != null && folderOfInterest.Count() > 0)
            {
                System.Diagnostics.Debug.WriteLineIf(App.OutputVerbose, "In Completed: Insertable into folder: " + _currentIcon.Tag);

                var folderToInsertInto = folderOfInterest.First();

                var startPoint = _currentIcon.Location;

                float xDiff = (folderToInsertInto.Location.X + folderToInsertInto.Bounds.Width / 2f) - (startPoint.X + _currentIcon.Bounds.Width / 2f);
                float yDiff = (folderToInsertInto.Location.Y + folderToInsertInto.Bounds.Height / 2f) - (startPoint.Y + _currentIcon.Bounds.Height / 2f);

                new Xamarin.Forms.Animation((value) =>
                {
                    if (_currentIcon != null)
                    {
                        try
                        {
                            _currentIcon.Location = new SKPoint((startPoint.X) + (xDiff * (float)value),
                                                                (startPoint.Y) + (yDiff * (float)value));
                        }
                        catch (System.Exception e)
                        {
                            System.Diagnostics.Debug.WriteLineIf(App.OutputVerbose, e.ToString());
                        }
                    }
                }).Commit(Xamarin.Forms.Application.Current.MainPage, "Anim", length: Constants.DeviceLayout.AnimationMoveMillis, finished: (v, c) =>
                {
                    new Xamarin.Forms.Animation((value) =>
                    {
                        try
                        {
                            if (_currentIcon != null)
                            {
                                _currentIcon.Transformation = SKMatrix.MakeScale(1 - (float)value, 1 - (float)value);
                            }
                        }
                        catch (System.Exception e)
                        {
                            System.Diagnostics.Debug.WriteLineIf(App.OutputVerbose, e.ToString());
                        }
                    }).Commit(Xamarin.Forms.Application.Current.MainPage, "Anim", length: Constants.DeviceLayout.AnimationShrinkMillis, finished: (v2, c2) =>
                    {
                        try
                        {
                            if (_currentIcon != null)
                            {
                                _currentIcon.IsStoredInAFolder = true;
                                _currentIcon.Transformation    = SKMatrix.MakeScale(1, 1);
                                _currentIcon.StoredFolderTag   = folderToInsertInto.Text;

                                canvasRef.Icons.SendToBack(_currentIcon);
                                canvasRef.Controller.PromptResave();
                            }
                        }
                        catch (System.Exception e)
                        {
                            System.Diagnostics.Debug.WriteLineIf(App.OutputVerbose, e.ToString());
                        }
                    });
                });
            }
        }
Example #17
0
        internal void DrawMarker(SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pMarkerPoint, float fAngle)
        {
            var markerElement = GetMarkerElement(svgMarker);

            if (markerElement == null)
            {
                return;
            }

            var skMarkerMatrix = SKMatrix.MakeIdentity();

            var skMatrixMarkerPoint = SKMatrix.MakeTranslation(pMarkerPoint.X, pMarkerPoint.Y);

            SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixMarkerPoint);

            var skMatrixAngle = SKMatrix.MakeRotationDegrees(svgMarker.Orient.IsAuto ? fAngle : svgMarker.Orient.Angle);

            SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixAngle);

            var strokeWidth = pOwner.StrokeWidth.ToDeviceValue(null, UnitRenderingType.Other, svgMarker);

            var   refX         = svgMarker.RefX.ToDeviceValue(null, UnitRenderingType.Horizontal, svgMarker);
            var   refY         = svgMarker.RefY.ToDeviceValue(null, UnitRenderingType.Horizontal, svgMarker);
            float markerWidth  = svgMarker.MarkerWidth;
            float markerHeight = svgMarker.MarkerHeight;
            float viewBoxToMarkerUnitsScaleX = 1f;
            float viewBoxToMarkerUnitsScaleY = 1f;

            switch (svgMarker.MarkerUnits)
            {
            case SvgMarkerUnits.StrokeWidth:
            {
                var skMatrixStrokeWidth = SKMatrix.MakeScale(strokeWidth, strokeWidth);
                SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixStrokeWidth);

                var viewBoxWidth  = svgMarker.ViewBox.Width;
                var viewBoxHeight = svgMarker.ViewBox.Height;

                var scaleFactorWidth  = (viewBoxWidth <= 0) ? 1 : (markerWidth / viewBoxWidth);
                var scaleFactorHeight = (viewBoxHeight <= 0) ? 1 : (markerHeight / viewBoxHeight);

                viewBoxToMarkerUnitsScaleX = Math.Min(scaleFactorWidth, scaleFactorHeight);
                viewBoxToMarkerUnitsScaleY = Math.Min(scaleFactorWidth, scaleFactorHeight);

                var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX * viewBoxToMarkerUnitsScaleX, -refY * viewBoxToMarkerUnitsScaleY);
                SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixTranslateRefXY);

                var skMatrixScaleXY = SKMatrix.MakeScale(viewBoxToMarkerUnitsScaleX, viewBoxToMarkerUnitsScaleY);
                SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixScaleXY);
            }
            break;

            case SvgMarkerUnits.UserSpaceOnUse:
            {
                var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX, -refY);
                SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixTranslateRefXY);
            }
            break;
            }

            _skCanvas.Save();

            var skMatrix = SkiaUtil.GetSKMatrix(svgMarker.Transforms);

            SKMatrix.PreConcat(ref skMatrix, ref skMarkerMatrix);
            SetTransform(skMatrix);
            SetClipPath(svgMarker, _disposable);

            var skPaintOpacity = SetOpacity(svgMarker, _disposable);

            var skPaintFilter = SetFilter(svgMarker, _disposable);

            switch (svgMarker.Overflow)
            {
            case SvgOverflow.Auto:
            case SvgOverflow.Visible:
            case SvgOverflow.Inherit:
                break;

            default:
                var skClipRect = SKRect.Create(
                    svgMarker.ViewBox.MinX,
                    svgMarker.ViewBox.MinY,
                    markerWidth / viewBoxToMarkerUnitsScaleX,
                    markerHeight / viewBoxToMarkerUnitsScaleY);
                _skCanvas.ClipRect(skClipRect, SKClipOperation.Intersect);
                break;
            }

            Draw(markerElement, true);

            if (skPaintFilter != null)
            {
                _skCanvas.Restore();
            }

            if (skPaintOpacity != null)
            {
                _skCanvas.Restore();
            }

            _skCanvas.Restore();
        }
        public override void Execute()
        {
            JsConfig.IncludeNullValues  = false;
            JsConfig.EmitCamelCaseNames = true;

            foreach (var platform in Configuration.Platforms)
            {
                var fileName = Path.Combine(WorkingDirectory, platform.IconFileName);
                var fileInfo = new FileInfo(fileName);
                if (!File.Exists(fileInfo.FullName))
                {
                    Log.Error($"Icon not found ({fileInfo.FullName})");
                    continue;
                }

                var svg = SkiaHelper.Load(fileInfo.FullName);

                var sourceActualWidth  = svg.Picture.CullRect.Width;
                var sourceActualHeight = svg.Picture.CullRect.Height;


                var assets = new List <ExportAsset>();

                var platformPath = new DirectoryInfo(Path.Combine(WorkingDirectory, platform.ProjectPath));
                if (!platformPath.Exists)
                {
                    Log.Error($"Platform path for {platform.Type} not found ({platformPath.FullName})");
                    continue;
                }

                switch (platform.Type)
                {
                case Platforms.iOS:
                {
                    var targetPath = Path.Combine(platformPath.FullName, "Assets.xcassets", "AppIcon.appiconset");
                    var sizes      = new[] { 20, 29, 40, 58, 60, 76, 80, 87, 120, 152, 167, 180, 1024 };
                    assets.AddRange(sizes.Select(size => new ExportAsset(fileInfo.FullName, targetPath, $"Icon-App-{size}x{size}.png", sourceActualWidth, sourceActualHeight, size, size)));
                    break;
                }

                case Platforms.AppleWatch:
                {
                    var targetPath = Path.Combine(platformPath.FullName, "Assets.xcassets", "AppIcon.appiconset");
                    var sizes      = new[] { 48, 55, 58, 80, 87, 88, 172, 196 };
                    assets.AddRange(sizes.Select(size => new ExportAsset(fileInfo.FullName, targetPath, $"Icon-App-{size}x{size}.png", sourceActualWidth, sourceActualHeight, size, size)));
                    break;
                }

                case Platforms.MacOs:
                {
                    var targetPath = Path.Combine(platformPath.FullName, "Assets.xcassets", "AppIcon.appiconset");
                    var sizes      = new[] { 16, 32, 64, 128, 256, 512, 1024 };
                    assets.AddRange(sizes.Select(size => new ExportAsset(fileInfo.FullName, targetPath, $"Icon-App-{size}x{size}.png", sourceActualWidth, sourceActualHeight, size, size)));
                    break;
                }

                case Platforms.Android:
                {
                    var folderPrefix = "mipmap";
                    if (platform.AndroidOptions != null && !string.IsNullOrEmpty(platform.AndroidOptions.AssetFolderPrefix.ToString()))
                    {
                        folderPrefix = platform.AndroidOptions.AssetFolderPrefix.ToString();
                    }
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-mdpi"), "Icon.png", sourceActualWidth, sourceActualHeight, 48,
                                               48));
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-hdpi"), "Icon.png", sourceActualWidth, sourceActualHeight, 72,
                                               72));
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-xhdpi"), "Icon.png", sourceActualWidth, sourceActualHeight, 96,
                                               96));
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-xxhdpi"), "Icon.png", sourceActualWidth, sourceActualHeight,
                                               144, 144));
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-xxxhdpi"), "Icon.png", sourceActualWidth, sourceActualHeight,
                                               192, 192));
                    break;
                }

                case Platforms.UWP:
                {
                    // https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/app-assets#asset-size-tables
                    var targetPath = Path.Combine(platformPath.FullName, "Assets");
                    var sizes      = new[] { 71, 150, 310, 44 };
                    var scales     = new[] { 100, 125, 150, 200, 400 };
                    foreach (var size in sizes)
                    {
                        assets.AddRange(scales.Select(scale =>
                                                      new ExportAsset(fileInfo.FullName, targetPath, $"Square{size}x{size}Logo.scale-{scale}.png", sourceActualWidth, sourceActualHeight, size, size)));
                    }
                    break;
                }

                default:
                    throw new ArgumentOutOfRangeException();
                }

                foreach (var asset in assets)
                {
                    var bmp    = new SKBitmap((int)asset.ScaledWidth, (int)asset.ScaledHeight);
                    var canvas = new SKCanvas(bmp);
                    var matrix = SKMatrix.MakeScale((float)asset.Ratio, (float)asset.Ratio);
                    canvas.Clear(SKColors.Transparent);
                    canvas.DrawPicture(svg.Picture, ref matrix);
                    canvas.Save();

                    // Export the canvas
                    var img = SKImage.FromBitmap(bmp);

                    var data = img.Encode(SKEncodedImageFormat.Png, 100);
                    asset.FileName.EnsureFolderExists();
                    using (var fs = File.Open(asset.FileName, FileMode.Create))
                    {
                        Log.Information($"Writing {asset.FileName}");
                        data.SaveTo(fs);
                    }

                    var platformProjectFolder = Path.Combine(WorkingDirectory, platform.ProjectPath);

                    var destinationFolder = "Resources";
                    if (platform.Type == Platforms.UWP)
                    {
                        destinationFolder = "Assets";
                    }
                    var destinationFile = Path.Combine(WorkingDirectory, platform.ProjectPath, destinationFolder, asset.FileName);

                    switch (platform.Type)
                    {
                    case Platforms.iOS:
                    case Platforms.AppleWatch:
                    case Platforms.MacOs:
                        FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.ImageAsset).AddToProject();
                        break;

                    case Platforms.Android:
                        FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.AndroidResource).AddToProject();
                        break;

                    case Platforms.UWP:
                        FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.Content).AddToProject();
                        break;
                    }
                }

                if (platform.Type == Platforms.iOS || platform.Type == Platforms.AppleWatch || platform.Type == Platforms.MacOs)
                {
                    var contentsFile = Path.Combine(platformPath.FullName, "Assets.xcassets", "AppIcon.appiconset", "Contents.json");
                    Log.Information($"Writing {contentsFile}");

                    var contents = File.ReadAllText(contentsFile).FromJson <XcodeContents>();

                    foreach (var contentsImage in contents.Images)
                    {
                        var process = false;
                        switch (platform.Type)
                        {
                        case Platforms.iOS when contentsImage.Idiom == "iphone" || contentsImage.Idiom == "ipad" || contentsImage.Idiom == "ios-marketing":
                        case Platforms.AppleWatch when contentsImage.Idiom == "watch":
                        case Platforms.MacOs when contentsImage.Idiom == "mac":
                            process = true;
                            break;
                        }

                        if (process)
                        {
                            // calculate needed size
                            var size  = double.Parse(contentsImage.Size.Split('x')[0], NumberStyles.Float, new CultureInfo("en-US"));
                            var scale = double.Parse(contentsImage.Scale.Substring(0, 1));

                            var foundSize = assets.FirstOrDefault(a => a.ScaledWidth == size * scale);
                            if (foundSize != null)
                            {
                                contentsImage.Filename = new FileInfo(foundSize.FileName).Name;
                            }
                        }
                    }

                    File.WriteAllText(contentsFile, contents.ToJson().IndentJson());
                }
            }
        }
Example #19
0
        public MultiPhotoSelectioControlsOverlayView(Context context) : base(context)
        {
            PaintSurface += Handle_PaintSurface;
            SetBackgroundColor(graphics.Color.Transparent);

            paint.IsAntialias = true;

            closeButton = new SvgButton("close_button.svg", "close_button_touched.svg", SKMatrix.MakeScale(0.8f, 0.8f), context);
            trashButton = new SvgButton("trash_button.svg", "trash_button_touched.svg", SKMatrix.MakeScale(0.8f, 0.8f), context);
            sendButton  = new SvgButton("send_button.svg", "send_button_touched.svg", SKMatrix.MakeScale(2.5f, 2.5f), context);

            buttons.AddRange(new[] { closeButton, trashButton, sendButton });

            Device.StartTimer(TimeSpan.FromMilliseconds(1000 / 60), () =>
            {
                Invalidate();
                return(timerActive);
            });
        }
Example #20
0
        public MarkerDrawable(SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pMarkerPoint, float fAngle, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgMarker, root, parent)
        {
            IgnoreAttributes = Attributes.Display | ignoreAttributes;
            IsDrawable       = true;

            if (!IsDrawable)
            {
                return;
            }

            var markerElement = GetMarkerElement(svgMarker);

            if (markerElement == null)
            {
                IsDrawable = false;
                return;
            }

            var skMarkerMatrix = SKMatrix.MakeIdentity();

            var skMatrixMarkerPoint = SKMatrix.MakeTranslation(pMarkerPoint.X, pMarkerPoint.Y);

            SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixMarkerPoint);

            var skMatrixAngle = SKMatrix.MakeRotationDegrees(svgMarker.Orient.IsAuto ? fAngle : svgMarker.Orient.Angle);

            SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixAngle);

            var strokeWidth = pOwner.StrokeWidth.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds);

            var   refX         = svgMarker.RefX.ToDeviceValue(UnitRenderingType.Horizontal, svgMarker, skOwnerBounds);
            var   refY         = svgMarker.RefY.ToDeviceValue(UnitRenderingType.Vertical, svgMarker, skOwnerBounds);
            float markerWidth  = svgMarker.MarkerWidth.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds);
            float markerHeight = svgMarker.MarkerHeight.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds);
            float viewBoxToMarkerUnitsScaleX = 1f;
            float viewBoxToMarkerUnitsScaleY = 1f;

            switch (svgMarker.MarkerUnits)
            {
            case SvgMarkerUnits.StrokeWidth:
            {
                var skMatrixStrokeWidth = SKMatrix.MakeScale(strokeWidth, strokeWidth);
                SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixStrokeWidth);

                var viewBoxWidth  = svgMarker.ViewBox.Width;
                var viewBoxHeight = svgMarker.ViewBox.Height;

                var scaleFactorWidth  = (viewBoxWidth <= 0) ? 1 : (markerWidth / viewBoxWidth);
                var scaleFactorHeight = (viewBoxHeight <= 0) ? 1 : (markerHeight / viewBoxHeight);

                viewBoxToMarkerUnitsScaleX = Math.Min(scaleFactorWidth, scaleFactorHeight);
                viewBoxToMarkerUnitsScaleY = Math.Min(scaleFactorWidth, scaleFactorHeight);

                var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX * viewBoxToMarkerUnitsScaleX, -refY * viewBoxToMarkerUnitsScaleY);
                SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixTranslateRefXY);

                var skMatrixScaleXY = SKMatrix.MakeScale(viewBoxToMarkerUnitsScaleX, viewBoxToMarkerUnitsScaleY);
                SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixScaleXY);
            }
            break;

            case SvgMarkerUnits.UserSpaceOnUse:
            {
                var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX, -refY);
                SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixTranslateRefXY);
            }
            break;
            }

            switch (svgMarker.Overflow)
            {
            case SvgOverflow.Auto:
            case SvgOverflow.Visible:
            case SvgOverflow.Inherit:
                break;

            default:
                MarkerClipRect = SKRect.Create(
                    svgMarker.ViewBox.MinX,
                    svgMarker.ViewBox.MinY,
                    markerWidth / viewBoxToMarkerUnitsScaleX,
                    markerHeight / viewBoxToMarkerUnitsScaleY);
                break;
            }

            var drawable = DrawableFactory.Create(markerElement, skOwnerBounds, root, this, Attributes.Display);

            if (drawable != null)
            {
                MarkerElementDrawable = drawable;
                _disposable.Add(MarkerElementDrawable);
            }
            else
            {
                IsDrawable = false;
                return;
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgMarker);

            TransformedBounds = MarkerElementDrawable.TransformedBounds;

            Transform = SvgTransformsExtensions.ToSKMatrix(svgMarker.Transforms);
            SKMatrix.PreConcat(ref Transform, ref skMarkerMatrix);

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            SKMatrix.MapRect(ref Transform, out TransformedBounds, ref TransformedBounds);
        }
        public async Task <DataResolverResult> Resolve(string identifier, TaskParameter parameters, CancellationToken token)
        {
            var source = parameters.Source;

            if (!string.IsNullOrWhiteSpace(parameters.LoadingPlaceholderPath) && parameters.LoadingPlaceholderPath == identifier)
            {
                source = parameters.LoadingPlaceholderSource;
            }
            else if (!string.IsNullOrWhiteSpace(parameters.ErrorPlaceholderPath) && parameters.ErrorPlaceholderPath == identifier)
            {
                source = parameters.ErrorPlaceholderSource;
            }

            var resolvedData = await(Configuration.DataResolverFactory ?? new DataResolverFactory())
                               .GetResolver(identifier, source, parameters, Configuration)
                               .Resolve(identifier, parameters, token).ConfigureAwait(false);

            if (resolvedData?.Stream == null)
            {
                throw new FileNotFoundException(identifier);
            }

            var svg = new SKSvg()
            {
                ThrowOnUnsupportedElement = false,
            };
            SKPicture picture;

            if (ReplaceStringMap == null || ReplaceStringMap.Count == 0)
            {
                using (var svgStream = resolvedData.Stream)
                {
                    picture = svg.Load(svgStream, token);
                }
            }
            else
            {
                using (var svgStream = resolvedData.Stream)
                    using (var reader = new StreamReader(svgStream))
                    {
                        var inputString = await reader.ReadToEndAsync().ConfigureAwait(false);

                        foreach (var map in ReplaceStringMap
                                 .Where(v => v.Key.StartsWith("regex:", StringComparison.OrdinalIgnoreCase)))
                        {
                            inputString = Regex.Replace(inputString, map.Key.Substring(6), map.Value);
                        }

                        var builder = new StringBuilder(inputString);

                        foreach (var map in ReplaceStringMap
                                 .Where(v => !v.Key.StartsWith("regex:", StringComparison.OrdinalIgnoreCase)))
                        {
                            builder.Replace(map.Key, map.Value);
                        }

                        token.ThrowIfCancellationRequested();

                        using (var svgFinalStream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString())))
                        {
                            picture = svg.Load(svgFinalStream);
                        }
                    }
            }

            token.ThrowIfCancellationRequested();

            double sizeX = VectorWidth;
            double sizeY = VectorHeight;

            if (UseDipUnits)
            {
                sizeX = VectorWidth.DpToPixels();
                sizeY = VectorHeight.DpToPixels();
            }

            if (sizeX <= 0 && sizeY <= 0)
            {
                if (picture.CullRect.Width > 0)
                {
                    sizeX = picture.CullRect.Width;
                }
                else
                {
                    sizeX = 400;
                }

                if (picture.CullRect.Height > 0)
                {
                    sizeY = picture.CullRect.Height;
                }
                else
                {
                    sizeY = 400;
                }
            }
            else if (sizeX > 0 && sizeY <= 0)
            {
                sizeY = (int)(sizeX / picture.CullRect.Width * picture.CullRect.Height);
            }
            else if (sizeX <= 0 && sizeY > 0)
            {
                sizeX = (int)(sizeY / picture.CullRect.Height * picture.CullRect.Width);
            }

            resolvedData.ImageInformation.SetType(ImageInformation.ImageType.SVG);

            using (var bitmap = new SKBitmap(new SKImageInfo((int)sizeX, (int)sizeY)))
                using (var canvas = new SKCanvas(bitmap))
                    using (var paint = new SKPaint())
                    {
                        canvas.Clear(SKColors.Transparent);
                        var scaleX = (float)sizeX / picture.CullRect.Width;
                        var scaleY = (float)sizeY / picture.CullRect.Height;
                        var matrix = SKMatrix.MakeScale(scaleX, scaleY);
                        canvas.DrawPicture(picture, ref matrix, paint);
                        canvas.Flush();

                        token.ThrowIfCancellationRequested();

                        return(await Decode(picture, bitmap, resolvedData).ConfigureAwait(false));
                    }
        }
Example #22
0
        public void WriteToStream(MemoryStream output)
        {
            var converter = new Converter(PakSupplier.Index);

            StoreItem[] weekly = new StoreItem[Store.Weekly.Length];
            for (int i = 0; i < weekly.Length; i++)
            {
                try
                {
                    weekly[i] = converter.ConvertItem(Store.Weekly[i]);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }
            StoreItem[] daily = new StoreItem[Store.Daily.Length];
            for (int i = 0; i < daily.Length; i++)
            {
                try
                {
                    daily[i] = converter.ConvertItem(Store.Daily[i]);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw e;
                }
            }
            // number of featured categories
            var weeklies = Converter.GetCategorySlots(weekly, out var count, out var sizes, out var size);

            Config.SelectedCategory = count;
            var gc = new GlobalCache(converter.Index);

            // TODO: making it any larger doesn't affect the text or icon resolution :(
            // might have to do with the canvas only writing 1080p pixels on a 4k (e.g) image
            const int w = 1280;
            const int h = 720;

            using var ret    = new SKBitmap(w, h, SKColorType.Rgba8888, SKAlphaType.Opaque);
            using var stream = new VideoOutputStream(ret, 30, 1024 * 1024 * 5, output, true);
            using (var c = new SKCanvas(ret))
            {
                if (!string.IsNullOrWhiteSpace(Background) && File.Exists(Background))
                {
                    try
                    {
                        // TODO: make this permanent or part of drawing the cache (maybe?) just do something
                        using var bmp = SKBitmap.Decode(Background);
                        c.DrawBitmap(bmp, new SKRect(0, 0, w, h), new SKPaint {
                            FilterQuality = SKFilterQuality.High, IsAntialias = true
                        });
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                }
                c.SetMatrix(SKMatrix.MakeScale(w / 1920f, h / 1080f));
                for (int i = 0; i < size; i++)
                {
                    gc.GetSection(DrawType.DAILY).Draw(c, daily);
                    gc.GetSection(DrawType.FEATURED).Draw(c, weeklies[i]);
                    gc.GetSection(DrawType.FEATURED).InitializeCategory(c, weeklies[i], sizes, i + 1, 0);
                    float tickAmt = 1 / 150f;
                    for (int j = 0; j < 150; j++)
                    {
                        gc.GetSection(DrawType.DAILY).DrawBorder(c, daily, j);
                        gc.GetSection(DrawType.FEATURED).DrawBorder(c, weeklies[i], j + i * 150);
                        stream.EncodeFrame();
                        gc.GetSection(DrawType.FEATURED).TickCategory(c, weeklies[i], sizes, j * tickAmt, tickAmt);
                    }
                }
            }

            /*
             * using var bmp = new SKBitmap(1280, 720, SKColorType.Rgba8888, SKAlphaType.Opaque);
             * using var stream = new VideoOutputStream(bmp, 30, 1024 * 1024 * 4, output, true);
             * using var c = new SKCanvas(bmp);
             */
        }
Example #23
0
        public static SKMatrix ToSKMatrix(this SvgViewBox svgViewBox, SvgAspectRatio svgAspectRatio, float x, float y, float width, float height)
        {
            if (svgViewBox.Equals(SvgViewBox.Empty))
            {
                return(SKMatrix.MakeTranslation(x, y));
            }

            float fScaleX = width / svgViewBox.Width;
            float fScaleY = height / svgViewBox.Height;
            float fMinX   = -svgViewBox.MinX * fScaleX;
            float fMinY   = -svgViewBox.MinY * fScaleY;

            if (svgAspectRatio == null)
            {
                svgAspectRatio = new SvgAspectRatio(SvgPreserveAspectRatio.xMidYMid);
            }

            if (svgAspectRatio.Align != SvgPreserveAspectRatio.none)
            {
                if (svgAspectRatio.Slice)
                {
                    fScaleX = Math.Max(fScaleX, fScaleY);
                    fScaleY = Math.Max(fScaleX, fScaleY);
                }
                else
                {
                    fScaleX = Math.Min(fScaleX, fScaleY);
                    fScaleY = Math.Min(fScaleX, fScaleY);
                }
                float fViewMidX = (svgViewBox.Width / 2) * fScaleX;
                float fViewMidY = (svgViewBox.Height / 2) * fScaleY;
                float fMidX     = width / 2;
                float fMidY     = height / 2;
                fMinX = -svgViewBox.MinX * fScaleX;
                fMinY = -svgViewBox.MinY * fScaleY;

                switch (svgAspectRatio.Align)
                {
                case SvgPreserveAspectRatio.xMinYMin:
                    break;

                case SvgPreserveAspectRatio.xMidYMin:
                    fMinX += fMidX - fViewMidX;
                    break;

                case SvgPreserveAspectRatio.xMaxYMin:
                    fMinX += width - svgViewBox.Width * fScaleX;
                    break;

                case SvgPreserveAspectRatio.xMinYMid:
                    fMinY += fMidY - fViewMidY;
                    break;

                case SvgPreserveAspectRatio.xMidYMid:
                    fMinX += fMidX - fViewMidX;
                    fMinY += fMidY - fViewMidY;
                    break;

                case SvgPreserveAspectRatio.xMaxYMid:
                    fMinX += width - svgViewBox.Width * fScaleX;
                    fMinY += fMidY - fViewMidY;
                    break;

                case SvgPreserveAspectRatio.xMinYMax:
                    fMinY += height - svgViewBox.Height * fScaleY;
                    break;

                case SvgPreserveAspectRatio.xMidYMax:
                    fMinX += fMidX - fViewMidX;
                    fMinY += height - svgViewBox.Height * fScaleY;
                    break;

                case SvgPreserveAspectRatio.xMaxYMax:
                    fMinX += width - svgViewBox.Width * fScaleX;
                    fMinY += height - svgViewBox.Height * fScaleY;
                    break;

                default:
                    break;
                }
            }

            var skMatrixTotal = SKMatrix.MakeIdentity();

            var skMatrixXY = SKMatrix.MakeTranslation(x, y);

            SKMatrix.PreConcat(ref skMatrixTotal, ref skMatrixXY);

            var skMatrixMinXY = SKMatrix.MakeTranslation(fMinX, fMinY);

            SKMatrix.PreConcat(ref skMatrixTotal, ref skMatrixMinXY);

            var skMatrixScale = SKMatrix.MakeScale(fScaleX, fScaleY);

            SKMatrix.PreConcat(ref skMatrixTotal, ref skMatrixScale);

            return(skMatrixTotal);
        }
Example #24
0
        public void DrawPath(SKPath path, Point point, SKPaint paint)
        {
            path.Transform(SKMatrix.MakeScale(Scale, Scale));

            Canvas.DrawPath(path, paint);
        }
Example #25
0
        private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height)
        {
            var bitmap = new SKBitmap(width, height);

            using (var canvas = new SKCanvas(bitmap))
            {
                canvas.Clear(SKColors.Black);

                // determine sizes for each image that will composited into the final image
                var iSlice  = Convert.ToInt32(width * 0.23475);
                int iTrans  = Convert.ToInt32(height * .25);
                int iHeight = Convert.ToInt32(height * .70);
                var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
                var verticalSpacing        = Convert.ToInt32(height * 0.01111111111111111111111111111111);
                int imageIndex             = 0;

                for (int i = 0; i < 4; i++)
                {
                    SKCodecOrigin origin;
                    using (var currentBitmap = SkiaEncoder.Decode(paths[imageIndex], false, _fileSystem, out origin))
                    {
                        // resize to the same aspect as the original
                        int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
                        using (var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
                        {
                            currentBitmap.Resize(resizeBitmap, SKBitmapResizeMethod.Lanczos3);
                            // determine how much to crop
                            int ix = (int)Math.Abs((iWidth - iSlice) / 2);
                            using (var image = SKImage.FromBitmap(resizeBitmap))
                            {
                                // crop image
                                using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight)))
                                {
                                    // draw image onto canvas
                                    canvas.DrawImage(subset, (horizontalImagePadding * (i + 1)) + (iSlice * i), verticalSpacing);

                                    using (var croppedBitmap = SKBitmap.FromImage(subset))
                                    {
                                        // create reflection of image below the drawn image
                                        using (var reflectionBitmap = new SKBitmap(croppedBitmap.Width, croppedBitmap.Height / 2, croppedBitmap.ColorType, croppedBitmap.AlphaType))
                                        {
                                            // resize to half height
                                            croppedBitmap.Resize(reflectionBitmap, SKBitmapResizeMethod.Lanczos3);

                                            using (var flippedBitmap = new SKBitmap(reflectionBitmap.Width, reflectionBitmap.Height, reflectionBitmap.ColorType, reflectionBitmap.AlphaType))
                                            {
                                                using (var flippedCanvas = new SKCanvas(flippedBitmap))
                                                {
                                                    // flip image vertically
                                                    var matrix = SKMatrix.MakeScale(1, -1);
                                                    matrix.SetScaleTranslate(1, -1, 0, flippedBitmap.Height);
                                                    flippedCanvas.SetMatrix(matrix);
                                                    flippedCanvas.DrawBitmap(reflectionBitmap, 0, 0);
                                                    flippedCanvas.ResetMatrix();

                                                    // create gradient to make image appear as a reflection
                                                    var remainingHeight = height - (iHeight + (2 * verticalSpacing));
                                                    flippedCanvas.ClipRect(SKRect.Create(reflectionBitmap.Width, remainingHeight));
                                                    using (var gradient = new SKPaint())
                                                    {
                                                        gradient.IsAntialias = true;
                                                        gradient.BlendMode   = SKBlendMode.SrcOver;
                                                        gradient.Shader      = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(0, remainingHeight), new[] { new SKColor(0, 0, 0, 128), new SKColor(0, 0, 0, 208), new SKColor(0, 0, 0, 240), new SKColor(0, 0, 0, 255) }, null, SKShaderTileMode.Clamp);
                                                        flippedCanvas.DrawPaint(gradient);
                                                    }

                                                    // finally draw reflection onto canvas
                                                    canvas.DrawBitmap(flippedBitmap, (horizontalImagePadding * (i + 1)) + (iSlice * i), iHeight + (2 * verticalSpacing));
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    imageIndex++;

                    if (imageIndex >= paths.Length)
                    {
                        imageIndex = 0;
                    }
                }
            }

            return(bitmap);
        }
Example #26
0
        public async Task <DataResolverResult> Resolve(string identifier, TaskParameter parameters, CancellationToken token)
        {
            ImageSource source = parameters.Source;

            if (!string.IsNullOrWhiteSpace(parameters.LoadingPlaceholderPath) && parameters.LoadingPlaceholderPath == identifier)
            {
                source = parameters.LoadingPlaceholderSource;
            }
            else if (!string.IsNullOrWhiteSpace(parameters.ErrorPlaceholderPath) && parameters.ErrorPlaceholderPath == identifier)
            {
                source = parameters.ErrorPlaceholderSource;
            }

            var resolvedData = await(Configuration.DataResolverFactory ?? new DataResolverFactory())
                               .GetResolver(identifier, source, parameters, Configuration)
                               .Resolve(identifier, parameters, token).ConfigureAwait(false);

            if (resolvedData?.Stream == null)
            {
                throw new FileNotFoundException(identifier);
            }

            var svg = new SKSvg()
            {
                ThrowOnUnsupportedElement = false,
            };
            SKPicture picture;

            if (ReplaceStringMap == null || ReplaceStringMap.Count == 0)
            {
                using (var svgStream = resolvedData.Stream)
                {
                    picture = svg.Load(svgStream);
                }
            }
            else
            {
                using (var svgStream = resolvedData.Stream)
                    using (var reader = new StreamReader(svgStream))
                    {
                        var inputString = await reader.ReadToEndAsync();

                        foreach (var map in ReplaceStringMap
                                 .Where(v => v.Key.StartsWith("regex:")))
                        {
                            inputString = Regex.Replace(inputString, map.Key.Substring(6), map.Value);
                        }

                        var builder = new StringBuilder(inputString);

                        foreach (var map in ReplaceStringMap
                                 .Where(v => !v.Key.StartsWith("regex:", StringComparison.OrdinalIgnoreCase)))
                        {
                            builder.Replace(map.Key, map.Value);
                        }

                        using (var svgFinalStream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString())))
                        {
                            picture = svg.Load(svgFinalStream);
                        }
                    }
            }

            double sizeX = 0;
            double sizeY = 0;

            if (VectorWidth <= 0 && VectorHeight <= 0)
            {
                if (picture.CullRect.Width > 0)
                {
                    sizeX = picture.CullRect.Width;
                }
                else
                {
                    sizeX = 300;
                }

                if (picture.CullRect.Height > 0)
                {
                    sizeY = picture.CullRect.Height;
                }
                else
                {
                    sizeY = 300;
                }
            }
            else if (VectorWidth > 0 && VectorHeight > 0)
            {
                sizeX = VectorWidth;
                sizeY = VectorHeight;
            }
            else if (VectorWidth > 0)
            {
                sizeX = VectorWidth;
                sizeY = (VectorWidth / picture.CullRect.Width) * picture.CullRect.Height;
            }
            else
            {
                sizeX = (VectorHeight / picture.CullRect.Height) * picture.CullRect.Width;
                sizeY = VectorHeight;
            }

            if (UseDipUnits)
            {
                sizeX = sizeX.DpToPixels();
                sizeY = sizeY.DpToPixels();
            }

            resolvedData.ImageInformation.SetType(ImageInformation.ImageType.SVG);

            using (var bitmap = new SKBitmap(new SKImageInfo((int)sizeX, (int)sizeY)))
                using (var canvas = new SKCanvas(bitmap))
                    using (var paint = new SKPaint())
                    {
                        canvas.Clear(SKColors.Transparent);
                        float scaleX = (float)sizeX / picture.CullRect.Width;
                        float scaleY = (float)sizeY / picture.CullRect.Height;
                        var   matrix = SKMatrix.MakeScale(scaleX, scaleY);
                        canvas.DrawPicture(picture, ref matrix, paint);
                        canvas.Flush();
#if __IOS__
                        var     info = bitmap.Info;
                        CGImage cgImage;
                        IntPtr  size;
                        using (var provider = new CGDataProvider(bitmap.GetPixels(out size), size.ToInt32()))
                            using (var colorSpace = CGColorSpace.CreateDeviceRGB())
                                using (cgImage = new CGImage(info.Width, info.Height, 8, info.BitsPerPixel, info.RowBytes,
                                                             colorSpace, CGBitmapFlags.PremultipliedLast | CGBitmapFlags.ByteOrder32Big,
                                                             provider, null, false, CGColorRenderingIntent.Default))
                                {
                                    IDecodedImage <object> container = new DecodedImage <object>()
                                    {
                                        Image = new UIImage(cgImage),
                                    };
                                    return(new DataResolverResult(container, resolvedData.LoadingResult, resolvedData.ImageInformation));
                                }
#elif __MACOS__
                        var     info = bitmap.Info;
                        CGImage cgImage;
                        IntPtr  size;
                        using (var provider = new CGDataProvider(bitmap.GetPixels(out size), size.ToInt32()))
                            using (var colorSpace = CGColorSpace.CreateDeviceRGB())
                                using (cgImage = new CGImage(info.Width, info.Height, 8, info.BitsPerPixel, info.RowBytes,
                                                             colorSpace, CGBitmapFlags.PremultipliedLast | CGBitmapFlags.ByteOrder32Big,
                                                             provider, null, false, CGColorRenderingIntent.Default))
                                {
                                    IDecodedImage <object> container = new DecodedImage <object>()
                                    {
                                        Image = new NSImage(cgImage, CGSize.Empty),
                                    };
                                    return(new DataResolverResult(container, resolvedData.LoadingResult, resolvedData.ImageInformation));
                                }
#elif __ANDROID__
                        using (var skiaPixmap = bitmap.PeekPixels())
                        {
                            var info = skiaPixmap.Info;

                            // destination values
                            var config  = Bitmap.Config.Argb8888;
                            var dstInfo = new SKImageInfo(info.Width, info.Height);

                            // try keep the pixel format if we can
                            switch (info.ColorType)
                            {
                            case SKColorType.Alpha8:
                                config            = Bitmap.Config.Alpha8;
                                dstInfo.ColorType = SKColorType.Alpha8;
                                break;

                            case SKColorType.Rgb565:
                                config            = Bitmap.Config.Rgb565;
                                dstInfo.ColorType = SKColorType.Rgb565;
                                dstInfo.AlphaType = SKAlphaType.Opaque;
                                break;

                            case SKColorType.Argb4444:
                                config            = Bitmap.Config.Argb4444;
                                dstInfo.ColorType = SKColorType.Argb4444;
                                break;
                            }

                            // destination bitmap
                            var bmp = Bitmap.CreateBitmap(info.Width, info.Height, config);
                            var ptr = bmp.LockPixels();

                            // copy
                            var success = skiaPixmap.ReadPixels(dstInfo, ptr, dstInfo.RowBytes);

                            // confirm
                            bmp.UnlockPixels();
                            if (!success)
                            {
                                bmp.Recycle();
                                bmp.Dispose();
                                bmp = null;
                            }

                            IDecodedImage <object> container = new DecodedImage <object>()
                            {
                                Image = bmp,
                            };
                            return(new DataResolverResult(container, resolvedData.LoadingResult, resolvedData.ImageInformation));
                        }
#elif __WINDOWS__
                        if (parameters.Transformations == null || parameters.Transformations.Count == 0)
                        {
                            WriteableBitmap writeableBitmap = null;

                            await Configuration.MainThreadDispatcher.PostAsync(async() =>
                            {
                                using (var skiaImage = SKImage.FromPixels(bitmap.PeekPixels()))
                                {
                                    var info        = new SKImageInfo(skiaImage.Width, skiaImage.Height);
                                    writeableBitmap = new WriteableBitmap(info.Width, info.Height);

                                    var buffer = writeableBitmap.PixelBuffer as IBufferByteAccess;
                                    if (buffer == null)
                                    {
                                        throw new InvalidCastException("Unable to convert WriteableBitmap.PixelBuffer to IBufferByteAccess.");
                                    }

                                    IntPtr ptr;
                                    var hr = buffer.Buffer(out ptr);
                                    if (hr < 0)
                                    {
                                        throw new InvalidCastException("Unable to retrieve pixel address from WriteableBitmap.PixelBuffer.");
                                    }

                                    using (var pixmap = new SKPixmap(info, ptr))
                                    {
                                        skiaImage.ReadPixels(pixmap, 0, 0);
                                    }
                                    writeableBitmap.Invalidate();
                                }
                            });

                            IDecodedImage <object> container = new DecodedImage <object>()
                            {
                                Image = writeableBitmap,
                            };
                            return(new DataResolverResult(container, resolvedData.LoadingResult, resolvedData.ImageInformation));
                        }
#endif
                        lock (_encodingLock)
                        {
                            using (var image = SKImage.FromBitmap(bitmap))
                                //using (var data = image.Encode(SKImageEncodeFormat.Png, 100))  //TODO disabled because of https://github.com/mono/SkiaSharp/issues/285
                                using (var data = image.Encode())
                                {
                                    var stream = new MemoryStream();
                                    data.SaveTo(stream);
                                    stream.Position = 0;
                                    return(new DataResolverResult(stream, resolvedData.LoadingResult, resolvedData.ImageInformation));
                                }
                        }
                    }
        }
        public override void PostLayout(bool IsTall, Grid grid, Controller GameController, IPlatformFoundry GameFoundry, IPage SourcePage)
        {
            Player PC = GameController.CurrentState.Player;

            // Calories
            if (GameController.GetCurrentPage().SubType == GameState.PageSubType.Dinner)
            {
                grid.Children.Add(_Text("Calories"), 1, 10, 4, 6);
                View CalorieView = ImageGradient.AsView(
                    0,
                    PC.TargetCalories,
                    PC.TargetCalories * 2,
                    PC.Calories,
                    true,
                    false
                    );

                grid.Children.Add(CalorieView, 10, 29, 4, 6);

                SortedDictionary <float, SKColor> MicroNutrients = new SortedDictionary <float, SKColor>();
                SortedDictionary <float, SKColor> MicroPotential = new SortedDictionary <float, SKColor>();
                SortedDictionary <float, SKColor> MacroNutrients = new SortedDictionary <float, SKColor>();
                float microNut = 0f;
                float microPot = 0f;
                float macroNut = 0f;
                foreach (KeyValuePair <Nutrient, NutrientAmount> kvp in PC.Nutrients)
                {
                    FlorineSkiaNutrient AdjNut = new FlorineSkiaNutrient(kvp.Key);
                    float curRatio             = kvp.Key.RatioRDV(kvp.Value);

                    switch (kvp.Key.Class)
                    {
                    case Nutrient.NutrientType.Macro:
                        if (curRatio > 2f)
                        {
                            curRatio = 2f;
                        }
                        if (curRatio <= 0f)
                        {
                            continue;
                        }
                        curRatio /= 8f;
                        macroNut += curRatio;
                        MacroNutrients.Add(macroNut, AdjNut.RingColor);
                        break;

                    case Nutrient.NutrientType.Mineral:
                    case Nutrient.NutrientType.Vitamin:
                        if (curRatio > 1f)
                        {
                            curRatio = 1f;
                        }
                        float fRestRatio = float.NaN;
                        if (curRatio < 1f)
                        {
                            fRestRatio  = 1f - curRatio;
                            fRestRatio /= 7f;
                        }
                        curRatio /= 7f;
                        microPot += 1f / 7f;

                        if (curRatio > float.Epsilon)
                        {
                            microNut += curRatio;
                            MicroNutrients.Add(microNut, AdjNut.RingColor);
                        }
                        if (!float.IsNaN(fRestRatio))
                        {
                            microNut += fRestRatio;
                            MicroNutrients.Add(microNut, SKColors.Transparent);
                        }
                        SKColor newCol = new SKColor(
                            AdjNut.RingColor.Red,
                            AdjNut.RingColor.Green,
                            AdjNut.RingColor.Blue,
                            80
                            );
                        MicroPotential.Add(microPot, newCol);
                        break;
                    }
                }
                grid.Children.Add(_Text("Vitamins"), 1, 10, 6, 8);
                //grid.Children.Add(ImageGradient.AsDivBar(WhiteBar), 20, 29, 6, 8);
                grid.Children.Add(ImageGradient.AsDivBar(MicroPotential), 10, 29, 6, 8);
                float gridSize = 5;
                grid.Children.Add(ImageGradient.AsDivBar(MicroPotential,
                                                         new SKPaint()
                {
                    PathEffect = SKPathEffect.Create2DLine(1,
                                                           MatrixMultiply(SKMatrix.MakeScale(gridSize, gridSize),
                                                                          SKMatrix.MakeRotationDegrees(45))),
                    Style       = SKPaintStyle.Stroke,
                    StrokeWidth = 1,
                    Color       = new SKColor(0, 0, 0, 20)
                }), 10, 29, 6, 8);

                grid.Children.Add(ImageGradient.AsDivBar(MicroPotential,
                                                         new SKPaint()
                {
                    PathEffect = SKPathEffect.Create2DLine(1,
                                                           MatrixMultiply(SKMatrix.MakeScale(gridSize, gridSize),
                                                                          SKMatrix.MakeRotationDegrees(-45))),
                    Style       = SKPaintStyle.Stroke,
                    StrokeWidth = 1,
                    Color       = new SKColor(0, 0, 0, 20)
                }), 10, 29, 6, 8);
                grid.Children.Add(ImageGradient.AsDivBar(MicroNutrients), 10, 29, 6, 8);

                grid.Children.Add(_Text("Nutrients"), 1, 10, 8, 10);
                grid.Children.Add(ImageGradient.AsDivBar(MacroNutrients), 10, 29, 8, 10);
            }

            if (GameController.GetCurrentPage().SubType == GameState.PageSubType.Lunch)
            {
                IGameOptionSet iActivities = GameController.GetCurrentPage().AppliedOptions;
                int            Amount      = 0;
                foreach (IGameOption act in iActivities)
                {
                    Activity mainAct = act as Activity;
                    if (null != mainAct)
                    {
                        Amount += mainAct.Pay;
                    }
                    if (null != act.SubOptions)
                    {
                        foreach (IGameOption subopt in act.SubOptions)
                        {
                            Activity subAct = subopt as Activity;
                            if (subAct != null)
                            {
                                Amount += subAct.Pay;
                            }
                        }
                    }
                }

                if (Amount != 0)
                {
                    View moneyGrid = MoneyView.RenderView(Amount);
                    grid.Children.Add(moneyGrid, 10, 20, 15, 18);
                }
            }
            else if (GameController.GetCurrentPage().SubType == GameState.PageSubType.Dinner)
            {
                View BackView = new FlorineSkiaCVWrap(new FlOval()
                {
                    backgroundColor = new SKPaint()
                    {
                        Color = new SKColor(0, 80, 190, 230)
                    },
                    Shape          = FlOval.OvalType.Rectangle,
                    ovalRatio      = float.NaN,
                    innerHighlight = new SKColor(100, 250, 250, 255),
                });
                View moneyGrid     = MoneyView.RenderView(PC.Money, false);
                View HappinessGrid = Happiness.RenderView(PC.Happiness, false);
                View TotalText     = new FlorineSkiaCVWrap(new ImageText("Total")
                {
                    FontSize = 48f, Overflow = ImageText.WrapType.None
                });


                View tdBackView = new FlorineSkiaCVWrap(new FlOval()
                {
                    backgroundColor = new SKPaint()
                    {
                        Color = new SKColor(0, 80, 190, 230)
                    },
                    Shape          = FlOval.OvalType.Rectangle,
                    ovalRatio      = float.NaN,
                    innerHighlight = new SKColor(100, 250, 250, 255),
                });
                View tdmoneyGrid     = MoneyView.RenderView(PC.MoneyToDate, false);
                View tdHappinessGrid = Happiness.RenderView(PC.HappinessToDate, false);
                View tdTotalText     = new FlorineSkiaCVWrap(new ImageText("Today")
                {
                    FontSize = 48f, Overflow = ImageText.WrapType.None
                });

                int TotalY = 13;
                int TodayY = 10;
                //grid.Children.Add(BackView, 0, 30, 10, 14);
                grid.Children.Add(TotalText, 2, 9, TotalY + 1, TotalY + 3);
                grid.Children.Add(moneyGrid, 8, 17, TotalY, TotalY + 3);
                grid.Children.Add(HappinessGrid, 17, 28, TotalY, TotalY + 3);

                //grid.Children.Add(tdBackView, 0, 30, 14, 18);
                grid.Children.Add(tdTotalText, 2, 9, TodayY + 1, TodayY + 3);
                grid.Children.Add(tdmoneyGrid, 8, 17, TodayY, TodayY + 3);
                grid.Children.Add(tdHappinessGrid, 17, 28, TodayY, TodayY + 3);
            }

            int EnergyY = 20;
            int FocusY  = EnergyY + 3;

            grid.Children.Add(_Text("Energy"), 15, 20, EnergyY, EnergyY + 2);
            grid.Children.Add(
                ImageGradient.AsView(
                    0.0,
                    100.0,
                    100.0,
                    PC.Energy,
                    false,
                    true
                    ),
                20, 29, EnergyY, EnergyY + 2
                );

            grid.Children.Add(_Text("Focus"), 15, 20, FocusY, FocusY + 2);
            grid.Children.Add(
                ImageGradient.AsView(
                    0.0,
                    100.0,
                    100.0,
                    PC.Focus,
                    false,
                    true
                    ),
                20, 29, FocusY, FocusY + 2
                );

            base.PostLayout(IsTall, grid, GameController, GameFoundry, SourcePage);
        }
Example #28
0
        public static void Draw(SKCanvas canvas, IViewport viewport, IStyle style, IFeature feature, IGeometry geometry,
                                float opacity, SymbolCache symbolCache = null)
        {
            if (style is LabelStyle)
            {
                var worldCenter = geometry.GetBoundingBox().GetCentroid();
                var center      = viewport.WorldToScreen(worldCenter);
                LabelRenderer.Draw(canvas, (LabelStyle)style, feature, (float)center.X, (float)center.Y, opacity);
            }
            else if (style is StyleCollection styleCollection)
            {
                foreach (var s in styleCollection)
                {
                    Draw(canvas, viewport, s, feature, geometry, opacity, symbolCache);
                }
            }
            else
            {
                var polygon = (Polygon)geometry;

                float   lineWidth        = 1;
                var     lineColor        = Color.Black;       // default
                var     fillColor        = Color.Gray;        // default
                var     strokeCap        = PenStrokeCap.Butt; // default
                var     strokeJoin       = StrokeJoin.Miter;  // default
                var     strokeMiterLimit = 4f;                // default
                var     strokeStyle      = PenStyle.Solid;    // default
                float[] dashArray        = null;              // default

                var vectorStyle = style as VectorStyle;

                if (vectorStyle != null)
                {
                    lineWidth        = (float)vectorStyle.Outline.Width;
                    lineColor        = vectorStyle.Outline.Color;
                    strokeCap        = vectorStyle.Outline.PenStrokeCap;
                    strokeJoin       = vectorStyle.Outline.StrokeJoin;
                    strokeMiterLimit = vectorStyle.Outline.StrokeMiterLimit;
                    strokeStyle      = vectorStyle.Outline.PenStyle;
                    dashArray        = vectorStyle.Outline.DashArray;

                    fillColor = vectorStyle.Fill?.Color;
                }

                using (var path = polygon.ToSkiaPath(viewport, canvas.LocalClipBounds, lineWidth))
                {
                    // Is there a FillStyle?
                    if (vectorStyle.Fill?.FillStyle == FillStyle.Solid)
                    {
                        PaintFill.StrokeWidth = lineWidth;
                        PaintFill.Style       = SKPaintStyle.Fill;
                        PaintFill.PathEffect  = null;
                        PaintFill.Shader      = null;
                        PaintFill.Color       = fillColor.ToSkia(opacity);
                        canvas.DrawPath(path, PaintFill);
                    }
                    else
                    {
                        PaintFill.StrokeWidth = 1;
                        PaintFill.Style       = SKPaintStyle.Stroke;
                        PaintFill.Shader      = null;
                        PaintFill.Color       = fillColor.ToSkia(opacity);
                        float    scale    = 10.0f;
                        SKPath   fillPath = new SKPath();
                        SKMatrix matrix   = SKMatrix.MakeScale(scale, scale);

                        switch (vectorStyle.Fill?.FillStyle)
                        {
                        case FillStyle.Cross:
                            fillPath.MoveTo(scale * 0.8f, scale * 0.8f);
                            fillPath.LineTo(0, 0);
                            fillPath.MoveTo(0, scale * 0.8f);
                            fillPath.LineTo(scale * 0.8f, 0);
                            PaintFill.PathEffect = SKPathEffect.Create2DPath(matrix, fillPath);
                            break;

                        case FillStyle.DiagonalCross:
                            fillPath.MoveTo(scale, scale);
                            fillPath.LineTo(0, 0);
                            fillPath.MoveTo(0, scale);
                            fillPath.LineTo(scale, 0);
                            PaintFill.PathEffect = SKPathEffect.Create2DPath(matrix, fillPath);
                            break;

                        case FillStyle.BackwardDiagonal:
                            fillPath.MoveTo(0, scale);
                            fillPath.LineTo(scale, 0);
                            PaintFill.PathEffect = SKPathEffect.Create2DPath(matrix, fillPath);
                            break;

                        case FillStyle.ForwardDiagonal:
                            fillPath.MoveTo(scale, scale);
                            fillPath.LineTo(0, 0);
                            PaintFill.PathEffect = SKPathEffect.Create2DPath(matrix, fillPath);
                            break;

                        case FillStyle.Dotted:
                            PaintFill.Style = SKPaintStyle.StrokeAndFill;
                            fillPath.AddCircle(scale * 0.5f, scale * 0.5f, scale * 0.35f);
                            PaintFill.PathEffect = SKPathEffect.Create2DPath(matrix, fillPath);
                            break;

                        case FillStyle.Horizontal:
                            fillPath.MoveTo(0, scale * 0.5f);
                            fillPath.LineTo(scale, scale * 0.5f);
                            PaintFill.PathEffect = SKPathEffect.Create2DPath(matrix, fillPath);
                            break;

                        case FillStyle.Vertical:
                            fillPath.MoveTo(scale * 0.5f, 0);
                            fillPath.LineTo(scale * 0.5f, scale);
                            PaintFill.PathEffect = SKPathEffect.Create2DPath(matrix, fillPath);
                            break;

                        case FillStyle.Bitmap:
                            PaintFill.Style = SKPaintStyle.Fill;
                            var image = GetImage(symbolCache, vectorStyle.Fill.BitmapId);
                            if (image != null)
                            {
                                PaintFill.Shader = image.ToShader(SKShaderTileMode.Repeat, SKShaderTileMode.Repeat);
                            }
                            break;

                        case FillStyle.BitmapRotated:
                            PaintFill.Style = SKPaintStyle.Fill;
                            image           = GetImage(symbolCache, vectorStyle.Fill.BitmapId);
                            if (image != null)
                            {
                                PaintFill.Shader = image.ToShader(SKShaderTileMode.Repeat,
                                                                  SKShaderTileMode.Repeat,
                                                                  SKMatrix.MakeRotation((float)(viewport.Rotation * System.Math.PI / 180.0f), image.Width >> 1, image.Height >> 1));
                            }
                            break;

                        default:
                            PaintFill.PathEffect = null;
                            break;
                        }

                        // Do this, because if not, path isn't filled complete
                        using (new SKAutoCanvasRestore(canvas))
                        {
                            canvas.ClipPath(path);
                            var bounds = path.Bounds;
                            // Make sure, that the brush starts with the correct position
                            var inflate = ((int)path.Bounds.Width * 0.3f / scale) * scale;
                            bounds.Inflate(inflate, inflate);
                            // Draw rect with bigger size, which is clipped by path
                            canvas.DrawRect(bounds, PaintFill);
                        }
                    }

                    PaintStroke.Style       = SKPaintStyle.Stroke;
                    PaintStroke.StrokeWidth = lineWidth;
                    PaintStroke.Color       = lineColor.ToSkia(opacity);
                    PaintStroke.StrokeCap   = strokeCap.ToSkia();
                    PaintStroke.StrokeJoin  = strokeJoin.ToSkia();
                    PaintStroke.StrokeMiter = strokeMiterLimit;
                    if (strokeStyle != PenStyle.Solid)
                    {
                        PaintStroke.PathEffect = strokeStyle.ToSkia(lineWidth, dashArray);
                    }
                    else
                    {
                        PaintStroke.PathEffect = null;
                    }

                    canvas.DrawPath(path, PaintStroke);
                }
            }
        }
Example #29
0
        public async Task <Tuple <Stream, LoadingResult, ImageInformation> > Resolve(string identifier, TaskParameter parameters, CancellationToken token)
        {
            ImageSource source = parameters.Source;

            if (!string.IsNullOrWhiteSpace(parameters.LoadingPlaceholderPath) && parameters.LoadingPlaceholderPath == identifier)
            {
                source = parameters.LoadingPlaceholderSource;
            }
            else if (!string.IsNullOrWhiteSpace(parameters.ErrorPlaceholderPath) && parameters.ErrorPlaceholderPath == identifier)
            {
                source = parameters.ErrorPlaceholderSource;
            }

            var resolvedData = await(Configuration.DataResolverFactory ?? new DataResolverFactory())
                               .GetResolver(identifier, source, parameters, Configuration)
                               .Resolve(identifier, parameters, token).ConfigureAwait(false);

            if (resolvedData?.Item1 == null)
            {
                throw new FileNotFoundException(identifier);
            }

            var svg = new SKSvg()
            {
                ThrowOnUnsupportedElement = false,
            };
            SKPicture picture;

            if (ReplaceStringMap == null || ReplaceStringMap.Count == 0)
            {
                using (var svgStream = resolvedData.Item1)
                {
                    picture = svg.Load(resolvedData?.Item1);
                }
            }
            else
            {
                using (var svgStream = resolvedData.Item1)
                    using (var reader = new StreamReader(svgStream))
                    {
                        var builder = new StringBuilder(await reader.ReadToEndAsync());
                        foreach (var map in ReplaceStringMap)
                        {
                            builder.Replace(map.Key, map.Value);
                        }

                        using (var svgFinalStream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString())))
                        {
                            picture = svg.Load(svgFinalStream);
                        }
                    }
            }

            double sizeX = 0;
            double sizeY = 0;

            if (VectorWidth == 0 && VectorHeight == 0)
            {
                if (picture.CullRect.Width > 0)
                {
                    sizeX = picture.CullRect.Width;
                }
                else
                {
                    sizeX = 300;
                }

                if (picture.CullRect.Height > 0)
                {
                    sizeY = picture.CullRect.Height;
                }
                else
                {
                    sizeY = 300;
                }
            }
            else if (VectorWidth > 0 && VectorHeight > 0)
            {
                sizeX = VectorWidth;
                sizeY = VectorHeight;
            }
            else if (VectorWidth > 0)
            {
                sizeX = VectorWidth;
                sizeY = (VectorWidth / picture.CullRect.Width) * picture.CullRect.Height;
            }
            else
            {
                sizeX = (VectorHeight / picture.CullRect.Height) * picture.CullRect.Width;
                sizeY = VectorHeight;
            }

            if (UseDipUnits)
            {
#if __ANDROID__
                sizeX = sizeX.DpToPixels();
                sizeY = sizeY.DpToPixels();
#else
                sizeX = sizeX.PointsToPixels();
                sizeY = sizeY.PointsToPixels();
#endif
            }

            using (var bitmap = new SKBitmap(new SKImageInfo((int)sizeX, (int)sizeY)))
                //using (var bitmap = new SKBitmap((int)sizeX, (int)sizeY))
                using (var canvas = new SKCanvas(bitmap))
                    using (var paint = new SKPaint())
                    {
                        canvas.Clear(SKColors.Transparent);
                        float scaleX = (float)sizeX / picture.CullRect.Width;
                        float scaleY = (float)sizeY / picture.CullRect.Height;
                        var   matrix = SKMatrix.MakeScale(scaleX, scaleY);

                        canvas.DrawPicture(picture, ref matrix, paint);
                        canvas.Flush();

                        using (var image = SKImage.FromBitmap(bitmap))
                            //using (var data = image.Encode(SKImageEncodeFormat.Png, 100))  //TODO disabled because of https://github.com/mono/SkiaSharp/issues/285
                            using (var data = image.Encode())
                            {
                                var stream = new MemoryStream();
                                data.SaveTo(stream);
                                stream.Position = 0;
                                resolvedData.Item3.SetType(ImageInformation.ImageType.SVG);
                                return(new Tuple <Stream, LoadingResult, ImageInformation>(stream, resolvedData.Item2, resolvedData.Item3));
                            }
                    }
        }
Example #30
0
        public MaskDrawable(SvgMask svgMask, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgMask, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = true;

            if (!IsDrawable)
            {
                return;
            }
            var   maskUnits        = svgMask.MaskUnits;
            var   maskContentUnits = svgMask.MaskContentUnits;
            var   xUnit            = svgMask.X;
            var   yUnit            = svgMask.Y;
            var   widthUnit        = svgMask.Width;
            var   heightUnit       = svgMask.Height;
            float x      = xUnit.ToDeviceValue(UnitRenderingType.Horizontal, svgMask, skOwnerBounds);
            float y      = yUnit.ToDeviceValue(UnitRenderingType.Vertical, svgMask, skOwnerBounds);
            float width  = widthUnit.ToDeviceValue(UnitRenderingType.Horizontal, svgMask, skOwnerBounds);
            float height = heightUnit.ToDeviceValue(UnitRenderingType.Vertical, svgMask, skOwnerBounds);

            if (width <= 0 || height <= 0)
            {
                IsDrawable = false;
                return;
            }

            if (maskUnits == SvgCoordinateUnits.ObjectBoundingBox)
            {
                if (xUnit.Type != SvgUnitType.Percentage)
                {
                    x *= skOwnerBounds.Width;
                }

                if (yUnit.Type != SvgUnitType.Percentage)
                {
                    y *= skOwnerBounds.Height;
                }

                if (widthUnit.Type != SvgUnitType.Percentage)
                {
                    width *= skOwnerBounds.Width;
                }

                if (heightUnit.Type != SvgUnitType.Percentage)
                {
                    height *= skOwnerBounds.Height;
                }

                x += skOwnerBounds.Left;
                y += skOwnerBounds.Top;
            }

            SKRect skRectTransformed = SKRect.Create(x, y, width, height);

            var skMatrix = SKMatrix.MakeIdentity();

            if (maskContentUnits == SvgCoordinateUnits.ObjectBoundingBox)
            {
                var skBoundsTranslateTransform = SKMatrix.MakeTranslation(skOwnerBounds.Left, skOwnerBounds.Top);
                SKMatrix.PreConcat(ref skMatrix, ref skBoundsTranslateTransform);

                var skBoundsScaleTransform = SKMatrix.MakeScale(skOwnerBounds.Width, skOwnerBounds.Height);
                SKMatrix.PreConcat(ref skMatrix, ref skBoundsScaleTransform);
            }

            CreateChildren(svgMask, skOwnerBounds, root, this, ignoreAttributes);

            Overflow = skRectTransformed;

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgMask);

            TransformedBounds = skRectTransformed;

            Transform = skMatrix;

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            SKMatrix.MapRect(ref Transform, out TransformedBounds, ref TransformedBounds);
        }