diff --git a/src/Models/ImageDecoder.cs b/src/Models/ImageDecoder.cs
index 3a758882..ce3a44c1 100644
--- a/src/Models/ImageDecoder.cs
+++ b/src/Models/ImageDecoder.cs
@@ -4,5 +4,6 @@
{
None = 0,
Builtin,
+ Pfim
}
}
diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj
index 3fe21b1a..62ec6255 100644
--- a/src/SourceGit.csproj
+++ b/src/SourceGit.csproj
@@ -50,6 +50,7 @@
+
diff --git a/src/ViewModels/ImageSource.cs b/src/ViewModels/ImageSource.cs
index ec6b6a8d..2be09809 100644
--- a/src/ViewModels/ImageSource.cs
+++ b/src/ViewModels/ImageSource.cs
@@ -1,5 +1,7 @@
using System.IO;
+using System.Runtime.InteropServices;
using Avalonia.Media.Imaging;
+using Pfim;
namespace SourceGit.ViewModels
{
@@ -27,6 +29,9 @@ namespace SourceGit.ViewModels
case ".png":
case ".webp":
return Models.ImageDecoder.Builtin;
+ case ".tga":
+ case ".dds":
+ return Models.ImageDecoder.Pfim;
default:
return Models.ImageDecoder.None;
}
@@ -70,9 +75,93 @@ namespace SourceGit.ViewModels
// Just ignore.
}
}
+ else if (decoder == Models.ImageDecoder.Pfim)
+ {
+ return new ImageSource(LoadWithPfim(stream), size);
+ }
}
return new ImageSource(null, 0);
}
+
+ private static Bitmap LoadWithPfim(Stream stream)
+ {
+ var image = Pfim.Pfimage.FromStream(stream);
+ byte[] data;
+ int stride;
+ if (image.Format == ImageFormat.Rgba32)
+ {
+ data = image.Data;
+ stride = image.Stride;
+ }
+ else
+ {
+ int pixels = image.Width * image.Height;
+ data = new byte[pixels * 4];
+ stride = image.Width * 4;
+
+ switch (image.Format)
+ {
+ case ImageFormat.Rgba16:
+ case ImageFormat.R5g5b5a1:
+ {
+ for (int i = 0; i < pixels; i++)
+ {
+ data[i * 4 + 0] = image.Data[i * 4 + 2]; // B
+ data[i * 4 + 1] = image.Data[i * 4 + 1]; // G
+ data[i * 4 + 2] = image.Data[i * 4 + 0]; // R
+ data[i * 4 + 3] = image.Data[i * 4 + 3]; // A
+ }
+ }
+ break;
+ case ImageFormat.R5g5b5:
+ case ImageFormat.R5g6b5:
+ case ImageFormat.Rgb24:
+ {
+ for (int i = 0; i < pixels; i++)
+ {
+ data[i * 4 + 0] = image.Data[i * 3 + 2]; // B
+ data[i * 4 + 1] = image.Data[i * 3 + 1]; // G
+ data[i * 4 + 2] = image.Data[i * 3 + 0]; // R
+ data[i * 4 + 3] = 255; // A
+ }
+ }
+ break;
+ case ImageFormat.Rgb8:
+ {
+ for (int i = 0; i < pixels; i++)
+ {
+ var color = image.Data[i];
+ data[i * 4 + 0] = color;
+ data[i * 4 + 1] = color;
+ data[i * 4 + 2] = color;
+ data[i * 4 + 3] = 255;
+ }
+ }
+ break;
+ default:
+ return null;
+ }
+ }
+
+ // Pin the array and pass the pointer to Bitmap
+ var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
+ try
+ {
+ var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);
+ var bitmap = new Bitmap(
+ Avalonia.Platform.PixelFormat.Bgra8888,
+ Avalonia.Platform.AlphaFormat.Unpremul,
+ ptr,
+ new Avalonia.PixelSize(image.Width, image.Height),
+ new Avalonia.Vector(96, 96),
+ stride);
+ return bitmap;
+ }
+ finally
+ {
+ handle.Free();
+ }
+ }
}
}