@@ -361,4 +361,119 @@ private void RenderSingleSide(DrawingContext context, Bitmap img, double w, doub
361361 private static readonly RenderOptions RO_SRC = new RenderOptions ( ) { BitmapBlendingMode = BitmapBlendingMode . Source , BitmapInterpolationMode = BitmapInterpolationMode . HighQuality } ;
362362 private static readonly RenderOptions RO_DST = new RenderOptions ( ) { BitmapBlendingMode = BitmapBlendingMode . Plus , BitmapInterpolationMode = BitmapInterpolationMode . HighQuality } ;
363363 }
364+
365+ public class ImageDifferenceControl : ImageContainer
366+ {
367+ public static readonly StyledProperty < double > AlphaProperty =
368+ AvaloniaProperty . Register < ImageDifferenceControl , double > ( nameof ( Alpha ) , 1.0 ) ;
369+
370+ public double Alpha
371+ {
372+ get => GetValue ( AlphaProperty ) ;
373+ set => SetValue ( AlphaProperty , value ) ;
374+ }
375+
376+ public static readonly StyledProperty < Bitmap > OldImageProperty =
377+ AvaloniaProperty . Register < ImageDifferenceControl , Bitmap > ( nameof ( OldImage ) ) ;
378+
379+ public Bitmap OldImage
380+ {
381+ get => GetValue ( OldImageProperty ) ;
382+ set => SetValue ( OldImageProperty , value ) ;
383+ }
384+
385+ public static readonly StyledProperty < Bitmap > NewImageProperty =
386+ AvaloniaProperty . Register < ImageDifferenceControl , Bitmap > ( nameof ( NewImage ) ) ;
387+
388+ public Bitmap NewImage
389+ {
390+ get => GetValue ( NewImageProperty ) ;
391+ set => SetValue ( NewImageProperty , value ) ;
392+ }
393+
394+ static ImageDifferenceControl ( )
395+ {
396+ AffectsMeasure < ImageDifferenceControl > ( OldImageProperty , NewImageProperty ) ;
397+ AffectsRender < ImageDifferenceControl > ( AlphaProperty ) ;
398+ }
399+
400+ public override void Render ( DrawingContext context )
401+ {
402+ base . Render ( context ) ;
403+
404+ var alpha = Alpha ;
405+ var left = OldImage ;
406+ var right = NewImage ;
407+ var drawLeft = left != null && alpha < 1.0 ;
408+ var drawRight = right != null && alpha > 0.0 ;
409+
410+ if ( drawLeft && drawRight )
411+ {
412+ using ( var rt = new RenderTargetBitmap ( new PixelSize ( ( int ) Bounds . Width , ( int ) Bounds . Height ) , right . Dpi ) )
413+ {
414+ using ( var dc = rt . CreateDrawingContext ( ) )
415+ {
416+ using ( dc . PushRenderOptions ( RO_SRC ) )
417+ RenderSingleSide ( dc , left , rt . Size . Width , rt . Size . Height , Math . Min ( 1.0 , 2.0 - 2.0 * alpha ) ) ;
418+
419+ using ( dc . PushRenderOptions ( RO_DST ) )
420+ RenderSingleSide ( dc , right , rt . Size . Width , rt . Size . Height , Math . Min ( 1.0 , 2.0 * alpha ) ) ;
421+ }
422+
423+ context . DrawImage ( rt , new Rect ( 0 , 0 , Bounds . Width , Bounds . Height ) ) ;
424+ }
425+ }
426+ else if ( drawLeft )
427+ {
428+ RenderSingleSide ( context , left , Bounds . Width , Bounds . Height , 1 - alpha ) ;
429+ }
430+ else if ( drawRight )
431+ {
432+ RenderSingleSide ( context , right , Bounds . Width , Bounds . Height , alpha ) ;
433+ }
434+ }
435+
436+ protected override Size MeasureOverride ( Size availableSize )
437+ {
438+ var left = OldImage ;
439+ var right = NewImage ;
440+
441+ if ( left == null )
442+ return right == null ? availableSize : GetDesiredSize ( right . Size , availableSize ) ;
443+
444+ if ( right == null )
445+ return GetDesiredSize ( left . Size , availableSize ) ;
446+
447+ var ls = GetDesiredSize ( left . Size , availableSize ) ;
448+ var rs = GetDesiredSize ( right . Size , availableSize ) ;
449+ return ls . Width > rs . Width ? ls : rs ;
450+ }
451+
452+ private Size GetDesiredSize ( Size img , Size available )
453+ {
454+ var sw = available . Width / img . Width ;
455+ var sh = available . Height / img . Height ;
456+ var scale = Math . Min ( 1 , Math . Min ( sw , sh ) ) ;
457+ return new Size ( scale * img . Width , scale * img . Height ) ;
458+ }
459+
460+ private void RenderSingleSide ( DrawingContext context , Bitmap img , double w , double h , double alpha )
461+ {
462+ var imgW = img . Size . Width ;
463+ var imgH = img . Size . Height ;
464+ var scale = Math . Min ( 1 , Math . Min ( w / imgW , h / imgH ) ) ;
465+
466+ var scaledW = img . Size . Width * scale ;
467+ var scaledH = img . Size . Height * scale ;
468+
469+ var src = new Rect ( 0 , 0 , imgW , imgH ) ;
470+ var dst = new Rect ( ( w - scaledW ) * 0.5 , ( h - scaledH ) * 0.5 , scaledW , scaledH ) ;
471+
472+ using ( context . PushOpacity ( alpha ) )
473+ context . DrawImage ( img , src , dst ) ;
474+ }
475+
476+ private static readonly RenderOptions RO_SRC = new RenderOptions ( ) { BitmapBlendingMode = BitmapBlendingMode . Source , BitmapInterpolationMode = BitmapInterpolationMode . HighQuality } ;
477+ private static readonly RenderOptions RO_DST = new RenderOptions ( ) { BitmapBlendingMode = BitmapBlendingMode . Difference , BitmapInterpolationMode = BitmapInterpolationMode . HighQuality } ;
478+ }
364479}
0 commit comments