-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2000 from erri120/feat/1864-9
Image store
- Loading branch information
Showing
14 changed files
with
522 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
src/Abstractions/NexusMods.Abstractions.Media/IImageStore.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using Avalonia.Media.Imaging; | ||
using BitFaster.Caching; | ||
using JetBrains.Annotations; | ||
using NexusMods.MnemonicDB.Abstractions; | ||
using OneOf; | ||
|
||
namespace NexusMods.Abstractions.Media; | ||
|
||
/// <summary> | ||
/// Optimized storage for images. | ||
/// </summary> | ||
[PublicAPI] | ||
public interface IImageStore | ||
{ | ||
ValueTask<StoredImage.ReadOnly> PutAsync(Bitmap bitmap); | ||
|
||
[MustDisposeResource] Lifetime<Bitmap>? Get(OneOf<StoredImageId, StoredImage.ReadOnly> input); | ||
|
||
StoredImage.New CreateStoredImage(ITransaction transaction, Bitmap bitmap); | ||
} |
37 changes: 37 additions & 0 deletions
37
src/Abstractions/NexusMods.Abstractions.Media/ImageData.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
namespace NexusMods.Abstractions.Media; | ||
|
||
/// <summary> | ||
/// Image data. | ||
/// </summary> | ||
public readonly struct ImageData | ||
{ | ||
/// <summary> | ||
/// Compression type. | ||
/// </summary> | ||
public readonly ImageDataCompression Compression; | ||
|
||
/// <summary> | ||
/// Binary data. | ||
/// </summary> | ||
public readonly byte[] Data; | ||
|
||
/// <summary> | ||
/// Constructor. | ||
/// </summary> | ||
public ImageData(ImageDataCompression compression, byte[] data) | ||
{ | ||
Compression = compression; | ||
Data = data; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Compression types. | ||
/// </summary> | ||
public enum ImageDataCompression : byte | ||
{ | ||
/// <summary> | ||
/// No compression. | ||
/// </summary> | ||
None = 0, | ||
} |
58 changes: 58 additions & 0 deletions
58
src/Abstractions/NexusMods.Abstractions.Media/ImageDataAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
using System.Diagnostics; | ||
using NexusMods.MnemonicDB.Abstractions; | ||
using NexusMods.MnemonicDB.Abstractions.Attributes; | ||
using NexusMods.MnemonicDB.Abstractions.ElementComparers; | ||
|
||
namespace NexusMods.Abstractions.Media; | ||
|
||
/// <summary> | ||
/// Binary blob containing image data. | ||
/// </summary> | ||
public class ImageDataAttribute(string ns, string name) : BlobAttribute<ImageData>(ns, name) | ||
{ | ||
/// <inheritdoc/> | ||
protected override ImageData FromLowLevel(ReadOnlySpan<byte> value, ValueTags tags, RegistryId registryId) | ||
{ | ||
Debug.Assert(sizeof(ImageDataCompression) == 1); | ||
var compression = (ImageDataCompression)value[0]; | ||
|
||
var data = Decompress(compression, value[1..]); | ||
return new ImageData(compression, data); | ||
} | ||
|
||
/// <inheritdoc/> | ||
protected override void WriteValue<TWriter>(ImageData value, TWriter writer) | ||
{ | ||
Debug.Assert(sizeof(ImageDataCompression) == 1); | ||
var count = value.Data.Length + sizeof(ImageDataCompression); | ||
|
||
var span = writer.GetSpan(sizeHint: count); | ||
span[0] = (byte)value.Compression; | ||
|
||
var bytesWritten = Compress(value.Compression, value.Data, span[1..]); | ||
writer.Advance(bytesWritten + sizeof(ImageDataCompression)); | ||
} | ||
|
||
private static int Compress(ImageDataCompression compression, byte[] data, Span<byte> outputSpan) | ||
{ | ||
switch (compression) | ||
{ | ||
case ImageDataCompression.None: | ||
data.CopyTo(outputSpan); | ||
return data.Length; | ||
default: | ||
throw new ArgumentOutOfRangeException(); | ||
} | ||
} | ||
|
||
private static byte[] Decompress(ImageDataCompression compression, ReadOnlySpan<byte> data) | ||
{ | ||
switch (compression) | ||
{ | ||
case ImageDataCompression.None: | ||
return data.ToArray(); | ||
default: | ||
throw new ArgumentOutOfRangeException(); | ||
} | ||
} | ||
} |
107 changes: 107 additions & 0 deletions
107
src/Abstractions/NexusMods.Abstractions.Media/ImageMetadata.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
using System.Diagnostics; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
using Avalonia; | ||
using Avalonia.Platform; | ||
using Avalonia.Skia; | ||
using SkiaSharp; | ||
|
||
namespace NexusMods.Abstractions.Media; | ||
|
||
/// <summary> | ||
/// Metadata of an image. | ||
/// </summary> | ||
[StructLayout(LayoutKind.Sequential)] | ||
public readonly struct ImageMetadata | ||
{ | ||
/// <summary> | ||
/// Width. | ||
/// </summary> | ||
public readonly uint ImageWidth; | ||
|
||
/// <summary> | ||
/// Height. | ||
/// </summary> | ||
public readonly uint ImageHeight; | ||
|
||
/// <summary> | ||
/// Color type. | ||
/// </summary> | ||
public readonly SKColorType SkColorType; | ||
|
||
/// <summary> | ||
/// Alpha format. | ||
/// </summary> | ||
public readonly AlphaFormat AlphaFormat; | ||
|
||
/// <summary> | ||
/// DPI. | ||
/// </summary> | ||
public readonly uint Dpi; | ||
|
||
/// <summary> | ||
/// Pixel size. | ||
/// </summary> | ||
public PixelSize PixelSize => new((int)ImageWidth, (int)ImageHeight); | ||
|
||
/// <summary> | ||
/// Pixel format. | ||
/// </summary> | ||
public PixelFormat PixelFormat => SkColorType.ToPixelFormat(); | ||
|
||
// NOTE(erri120): Going from bits to bytes requires dividing by 8, aka bit shift by 3 | ||
|
||
/// <summary> | ||
/// Stride is the number of bytes from one row pixels in memory to the next row. | ||
/// </summary> | ||
public int Stride => ((int)ImageWidth * PixelFormat.BitsPerPixel) >> 3; | ||
|
||
/// <summary> | ||
/// Total length of the raw data. | ||
/// </summary> | ||
public ulong DataLength => (ImageWidth * ImageHeight * (uint)PixelFormat.BitsPerPixel) >> 3; | ||
|
||
/// <summary> | ||
/// Constructor. | ||
/// </summary> | ||
public ImageMetadata(uint imageWidth, uint imageHeight, SKColorType skColorType, AlphaFormat alphaFormat, uint dpi) | ||
{ | ||
ImageWidth = imageWidth; | ||
ImageHeight = imageHeight; | ||
SkColorType = skColorType; | ||
AlphaFormat = alphaFormat; | ||
Dpi = dpi; | ||
} | ||
|
||
/// <summary> | ||
/// Reads the binary data as metadata. | ||
/// </summary> | ||
public static ImageMetadata Read(ReadOnlySpan<byte> bytes) | ||
{ | ||
Debug.Assert(bytes.Length == Marshal.SizeOf<ImageMetadata>()); | ||
|
||
unsafe | ||
{ | ||
fixed (byte* b = bytes) | ||
{ | ||
return Unsafe.Read<ImageMetadata>(b); | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Writes the metadata as binary data. | ||
/// </summary> | ||
public void Write(Span<byte> bytes) | ||
{ | ||
Debug.Assert(bytes.Length == Marshal.SizeOf<ImageMetadata>()); | ||
|
||
unsafe | ||
{ | ||
fixed (void* b = bytes) | ||
{ | ||
Unsafe.Write(b, this); | ||
} | ||
} | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
src/Abstractions/NexusMods.Abstractions.Media/ImageMetadataAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System.Runtime.InteropServices; | ||
using NexusMods.MnemonicDB.Abstractions; | ||
using NexusMods.MnemonicDB.Abstractions.Attributes; | ||
using NexusMods.MnemonicDB.Abstractions.ElementComparers; | ||
|
||
namespace NexusMods.Abstractions.Media; | ||
|
||
/// <summary> | ||
/// Binary blob representation of <see cref="ImageMetadata"/>. | ||
/// </summary> | ||
public class ImageMetadataAttribute(string ns, string name) : BlobAttribute<ImageMetadata>(ns, name) | ||
{ | ||
private static readonly int ImageMetadataSize = Marshal.SizeOf<ImageMetadata>(); | ||
|
||
/// <inheritdoc/> | ||
protected override ImageMetadata FromLowLevel(ReadOnlySpan<byte> value, ValueTags tags, RegistryId registryId) | ||
{ | ||
return ImageMetadata.Read(value); | ||
} | ||
|
||
/// <inheritdoc/> | ||
protected override void WriteValue<TWriter>(ImageMetadata value, TWriter writer) | ||
{ | ||
var span = writer.GetSpan(sizeHint: ImageMetadataSize); | ||
value.Write(span); | ||
writer.Advance(ImageMetadataSize); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/Abstractions/NexusMods.Abstractions.Media/NexusMods.Abstractions.Media.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<!-- NuGet Package Shared Details --> | ||
<Import Project="$([MSBuild]::GetPathOfFileAbove('NuGet.Build.props', '$(MSBuildThisFileDirectory)../'))" /> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Avalonia.Skia" /> | ||
<PackageReference Include="OneOf"/> | ||
<PackageReference Include="NexusMods.MnemonicDB.Abstractions"/> | ||
<PackageReference Include="NexusMods.MnemonicDB.SourceGenerator" PrivateAssets="all" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> | ||
<PackageReference Include="BitFaster.Caching"/> | ||
</ItemGroup> | ||
|
||
</Project> |
17 changes: 17 additions & 0 deletions
17
src/Abstractions/NexusMods.Abstractions.Media/ServiceExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace NexusMods.Abstractions.Media; | ||
|
||
/// <summary> | ||
/// Extension methods. | ||
/// </summary> | ||
public static class ServiceExtensions | ||
{ | ||
/// <summary> | ||
/// Adds media. | ||
/// </summary> | ||
public static IServiceCollection AddMedia(this IServiceCollection serviceCollection) | ||
{ | ||
return serviceCollection.AddStoredImageModel(); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/Abstractions/NexusMods.Abstractions.Media/StoredImage.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using JetBrains.Annotations; | ||
using NexusMods.MnemonicDB.Abstractions.Models; | ||
|
||
namespace NexusMods.Abstractions.Media; | ||
|
||
/// <summary> | ||
/// Represent an image. | ||
/// </summary> | ||
[UsedImplicitly] | ||
public partial class StoredImage : IModelDefinition | ||
{ | ||
private const string Namespace = "NexusMods.ImageStore.StoredImage"; | ||
|
||
/// <summary> | ||
/// Image data. | ||
/// </summary> | ||
public static readonly ImageDataAttribute ImageData = new(Namespace, nameof(ImageData)) { NoHistory = true }; | ||
|
||
/// <summary> | ||
/// Image metadata. | ||
/// </summary> | ||
public static readonly ImageMetadataAttribute Metadata = new(Namespace, nameof(Metadata)); | ||
} |
Oops, something went wrong.