wabbajack/Wabbajack.ImageHashing/DDSImage.cs

165 lines
4.9 KiB
C#
Raw Normal View History

2021-06-15 03:39:17 +00:00
using System;
2021-06-16 05:16:25 +00:00
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
2021-06-15 03:39:17 +00:00
using DirectXTexNet;
2021-06-16 05:16:25 +00:00
using Shipwreck.Phash;
using Shipwreck.Phash.Imaging;
2021-06-15 03:39:17 +00:00
using Wabbajack.Common;
namespace Wabbajack.ImageHashing
{
2021-06-16 05:16:25 +00:00
public class DDSImage
2021-06-15 03:39:17 +00:00
{
2021-06-16 21:07:16 +00:00
private DDSImage(ScratchImage img, TexMetadata metadata, Extension ext)
2021-06-15 03:39:17 +00:00
{
2021-06-16 05:16:25 +00:00
_image = img;
_metaData = metadata;
2021-06-16 21:07:16 +00:00
_extension = ext;
2021-06-15 03:39:17 +00:00
}
private static Extension DDSExtension = new(".dds");
private ScratchImage _image;
private TexMetadata _metaData;
public static DDSImage FromFile(AbsolutePath file)
{
if (file.Extension != DDSExtension)
throw new Exception("File does not end in DDS");
var img = TexHelper.Instance.LoadFromDDSFile(file.ToString(), DDS_FLAGS.NONE);
2021-06-16 21:07:16 +00:00
return new DDSImage(img, img.GetMetadata(), new Extension(".dds"));
2021-06-16 05:16:25 +00:00
}
public static DDSImage FromDDSMemory(byte[] data)
{
unsafe
{
fixed (byte* ptr = data)
{
var img = TexHelper.Instance.LoadFromDDSMemory((IntPtr)ptr, data.Length, DDS_FLAGS.NONE);
2021-06-16 21:07:16 +00:00
return new DDSImage(img, img.GetMetadata(), new Extension(".dds"));
2021-06-16 05:16:25 +00:00
}
}
}
public static DDSImage FromTGAMemory(byte[] data)
{
unsafe
{
fixed (byte* ptr = data)
{
var img = TexHelper.Instance.LoadFromTGAMemory((IntPtr)ptr, data.Length);
2021-06-16 21:07:16 +00:00
return new DDSImage(img, img.GetMetadata(), new Extension(".tga"));
2021-06-16 05:16:25 +00:00
}
}
2021-06-15 03:39:17 +00:00
}
public void Dispose()
{
if (!_image.IsDisposed)
_image.Dispose();
}
public int Width => _metaData.Width;
public int Height => _metaData.Height;
2021-06-16 05:16:25 +00:00
public void Resize(int width, int height)
{
}
private static HashSet<DXGI_FORMAT> CompressedTypes = new HashSet<DXGI_FORMAT>()
{
DXGI_FORMAT.BC1_TYPELESS,
DXGI_FORMAT.BC1_UNORM,
DXGI_FORMAT.BC1_UNORM_SRGB,
DXGI_FORMAT.BC2_TYPELESS,
DXGI_FORMAT.BC2_UNORM,
DXGI_FORMAT.BC2_UNORM_SRGB,
DXGI_FORMAT.BC3_TYPELESS,
DXGI_FORMAT.BC3_UNORM,
DXGI_FORMAT.BC3_UNORM_SRGB,
DXGI_FORMAT.BC4_TYPELESS,
DXGI_FORMAT.BC4_UNORM,
DXGI_FORMAT.BC4_SNORM,
DXGI_FORMAT.BC5_TYPELESS,
DXGI_FORMAT.BC5_UNORM,
DXGI_FORMAT.BC5_SNORM,
DXGI_FORMAT.BC6H_TYPELESS,
DXGI_FORMAT.BC6H_UF16,
DXGI_FORMAT.BC6H_SF16,
DXGI_FORMAT.BC7_TYPELESS,
DXGI_FORMAT.BC7_UNORM,
DXGI_FORMAT.BC7_UNORM_SRGB,
};
2021-06-16 21:07:16 +00:00
private Extension _extension;
public ImageState ImageState()
{
return new()
{
Width = _metaData.Width,
Height = _metaData.Height,
PerceptualHash = PerceptionHash()
};
}
2021-06-16 05:16:25 +00:00
public PHash PerceptionHash()
{
ScratchImage? resized = default;
try
{
2021-06-16 21:07:16 +00:00
// First we resize the image, so that changes due to image scaling matter less in the final hash
2021-06-16 05:16:25 +00:00
if (CompressedTypes.Contains(_metaData.Format))
{
using var decompressed = _image.Decompress(DXGI_FORMAT.UNKNOWN);
resized = decompressed.Resize(512, 512, TEX_FILTER_FLAGS.DEFAULT);
}
else
{
resized = _image.Resize(512, 512, TEX_FILTER_FLAGS.DEFAULT);
}
2021-06-16 21:07:16 +00:00
2021-06-16 05:16:25 +00:00
var image = new byte[512 * 512];
unsafe void EvaluatePixels(IntPtr pixels, IntPtr width, IntPtr line)
{
float* ptr = (float*)pixels.ToPointer();
int widthV = width.ToInt32();
if (widthV != 512) return;
var y = line.ToInt32();
for (int i = 0; i < widthV; i++)
{
var r = ptr[0] * 0.229f;
var g = ptr[1] * 0.587f;
var b = ptr[2] * 0.114f;
var combined = (r + g + b) * 255.0f;
image[(y * widthV) + i] = (byte)combined;
ptr += 4;
}
}
resized.EvaluateImage(EvaluatePixels);
var digest = ImagePhash.ComputeDigest(new ByteImage(512, 512, image));
return PHash.FromDigest(digest);
}
finally
{
resized?.Dispose();
}
}
2021-06-15 03:39:17 +00:00
}
}