diff --git a/src/Commands/QueryFileContent.cs b/src/Commands/QueryFileContent.cs index f887859c..83d0a575 100644 --- a/src/Commands/QueryFileContent.cs +++ b/src/Commands/QueryFileContent.cs @@ -35,5 +35,39 @@ namespace SourceGit.Commands return stream; } + + public static Stream FromLFS(string repo, string oid, long size) + { + var starter = new ProcessStartInfo(); + starter.WorkingDirectory = repo; + starter.FileName = Native.OS.GitExecutable; + starter.Arguments = $"lfs smudge"; + starter.UseShellExecute = false; + starter.CreateNoWindow = true; + starter.WindowStyle = ProcessWindowStyle.Hidden; + starter.RedirectStandardInput = true; + starter.RedirectStandardOutput = true; + + var stream = new MemoryStream(); + try + { + var proc = new Process() { StartInfo = starter }; + proc.Start(); + proc.StandardInput.WriteLine("version https://git-lfs.github.com/spec/v1"); + proc.StandardInput.WriteLine($"oid sha256:{oid}"); + proc.StandardInput.WriteLine($"size {size}"); + proc.StandardOutput.BaseStream.CopyTo(stream); + proc.WaitForExit(); + proc.Close(); + + stream.Position = 0; + } + catch (Exception e) + { + App.RaiseException(repo, $"Failed to query file content: {e}"); + } + + return stream; + } } } diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index ce13e655..af089635 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -207,7 +207,10 @@ namespace SourceGit.ViewModels } else if (latest.IsLFS) { - rs = latest.LFSDiff; + if (IMG_EXTS.Contains(Path.GetExtension(_option.Path) ?? ".invalid")) + rs = new LFSImageDiff(_repo, latest.LFSDiff); + else + rs = latest.LFSDiff; } else { diff --git a/src/ViewModels/LFSImageDiff.cs b/src/ViewModels/LFSImageDiff.cs new file mode 100644 index 00000000..655004a6 --- /dev/null +++ b/src/ViewModels/LFSImageDiff.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; + +using Avalonia.Media.Imaging; +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class LFSImageDiff : ObservableObject + { + public Models.LFSDiff LFS + { + get; + } + + public Models.ImageDiff Image + { + get => _image; + private set => SetProperty(ref _image, value); + } + + public LFSImageDiff(string repo, Models.LFSDiff lfs) + { + LFS = lfs; + + Task.Run(() => + { + var img = new Models.ImageDiff(); + (img.Old, img.OldFileSize) = BitmapFromLFSObject(repo, lfs.Old); + (img.New, img.NewFileSize) = BitmapFromLFSObject(repo, lfs.New); + + Dispatcher.UIThread.Invoke(() => Image = img); + }); + } + + private (Bitmap, long) BitmapFromLFSObject(string repo, Models.LFSObject lfs) + { + if (string.IsNullOrEmpty(lfs.Oid) || lfs.Size == 0) + return (null, 0); + + var stream = Commands.QueryFileContent.FromLFS(repo, lfs.Oid, lfs.Size); + var size = stream.Length; + return size > 0 ? (new Bitmap(stream), size) : (null, size); + } + + private Models.ImageDiff _image; + } +} diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index 559ad14d..50a3de62 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -224,29 +224,7 @@ - - - - - - - - - - - - - - - - - - - + @@ -302,6 +280,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Views/LFSDiffView.axaml.cs b/src/Views/LFSDiffView.axaml.cs new file mode 100644 index 00000000..a16a6fd3 --- /dev/null +++ b/src/Views/LFSDiffView.axaml.cs @@ -0,0 +1,12 @@ +using Avalonia.Controls; + +namespace SourceGit.Views +{ + public partial class LFSDiffView : UserControl + { + public LFSDiffView() + { + InitializeComponent(); + } + } +}