diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Events.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Events.cs index a8a7109c735..cb0e4b1af39 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Events.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Events.cs @@ -106,7 +106,11 @@ private void ImageCropperThumb_KeyUp(object sender, KeyRoutedEventArgs e) _currentCroppedRect = croppedRect; } - UpdateImageLayout(true); + if (TryUpdateImageLayout(true)) + { + UpdateSelectionThumbs(true); + UpdateMaskArea(true); + } } private void ImageCropperThumb_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) @@ -119,7 +123,11 @@ private void ImageCropperThumb_ManipulationCompleted(object sender, Manipulation _currentCroppedRect = croppedRect; } - UpdateImageLayout(true); + if (TryUpdateImageLayout(true)) + { + UpdateSelectionThumbs(true); + UpdateMaskArea(true); + } } private void ImageCropperThumb_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) @@ -161,7 +169,12 @@ private void SourceImage_ManipulationDelta(object sender, ManipulationDeltaRoute var croppedRect = _inverseImageTransform.TransformBounds(selectedRect); croppedRect.Intersect(_restrictedCropRect); _currentCroppedRect = croppedRect; - UpdateImageLayout(); + + if (TryUpdateImageLayout()) + { + UpdateSelectionThumbs(); + UpdateMaskArea(); + } } private void ImageCanvas_SizeChanged(object sender, SizeChangedEventArgs e) @@ -171,8 +184,16 @@ private void ImageCanvas_SizeChanged(object sender, SizeChangedEventArgs e) return; } - UpdateImageLayout(); - UpdateMaskArea(); + if (TryUpdateImageLayout()) + { + UpdateSelectionThumbs(); + } + + if (TryUpdateAspectRatio()) + { + UpdateSelectionThumbs(); + UpdateMaskArea(); + } } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Logic.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Logic.cs index 47f87baed84..368d9f17a9b 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Logic.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Logic.cs @@ -28,8 +28,13 @@ private void InitImageLayout(bool animate = false) _restrictedCropRect = new Rect(0, 0, Source.PixelWidth, Source.PixelHeight); if (IsValidRect(_restrictedCropRect)) { - _currentCroppedRect = KeepAspectRatio ? GetUniformRect(_restrictedCropRect, UsedAspectRatio) : _restrictedCropRect; - UpdateImageLayout(animate); + _currentCroppedRect = KeepAspectRatio ? GetUniformRect(_restrictedCropRect, ActualAspectRatio) : _restrictedCropRect; + + if (TryUpdateImageLayout(animate)) + { + UpdateSelectionThumbs(animate); + UpdateMaskArea(animate); + } } } @@ -40,13 +45,16 @@ private void InitImageLayout(bool animate = false) /// Update image source transform. /// /// Whether animation is enabled. - private void UpdateImageLayout(bool animate = false) + private bool TryUpdateImageLayout(bool animate = false) { if (Source != null && IsValidRect(CanvasRect)) { var uniformSelectedRect = GetUniformRect(CanvasRect, _currentCroppedRect.Width / _currentCroppedRect.Height); - UpdateImageLayoutWithViewport(uniformSelectedRect, _currentCroppedRect, animate); + + return TryUpdateImageLayoutWithViewport(uniformSelectedRect, _currentCroppedRect, animate); } + + return false; } /// @@ -55,11 +63,11 @@ private void UpdateImageLayout(bool animate = false) /// Viewport /// The real image area of viewport. /// Whether animation is enabled. - private void UpdateImageLayoutWithViewport(Rect viewport, Rect viewportImageRect, bool animate = false) + private bool TryUpdateImageLayoutWithViewport(Rect viewport, Rect viewportImageRect, bool animate = false) { if (!IsValidRect(viewport) || !IsValidRect(viewportImageRect)) { - return; + return false; } var imageScale = viewport.Width / viewportImageRect.Width; @@ -69,12 +77,8 @@ private void UpdateImageLayoutWithViewport(Rect viewport, Rect viewportImageRect _inverseImageTransform.ScaleX = _inverseImageTransform.ScaleY = 1 / imageScale; _inverseImageTransform.TranslateX = -_imageTransform.TranslateX / imageScale; _inverseImageTransform.TranslateY = -_imageTransform.TranslateY / imageScale; - var selectedRect = _imageTransform.TransformBounds(_currentCroppedRect); _restrictedSelectRect = _imageTransform.TransformBounds(_restrictedCropRect); - var startPoint = GetSafePoint(_restrictedSelectRect, new Point(selectedRect.X, selectedRect.Y)); - var endPoint = GetSafePoint(_restrictedSelectRect, new Point( - selectedRect.X + selectedRect.Width, - selectedRect.Y + selectedRect.Height)); + if (animate) { AnimateUIElementOffset(new Point(_imageTransform.TranslateX, _imageTransform.TranslateY), _animationDuration, _sourceImage); @@ -87,7 +91,7 @@ private void UpdateImageLayoutWithViewport(Rect viewport, Rect viewportImageRect targetVisual.Scale = new Vector3((float)imageScale); } - UpdateSelectedRect(startPoint, endPoint, animate); + return true; } /// @@ -105,7 +109,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) double radian = 0d, diffPointRadian = 0d; if (KeepAspectRatio) { - radian = Math.Atan(UsedAspectRatio); + radian = Math.Atan(ActualAspectRatio); diffPointRadian = Math.Atan(diffPos.X / diffPos.Y); } @@ -117,8 +121,8 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) case ThumbPosition.Top: if (KeepAspectRatio) { - var originSizeChange = new Point(-diffPos.Y * UsedAspectRatio, -diffPos.Y); - var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio); + var originSizeChange = new Point(-diffPos.Y * ActualAspectRatio, -diffPos.Y); + var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, ActualAspectRatio); startPoint.X += -safeChange.X / 2; endPoint.X += safeChange.X / 2; startPoint.Y += -safeChange.Y; @@ -132,8 +136,8 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) case ThumbPosition.Bottom: if (KeepAspectRatio) { - var originSizeChange = new Point(diffPos.Y * UsedAspectRatio, diffPos.Y); - var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio); + var originSizeChange = new Point(diffPos.Y * ActualAspectRatio, diffPos.Y); + var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, ActualAspectRatio); startPoint.X += -safeChange.X / 2; endPoint.X += safeChange.X / 2; endPoint.Y += safeChange.Y; @@ -147,8 +151,8 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) case ThumbPosition.Left: if (KeepAspectRatio) { - var originSizeChange = new Point(-diffPos.X, -diffPos.X / UsedAspectRatio); - var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio); + var originSizeChange = new Point(-diffPos.X, -diffPos.X / ActualAspectRatio); + var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, ActualAspectRatio); startPoint.Y += -safeChange.Y / 2; endPoint.Y += safeChange.Y / 2; startPoint.X += -safeChange.X; @@ -162,8 +166,8 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) case ThumbPosition.Right: if (KeepAspectRatio) { - var originSizeChange = new Point(diffPos.X, diffPos.X / UsedAspectRatio); - var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio); + var originSizeChange = new Point(diffPos.X, diffPos.X / ActualAspectRatio); + var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, ActualAspectRatio); startPoint.Y += -safeChange.Y / 2; endPoint.Y += safeChange.Y / 2; endPoint.X += safeChange.X; @@ -179,7 +183,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) { var effectiveLength = diffPos.Y / Math.Cos(diffPointRadian) * Math.Cos(diffPointRadian - radian); var originSizeChange = new Point(-effectiveLength * Math.Sin(radian), -effectiveLength * Math.Cos(radian)); - var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio); + var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, ActualAspectRatio); diffPos.X = -safeChange.X; diffPos.Y = -safeChange.Y; } @@ -193,7 +197,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) diffPointRadian = -diffPointRadian; var effectiveLength = diffPos.Y / Math.Cos(diffPointRadian) * Math.Cos(diffPointRadian - radian); var originSizeChange = new Point(-effectiveLength * Math.Sin(radian), -effectiveLength * Math.Cos(radian)); - var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio); + var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, ActualAspectRatio); diffPos.X = safeChange.X; diffPos.Y = -safeChange.Y; } @@ -207,7 +211,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) diffPointRadian = -diffPointRadian; var effectiveLength = diffPos.Y / Math.Cos(diffPointRadian) * Math.Cos(diffPointRadian - radian); var originSizeChange = new Point(effectiveLength * Math.Sin(radian), effectiveLength * Math.Cos(radian)); - var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio); + var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, ActualAspectRatio); diffPos.X = -safeChange.X; diffPos.Y = safeChange.Y; } @@ -220,7 +224,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) { var effectiveLength = diffPos.Y / Math.Cos(diffPointRadian) * Math.Cos(diffPointRadian - radian); var originSizeChange = new Point(effectiveLength * Math.Sin(radian), effectiveLength * Math.Cos(radian)); - var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio); + var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, ActualAspectRatio); diffPos.X = safeChange.X; diffPos.Y = safeChange.Y; } @@ -273,28 +277,43 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos) _currentCroppedRect = croppedRect; var viewportRect = GetUniformRect(CanvasRect, selectedRect.Width / selectedRect.Height); var viewportImgRect = _inverseImageTransform.TransformBounds(selectedRect); - UpdateImageLayoutWithViewport(viewportRect, viewportImgRect); + + if (TryUpdateImageLayoutWithViewport(viewportRect, viewportImgRect)) + { + UpdateSelectionThumbs(); + UpdateMaskArea(); + } } else { - UpdateSelectedRect(startPoint, endPoint); + UpdateSelectionThumbs(startPoint, endPoint); + UpdateMaskArea(); } } + private void UpdateSelectionThumbs(bool animate = false) + { + var selectedRect = _imageTransform.TransformBounds(_currentCroppedRect); + var startPoint = GetSafePoint(_restrictedSelectRect, new Point(selectedRect.X, selectedRect.Y)); + var endPoint = GetSafePoint(_restrictedSelectRect, new Point(selectedRect.X + selectedRect.Width, selectedRect.Y + selectedRect.Height)); + + UpdateSelectionThumbs(startPoint, endPoint, animate); + } + /// - /// Update selection area. + /// Positions the thumbs for the selection rectangle. /// /// The point on the upper left corner. /// The point on the lower right corner. /// Whether animation is enabled. - private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate = false) + private void UpdateSelectionThumbs(Point startPoint, Point endPoint, bool animate = false) { _startX = startPoint.X; _startY = startPoint.Y; _endX = endPoint.X; _endY = endPoint.Y; - var centerX = ((_endX - _startX) / 2) + _startX; - var centerY = ((_endY - _startY) / 2) + _startY; + var center = SelectionAreaCenter; + Storyboard storyboard = null; if (animate) { @@ -305,12 +324,12 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate = { if (animate) { - storyboard.Children.Add(CreateDoubleAnimation(centerX, _animationDuration, _topThumb, nameof(ImageCropperThumb.X), true)); + storyboard.Children.Add(CreateDoubleAnimation(center.X, _animationDuration, _topThumb, nameof(ImageCropperThumb.X), true)); storyboard.Children.Add(CreateDoubleAnimation(_startY, _animationDuration, _topThumb, nameof(ImageCropperThumb.Y), true)); } else { - _topThumb.X = centerX; + _topThumb.X = center.X; _topThumb.Y = _startY; } } @@ -319,12 +338,12 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate = { if (animate) { - storyboard.Children.Add(CreateDoubleAnimation(centerX, _animationDuration, _bottomThumb, nameof(ImageCropperThumb.X), true)); + storyboard.Children.Add(CreateDoubleAnimation(center.X, _animationDuration, _bottomThumb, nameof(ImageCropperThumb.X), true)); storyboard.Children.Add(CreateDoubleAnimation(_endY, _animationDuration, _bottomThumb, nameof(ImageCropperThumb.Y), true)); } else { - _bottomThumb.X = centerX; + _bottomThumb.X = center.X; _bottomThumb.Y = _endY; } } @@ -334,12 +353,12 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate = if (animate) { storyboard.Children.Add(CreateDoubleAnimation(_startX, _animationDuration, _leftThumb, nameof(ImageCropperThumb.X), true)); - storyboard.Children.Add(CreateDoubleAnimation(centerY, _animationDuration, _leftThumb, nameof(ImageCropperThumb.Y), true)); + storyboard.Children.Add(CreateDoubleAnimation(center.Y, _animationDuration, _leftThumb, nameof(ImageCropperThumb.Y), true)); } else { _leftThumb.X = _startX; - _leftThumb.Y = centerY; + _leftThumb.Y = center.Y; } } @@ -348,12 +367,12 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate = if (animate) { storyboard.Children.Add(CreateDoubleAnimation(_endX, _animationDuration, _rightThumb, nameof(ImageCropperThumb.X), true)); - storyboard.Children.Add(CreateDoubleAnimation(centerY, _animationDuration, _rightThumb, nameof(ImageCropperThumb.Y), true)); + storyboard.Children.Add(CreateDoubleAnimation(center.Y, _animationDuration, _rightThumb, nameof(ImageCropperThumb.Y), true)); } else { _rightThumb.X = _endX; - _rightThumb.Y = centerY; + _rightThumb.Y = center.Y; } } @@ -417,8 +436,6 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate = { storyboard.Begin(); } - - UpdateMaskArea(animate); } /// @@ -507,58 +524,69 @@ private void UpdateMaskArea(bool animate = false) /// /// Update image aspect ratio. /// - private void UpdateAspectRatio(bool animate = false) + private bool TryUpdateAspectRatio() { - if (KeepAspectRatio && Source != null && IsValidRect(_restrictedSelectRect)) - { - var centerX = ((_endX - _startX) / 2) + _startX; - var centerY = ((_endY - _startY) / 2) + _startY; - var restrictedMinLength = MinCroppedPixelLength * _imageTransform.ScaleX; - var maxSelectedLength = Math.Max(_endX - _startX, _endY - _startY); - var viewRect = new Rect(centerX - (maxSelectedLength / 2), centerY - (maxSelectedLength / 2), maxSelectedLength, maxSelectedLength); - var uniformSelectedRect = GetUniformRect(viewRect, UsedAspectRatio); - if (uniformSelectedRect.Width > _restrictedSelectRect.Width || uniformSelectedRect.Height > _restrictedSelectRect.Height) - { - uniformSelectedRect = GetUniformRect(_restrictedSelectRect, UsedAspectRatio); - } + if (KeepAspectRatio is false || Source is null || IsValidRect(_restrictedSelectRect) is false) + { + return false; + } - if (uniformSelectedRect.Width < restrictedMinLength || uniformSelectedRect.Height < restrictedMinLength) - { - var scale = restrictedMinLength / Math.Min(uniformSelectedRect.Width, uniformSelectedRect.Height); - uniformSelectedRect.Width *= scale; - uniformSelectedRect.Height *= scale; - if (uniformSelectedRect.Width > _restrictedSelectRect.Width || uniformSelectedRect.Height > _restrictedSelectRect.Height) - { - AspectRatio = -1; - return; - } - } + var center = SelectionAreaCenter; + var restrictedMinLength = MinCroppedPixelLength * _imageTransform.ScaleX; + var maxSelectedLength = Math.Max(_endX - _startX, _endY - _startY); + var viewRect = new Rect(center.X - (maxSelectedLength / 2), center.Y - (maxSelectedLength / 2), maxSelectedLength, maxSelectedLength); - if (_restrictedSelectRect.X > uniformSelectedRect.X) - { - uniformSelectedRect.X += _restrictedSelectRect.X - uniformSelectedRect.X; - } + var uniformSelectedRect = GetUniformRect(viewRect, ActualAspectRatio); + if (uniformSelectedRect.Width > _restrictedSelectRect.Width || uniformSelectedRect.Height > _restrictedSelectRect.Height) + { + uniformSelectedRect = GetUniformRect(_restrictedSelectRect, ActualAspectRatio); + } - if (_restrictedSelectRect.Y > uniformSelectedRect.Y) - { - uniformSelectedRect.Y += _restrictedSelectRect.Y - uniformSelectedRect.Y; - } + // If selection area is smaller than allowed. + if (uniformSelectedRect.Width < restrictedMinLength || uniformSelectedRect.Height < restrictedMinLength) + { + // Scale selection area to fit. + var scale = restrictedMinLength / Math.Min(uniformSelectedRect.Width, uniformSelectedRect.Height); + uniformSelectedRect.Width *= scale; + uniformSelectedRect.Height *= scale; - if ((_restrictedSelectRect.X + _restrictedSelectRect.Width) < (uniformSelectedRect.X + uniformSelectedRect.Width)) + // If selection area is larger than allowed. + if (uniformSelectedRect.Width > _restrictedSelectRect.Width || uniformSelectedRect.Height > _restrictedSelectRect.Height) { - uniformSelectedRect.X += (_restrictedSelectRect.X + _restrictedSelectRect.Width) - (uniformSelectedRect.X + uniformSelectedRect.Width); + // Sentinal value. Equivelant to setting KeepAspectRatio to false. Causes AspectRatio to be recalculated. + AspectRatio = -1; + return false; } + } - if ((_restrictedSelectRect.Y + _restrictedSelectRect.Height) < (uniformSelectedRect.Y + uniformSelectedRect.Height)) - { - uniformSelectedRect.Y += (_restrictedSelectRect.Y + _restrictedSelectRect.Height) - (uniformSelectedRect.Y + uniformSelectedRect.Height); - } + // Fix positioning + if (_restrictedSelectRect.X > uniformSelectedRect.X) + { + uniformSelectedRect.X += _restrictedSelectRect.X - uniformSelectedRect.X; + } - var croppedRect = _inverseImageTransform.TransformBounds(uniformSelectedRect); - croppedRect.Intersect(_restrictedCropRect); - _currentCroppedRect = croppedRect; - UpdateImageLayout(animate); + if (_restrictedSelectRect.Y > uniformSelectedRect.Y) + { + uniformSelectedRect.Y += _restrictedSelectRect.Y - uniformSelectedRect.Y; + } + + // Fix size + if ((_restrictedSelectRect.X + _restrictedSelectRect.Width) < (uniformSelectedRect.X + uniformSelectedRect.Width)) + { + uniformSelectedRect.X += (_restrictedSelectRect.X + _restrictedSelectRect.Width) - (uniformSelectedRect.X + uniformSelectedRect.Width); + } + + if ((_restrictedSelectRect.Y + _restrictedSelectRect.Height) < (uniformSelectedRect.Y + uniformSelectedRect.Height)) + { + uniformSelectedRect.Y += (_restrictedSelectRect.Y + _restrictedSelectRect.Height) - (uniformSelectedRect.Y + uniformSelectedRect.Height); } + + // Apply transformation + var croppedRect = _inverseImageTransform.TransformBounds(uniformSelectedRect); + croppedRect.Intersect(_restrictedCropRect); + _currentCroppedRect = croppedRect; + + return true; } /// @@ -632,5 +660,10 @@ private void UpdateThumbsVisibility() _lowerRigthThumb.Visibility = cornerThumbsVisibility; } } + + /// + /// Gets a value that indicates the center of the visible selection rectangle. + /// + private Point SelectionAreaCenter => new Point(((_endX - _startX) / 2) + _startX, ((_endY - _startY) / 2) + _startY); } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Properties.cs index f0640486f23..97eaf0567b6 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Properties.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.Properties.cs @@ -51,7 +51,15 @@ private static void OnAspectRatioChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var target = (ImageCropper)d; - target.UpdateAspectRatio(true); + + if (target.TryUpdateAspectRatio()) + { + if (target.TryUpdateImageLayout(true)) + { + target.UpdateSelectionThumbs(true); + target.UpdateMaskArea(true); + } + } } private static void OnCropShapeChanged( @@ -60,7 +68,15 @@ private static void OnCropShapeChanged( var target = (ImageCropper)d; target.UpdateCropShape(); target.UpdateThumbsVisibility(); - target.UpdateAspectRatio(); + + if (target.TryUpdateAspectRatio()) + { + if (target.TryUpdateImageLayout()) + { + target.UpdateSelectionThumbs(); + } + } + target.UpdateMaskArea(); } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.cs index 60ed065fbdd..260ef1a0172 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Media/ImageCropper/ImageCropper.cs @@ -49,10 +49,13 @@ public partial class ImageCropper : Control private ImageCropperThumb _upperRightThumb; private ImageCropperThumb _lowerLeftThumb; private ImageCropperThumb _lowerRigthThumb; + + // Selection area private double _startX; private double _startY; private double _endX; private double _endY; + private Rect _currentCroppedRect = Rect.Empty; private Rect _restrictedCropRect = Rect.Empty; private Rect _restrictedSelectRect = Rect.Empty; @@ -70,23 +73,36 @@ public ImageCropper() private Rect CanvasRect => new Rect(0, 0, _imageCanvas?.ActualWidth ?? 0, _imageCanvas?.ActualHeight ?? 0); - private bool KeepAspectRatio => UsedAspectRatio > 0; + /// + /// Gets a value indicating whether the user-provided is valid and should be kept during manipulation of the image cropper. + /// + private bool KeepAspectRatio => ActualAspectRatio > 0; - private double UsedAspectRatio + /// + /// Gets the internally used aspect ratio, rather than the user-provided value. Adjusted to handle crop shape and invalid values. + /// + private double ActualAspectRatio { get { - var aspectRatio = AspectRatio; - switch (CropShape) + var aspectRatio = CropShape switch { - case CropShape.Rectangular: - break; - case CropShape.Circular: - aspectRatio = 1; - break; - } + CropShape.Rectangular => AspectRatio, + CropShape.Circular => 1, + _ => AspectRatio, + }; - return aspectRatio != null && aspectRatio > 0 ? aspectRatio.Value : -1; + if (aspectRatio is not null && aspectRatio > 0) + { + // When not null or 0. + return aspectRatio.Value; + } + else + { + // Fallback to sentinal value. + // Used to indicate aspect ratio should be discarded and reset during manipulation of the image cropper. + return -1; + } } } @@ -97,7 +113,7 @@ private Size MinCropSize { get { - var aspectRatio = KeepAspectRatio ? UsedAspectRatio : 1; + var aspectRatio = KeepAspectRatio ? ActualAspectRatio : 1; var size = new Size(MinCroppedPixelLength, MinCroppedPixelLength); if (aspectRatio >= 1) { @@ -123,7 +139,7 @@ private Size MinSelectSize var minLength = Math.Min(realMinSelectSize.Width, realMinSelectSize.Height); if (minLength < MinSelectedLength) { - var aspectRatio = KeepAspectRatio ? UsedAspectRatio : 1; + var aspectRatio = KeepAspectRatio ? ActualAspectRatio : 1; var minSelectSize = new Size(MinSelectedLength, MinSelectedLength); if (aspectRatio >= 1) { @@ -433,13 +449,18 @@ public bool TrySetCroppedRegion(Rect rect) // If an aspect ratio is set, reject regions that don't respect it // If cropping a circle, reject regions where the aspect ratio is not 1 - if (KeepAspectRatio && UsedAspectRatio != rect.Width / rect.Height) + if (KeepAspectRatio && ActualAspectRatio != rect.Width / rect.Height) { return false; } _currentCroppedRect = rect; - UpdateImageLayout(true); + if (TryUpdateImageLayout(true)) + { + UpdateSelectionThumbs(true); + UpdateMaskArea(true); + } + return true; } }