enhance: new image alpha blend implementation

This commit is contained in:
leo 2024-06-22 11:25:19 +08:00
parent 7a5279f717
commit 209f51da9e
No known key found for this signature in database
2 changed files with 59 additions and 39 deletions

View file

@ -21,8 +21,8 @@
<TextBlock Text="SIDE-BY-SIDE" FontSize="11"/> <TextBlock Text="SIDE-BY-SIDE" FontSize="11"/>
</TabItem.Header> </TabItem.Header>
<UniformGrid Rows="1" Margin="8,16" HorizontalAlignment="Center" VerticalAlignment="Center"> <UniformGrid Rows="1" Margin="0,16" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid RowDefinitions="Auto,*" IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNotNull}}"> <Grid RowDefinitions="Auto,*" Margin="16,0" IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center">
<Border Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center"> <Border Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center">
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/> <TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/>
@ -36,15 +36,16 @@
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)"> <Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
<Border Background="{DynamicResource Brush.Popup}" HorizontalAlignment="Center" Padding="8"> <Border Background="{DynamicResource Brush.Popup}" HorizontalAlignment="Center" Padding="8">
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"> <Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}">
<v:ImageContainer> <Grid>
<v:ImageContainer/>
<Image Source="{Binding Old}" Stretch="Uniform" VerticalAlignment="Center"/> <Image Source="{Binding Old}" Stretch="Uniform" VerticalAlignment="Center"/>
</v:ImageContainer> </Grid>
</Border> </Border>
</Border> </Border>
</Border> </Border>
</Grid> </Grid>
<Grid RowDefinitions="Auto,*" Margin="32,0,0,0" IsVisible="{Binding New, Converter={x:Static ObjectConverters.IsNotNull}}"> <Grid RowDefinitions="Auto,*" Margin="16,0" IsVisible="{Binding New, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center">
<Border Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center"> <Border Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center">
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/> <TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/>
@ -58,9 +59,10 @@
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)"> <Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
<Border Background="{DynamicResource Brush.Popup}" HorizontalAlignment="Center" Padding="8"> <Border Background="{DynamicResource Brush.Popup}" HorizontalAlignment="Center" Padding="8">
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"> <Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}">
<v:ImageContainer> <Grid>
<v:ImageContainer/>
<Image Source="{Binding New}" Stretch="Uniform" VerticalAlignment="Center"/> <Image Source="{Binding New}" Stretch="Uniform" VerticalAlignment="Center"/>
</v:ImageContainer> </Grid>
</Border> </Border>
</Border> </Border>
</Border> </Border>
@ -95,11 +97,9 @@
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)"> <Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
<Border HorizontalAlignment="Center" Background="{DynamicResource Brush.Window}"> <Border HorizontalAlignment="Center" Background="{DynamicResource Brush.Window}">
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8"> <Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
<v:ImageContainer> <v:ImagesSwipeControl OldImage="{Binding Old}"
<v:ImagesSwipeControl OldImage="{Binding Old}" NewImage="{Binding New}"
NewImage="{Binding New}" RenderOptions.BitmapInterpolationMode="HighQuality"/>
RenderOptions.BitmapInterpolationMode="HighQuality"/>
</v:ImageContainer>
</Border> </Border>
</Border> </Border>
</Border> </Border>
@ -133,12 +133,9 @@
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)"> <Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
<Border HorizontalAlignment="Center" Background="{DynamicResource Brush.Window}"> <Border HorizontalAlignment="Center" Background="{DynamicResource Brush.Window}">
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8"> <Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
<v:ImageContainer> <v:ImageBlendControl Alpha="{Binding #ImageBlendSlider.Value}"
<v:ImageBlendControl Alpha="{Binding #ImageBlendSlider.Value}" OldImage="{Binding Old}"
OldImage="{Binding Old}" NewImage="{Binding New}"/>
NewImage="{Binding New}"
RenderOptions.BitmapInterpolationMode="HighQuality"/>
</v:ImageContainer>
</Border> </Border>
</Border> </Border>
</Border> </Border>

View file

@ -9,10 +9,8 @@ using Avalonia.Styling;
namespace SourceGit.Views namespace SourceGit.Views
{ {
public class ImageContainer : ContentControl public class ImageContainer : Control
{ {
protected override Type StyleKeyOverride => typeof(ContentControl);
public override void Render(DrawingContext context) public override void Render(DrawingContext context)
{ {
if (_bgBrush == null) if (_bgBrush == null)
@ -54,7 +52,7 @@ namespace SourceGit.Views
private DrawingBrush _bgBrush = null; private DrawingBrush _bgBrush = null;
} }
public class ImagesSwipeControl : Control public class ImagesSwipeControl : ImageContainer
{ {
public static readonly StyledProperty<double> AlphaProperty = public static readonly StyledProperty<double> AlphaProperty =
AvaloniaProperty.Register<ImagesSwipeControl, double>(nameof(Alpha), 0.5); AvaloniaProperty.Register<ImagesSwipeControl, double>(nameof(Alpha), 0.5);
@ -91,6 +89,8 @@ namespace SourceGit.Views
public override void Render(DrawingContext context) public override void Render(DrawingContext context)
{ {
base.Render(context);
var alpha = Alpha; var alpha = Alpha;
var w = Bounds.Width; var w = Bounds.Width;
var h = Bounds.Height; var h = Bounds.Height;
@ -199,7 +199,7 @@ namespace SourceGit.Views
private bool _lastInSlider = false; private bool _lastInSlider = false;
} }
public class ImageBlendControl : Control public class ImageBlendControl : ImageContainer
{ {
public static readonly StyledProperty<double> AlphaProperty = public static readonly StyledProperty<double> AlphaProperty =
AvaloniaProperty.Register<ImageBlendControl, double>(nameof(Alpha), 1.0); AvaloniaProperty.Register<ImageBlendControl, double>(nameof(Alpha), 1.0);
@ -236,30 +236,50 @@ namespace SourceGit.Views
public override void Render(DrawingContext context) public override void Render(DrawingContext context)
{ {
base.Render(context);
var rect = new Rect(0, 0, Bounds.Width, Bounds.Height); var rect = new Rect(0, 0, Bounds.Width, Bounds.Height);
var alpha = Alpha; var alpha = Alpha;
var left = OldImage; var left = OldImage;
var right = NewImage; var right = NewImage;
var drawLeft = left != null && alpha < 1.0; var drawLeft = left != null && alpha < 1.0;
var drawRight = right != null && alpha > 0; var drawRight = right != null && alpha > 0;
if (drawLeft) var psize = left == null ? right.PixelSize : left.PixelSize;
{ var dpi = left == null ? right.Dpi : left.Dpi;
using (context.PushRenderOptions(new RenderOptions() { BitmapBlendingMode = BitmapBlendingMode.Source }))
using (context.PushOpacity(1 - alpha))
context.DrawImage(left, rect);
if (drawRight) using (var rt = new RenderTargetBitmap(psize, dpi))
{
using (context.PushRenderOptions(new RenderOptions() { BitmapBlendingMode = BitmapBlendingMode.Plus }))
using (context.PushOpacity(alpha))
context.DrawImage(right, rect);
}
}
else if (drawRight)
{ {
using (context.PushOpacity(alpha)) var rtRect = new Rect(rt.Size);
context.DrawImage(right, rect); using (var dc = rt.CreateDrawingContext())
{
if (drawLeft)
{
if (drawRight)
{
using (dc.PushRenderOptions(RO_SRC))
using (dc.PushOpacity(1 - alpha))
dc.DrawImage(left, rtRect);
using (dc.PushRenderOptions(RO_DST))
using (dc.PushOpacity(alpha))
dc.DrawImage(right, rtRect);
}
else
{
using (dc.PushRenderOptions(RO_SRC))
using (dc.PushOpacity(1 - alpha))
dc.DrawImage(left, rtRect);
}
}
else if (drawRight)
{
using (dc.PushRenderOptions(RO_SRC))
using (dc.PushOpacity(alpha))
dc.DrawImage(right, rtRect);
}
}
context.DrawImage(rt, rtRect, rect);
} }
} }
@ -290,6 +310,9 @@ namespace SourceGit.Views
return new Size(scale * img.Width, scale * img.Height); return new Size(scale * img.Width, scale * img.Height);
} }
private static readonly RenderOptions RO_SRC = new RenderOptions() { BitmapBlendingMode = BitmapBlendingMode.Source, BitmapInterpolationMode = BitmapInterpolationMode.HighQuality };
private static readonly RenderOptions RO_DST = new RenderOptions() { BitmapBlendingMode = BitmapBlendingMode.Plus, BitmapInterpolationMode = BitmapInterpolationMode.HighQuality };
} }
public partial class ImageDiffView : UserControl public partial class ImageDiffView : UserControl