mirror of
https://github.com/lifegpc/GARbro.git
synced 2026-06-22 03:44:18 +08:00
Add AVIF Image decode support
This commit is contained in:
@@ -111,6 +111,7 @@
|
||||
<Compile Include="FC01\ArcBDT.cs" />
|
||||
<Compile Include="FC01\BdtTables.cs" />
|
||||
<Compile Include="GScripter\ArcDATA.cs" />
|
||||
<Compile Include="ImageAVIF.cs" />
|
||||
<Compile Include="ImageJXL.cs" />
|
||||
<Compile Include="Ism\ImagePNG.cs" />
|
||||
<Compile Include="Kogado\ArcARC.cs" />
|
||||
@@ -1271,6 +1272,9 @@
|
||||
<EmbeddedResource Include="Strings\arcStrings.ru-RU.resx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="x64\avif.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x64\jxl_dec.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -1280,6 +1284,9 @@
|
||||
<Content Include="x64\zstd-1.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x86\avif.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x86\jxl_dec.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
||||
251
ArcFormats/ImageAVIF.cs
Normal file
251
ArcFormats/ImageAVIF.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace GameRes.Formats
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class AvifImageFormat : ImageFormat, IDisposable
|
||||
{
|
||||
public override string Tag { get { return "AVIF"; } }
|
||||
public override string Description { get { return "AV1 Image File Format"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public AvifImageFormat()
|
||||
{
|
||||
Extensions = new[] { "avif" };
|
||||
}
|
||||
|
||||
public enum avifResult
|
||||
{
|
||||
OK = 0,
|
||||
UnknownError = 1,
|
||||
InvalidFtyp = 2,
|
||||
NoContent = 3,
|
||||
NoYuvFormatSelected = 4,
|
||||
ReformatFailed = 5,
|
||||
UnsupportedDepth = 6,
|
||||
EncodeColorFailed = 7,
|
||||
EncodeAlphaFailed = 8,
|
||||
BmffParseFailed = 9,
|
||||
MissingImageItem = 10,
|
||||
DecodeColorFailed = 11,
|
||||
DecodeAlphaFailed = 12,
|
||||
ColorAlphaSizeMismatch = 13,
|
||||
IspeSizeMismatch = 14,
|
||||
NoCodecAvailable = 15,
|
||||
NoImagesRemaining = 16,
|
||||
InvalidExifPayload = 17,
|
||||
InvalidImageGrid = 18,
|
||||
InvalidCodecSpecificOption = 19,
|
||||
TruncatedData = 20,
|
||||
IoNotSet = 21,
|
||||
IoError = 22,
|
||||
WaitingOnIo = 23,
|
||||
InvalidArgument = 24,
|
||||
NotImplemented = 25,
|
||||
OutOfMemory = 26,
|
||||
CannotChangeSetting = 27,
|
||||
IncompatibleImage = 28,
|
||||
InternalError = 29,
|
||||
EncodeGainMapFailed = 30,
|
||||
DecodeGainMapFailed = 31,
|
||||
InvalidToneMappedImage = 32,
|
||||
}
|
||||
|
||||
public enum avifRGBFormat
|
||||
{
|
||||
RGB = 0,
|
||||
RGBA,
|
||||
ARGB,
|
||||
BGR,
|
||||
BGRA,
|
||||
ABGR,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct avifRWData
|
||||
{
|
||||
public IntPtr data;
|
||||
public UIntPtr size;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct avifImage
|
||||
{
|
||||
public uint width;
|
||||
public uint height;
|
||||
public uint depth;
|
||||
public int yuvFormat;
|
||||
public int yuvRange;
|
||||
public int yuvChromaSamplePosition;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public IntPtr[] yuvPlanes;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] yuvRowBytes;
|
||||
public int imageOwnsYUVPlanes;
|
||||
public IntPtr alphaPlane;
|
||||
public uint alphaRowBytes;
|
||||
public int imageOwnsAlphaPlane;
|
||||
public int alphaPremultiplied;
|
||||
public avifRWData icc;
|
||||
public ushort colorPrimaries;
|
||||
public ushort transferCharacteristics;
|
||||
public ushort matrixCoefficients;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct avifRGBImage
|
||||
{
|
||||
public uint width;
|
||||
public uint height;
|
||||
public uint depth;
|
||||
public avifRGBFormat format;
|
||||
public int chromaUpsampling;
|
||||
public int chromaDownsampling;
|
||||
public int avoidLibYUV;
|
||||
public int ignoreAlpha;
|
||||
public int alphaPremultiplied;
|
||||
public int isFloat;
|
||||
public int maxThreads;
|
||||
public IntPtr pixels;
|
||||
public uint rowBytes;
|
||||
}
|
||||
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr avifDecoderCreate();
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void avifDecoderDestroy(IntPtr decoder);
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern avifResult avifDecoderReadMemory(IntPtr decoder, IntPtr image, byte[] data, UIntPtr size);
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr avifImageCreateEmpty();
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void avifImageDestroy(IntPtr image);
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void avifRGBImageSetDefaults(ref avifRGBImage rgb, IntPtr image);
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern avifResult avifImageYUVToRGB(IntPtr image, ref avifRGBImage rgb);
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern avifResult avifRGBImageAllocatePixels(ref avifRGBImage rgb);
|
||||
[DllImport("avif.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void avifRGBImageFreePixels(ref avifRGBImage rgb);
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader(12);
|
||||
if (header.Length < 12 || !header.AsciiEqual(4, "ftyp"))
|
||||
return null;
|
||||
if (!header.AsciiEqual(8, "avif") && !header.AsciiEqual(8, "avis"))
|
||||
return null;
|
||||
|
||||
IntPtr decoder = avifDecoderCreate();
|
||||
if (decoder == IntPtr.Zero)
|
||||
return null;
|
||||
IntPtr image = avifImageCreateEmpty();
|
||||
if (image == IntPtr.Zero)
|
||||
{
|
||||
avifDecoderDestroy(decoder);
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
file.Position = 0;
|
||||
var input = file.ReadBytes((int)file.Length);
|
||||
var result = avifDecoderReadMemory(decoder, image, input, (UIntPtr)input.Length);
|
||||
if (result != avifResult.OK)
|
||||
return null;
|
||||
|
||||
var img_info = (avifImage)Marshal.PtrToStructure(image, typeof(avifImage));
|
||||
return new ImageMetaData
|
||||
{
|
||||
Width = img_info.width,
|
||||
Height = img_info.height,
|
||||
BPP = img_info.alphaPlane != IntPtr.Zero ? 32 : 24,
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
avifImageDestroy(image);
|
||||
avifDecoderDestroy(decoder);
|
||||
}
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
IntPtr decoder = avifDecoderCreate();
|
||||
if (decoder == IntPtr.Zero)
|
||||
throw new ApplicationException("avifDecoderCreate failed.");
|
||||
IntPtr image = avifImageCreateEmpty();
|
||||
if (image == IntPtr.Zero)
|
||||
{
|
||||
avifDecoderDestroy(decoder);
|
||||
throw new ApplicationException("avifImageCreateEmpty failed.");
|
||||
}
|
||||
try
|
||||
{
|
||||
file.Position = 0;
|
||||
var input = file.ReadBytes((int)file.Length);
|
||||
var result = avifDecoderReadMemory(decoder, image, input, (UIntPtr)input.Length);
|
||||
if (result != avifResult.OK)
|
||||
throw new InvalidFormatException();
|
||||
|
||||
var img_info = (avifImage)Marshal.PtrToStructure(image, typeof(avifImage));
|
||||
|
||||
var rgb = new avifRGBImage();
|
||||
avifRGBImageSetDefaults(ref rgb, image);
|
||||
|
||||
PixelFormat wpf_format;
|
||||
if (img_info.alphaPlane != IntPtr.Zero)
|
||||
{
|
||||
rgb.format = avifRGBFormat.BGRA;
|
||||
wpf_format = PixelFormats.Bgra32;
|
||||
}
|
||||
else
|
||||
{
|
||||
rgb.format = avifRGBFormat.BGR;
|
||||
wpf_format = PixelFormats.Bgr24;
|
||||
}
|
||||
rgb.depth = 8;
|
||||
|
||||
if (avifResult.OK != avifRGBImageAllocatePixels(ref rgb))
|
||||
throw new ApplicationException("avifRGBImageAllocatePixels failed.");
|
||||
try
|
||||
{
|
||||
if (avifResult.OK != avifImageYUVToRGB(image, ref rgb))
|
||||
throw new ApplicationException("avifImageYUVToRGB failed.");
|
||||
|
||||
int stride = (int)rgb.rowBytes;
|
||||
var pixels = new byte[stride * rgb.height];
|
||||
Marshal.Copy(rgb.pixels, pixels, 0, pixels.Length);
|
||||
|
||||
var bitmap = BitmapSource.Create((int)info.Width, (int)info.Height, 96, 96, wpf_format, null, pixels, stride);
|
||||
bitmap.Freeze();
|
||||
return new ImageData(bitmap, info);
|
||||
}
|
||||
finally
|
||||
{
|
||||
avifRGBImageFreePixels(ref rgb);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
avifImageDestroy(image);
|
||||
avifDecoderDestroy(decoder);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("AvifImageFormat.Write not implemented");
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
ArcFormats/x64/avif.dll
Normal file
BIN
ArcFormats/x64/avif.dll
Normal file
Binary file not shown.
BIN
ArcFormats/x86/avif.dll
Normal file
BIN
ArcFormats/x86/avif.dll
Normal file
Binary file not shown.
Reference in New Issue
Block a user