Upgrade libraries

This commit is contained in:
Lani Aung
2026-07-08 21:25:50 -07:00
parent e3f23389da
commit 094f3abbff
14 changed files with 121 additions and 144 deletions
+2 -1
View File
@@ -8,4 +8,5 @@
*.Development.json
*.Release.json
.DS_Store
.DS_Store
*.lic
@@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
@@ -15,7 +16,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.8"/>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="10.0.9"/>
</ItemGroup>
</Project>
@@ -35,11 +35,12 @@ public class LhContainerTests
foreach (var file in files)
{
Assert.That(file.FileName, Is.Not.Null, "Filename is {0}", file.FileName);
Assert.That(file.CompressedSize, Is.GreaterThan(0), "Compressed size is {0}", file.CompressedSize);
Assert.That(file.UncompressedSize, Is.GreaterThan(0), "Uncompressed size is {0}", file.UncompressedSize);
Assert.IsNotNull(file.FileName, "Filename is {0}", file.FileName);
Assert.Greater(file.CompressedSize, 0, "Compressed size is {0}", file.CompressedSize);
Assert.Greater(file.CompressedSize, 0, "Compressed size is {0}", file.CompressedSize);
Assert.Greater(file.UncompressedSize, 0, "Uncompressed size is {0}", file.UncompressedSize);
Assert.That(file.UncompressedSize, Is.GreaterThan(file.CompressedSize), "Uncompressed is larger than compressed");
Assert.That(file.MethodId, Is.Not.Null, "Method id is {0}", file.MethodId);
Assert.IsNotNull(file.MethodId, "Method id is {0}", file.MethodId);
Assert.That(file.MethodId, Does.StartWith("-l"));
Assert.That(file.MethodId, Does.EndWith("-"));
Console.WriteLine($"Archive name: {file.FileName}, compression method: {file.MethodId}, file at {file.FileDataPosition}");
@@ -1,26 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
<PackageReference Include="NUnit" Version="3.13.3"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions">
<HintPath>..\..\..\..\..\usr\local\share\dotnet\shared\Microsoft.AspNetCore.App\8.0.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.7.0"/>
<PackageReference Include="NUnit" Version="4.6.1"/>
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.14.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="10.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
@@ -1,5 +1,8 @@
using System.Runtime.CompilerServices;
using System.Text;
[assembly: InternalsVisibleTo("fxl.codes.kisekae.data.test")]
namespace fxl.codes.kisekae.data.Archives;
internal class LhContainer
@@ -13,10 +16,10 @@ internal class LhContainer
var span = bytes.AsSpan();
Level = span[20];
MethodId = Encoding.ASCII.GetString(span[2..7]);
CompressedSize = EndianUtility.ToLittleEndian(span[7..11]);
CompressedSize = span[7..11].ToLittleEndian();
CompressedFile = new byte[CompressedSize];
UncompressedSize = EndianUtility.ToLittleEndian(span[11..15]);
Created = EndianUtility.ToDateTime(span[15..19]);
UncompressedSize = span[11..15].ToLittleEndian();
Created = span[15..19].ToDateTime();
FileOrDirectory = span[19];
switch (Level)
@@ -1,22 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
<UserSecretsId>c3253549-351f-4bcb-9c52-ce67c39cbeaf</UserSecretsId>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.9"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
<PackageReference Include="Npgsql" Version="8.0.4"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4"/>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.9"/>
<PackageReference Include="Npgsql" Version="10.0.3"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2"/>
</ItemGroup>
<ItemGroup>
+25 -26
View File
@@ -2,32 +2,31 @@ using System;
using System.Collections.Generic;
using fxl.codes.kisekae.data.Entities;
namespace fxl.codes.kisekae.Models
{
public class CelModel
{
internal CelModel(CelConfig celConfig, int zIndex)
{
Mark = celConfig.Mark;
Fix = celConfig.Fix;
ZIndex = zIndex;
Image = $"data:image/gif;base64,{Convert.ToBase64String(celConfig.Render.Image)}";
Height = celConfig.Cel.Height;
Width = celConfig.Cel.Width;
Opacity = (double)(255 - celConfig.Transparency) / 255;
Offset = new CoordinateModel(celConfig.Cel.OffsetX, celConfig.Cel.OffsetY);
foreach (var position in celConfig.Positions) InitialPositions.Add(position.Set, new CoordinateModel(position.X, position.Y));
}
namespace fxl.codes.kisekae.Models;
public int Fix { get; set; }
public int Height { get; set; }
public string Image { get; set; }
public int Mark { get; set; }
public double Opacity { get; set; }
public int Width { get; set; }
public int ZIndex { get; set; }
public IDictionary<int, CoordinateModel> InitialPositions { get; set; } = new Dictionary<int, CoordinateModel>();
public CoordinateModel Offset { get; set; }
public class CelModel
{
internal CelModel(CelConfig celConfig, int zIndex)
{
Mark = celConfig.Mark;
Fix = celConfig.Fix;
ZIndex = zIndex;
Image = $"data:image/gif;base64,{Convert.ToBase64String(celConfig.Render.Image)}";
Height = celConfig.Cel.Height;
Width = celConfig.Cel.Width;
Opacity = (double)(255 - celConfig.Transparency) / 255;
Offset = new CoordinateModel(celConfig.Cel.OffsetX, celConfig.Cel.OffsetY);
foreach (var position in celConfig.Positions) InitialPositions.Add(position.Set, new CoordinateModel(position.X, position.Y));
}
public int Fix { get; set; }
public int Height { get; set; }
public string Image { get; set; }
public int Mark { get; set; }
public double Opacity { get; set; }
public int Width { get; set; }
public int ZIndex { get; set; }
public IDictionary<int, CoordinateModel> InitialPositions { get; set; } = new Dictionary<int, CoordinateModel>();
public CoordinateModel Offset { get; set; }
}
+10 -11
View File
@@ -1,14 +1,13 @@
namespace fxl.codes.kisekae.Models
{
public class CoordinateModel
{
internal CoordinateModel(int x, int y)
{
X = x;
Y = y;
}
namespace fxl.codes.kisekae.Models;
public int X { get; set; }
public int Y { get; set; }
public class CoordinateModel
{
internal CoordinateModel(int x, int y)
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
}
+6 -7
View File
@@ -1,9 +1,8 @@
namespace fxl.codes.kisekae.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
namespace fxl.codes.kisekae.Models;
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
public class ErrorViewModel
{
public string RequestId { get; init; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
+6 -6
View File
@@ -4,7 +4,7 @@ using fxl.codes.kisekae.data.Entities;
namespace fxl.codes.kisekae.Models;
public class PlaysetModel
public record PlaysetModel
{
[JsonIgnore] public readonly string BorderColor;
@@ -24,9 +24,9 @@ public class PlaysetModel
for (var index = 0; index < 10; index++) Sets[index] = configuration.Cels.Any(x => x.Positions.Any(y => y.Set == index));
}
public CelModel[] Cels { get; set; }
public int Height { get; set; }
public string Name { get; set; }
public bool[] Sets { get; set; } = new bool[10];
public int Width { get; set; }
public CelModel[] Cels { get; init; }
public int Height { get; init; }
public string Name { get; init; }
public bool[] Sets { get; init; } = new bool[10];
public int Width { get; init; }
}
@@ -8,26 +8,19 @@ using Microsoft.Extensions.Logging;
namespace fxl.codes.kisekae.Services;
public class ConfigurationReaderService
public class ConfigurationReaderService(ILogger<ConfigurationReaderService> logger)
{
private const string CelRegex = @"#(?<Mark>\d*)\.?(?<Fix>\d*)\s*(?<FileName>[\w\d\-]*\.[cCeElL]*)\s*\*?"
+ @"(?<PaletteIndex>\d*)?\s*\:?(?<Sets>[\d\s]*)?;?(?<Comment>[\w\d\-\s\%]*)";
private const string ResolutionRegexPattern = @"\((?<Width>[0-9]*).(?<Height>[0-9]*)\)";
private readonly ILogger<ConfigurationReaderService> _logger;
public ConfigurationReaderService(ILogger<ConfigurationReaderService> logger)
{
_logger = logger;
}
public void ReadConfiguration(Configuration dto,
IDictionary<Configuration, int> backgroundColors,
IDictionary<string, Cel> cels,
Dictionary<string, Palette> palettes)
{
_logger.LogInformation($"Reading {dto.Name}");
logger.LogInformation("Reading {Name}", dto.Name);
var initialPositions = new StringBuilder();
var backgroundColorIndex = 0;
var paletteOrder = new List<Palette>();
+13 -28
View File
@@ -10,36 +10,21 @@ using fxl.codes.kisekae.data;
using fxl.codes.kisekae.data.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp;
using Configuration = fxl.codes.kisekae.data.Entities.Configuration;
namespace fxl.codes.kisekae.Services;
public class DatabaseService
public class DatabaseService(
ConfigurationReaderService configurationReaderService,
FileParserService fileParserService,
IDbContextFactory<KisekaeContext> contextFactory)
{
private readonly ConfigurationReaderService _configurationReaderService;
private readonly IDbContextFactory<KisekaeContext> _contextFactory;
private readonly FileParserService _fileParserService;
private readonly ILogger<DatabaseService> _logger;
private readonly IsolatedStorageFile _storage;
public DatabaseService(ILogger<DatabaseService> logger,
ConfigurationReaderService configurationReaderService,
FileParserService fileParserService,
IDbContextFactory<KisekaeContext> contextFactory)
{
_logger = logger;
_configurationReaderService = configurationReaderService;
_fileParserService = fileParserService;
_contextFactory = contextFactory;
_storage = IsolatedStorageFile.GetUserStoreForApplication();
}
private readonly IsolatedStorageFile _storage = IsolatedStorageFile.GetUserStoreForApplication();
public IEnumerable<Kisekae> GetAll()
{
using var context = _contextFactory.CreateDbContext();
using var context = contextFactory.CreateDbContext();
return context.KisekaeSets
.Include(x => x.Configurations)
.ToArray();
@@ -47,7 +32,7 @@ public class DatabaseService
public Configuration GetConfig(int id)
{
using var context = _contextFactory.CreateDbContext();
using var context = contextFactory.CreateDbContext();
return context.Configurations
.Include(x => x.Cels).ThenInclude(x => x.Render)
.Include(x => x.Cels).ThenInclude(x => x.Cel)
@@ -63,14 +48,14 @@ public class DatabaseService
var checksum = Convert.ToBase64String(SHA256.HashData(memoryStream.GetBuffer()));
memoryStream.Position = 0; // Reset for re-read
await using var context = await _contextFactory.CreateDbContextAsync();
await using var context = await contextFactory.CreateDbContextAsync();
var existing = await context.KisekaeSets
.FirstOrDefaultAsync(x => string.Equals(x.FileName, file.FileName)
|| string.Equals(x.CheckSum, checksum));
if (existing != null) context.KisekaeSets.Remove(existing);
await context.SaveChangesAsync();
await _fileParserService.UnzipLzh(file, memoryStream);
await fileParserService.UnzipLzh(file, memoryStream);
var directory = Path.GetFileNameWithoutExtension(file.FileName);
@@ -85,7 +70,7 @@ public class DatabaseService
var backgroundColors = new Dictionary<Configuration, int>();
foreach (var config in kisekae.Configurations)
_configurationReaderService.ReadConfiguration(config,
configurationReaderService.ReadConfiguration(config,
backgroundColors,
kisekae.Cels.ToDictionary(x => x.FileName.ToLowerInvariant()),
kisekae.Palettes.ToDictionary(x => x.FileName.ToLowerInvariant()));
@@ -95,7 +80,7 @@ public class DatabaseService
foreach (var (config, colorIndex) in backgroundColors)
config.BackgroundColorHex = kisekae.Palettes.First()?.Colors[colorIndex].Hex ?? Color.White.ToHex();
foreach (var celConfig in kisekae.Configurations.SelectMany(config => config.Cels))
_fileParserService.RenderCel(celConfig);
fileParserService.RenderCel(celConfig);
await context.AddAsync(kisekae);
await context.SaveChangesAsync();
@@ -109,7 +94,7 @@ public class DatabaseService
if (!reader.CanRead) throw new InvalidDataException();
var bytes = new byte[reader.Length];
reader.Read(bytes, 0, bytes.Length);
reader.ReadExactly(bytes);
switch (Path.GetExtension(filename).ToLower())
{
@@ -142,7 +127,7 @@ public class DatabaseService
{
foreach (var palette in palettes)
{
var colors = _fileParserService.ParsePalette(palette, out var groups, out var colorsPerGroup);
var colors = fileParserService.ParsePalette(palette, out var groups, out var colorsPerGroup);
for (var groupIndex = 0; groupIndex < groups; groupIndex++)
for (var colorIndex = 0; colorIndex < colorsPerGroup; colorIndex++)
+17 -24
View File
@@ -14,30 +14,23 @@ using SixLabors.ImageSharp.PixelFormats;
namespace fxl.codes.kisekae.Services;
public class FileParserService
public class FileParserService(ILogger<FileParserService> logger)
{
private static readonly byte[] KissHeader = "KiSS"u8.ToArray();
private static readonly Color Transparent = Color.Black.WithAlpha(0);
private readonly ILogger<FileParserService> _logger;
private readonly IsolatedStorageFile _storage;
public FileParserService(ILogger<FileParserService> logger)
{
_logger = logger;
_storage = IsolatedStorageFile.GetUserStoreForApplication();
}
private readonly IsolatedStorageFile _storage = IsolatedStorageFile.GetUserStoreForApplication();
public async Task UnzipLzh(IFormFile file, MemoryStream memoryStream = null)
{
if (!_storage.FileExists(file.FileName))
{
using var writer = _storage.CreateFile(file.FileName);
await using var writer = _storage.CreateFile(file.FileName);
if (memoryStream != null)
memoryStream.CopyTo(writer);
await memoryStream.CopyToAsync(writer);
else
file.CopyTo(writer);
await file.CopyToAsync(writer);
writer.Flush();
writer.Close();
@@ -58,7 +51,7 @@ public class FileParserService
await process.WaitForExitAsync();
}
public Color[] ParsePalette(Palette palette, out int groups, out int colorsPerGroup)
public Rgba32[] ParsePalette(Palette palette, out int groups, out int colorsPerGroup)
{
groups = 0;
colorsPerGroup = 0;
@@ -67,7 +60,7 @@ public class FileParserService
if (!palette.Data[..KissHeader.Length].SequenceEqual(KissHeader)) return GetColors(palette.Data);
// Verify palette mark?
if (palette.Data[4] != 16) _logger.LogError($"{palette.FileName} is not a valid palette file");
if (palette.Data[4] != 16) logger.LogError("{PaletteFileName} is not a valid palette file", palette.FileName);
var colorDepth = Convert.ToInt32(palette.Data[5]);
colorsPerGroup = BitConverter.ToInt16(palette.Data, 8);
@@ -78,14 +71,14 @@ public class FileParserService
public void RenderCel(CelConfig celConfig)
{
_logger.LogTrace($"Reading cel {celConfig.Cel.FileName}");
var buffer = celConfig.Cel?.Data?.ToArray();
if (buffer == null || buffer.Length == 0) return;
logger.LogTrace("Reading cel {CelFileName}", celConfig.Cel.FileName);
var buffer = celConfig.Cel.Data.ToArray();
if (buffer.Length == 0) return;
if (buffer[..KissHeader.Length].SequenceEqual(KissHeader))
{
// Verify cel mark?
if (buffer[4] != 32) _logger.LogError($"{celConfig.Cel.FileName} is not a valid cel file");
if (buffer[4] != 32) logger.LogError("{CelFileName} is not a valid cel file", celConfig.Cel.FileName);
var pixelBits = Convert.ToInt32(buffer[5]);
var width = BitConverter.ToInt16(buffer, 8);
@@ -111,11 +104,11 @@ public class FileParserService
}
}
private Color[] GetColors(IReadOnlyCollection<byte> bytes, int depth = 12, int colorsPerGroup = 16, int groups = 10)
private Rgba32[] GetColors(IReadOnlyCollection<byte> bytes, int depth = 12, int colorsPerGroup = 16, int groups = 10)
{
_logger.LogTrace("Converting byte array to colors");
logger.LogTrace("Converting byte array to colors");
var colorValues = GetValues(bytes, depth / 3);
var colors = new Color[colorsPerGroup * groups];
var colors = new Rgba32[colorsPerGroup * groups];
var length = depth == 12 ? 4 : 3;
var multiplier = depth == 12 ? 16 : 1;
// Nibbles order for 12 bits: R, B, 0, G
@@ -127,7 +120,7 @@ public class FileParserService
var red = colorValues[start] * multiplier;
var green = colorValues[start + (depth == 12 ? 3 : 1)] * multiplier;
var blue = colorValues[start + (depth == 12 ? 1 : 2)] * multiplier;
colors[groupIndex + colorIndex] = Color.FromRgb(Convert.ToByte(red), Convert.ToByte(green), Convert.ToByte(blue));
colors[groupIndex + colorIndex] = new Rgba32(Convert.ToByte(red), Convert.ToByte(green), Convert.ToByte(blue));
}
return colors;
@@ -139,7 +132,7 @@ public class FileParserService
int height,
int pixelBits = 4)
{
_logger.LogTrace("Converting byte array to base64 encoded gifs per palette");
logger.LogTrace("Converting byte array to base64 encoded gifs per palette");
var values = GetValues(bytes, pixelBits);
using var bitmap = new Image<Rgba32>(width, height);
@@ -153,7 +146,7 @@ public class FileParserService
{
var value = values[index];
var isTransparent = value == 0 || value >= palette.Colors.Count;
row[x] = isTransparent ? Transparent : Color.ParseHex(palette.Colors[value].Hex);
row[x] = (isTransparent ? Transparent : Color.ParseHex(palette.Colors[value].Hex)).ToPixel<Rgba32>();
index++;
}
+6 -5
View File
@@ -1,14 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<CopyRazorGenerateFilesToPublishDirectory>true</CopyRazorGenerateFilesToPublishDirectory>
<LangVersion>latestmajor</LangVersion>
<LangVersion>default</LangVersion>
<UserSecretsId>b2886b11-62f3-4354-b5c5-eaa9ea9678d3</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.8"/>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.9"/>
<PackageReference Include="SixLabors.ImageSharp" Version="4.0.0"/>
</ItemGroup>
<ItemGroup>
@@ -25,6 +26,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\fxl.codes.kisekae.data\fxl.codes.kisekae.data.csproj" />
<ProjectReference Include="..\fxl.codes.kisekae.data\fxl.codes.kisekae.data.csproj"/>
</ItemGroup>
</Project>