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); }
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; } }
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; }
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); }
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); }
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); }
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); }
} // 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); }
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); }
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); }
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); } }
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); }
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; } }
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); }
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); }