@@ -28,21 +28,23 @@ private void InitImageLayout(bool animate = false)
2828 _restrictedCropRect = new Rect ( 0 , 0 , Source . PixelWidth , Source . PixelHeight ) ;
2929 if ( IsValidRect ( _restrictedCropRect ) )
3030 {
31- _currentCroppedRect = KeepAspectRatio ? GetUniformRect ( _restrictedCropRect , UsedAspectRatio ) : _restrictedCropRect ;
31+ _currentCroppedRect = KeepAspectRatio ? GetUniformRect ( _restrictedCropRect , ActualAspectRatio ) : _restrictedCropRect ;
3232 UpdateImageLayout ( animate ) ;
3333 }
3434 }
3535
3636 UpdateThumbsVisibility ( ) ;
3737 }
3838
39+ private bool ShouldUpdateImageLayout => Source != null && IsValidRect ( CanvasRect ) ;
40+
3941 /// <summary>
4042 /// Update image source transform.
4143 /// </summary>
4244 /// <param name="animate">Whether animation is enabled.</param>
4345 private void UpdateImageLayout ( bool animate = false )
4446 {
45- if ( Source != null && IsValidRect ( CanvasRect ) )
47+ if ( ShouldUpdateImageLayout )
4648 {
4749 var uniformSelectedRect = GetUniformRect ( CanvasRect , _currentCroppedRect . Width / _currentCroppedRect . Height ) ;
4850 UpdateImageLayoutWithViewport ( uniformSelectedRect , _currentCroppedRect , animate ) ;
@@ -105,7 +107,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
105107 double radian = 0d , diffPointRadian = 0d ;
106108 if ( KeepAspectRatio )
107109 {
108- radian = Math . Atan ( UsedAspectRatio ) ;
110+ radian = Math . Atan ( ActualAspectRatio ) ;
109111 diffPointRadian = Math . Atan ( diffPos . X / diffPos . Y ) ;
110112 }
111113
@@ -117,8 +119,8 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
117119 case ThumbPosition . Top :
118120 if ( KeepAspectRatio )
119121 {
120- var originSizeChange = new Point ( - diffPos . Y * UsedAspectRatio , - diffPos . Y ) ;
121- var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , UsedAspectRatio ) ;
122+ var originSizeChange = new Point ( - diffPos . Y * ActualAspectRatio , - diffPos . Y ) ;
123+ var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , ActualAspectRatio ) ;
122124 startPoint . X += - safeChange . X / 2 ;
123125 endPoint . X += safeChange . X / 2 ;
124126 startPoint . Y += - safeChange . Y ;
@@ -132,8 +134,8 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
132134 case ThumbPosition . Bottom :
133135 if ( KeepAspectRatio )
134136 {
135- var originSizeChange = new Point ( diffPos . Y * UsedAspectRatio , diffPos . Y ) ;
136- var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , UsedAspectRatio ) ;
137+ var originSizeChange = new Point ( diffPos . Y * ActualAspectRatio , diffPos . Y ) ;
138+ var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , ActualAspectRatio ) ;
137139 startPoint . X += - safeChange . X / 2 ;
138140 endPoint . X += safeChange . X / 2 ;
139141 endPoint . Y += safeChange . Y ;
@@ -147,8 +149,8 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
147149 case ThumbPosition . Left :
148150 if ( KeepAspectRatio )
149151 {
150- var originSizeChange = new Point ( - diffPos . X , - diffPos . X / UsedAspectRatio ) ;
151- var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , UsedAspectRatio ) ;
152+ var originSizeChange = new Point ( - diffPos . X , - diffPos . X / ActualAspectRatio ) ;
153+ var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , ActualAspectRatio ) ;
152154 startPoint . Y += - safeChange . Y / 2 ;
153155 endPoint . Y += safeChange . Y / 2 ;
154156 startPoint . X += - safeChange . X ;
@@ -162,8 +164,8 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
162164 case ThumbPosition . Right :
163165 if ( KeepAspectRatio )
164166 {
165- var originSizeChange = new Point ( diffPos . X , diffPos . X / UsedAspectRatio ) ;
166- var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , UsedAspectRatio ) ;
167+ var originSizeChange = new Point ( diffPos . X , diffPos . X / ActualAspectRatio ) ;
168+ var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , ActualAspectRatio ) ;
167169 startPoint . Y += - safeChange . Y / 2 ;
168170 endPoint . Y += safeChange . Y / 2 ;
169171 endPoint . X += safeChange . X ;
@@ -179,7 +181,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
179181 {
180182 var effectiveLength = diffPos . Y / Math . Cos ( diffPointRadian ) * Math . Cos ( diffPointRadian - radian ) ;
181183 var originSizeChange = new Point ( - effectiveLength * Math . Sin ( radian ) , - effectiveLength * Math . Cos ( radian ) ) ;
182- var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , UsedAspectRatio ) ;
184+ var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , ActualAspectRatio ) ;
183185 diffPos . X = - safeChange . X ;
184186 diffPos . Y = - safeChange . Y ;
185187 }
@@ -193,7 +195,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
193195 diffPointRadian = - diffPointRadian ;
194196 var effectiveLength = diffPos . Y / Math . Cos ( diffPointRadian ) * Math . Cos ( diffPointRadian - radian ) ;
195197 var originSizeChange = new Point ( - effectiveLength * Math . Sin ( radian ) , - effectiveLength * Math . Cos ( radian ) ) ;
196- var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , UsedAspectRatio ) ;
198+ var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , ActualAspectRatio ) ;
197199 diffPos . X = safeChange . X ;
198200 diffPos . Y = - safeChange . Y ;
199201 }
@@ -207,7 +209,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
207209 diffPointRadian = - diffPointRadian ;
208210 var effectiveLength = diffPos . Y / Math . Cos ( diffPointRadian ) * Math . Cos ( diffPointRadian - radian ) ;
209211 var originSizeChange = new Point ( effectiveLength * Math . Sin ( radian ) , effectiveLength * Math . Cos ( radian ) ) ;
210- var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , UsedAspectRatio ) ;
212+ var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , ActualAspectRatio ) ;
211213 diffPos . X = - safeChange . X ;
212214 diffPos . Y = safeChange . Y ;
213215 }
@@ -220,7 +222,7 @@ private void UpdateCroppedRect(ThumbPosition position, Point diffPos)
220222 {
221223 var effectiveLength = diffPos . Y / Math . Cos ( diffPointRadian ) * Math . Cos ( diffPointRadian - radian ) ;
222224 var originSizeChange = new Point ( effectiveLength * Math . Sin ( radian ) , effectiveLength * Math . Cos ( radian ) ) ;
223- var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , UsedAspectRatio ) ;
225+ var safeChange = GetSafeSizeChangeWhenKeepAspectRatio ( _restrictedSelectRect , position , currentSelectedRect , originSizeChange , ActualAspectRatio ) ;
224226 diffPos . X = safeChange . X ;
225227 diffPos . Y = safeChange . Y ;
226228 }
@@ -293,8 +295,8 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate =
293295 _startY = startPoint . Y ;
294296 _endX = endPoint . X ;
295297 _endY = endPoint . Y ;
296- var centerX = ( ( _endX - _startX ) / 2 ) + _startX ;
297- var centerY = ( ( _endY - _startY ) / 2 ) + _startY ;
298+ var center = SelectionAreaCenter ;
299+
298300 Storyboard storyboard = null ;
299301 if ( animate )
300302 {
@@ -305,12 +307,12 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate =
305307 {
306308 if ( animate )
307309 {
308- storyboard . Children . Add ( CreateDoubleAnimation ( centerX , _animationDuration , _topThumb , nameof ( ImageCropperThumb . X ) , true ) ) ;
310+ storyboard . Children . Add ( CreateDoubleAnimation ( center . X , _animationDuration , _topThumb , nameof ( ImageCropperThumb . X ) , true ) ) ;
309311 storyboard . Children . Add ( CreateDoubleAnimation ( _startY , _animationDuration , _topThumb , nameof ( ImageCropperThumb . Y ) , true ) ) ;
310312 }
311313 else
312314 {
313- _topThumb . X = centerX ;
315+ _topThumb . X = center . X ;
314316 _topThumb . Y = _startY ;
315317 }
316318 }
@@ -319,12 +321,12 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate =
319321 {
320322 if ( animate )
321323 {
322- storyboard . Children . Add ( CreateDoubleAnimation ( centerX , _animationDuration , _bottomThumb , nameof ( ImageCropperThumb . X ) , true ) ) ;
324+ storyboard . Children . Add ( CreateDoubleAnimation ( center . X , _animationDuration , _bottomThumb , nameof ( ImageCropperThumb . X ) , true ) ) ;
323325 storyboard . Children . Add ( CreateDoubleAnimation ( _endY , _animationDuration , _bottomThumb , nameof ( ImageCropperThumb . Y ) , true ) ) ;
324326 }
325327 else
326328 {
327- _bottomThumb . X = centerX ;
329+ _bottomThumb . X = center . X ;
328330 _bottomThumb . Y = _endY ;
329331 }
330332 }
@@ -334,12 +336,12 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate =
334336 if ( animate )
335337 {
336338 storyboard . Children . Add ( CreateDoubleAnimation ( _startX , _animationDuration , _leftThumb , nameof ( ImageCropperThumb . X ) , true ) ) ;
337- storyboard . Children . Add ( CreateDoubleAnimation ( centerY , _animationDuration , _leftThumb , nameof ( ImageCropperThumb . Y ) , true ) ) ;
339+ storyboard . Children . Add ( CreateDoubleAnimation ( center . Y , _animationDuration , _leftThumb , nameof ( ImageCropperThumb . Y ) , true ) ) ;
338340 }
339341 else
340342 {
341343 _leftThumb . X = _startX ;
342- _leftThumb . Y = centerY ;
344+ _leftThumb . Y = center . Y ;
343345 }
344346 }
345347
@@ -348,12 +350,12 @@ private void UpdateSelectedRect(Point startPoint, Point endPoint, bool animate =
348350 if ( animate )
349351 {
350352 storyboard . Children . Add ( CreateDoubleAnimation ( _endX , _animationDuration , _rightThumb , nameof ( ImageCropperThumb . X ) , true ) ) ;
351- storyboard . Children . Add ( CreateDoubleAnimation ( centerY , _animationDuration , _rightThumb , nameof ( ImageCropperThumb . Y ) , true ) ) ;
353+ storyboard . Children . Add ( CreateDoubleAnimation ( center . Y , _animationDuration , _rightThumb , nameof ( ImageCropperThumb . Y ) , true ) ) ;
352354 }
353355 else
354356 {
355357 _rightThumb . X = _endX ;
356- _rightThumb . Y = centerY ;
358+ _rightThumb . Y = center . Y ;
357359 }
358360 }
359361
@@ -504,61 +506,74 @@ private void UpdateMaskArea(bool animate = false)
504506 } ;
505507 }
506508
509+ private bool ShouldUpdateAspectRatio => KeepAspectRatio && Source != null && IsValidRect ( _restrictedSelectRect ) ;
510+
507511 /// <summary>
508512 /// Update image aspect ratio.
509513 /// </summary>
510514 private void UpdateAspectRatio ( bool animate = false )
511515 {
512- if ( KeepAspectRatio && Source != null && IsValidRect ( _restrictedSelectRect ) )
513- {
514- var centerX = ( ( _endX - _startX ) / 2 ) + _startX ;
515- var centerY = ( ( _endY - _startY ) / 2 ) + _startY ;
516- var restrictedMinLength = MinCroppedPixelLength * _imageTransform . ScaleX ;
517- var maxSelectedLength = Math . Max ( _endX - _startX , _endY - _startY ) ;
518- var viewRect = new Rect ( centerX - ( maxSelectedLength / 2 ) , centerY - ( maxSelectedLength / 2 ) , maxSelectedLength , maxSelectedLength ) ;
519- var uniformSelectedRect = GetUniformRect ( viewRect , UsedAspectRatio ) ;
520- if ( uniformSelectedRect . Width > _restrictedSelectRect . Width || uniformSelectedRect . Height > _restrictedSelectRect . Height )
521- {
522- uniformSelectedRect = GetUniformRect ( _restrictedSelectRect , UsedAspectRatio ) ;
523- }
516+ if ( ! ShouldUpdateAspectRatio )
517+ {
518+ return ;
519+ }
524520
525- if ( uniformSelectedRect . Width < restrictedMinLength || uniformSelectedRect . Height < restrictedMinLength )
526- {
527- var scale = restrictedMinLength / Math . Min ( uniformSelectedRect . Width , uniformSelectedRect . Height ) ;
528- uniformSelectedRect . Width *= scale ;
529- uniformSelectedRect . Height *= scale ;
530- if ( uniformSelectedRect . Width > _restrictedSelectRect . Width || uniformSelectedRect . Height > _restrictedSelectRect . Height )
531- {
532- AspectRatio = - 1 ;
533- return ;
534- }
535- }
521+ var center = SelectionAreaCenter ;
522+ var restrictedMinLength = MinCroppedPixelLength * _imageTransform . ScaleX ;
523+ var maxSelectedLength = Math . Max ( _endX - _startX , _endY - _startY ) ;
524+ var viewRect = new Rect ( center . X - ( maxSelectedLength / 2 ) , center . Y - ( maxSelectedLength / 2 ) , maxSelectedLength , maxSelectedLength ) ;
536525
537- if ( _restrictedSelectRect . X > uniformSelectedRect . X )
538- {
539- uniformSelectedRect . X += _restrictedSelectRect . X - uniformSelectedRect . X ;
540- }
526+ var uniformSelectedRect = GetUniformRect ( viewRect , ActualAspectRatio ) ;
527+ if ( uniformSelectedRect . Width > _restrictedSelectRect . Width || uniformSelectedRect . Height > _restrictedSelectRect . Height )
528+ {
529+ uniformSelectedRect = GetUniformRect ( _restrictedSelectRect , ActualAspectRatio ) ;
530+ }
541531
542- if ( _restrictedSelectRect . Y > uniformSelectedRect . Y )
543- {
544- uniformSelectedRect . Y += _restrictedSelectRect . Y - uniformSelectedRect . Y ;
545- }
532+ // If selection area is smaller than allowed.
533+ if ( uniformSelectedRect . Width < restrictedMinLength || uniformSelectedRect . Height < restrictedMinLength )
534+ {
535+ // Scale selection area to fit.
536+ var scale = restrictedMinLength / Math . Min ( uniformSelectedRect . Width , uniformSelectedRect . Height ) ;
537+ uniformSelectedRect . Width *= scale ;
538+ uniformSelectedRect . Height *= scale ;
546539
547- if ( ( _restrictedSelectRect . X + _restrictedSelectRect . Width ) < ( uniformSelectedRect . X + uniformSelectedRect . Width ) )
540+ // If selection area is larger than allowed.
541+ if ( uniformSelectedRect . Width > _restrictedSelectRect . Width || uniformSelectedRect . Height > _restrictedSelectRect . Height )
548542 {
549- uniformSelectedRect . X += ( _restrictedSelectRect . X + _restrictedSelectRect . Width ) - ( uniformSelectedRect . X + uniformSelectedRect . Width ) ;
543+ // Sentinal value. Equivelant to setting KeepAspectRatio to false. Causes AspectRatio to be recalculated.
544+ AspectRatio = - 1 ;
545+ return ;
550546 }
547+ }
551548
552- if ( ( _restrictedSelectRect . Y + _restrictedSelectRect . Height ) < ( uniformSelectedRect . Y + uniformSelectedRect . Height ) )
553- {
554- uniformSelectedRect . Y += ( _restrictedSelectRect . Y + _restrictedSelectRect . Height ) - ( uniformSelectedRect . Y + uniformSelectedRect . Height ) ;
555- }
549+ // Fix positioning
550+ if ( _restrictedSelectRect . X > uniformSelectedRect . X )
551+ {
552+ uniformSelectedRect . X += _restrictedSelectRect . X - uniformSelectedRect . X ;
553+ }
556554
557- var croppedRect = _inverseImageTransform . TransformBounds ( uniformSelectedRect ) ;
558- croppedRect . Intersect ( _restrictedCropRect ) ;
559- _currentCroppedRect = croppedRect ;
560- UpdateImageLayout ( animate ) ;
555+ if ( _restrictedSelectRect . Y > uniformSelectedRect . Y )
556+ {
557+ uniformSelectedRect . Y += _restrictedSelectRect . Y - uniformSelectedRect . Y ;
561558 }
559+
560+ // Fix size
561+ if ( ( _restrictedSelectRect . X + _restrictedSelectRect . Width ) < ( uniformSelectedRect . X + uniformSelectedRect . Width ) )
562+ {
563+ uniformSelectedRect . X += ( _restrictedSelectRect . X + _restrictedSelectRect . Width ) - ( uniformSelectedRect . X + uniformSelectedRect . Width ) ;
564+ }
565+
566+ if ( ( _restrictedSelectRect . Y + _restrictedSelectRect . Height ) < ( uniformSelectedRect . Y + uniformSelectedRect . Height ) )
567+ {
568+ uniformSelectedRect . Y += ( _restrictedSelectRect . Y + _restrictedSelectRect . Height ) - ( uniformSelectedRect . Y + uniformSelectedRect . Height ) ;
569+ }
570+
571+ // Apply transformation
572+ var croppedRect = _inverseImageTransform . TransformBounds ( uniformSelectedRect ) ;
573+ croppedRect . Intersect ( _restrictedCropRect ) ;
574+ _currentCroppedRect = croppedRect ;
575+
576+ UpdateImageLayout ( animate ) ;
562577 }
563578
564579 /// <summary>
@@ -632,5 +647,10 @@ private void UpdateThumbsVisibility()
632647 _lowerRigthThumb . Visibility = cornerThumbsVisibility ;
633648 }
634649 }
650+
651+ /// <summary>
652+ /// Gets a value that indicates the center of the visible selection rectangle.
653+ /// </summary>
654+ private Point SelectionAreaCenter => new Point ( ( ( _endX - _startX ) / 2 ) + _startX , ( ( _endY - _startY ) / 2 ) + _startY ) ;
635655 }
636656}
0 commit comments