Exemple #1
0
        public SKBitmap Crop(SKRect cropRect)
        {
            SKMatrix invertedMatrix = Matrix.Invert();

            SKRect mappedCropRect = invertedMatrix.MapRect(cropRect);

            //由于任意旋转下,矩阵旋转后,不能再用SKRect表示,这里不用任意旋转

            float sourceX      = (mappedCropRect.Left - _drawBitmapResult !.DisplayRect.Left) / _drawBitmapResult.WidthScale;
            float sourceY      = (mappedCropRect.Top - _drawBitmapResult.DisplayRect.Top) / _drawBitmapResult.HeightScale;
            float sourceWidth  = mappedCropRect.Width / _drawBitmapResult.WidthScale;
            float sourceHeight = mappedCropRect.Height / _drawBitmapResult.HeightScale;

            //得到原始图片上的原始区域
            SKRect sourceRect = SKRect.Create(sourceX, sourceY, sourceWidth, sourceHeight);

            //将SourceRect区域投射到新的canvas

            SKBitmap croppedBitmap = new SKBitmap((int)cropRect.Width, (int)cropRect.Height);

            using SKCanvas newCanvas = new SKCanvas(croppedBitmap);

            newCanvas.RotateDegrees(_rotatedDegrees, croppedBitmap.Width / 2f, croppedBitmap.Height / 2f);

            SKRect newDestRect = SKRect.Create(0, 0, croppedBitmap.Width, croppedBitmap.Height);

            newCanvas.DrawBitmap(_bitmap, sourceRect, newDestRect);

            return(croppedBitmap);

            //SetBitmap(croppedBitmap);
        }
Exemple #2
0
        void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e)
        {
            var canvas = e.Surface.Canvas;

            _drawableBounds = e.Info.Rect;
            canvas.Clear();

            if (_skPath == null)
            {
                return;
            }

            SKMatrix transformMatrix   = CreateMatrix();
            SKPath   transformedSkPath = new SKPath();

            _skPath.Transform(transformMatrix, transformedSkPath);
            SKRect fillBounds = transformMatrix.MapRect(_pathFillBounds);
            SKRect strokeBounds;

            using (SKPath strokePath = new SKPath())
            {
                _skPaint.GetFillPath(transformedSkPath, strokePath);
                strokeBounds = strokePath.Bounds;
            }

            if (_fill != null)
            {
                _skPaint.Style = SKPaintStyle.Fill;

                if (_fill is GradientBrush fillGradientBrush)
                {
                    _skPaint.Shader = fillGradientBrush.CreateShader(fillBounds);
                }
                else if (_fill is SolidColorBrush fillSolidColorBrush)
                {
                    _skPaint.Color = fillSolidColorBrush.ToSolidColor();
                }

                canvas.DrawPath(transformedSkPath, _skPaint);
                _skPaint.Shader = null;
            }

            if (_stroke != null)
            {
                _skPaint.Style = SKPaintStyle.Stroke;

                if (_stroke is GradientBrush strokeGradientBrush)
                {
                    UpdatePathStrokeBounds();
                    _skPaint.Shader = strokeGradientBrush.CreateShader(strokeBounds);
                }
                else if (_stroke is SolidColorBrush strokeSolidColorBrush)
                {
                    _skPaint.Color = strokeSolidColorBrush.ToSolidColor();
                }

                canvas.DrawPath(transformedSkPath, _skPaint);
                _skPaint.Shader = null;
            }
        }
        private void ImageControls_TouchAction(object sender, TouchActionEventArgs args)
        {
            // https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/touch

            var point = new SKPoint((float)(CanvasView.CanvasSize.Width * args.Location.X / CanvasView.Width),
                                    (float)(CanvasView.CanvasSize.Height * args.Location.Y / CanvasView.Height));

            switch (args.Type)
            {
            case TouchActionType.Pressed:
                var rect = new SKRect(0, 0, Design.Bitmap.Width, Design.Bitmap.Height);
                rect = Matrix.MapRect(rect);

                if (rect.Contains(point) && !Touches.ContainsKey(args.Id))
                {
                    Touches.Add(args.Id, point);
                }
                break;

            case TouchActionType.Moved:
                MoveOrScaleCanvas(args.Id, point);
                break;

            case TouchActionType.Released:
            case TouchActionType.Exited:
            case TouchActionType.Cancelled:
                if (Touches.ContainsKey(args.Id))
                {
                    Touches.Remove(args.Id);
                }
                return;
            }
        }
Exemple #4
0
        public AnchorDrawable(SvgAnchor svgAnchor, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgAnchor, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = true;

            if (!IsDrawable)
            {
                return;
            }

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

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgAnchor);

            TransformedBounds = SKRect.Empty;

            CreateTransformedBounds();

            Transform = SvgTransformsExtensions.ToSKMatrix(svgAnchor.Transforms);

            Fill   = null;
            Stroke = null;

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

            ClipPath     = null;
            MaskDrawable = null;
            Opacity      = IgnoreAttributes.HasFlag(Attributes.Opacity) ? null : SvgPaintingExtensions.GetOpacitySKPaint(svgAnchor, _disposable);
            Filter       = null;
        }
Exemple #5
0
        public SwitchDrawable(SvgSwitch svgSwitch, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgSwitch, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgSwitch, IgnoreAttributes) && HasFeatures(svgSwitch, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            foreach (var child in svgSwitch.Children)
            {
                if (!IsKnownElement(child))
                {
                    continue;
                }

                bool hasRequiredFeatures   = HasRequiredFeatures(child);
                bool hasRequiredExtensions = HasRequiredExtensions(child);
                bool hasSystemLanguage     = HasSystemLanguage(child);

                if (hasRequiredFeatures && hasRequiredExtensions && hasSystemLanguage)
                {
                    //var ignoreAttributesSwitch = ignoreAttributes
                    //    | Attributes.Visibility
                    //    | Attributes.Display
                    //    | Attributes.RequiredFeatures
                    //    | Attributes.RequiredExtensions
                    //    | Attributes.SystemLanguage;

                    var drawable = DrawableFactory.Create(child, skOwnerBounds, root, parent, ignoreAttributes);
                    if (drawable != null)
                    {
                        FirstChild = drawable;
                        _disposable.Add(FirstChild);
                    }
                    break;
                }
            }

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

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgSwitch);

            TransformedBounds = FirstChild.TransformedBounds;

            Transform = SvgTransformsExtensions.ToSKMatrix(svgSwitch.Transforms);

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            SKMatrix.MapRect(ref Transform, out TransformedBounds, ref TransformedBounds);
        }
Exemple #6
0
        private SKMatrix GetTranslationMatrix(SKImageInfo canvasInfo, SKMatrix scaleMatrix)
        {
            SKRect scaledSvgBounds = scaleMatrix.MapRect(_svgRect);
            float  xTranslation    = GetTranslation(canvasInfo.Width, scaledSvgBounds.Width, HorizontalAligment);
            float  yTranslation    = GetTranslation(canvasInfo.Height, scaledSvgBounds.Height, VerticalAligment);

            return(SKMatrix.MakeTranslation(xTranslation, yTranslation));
        }
        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:
        //  public void Dispose();

        public static SKRectI GetDeviceBounds(SKRect rect, SKMatrix ctm)
        {
            SKRect device_rect = new SKRect();

            SKMatrix.MapRect(ref ctm, out device_rect, ref rect);
            var bounds = SKRectI.Round(device_rect);

            return(bounds);
        }
Exemple #8
0
        public PolylineDrawable(SvgPolyline svgPolyline, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgPolyline, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgPolyline, IgnoreAttributes) && HasFeatures(svgPolyline, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            Path = svgPolyline.Points?.ToSKPath(svgPolyline.FillRule, false, skOwnerBounds, _disposable);
            if (Path == null || Path.IsEmpty)
            {
                IsDrawable = false;
                return;
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgPolyline);

            TransformedBounds = Path.Bounds;

            Transform = SvgTransformsExtensions.ToSKMatrix(svgPolyline.Transforms);

            bool canDrawFill   = true;
            bool canDrawStroke = true;

            if (SvgPaintingExtensions.IsValidFill(svgPolyline))
            {
                Fill = SvgPaintingExtensions.GetFillSKPaint(svgPolyline, TransformedBounds, ignoreAttributes, _disposable);
                if (Fill == null)
                {
                    canDrawFill = false;
                }
            }

            if (SvgPaintingExtensions.IsValidStroke(svgPolyline, TransformedBounds))
            {
                Stroke = SvgPaintingExtensions.GetStrokeSKPaint(svgPolyline, TransformedBounds, ignoreAttributes, _disposable);
                if (Stroke == null)
                {
                    canDrawStroke = false;
                }
            }

            if (canDrawFill && !canDrawStroke)
            {
                IsDrawable = false;
                return;
            }

            SvgMarkerExtensions.CreateMarkers(svgPolyline, Path, skOwnerBounds, ref MarkerDrawables, _disposable);

            // TODO: Transform _skBounds using _skMatrix.
            SKMatrix.MapRect(ref Transform, out TransformedBounds, ref TransformedBounds);
        }
        protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
        {
            base.OnPaintSurface(args);

            SKImageInfo info    = args.Info;
            SKSurface   surface = args.Surface;
            SKCanvas    canvas  = surface.Canvas;

            canvas.Clear(SKColors.Gray);

            // Calculate rectangle for displaying bitmap
            float  scale      = Math.Min((float)info.Width / bitmap.Width, (float)info.Height / bitmap.Height);
            float  x          = (info.Width - scale * bitmap.Width) / 2;
            float  y          = (info.Height - scale * bitmap.Height) / 2;
            SKRect bitmapRect = new SKRect(x, y, x + scale * bitmap.Width, y + scale * bitmap.Height);

            canvas.DrawBitmap(bitmap, bitmapRect);

            // Calculate a matrix transform for displaying the cropping rectangle
            SKMatrix bitmapScaleMatrix = SKMatrix.MakeIdentity();

            bitmapScaleMatrix.SetScaleTranslate(scale, scale, x, y);

            // Display rectangle
            SKRect scaledCropRect = bitmapScaleMatrix.MapRect(croppingRect.Rect);

            canvas.DrawRect(scaledCropRect, edgeStroke);

            // Display heavier corners
            using (SKPath path = new SKPath())
            {
                path.MoveTo(scaledCropRect.Left, scaledCropRect.Top + CORNER);
                path.LineTo(scaledCropRect.Left, scaledCropRect.Top);
                path.LineTo(scaledCropRect.Left + CORNER, scaledCropRect.Top);

                path.MoveTo(scaledCropRect.Right - CORNER, scaledCropRect.Top);
                path.LineTo(scaledCropRect.Right, scaledCropRect.Top);
                path.LineTo(scaledCropRect.Right, scaledCropRect.Top + CORNER);

                path.MoveTo(scaledCropRect.Right, scaledCropRect.Bottom - CORNER);
                path.LineTo(scaledCropRect.Right, scaledCropRect.Bottom);
                path.LineTo(scaledCropRect.Right - CORNER, scaledCropRect.Bottom);

                path.MoveTo(scaledCropRect.Left + CORNER, scaledCropRect.Bottom);
                path.LineTo(scaledCropRect.Left, scaledCropRect.Bottom);
                path.LineTo(scaledCropRect.Left, scaledCropRect.Bottom - CORNER);

                canvas.DrawPath(path, cornerStroke);
            }

            // Invert the transform for touch tracking
            bitmapScaleMatrix.TryInvert(out inverseBitmapMatrix);
        }
Exemple #10
0
        public GroupDrawable(SvgGroup svgGroup, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgGroup, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgGroup, IgnoreAttributes) && HasFeatures(svgGroup, IgnoreAttributes);

            // NOTE: Call AddMarkers only once.
            SvgMarkerExtensions.AddMarkers(svgGroup);

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

            // TODO: Check if children are explicitly set to be visible.
            //foreach (var child in ChildrenDrawables)
            //{
            //    if (child.IsDrawable)
            //    {
            //        IsDrawable = true;
            //        break;
            //    }
            //}

            if (!IsDrawable)
            {
                return;
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgGroup);

            TransformedBounds = SKRect.Empty;

            CreateTransformedBounds();

            Transform = SvgTransformsExtensions.ToSKMatrix(svgGroup.Transforms);

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            SKMatrix.MapRect(ref Transform, out TransformedBounds, ref TransformedBounds);
        }
Exemple #11
0
        }         // loadPlan()

        /// <summary>
        /// This function is called by the parent class as part of the displayPlan() method.
        /// It only implements the actual drawing of the plan, which is different depending on
        /// whether an SVG or a JPEG plan is used.
        /// </summary>
        /// <param name="canvas"></param>
        public override void drawPlan(SKCanvas canvas)
        {
            // Set up scaling matrix to zoom around pivot point at centre of display, then modify to take
            // account of translation. It would seem like a nice idea to set up the scaling matrix only
            // when we actually change the scale, but, actually, this gets extremely messy, because both
            // scaling and translating affect the "TransX" and "TransY" values of the matrix. See design
            // documentation.
            float    scale  = base.getCurrentScaleFactor();
            SKMatrix matrix = new SKMatrix(scale, 0, base.getTranslationX(), 0, scale, base.getTranslationY(), 0, 0, 1);

            try
            {
                // Draw the plan
                canvas.DrawPicture(SVGCanvas.Picture, ref matrix);
            }
            catch (Exception e)
            {
                string errorString = "Cannot draw SVG plan: ";
                LogFile.WriteError(errorString + e.Message);
                throw new Exception(errorString, e);
            }

            // Draw an outline around the plan, just so we can see where it is
            SKPaint paint = new SKPaint();

            // ***** There is an issue with SKColor; using pre-defined SkiaSharp colour, as it does not
            // seem to be possible to set SKColor to one of the colours defined in colors.xml. *****
            paint.Color       = SKColors.Black;
            paint.IsStroke    = true;
            paint.StrokeWidth = 2;
            // The transformation matrix was applied to the picture, not to the canvas, so we have to
            // apply the same transformtion to the frame.
            SKRect transformedRect = matrix.MapRect(SKRect.Create(0, 0, drawingWidth, drawingHeight));

            canvas.DrawRect(transformedRect, paint);
        } // drawPlan
        void OnTouchEffectAction(object sender, TouchActionEventArgs args)
        {
            // Convert Xamarin.Forms point to pixels
            Point   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:
                // Track only one finger
                if (touchId.HasValue)
                {
                    return;
                }

                // Check if the finger is within the boundaries of the bitmap
                SKRect rect = new SKRect(0, 0, bitmap.Width, bitmap.Height);
                rect = currentMatrix.MapRect(rect);
                if (!rect.Contains(point))
                {
                    return;
                }

                // First assume there will be no scaling
                isScaling = false;

                // If touch is outside interior ellipse, make this a scaling operation
                if (Math.Pow((point.X - rect.MidX) / (rect.Width / 2), 2) +
                    Math.Pow((point.Y - rect.MidY) / (rect.Height / 2), 2) > 1)
                {
                    isScaling = true;
                    float xPivot = point.X < rect.MidX ? rect.Right : rect.Left;
                    float yPivot = point.Y < rect.MidY ? rect.Bottom : rect.Top;
                    pivotPoint = new SKPoint(xPivot, yPivot);
                }

                // Common for either pan or scale
                touchId         = args.Id;
                pressedLocation = point;
                pressedMatrix   = currentMatrix;
                break;

            case TouchActionType.Moved:
                if (!touchId.HasValue || args.Id != touchId.Value)
                {
                    return;
                }

                SKMatrix matrix = SKMatrix.MakeIdentity();

                // Translating
                if (!isScaling)
                {
                    SKPoint delta = point - pressedLocation;
                    matrix = SKMatrix.MakeTranslation(delta.X, delta.Y);
                }
                // Scaling
                else
                {
                    float scaleX = (point.X - pivotPoint.X) / (pressedLocation.X - pivotPoint.X);
                    float scaleY = (point.Y - pivotPoint.Y) / (pressedLocation.Y - pivotPoint.Y);
                    matrix = SKMatrix.MakeScale(scaleX, scaleY, pivotPoint.X, pivotPoint.Y);
                }

                // Concatenate the matrices
                SKMatrix.PreConcat(ref matrix, pressedMatrix);
                currentMatrix = matrix;
                canvasView.InvalidateSurface();
                break;

            case TouchActionType.Released:
            case TouchActionType.Cancelled:
                touchId = null;
                break;
            }
        }
        protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
        {
            base.OnPaintSurface(args);

            SKImageInfo info    = args.Info;
            SKSurface   surface = args.Surface;
            SKCanvas    canvas  = surface.Canvas;

            canvas.Clear(SkiaHelper.backgroundColor);

            // 计算显示位图的矩形
            var rect = SkiaHelper.CalculateRectangle(new SKRect(0, 0, info.Width, info.Height), bitmap);

            canvas.DrawBitmap(bitmap, rect.rect);

            // 计算用于显示裁剪矩形的矩阵变换
            SKMatrix bitmapScaleMatrix = SKMatrix.CreateIdentity();

            SKMatrix.CreateScaleTranslation(rect.scaleX, rect.scaleX, rect.rect.Left, rect.rect.Top);

            // 显示矩形
            SKRect scaledCropRect = bitmapScaleMatrix.MapRect(croppingRect.Rect);


            using (SKPaint edgeStroke = new SKPaint())
            {
                edgeStroke.Style       = SKPaintStyle.Stroke;
                edgeStroke.Color       = SKColors.White;
                edgeStroke.StrokeWidth = 3;
                edgeStroke.IsAntialias = true;
                canvas.DrawRect(scaledCropRect, edgeStroke);
            }

            canvas.DrawSurrounding(rect.rect, scaledCropRect, SKColors.Gray.WithAlpha(190));

            // Display heavier corners
            using (SKPaint cornerStroke = new SKPaint())
                using (SKPath path = new SKPath())
                {
                    cornerStroke.Style       = SKPaintStyle.Stroke;
                    cornerStroke.Color       = SKColors.White;
                    cornerStroke.StrokeWidth = 7;

                    path.MoveTo(scaledCropRect.Left, scaledCropRect.Top + corner);
                    path.LineTo(scaledCropRect.Left, scaledCropRect.Top);
                    path.LineTo(scaledCropRect.Left + corner, scaledCropRect.Top);

                    path.MoveTo(scaledCropRect.Right - corner, scaledCropRect.Top);
                    path.LineTo(scaledCropRect.Right, scaledCropRect.Top);
                    path.LineTo(scaledCropRect.Right, scaledCropRect.Top + corner);

                    path.MoveTo(scaledCropRect.Right, scaledCropRect.Bottom - corner);
                    path.LineTo(scaledCropRect.Right, scaledCropRect.Bottom);
                    path.LineTo(scaledCropRect.Right - corner, scaledCropRect.Bottom);

                    path.MoveTo(scaledCropRect.Left + corner, scaledCropRect.Bottom);
                    path.LineTo(scaledCropRect.Left, scaledCropRect.Bottom);
                    path.LineTo(scaledCropRect.Left, scaledCropRect.Bottom - corner);

                    canvas.DrawPath(path, cornerStroke);
                }

            // 反转变换以进行触摸跟踪
            bitmapScaleMatrix.TryInvert(out inverseBitmapMatrix);
        }
Exemple #14
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);
        }
Exemple #15
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);
                SKMatrix.PreConcat(ref FragmentTransform, ref skTranslationMatrix);
                SKMatrix.PreConcat(ref FragmentTransform, ref skScaleMatrix);
            }

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            SKMatrix.MapRect(ref Transform, out TransformedBounds, ref TransformedBounds);
        }
Exemple #16
0
        public UseDrawable(SvgUse svgUse, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgUse, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgUse, IgnoreAttributes) && HasFeatures(svgUse, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            if (SvgExtensions.HasRecursiveReference(svgUse, (e) => e.ReferencedElement, new HashSet <Uri>()))
            {
                IsDrawable = false;
                return;
            }

            var svgReferencedElement = SvgExtensions.GetReference <SvgElement>(svgUse, svgUse.ReferencedElement);

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

            float x      = svgUse.X.ToDeviceValue(UnitRenderingType.Horizontal, svgUse, skOwnerBounds);
            float y      = svgUse.Y.ToDeviceValue(UnitRenderingType.Vertical, svgUse, skOwnerBounds);
            float width  = svgUse.Width.ToDeviceValue(UnitRenderingType.Horizontal, svgUse, skOwnerBounds);
            float height = svgUse.Height.ToDeviceValue(UnitRenderingType.Vertical, svgUse, skOwnerBounds);

            if (width <= 0f)
            {
                width = new SvgUnit(SvgUnitType.Percentage, 100f).ToDeviceValue(UnitRenderingType.Horizontal, svgUse, skOwnerBounds);
            }

            if (height <= 0f)
            {
                height = new SvgUnit(SvgUnitType.Percentage, 100f).ToDeviceValue(UnitRenderingType.Vertical, svgUse, skOwnerBounds);
            }

            var originalReferencedElementParent = svgReferencedElement.Parent;
            var referencedElementParent         = default(FieldInfo);

            try
            {
                referencedElementParent = svgReferencedElement.GetType().GetField("_parent", BindingFlags.NonPublic | BindingFlags.Instance);
                if (referencedElementParent != null)
                {
                    referencedElementParent.SetValue(svgReferencedElement, svgUse);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                Debug.WriteLine(ex.StackTrace);
            }

            svgReferencedElement.InvalidateChildPaths();

            if (svgReferencedElement is SvgSymbol svgSymbol)
            {
                ReferencedDrawable = new SymbolDrawable(svgSymbol, x, y, width, height, skOwnerBounds, root, this, ignoreAttributes);
                _disposable.Add(ReferencedDrawable);
            }
            else
            {
                var drawable = DrawableFactory.Create(svgReferencedElement, skOwnerBounds, root, this, ignoreAttributes);
                if (drawable != null)
                {
                    ReferencedDrawable = drawable;
                    _disposable.Add(ReferencedDrawable);
                }
                else
                {
                    IsDrawable = false;
                    return;
                }
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgUse);

            TransformedBounds = ReferencedDrawable.TransformedBounds;

            Transform = SvgTransformsExtensions.ToSKMatrix(svgUse.Transforms);
            if (!(svgReferencedElement is SvgSymbol))
            {
                var skMatrixTranslateXY = SKMatrix.MakeTranslation(x, y);
                SKMatrix.PreConcat(ref Transform, ref skMatrixTranslateXY);
            }

            Fill   = null;
            Stroke = null;

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

            try
            {
                if (referencedElementParent != null)
                {
                    referencedElementParent.SetValue(svgReferencedElement, originalReferencedElementParent);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                Debug.WriteLine(ex.StackTrace);
            }
        }
Exemple #17
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);
        }
Exemple #18
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;
            }
        }
Exemple #19
0
        public FragmentDrawable(SvgFragment svgFragment, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgFragment, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = HasFeatures(svgFragment, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            var svgFragmentParent = svgFragment.Parent;

            float x = svgFragmentParent == null ? 0f : svgFragment.X.ToDeviceValue(UnitRenderingType.Horizontal, svgFragment, skOwnerBounds);
            float y = svgFragmentParent == null ? 0f : svgFragment.Y.ToDeviceValue(UnitRenderingType.Vertical, svgFragment, skOwnerBounds);

            var skSize = SvgExtensions.GetDimensions(svgFragment);

            if (skOwnerBounds.IsEmpty)
            {
                skOwnerBounds = SKRect.Create(x, y, skSize.Width, skSize.Height);
            }

            CreateChildren(svgFragment, skOwnerBounds, this, this, ignoreAttributes);

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgFragment);

            TransformedBounds = skOwnerBounds;

            CreateTransformedBounds();

            Transform = SvgTransformsExtensions.ToSKMatrix(svgFragment.Transforms);
            var skMatrixViewBox = SvgTransformsExtensions.ToSKMatrix(svgFragment.ViewBox, svgFragment.AspectRatio, x, y, skSize.Width, skSize.Height);

            SKMatrix.PreConcat(ref Transform, ref skMatrixViewBox);

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

            default:
                if (skSize.IsEmpty)
                {
                    Overflow = SKRect.Create(
                        x,
                        y,
                        Math.Abs(TransformedBounds.Left) + TransformedBounds.Width,
                        Math.Abs(TransformedBounds.Top) + TransformedBounds.Height);
                }
                else
                {
                    Overflow = SKRect.Create(x, y, skSize.Width, skSize.Height);
                }
                break;
            }

            var clipPathUris = new HashSet <Uri>();
            var svgClipPath  = svgFragment.GetUriElementReference <SvgClipPath>("clip-path", clipPathUris);

            if (svgClipPath != null && svgClipPath.Children != null)
            {
                ClipPath = IgnoreAttributes.HasFlag(Attributes.ClipPath) ? null : SvgClippingExtensions.GetClipPath(svgClipPath, TransformedBounds, clipPathUris, _disposable);
            }
            else
            {
                ClipPath = null;
            }

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            SKMatrix.MapRect(ref Transform, out TransformedBounds, ref TransformedBounds);
        }
Exemple #20
0
        public SymbolDrawable(SvgSymbol svgSymbol, float x, float y, float width, float height, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes)
            : base(svgSymbol, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgSymbol, IgnoreAttributes) && HasFeatures(svgSymbol, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            if (svgSymbol.CustomAttributes.TryGetValue("width", out string?_widthString))
            {
                if (new SvgUnitConverter().ConvertFromString(_widthString) is SvgUnit _width)
                {
                    width = _width.ToDeviceValue(UnitRenderingType.Horizontal, svgSymbol, skOwnerBounds);
                }
            }

            if (svgSymbol.CustomAttributes.TryGetValue("height", out string?heightString))
            {
                if (new SvgUnitConverter().ConvertFromString(heightString) is SvgUnit _height)
                {
                    height = _height.ToDeviceValue(UnitRenderingType.Vertical, svgSymbol, skOwnerBounds);
                }
            }

            SvgOverflow svgOverflow = SvgOverflow.Hidden;

            if (svgSymbol.TryGetAttribute("overflow", out string overflowString))
            {
                if (new SvgOverflowConverter().ConvertFromString(overflowString) is SvgOverflow _svgOverflow)
                {
                    svgOverflow = _svgOverflow;
                }
            }

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

            default:
                Overflow = SKRect.Create(x, y, width, height);
                break;
            }

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

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgSymbol);

            TransformedBounds = SKRect.Empty;

            CreateTransformedBounds();

            Transform = SvgTransformsExtensions.ToSKMatrix(svgSymbol.Transforms);
            var skMatrixViewBox = SvgTransformsExtensions.ToSKMatrix(svgSymbol.ViewBox, svgSymbol.AspectRatio, x, y, width, height);

            SKMatrix.PreConcat(ref Transform, ref skMatrixViewBox);

            Fill   = null;
            Stroke = null;

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