using LiteDB; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models.FileInterfaces; using JsonSerializer = System.Text.Json.JsonSerializer; using Size = System.Drawing.Size; namespace StabilityMatrix.Core.Models.Database; /// /// Represents a locally indexed image file. /// public class LocalImageFile { /// /// Relative path of the file from the root images directory ("%LIBRARY%/Images"). /// [BsonId] public required string RelativePath { get; set; } public required string AbsolutePath { get; set; } /// /// Type of the model file. /// public LocalImageFileType ImageType { get; set; } /// /// Creation time of the file. /// public DateTimeOffset CreatedAt { get; set; } /// /// Last modified time of the file. /// public DateTimeOffset LastModifiedAt { get; set; } /// /// Generation parameters metadata of the file. /// public GenerationParameters? GenerationParameters { get; set; } /// /// Dimensions of the image /// public Size? ImageSize { get; set; } /// /// File name of the relative path. /// public string FileName => Path.GetFileName(RelativePath); /// /// File name of the relative path without extension. /// public string FileNameWithoutExtension => Path.GetFileNameWithoutExtension(RelativePath); public string GlobalFullPath => GlobalConfig.LibraryDir.JoinDir("Images").JoinFile(RelativePath); public string GetFullPath(string rootImageDirectory) { return Path.Combine(rootImageDirectory, RelativePath); } public ( string? Parameters, string? ParametersJson, string? SMProject, string? ComfyNodes ) ReadMetadata() { using var stream = new FileStream( GlobalFullPath, FileMode.Open, FileAccess.Read, FileShare.Read ); using var reader = new BinaryReader(stream); var parameters = ImageMetadata.ReadTextChunk(reader, "parameters"); var parametersJson = ImageMetadata.ReadTextChunk(reader, "parameters-json"); var smProject = ImageMetadata.ReadTextChunk(reader, "smproj"); var comfyNodes = ImageMetadata.ReadTextChunk(reader, "prompt"); return ( string.IsNullOrEmpty(parameters) ? null : parameters, string.IsNullOrEmpty(parametersJson) ? null : parametersJson, string.IsNullOrEmpty(smProject) ? null : smProject, string.IsNullOrEmpty(comfyNodes) ? null : comfyNodes ); } public static LocalImageFile FromPath(FilePath filePath) { var relativePath = Path.GetRelativePath( GlobalConfig.LibraryDir.JoinDir("Images"), filePath ); // TODO: Support other types const LocalImageFileType imageType = LocalImageFileType.Inference | LocalImageFileType.TextToImage; // Get metadata using var stream = new FileStream( filePath.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read ); using var reader = new BinaryReader(stream); var imageSize = ImageMetadata.GetImageSize(reader); var metadata = ImageMetadata.ReadTextChunk(reader, "parameters-json"); GenerationParameters? genParams = null; if (!string.IsNullOrWhiteSpace(metadata)) { genParams = JsonSerializer.Deserialize(metadata); } else { metadata = ImageMetadata.ReadTextChunk(reader, "parameters"); GenerationParameters.TryParse(metadata, out genParams); } return new LocalImageFile { RelativePath = relativePath, AbsolutePath = filePath, ImageType = imageType, CreatedAt = filePath.Info.CreationTimeUtc, LastModifiedAt = filePath.Info.LastWriteTimeUtc, GenerationParameters = genParams, ImageSize = imageSize }; } public static readonly HashSet SupportedImageExtensions = new() { ".png", ".jpg", ".jpeg", ".webp" }; private sealed class LocalImageFileEqualityComparer : IEqualityComparer { public bool Equals(LocalImageFile? x, LocalImageFile? y) { if (ReferenceEquals(x, y)) return true; if (ReferenceEquals(x, null)) return false; if (ReferenceEquals(y, null)) return false; if (x.GetType() != y.GetType()) return false; return x.RelativePath == y.RelativePath && x.ImageType == y.ImageType && x.CreatedAt.Equals(y.CreatedAt) && x.LastModifiedAt.Equals(y.LastModifiedAt) && Equals(x.GenerationParameters, y.GenerationParameters); } public int GetHashCode(LocalImageFile obj) { return HashCode.Combine( obj.RelativePath, obj.ImageType, obj.CreatedAt, obj.LastModifiedAt, obj.GenerationParameters ); } } public static IEqualityComparer Comparer { get; } = new LocalImageFileEqualityComparer(); }