Skip to content

Commit a2ca071

Browse files
feature: .dds image support (#1392)
* Added Pfim as 3rdparty lib * Added support for parsing showing dds and tga images using Pfim --------- Co-authored-by: Snimax <[email protected]>
1 parent 7bba40d commit a2ca071

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

src/Models/ImageDecoder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ public enum ImageDecoder
44
{
55
None = 0,
66
Builtin,
7+
Pfim
78
}
89
}

src/SourceGit.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
5151
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc5.4" />
5252
<PackageReference Include="OpenAI" Version="2.2.0-beta.4" />
53+
<PackageReference Include="Pfim" Version="0.11.3" />
5354
<PackageReference Include="TextMateSharp" Version="1.0.66" />
5455
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.66" />
5556
</ItemGroup>

src/ViewModels/ImageSource.cs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System.IO;
2+
using System.Runtime.InteropServices;
23
using Avalonia.Media.Imaging;
4+
using Pfim;
35

46
namespace SourceGit.ViewModels
57
{
@@ -27,6 +29,9 @@ public static Models.ImageDecoder GetDecoder(string file)
2729
case ".png":
2830
case ".webp":
2931
return Models.ImageDecoder.Builtin;
32+
case ".tga":
33+
case ".dds":
34+
return Models.ImageDecoder.Pfim;
3035
default:
3136
return Models.ImageDecoder.None;
3237
}
@@ -70,9 +75,93 @@ private static ImageSource LoadFromStream(Stream stream, Models.ImageDecoder dec
7075
// Just ignore.
7176
}
7277
}
78+
else if (decoder == Models.ImageDecoder.Pfim)
79+
{
80+
return new ImageSource(LoadWithPfim(stream), size);
81+
}
7382
}
7483

7584
return new ImageSource(null, 0);
7685
}
86+
87+
private static Bitmap LoadWithPfim(Stream stream)
88+
{
89+
var image = Pfim.Pfimage.FromStream(stream);
90+
byte[] data;
91+
int stride;
92+
if (image.Format == ImageFormat.Rgba32)
93+
{
94+
data = image.Data;
95+
stride = image.Stride;
96+
}
97+
else
98+
{
99+
int pixels = image.Width * image.Height;
100+
data = new byte[pixels * 4];
101+
stride = image.Width * 4;
102+
103+
switch (image.Format)
104+
{
105+
case ImageFormat.Rgba16:
106+
case ImageFormat.R5g5b5a1:
107+
{
108+
for (int i = 0; i < pixels; i++)
109+
{
110+
data[i * 4 + 0] = image.Data[i * 4 + 2]; // B
111+
data[i * 4 + 1] = image.Data[i * 4 + 1]; // G
112+
data[i * 4 + 2] = image.Data[i * 4 + 0]; // R
113+
data[i * 4 + 3] = image.Data[i * 4 + 3]; // A
114+
}
115+
}
116+
break;
117+
case ImageFormat.R5g5b5:
118+
case ImageFormat.R5g6b5:
119+
case ImageFormat.Rgb24:
120+
{
121+
for (int i = 0; i < pixels; i++)
122+
{
123+
data[i * 4 + 0] = image.Data[i * 3 + 2]; // B
124+
data[i * 4 + 1] = image.Data[i * 3 + 1]; // G
125+
data[i * 4 + 2] = image.Data[i * 3 + 0]; // R
126+
data[i * 4 + 3] = 255; // A
127+
}
128+
}
129+
break;
130+
case ImageFormat.Rgb8:
131+
{
132+
for (int i = 0; i < pixels; i++)
133+
{
134+
var color = image.Data[i];
135+
data[i * 4 + 0] = color;
136+
data[i * 4 + 1] = color;
137+
data[i * 4 + 2] = color;
138+
data[i * 4 + 3] = 255;
139+
}
140+
}
141+
break;
142+
default:
143+
return null;
144+
}
145+
}
146+
147+
// Pin the array and pass the pointer to Bitmap
148+
var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
149+
try
150+
{
151+
var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);
152+
var bitmap = new Bitmap(
153+
Avalonia.Platform.PixelFormat.Bgra8888,
154+
Avalonia.Platform.AlphaFormat.Unpremul,
155+
ptr,
156+
new Avalonia.PixelSize(image.Width, image.Height),
157+
new Avalonia.Vector(96, 96),
158+
stride);
159+
return bitmap;
160+
}
161+
finally
162+
{
163+
handle.Free();
164+
}
165+
}
77166
}
78167
}

0 commit comments

Comments
 (0)