feature: supports to view .tiff images
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo 2025-06-12 18:15:25 +08:00
parent cb6d6a233f
commit 05757ebf40
No known key found for this signature in database
3 changed files with 90 additions and 64 deletions

View file

@ -4,6 +4,7 @@
{ {
None = 0, None = 0,
Builtin, Builtin,
Pfim Pfim,
Tiff,
} }
} }

View file

@ -47,6 +47,7 @@
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.2.0" /> <PackageReference Include="Avalonia.AvaloniaEdit" Version="11.2.0" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.2.0" /> <PackageReference Include="AvaloniaEdit.TextMate" Version="11.2.0" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.4" /> <PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.4" />
<PackageReference Include="BitMiracle.LibTiff.NET" Version="2.4.660" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc5.4" /> <PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc5.4" />
<PackageReference Include="OpenAI" Version="2.2.0-beta.4" /> <PackageReference Include="OpenAI" Version="2.2.0-beta.4" />

View file

@ -7,6 +7,7 @@ using Avalonia;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Platform; using Avalonia.Platform;
using BitMiracle.LibTiff.Classic;
using Pfim; using Pfim;
namespace SourceGit.ViewModels namespace SourceGit.ViewModels
@ -39,6 +40,9 @@ namespace SourceGit.ViewModels
case ".tga": case ".tga":
case ".dds": case ".dds":
return Models.ImageDecoder.Pfim; return Models.ImageDecoder.Pfim;
case ".tif":
case ".tiff":
return Models.ImageDecoder.Tiff;
default: default:
return Models.ImageDecoder.None; return Models.ImageDecoder.None;
} }
@ -70,31 +74,34 @@ namespace SourceGit.ViewModels
var size = stream.Length; var size = stream.Length;
if (size > 0) if (size > 0)
{ {
if (decoder == Models.ImageDecoder.Builtin) try
{
switch (decoder)
{
case Models.ImageDecoder.Builtin:
return DecodeWithAvalonia(stream, size); return DecodeWithAvalonia(stream, size);
else if (decoder == Models.ImageDecoder.Pfim) case Models.ImageDecoder.Pfim:
return DecodeWithPfim(stream, size); return DecodeWithPfim(stream, size);
case Models.ImageDecoder.Tiff:
return DecodeWithTiff(stream, size);
}
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
}
} }
return new ImageSource(null, 0); return new ImageSource(null, 0);
} }
private static ImageSource DecodeWithAvalonia(Stream stream, long size) private static ImageSource DecodeWithAvalonia(Stream stream, long size)
{
try
{ {
var bitmap = new Bitmap(stream); var bitmap = new Bitmap(stream);
return new ImageSource(bitmap, size); return new ImageSource(bitmap, size);
} }
catch
{
return new ImageSource(null, 0);
}
}
private static ImageSource DecodeWithPfim(Stream stream, long size) private static ImageSource DecodeWithPfim(Stream stream, long size)
{
try
{ {
using (var pfiImage = Pfimage.FromStream(stream)) using (var pfiImage = Pfimage.FromStream(stream))
{ {
@ -147,9 +154,26 @@ namespace SourceGit.ViewModels
return new ImageSource(bitmap, size); return new ImageSource(bitmap, size);
} }
} }
catch
private static ImageSource DecodeWithTiff(Stream stream, long size)
{ {
using (var tiff = Tiff.ClientOpen($"{Guid.NewGuid()}.tif", "r", stream, new TiffStream()))
{
if (tiff == null)
return new ImageSource(null, 0); return new ImageSource(null, 0);
var width = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
var height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
var pixels = new int[width * height];
// Currently only supports image when its `BITSPERSAMPLE` is one in [1,2,4,8,16]
tiff.ReadRGBAImageOriented(width, height, pixels, Orientation.TOPLEFT);
var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(pixels, 0);
var pixelSize = new PixelSize(width, height);
var dpi = new Vector(96, 96);
var bitmap = new Bitmap(PixelFormats.Rgba8888, AlphaFormat.Premul, ptr, pixelSize, dpi, width * 4);
return new ImageSource(bitmap, size);
} }
} }
} }