diff --git a/.gitignore b/.gitignore
index e23c412..4570597 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,5 @@
*.Development.json
*.Release.json
-.DS_Store
\ No newline at end of file
+.DS_Store
+*.lic
\ No newline at end of file
diff --git a/fxl.codes.kisekae.blazor/fxl.codes.kisekae.blazor.csproj b/fxl.codes.kisekae.blazor/fxl.codes.kisekae.blazor.csproj
index d72cbff..1570b01 100644
--- a/fxl.codes.kisekae.blazor/fxl.codes.kisekae.blazor.csproj
+++ b/fxl.codes.kisekae.blazor/fxl.codes.kisekae.blazor.csproj
@@ -1,9 +1,10 @@
- net8.0
+ net10.0
enable
enable
+ default
@@ -15,7 +16,7 @@
-
+
diff --git a/fxl.codes.kisekae.data.test/LhContainerTests.cs b/fxl.codes.kisekae.data.test/LhContainerTests.cs
index 6529d1f..b537385 100644
--- a/fxl.codes.kisekae.data.test/LhContainerTests.cs
+++ b/fxl.codes.kisekae.data.test/LhContainerTests.cs
@@ -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}");
diff --git a/fxl.codes.kisekae.data.test/fxl.codes.kisekae.data.test.csproj b/fxl.codes.kisekae.data.test/fxl.codes.kisekae.data.test.csproj
index fc11ded..fa8df17 100644
--- a/fxl.codes.kisekae.data.test/fxl.codes.kisekae.data.test.csproj
+++ b/fxl.codes.kisekae.data.test/fxl.codes.kisekae.data.test.csproj
@@ -1,26 +1,27 @@
- net8.0
+ net10.0
enable
enable
false
true
+ default
-
-
-
-
-
-
-
-
-
- ..\..\..\..\..\usr\local\share\dotnet\shared\Microsoft.AspNetCore.App\8.0.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll
-
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/fxl.codes.kisekae.data/Archives/LhContainer.cs b/fxl.codes.kisekae.data/Archives/LhContainer.cs
index 3203a7d..c26a346 100644
--- a/fxl.codes.kisekae.data/Archives/LhContainer.cs
+++ b/fxl.codes.kisekae.data/Archives/LhContainer.cs
@@ -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)
diff --git a/fxl.codes.kisekae.data/fxl.codes.kisekae.data.csproj b/fxl.codes.kisekae.data/fxl.codes.kisekae.data.csproj
index c4c15a5..8659e21 100644
--- a/fxl.codes.kisekae.data/fxl.codes.kisekae.data.csproj
+++ b/fxl.codes.kisekae.data/fxl.codes.kisekae.data.csproj
@@ -1,22 +1,23 @@
- net8.0
+ net10.0
enable
enable
Exe
c3253549-351f-4bcb-9c52-ce67c39cbeaf
+ default
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
+
+
diff --git a/fxl.codes.kisekae/Models/CelModel.cs b/fxl.codes.kisekae/Models/CelModel.cs
index 34d2efe..e3faab9 100644
--- a/fxl.codes.kisekae/Models/CelModel.cs
+++ b/fxl.codes.kisekae/Models/CelModel.cs
@@ -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 InitialPositions { get; set; } = new Dictionary();
- 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 InitialPositions { get; set; } = new Dictionary();
+ public CoordinateModel Offset { get; set; }
}
\ No newline at end of file
diff --git a/fxl.codes.kisekae/Models/CoordinateModel.cs b/fxl.codes.kisekae/Models/CoordinateModel.cs
index b1a6765..609d788 100644
--- a/fxl.codes.kisekae/Models/CoordinateModel.cs
+++ b/fxl.codes.kisekae/Models/CoordinateModel.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/fxl.codes.kisekae/Models/ErrorViewModel.cs b/fxl.codes.kisekae/Models/ErrorViewModel.cs
index 3d04f69..2634956 100644
--- a/fxl.codes.kisekae/Models/ErrorViewModel.cs
+++ b/fxl.codes.kisekae/Models/ErrorViewModel.cs
@@ -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);
}
\ No newline at end of file
diff --git a/fxl.codes.kisekae/Models/PlaysetModel.cs b/fxl.codes.kisekae/Models/PlaysetModel.cs
index 596b1a5..b4b23c6 100644
--- a/fxl.codes.kisekae/Models/PlaysetModel.cs
+++ b/fxl.codes.kisekae/Models/PlaysetModel.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/fxl.codes.kisekae/Services/ConfigurationReaderService.cs b/fxl.codes.kisekae/Services/ConfigurationReaderService.cs
index 828dd8a..e48bf9d 100644
--- a/fxl.codes.kisekae/Services/ConfigurationReaderService.cs
+++ b/fxl.codes.kisekae/Services/ConfigurationReaderService.cs
@@ -8,26 +8,19 @@ using Microsoft.Extensions.Logging;
namespace fxl.codes.kisekae.Services;
-public class ConfigurationReaderService
+public class ConfigurationReaderService(ILogger logger)
{
private const string CelRegex = @"#(?\d*)\.?(?\d*)\s*(?[\w\d\-]*\.[cCeElL]*)\s*\*?"
+ @"(?\d*)?\s*\:?(?[\d\s]*)?;?(?[\w\d\-\s\%]*)";
private const string ResolutionRegexPattern = @"\((?[0-9]*).(?[0-9]*)\)";
- private readonly ILogger _logger;
-
- public ConfigurationReaderService(ILogger logger)
- {
- _logger = logger;
- }
-
public void ReadConfiguration(Configuration dto,
IDictionary backgroundColors,
IDictionary cels,
Dictionary palettes)
{
- _logger.LogInformation($"Reading {dto.Name}");
+ logger.LogInformation("Reading {Name}", dto.Name);
var initialPositions = new StringBuilder();
var backgroundColorIndex = 0;
var paletteOrder = new List();
diff --git a/fxl.codes.kisekae/Services/DatabaseService.cs b/fxl.codes.kisekae/Services/DatabaseService.cs
index 5e806d4..fce6e3a 100644
--- a/fxl.codes.kisekae/Services/DatabaseService.cs
+++ b/fxl.codes.kisekae/Services/DatabaseService.cs
@@ -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 contextFactory)
{
- private readonly ConfigurationReaderService _configurationReaderService;
- private readonly IDbContextFactory _contextFactory;
-
- private readonly FileParserService _fileParserService;
- private readonly ILogger _logger;
- private readonly IsolatedStorageFile _storage;
-
- public DatabaseService(ILogger logger,
- ConfigurationReaderService configurationReaderService,
- FileParserService fileParserService,
- IDbContextFactory contextFactory)
- {
- _logger = logger;
- _configurationReaderService = configurationReaderService;
- _fileParserService = fileParserService;
- _contextFactory = contextFactory;
- _storage = IsolatedStorageFile.GetUserStoreForApplication();
- }
+ private readonly IsolatedStorageFile _storage = IsolatedStorageFile.GetUserStoreForApplication();
public IEnumerable 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();
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++)
diff --git a/fxl.codes.kisekae/Services/FileParserService.cs b/fxl.codes.kisekae/Services/FileParserService.cs
index 60d0acd..4073fa2 100644
--- a/fxl.codes.kisekae/Services/FileParserService.cs
+++ b/fxl.codes.kisekae/Services/FileParserService.cs
@@ -14,30 +14,23 @@ using SixLabors.ImageSharp.PixelFormats;
namespace fxl.codes.kisekae.Services;
-public class FileParserService
+public class FileParserService(ILogger logger)
{
private static readonly byte[] KissHeader = "KiSS"u8.ToArray();
private static readonly Color Transparent = Color.Black.WithAlpha(0);
- private readonly ILogger _logger;
- private readonly IsolatedStorageFile _storage;
-
- public FileParserService(ILogger 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 bytes, int depth = 12, int colorsPerGroup = 16, int groups = 10)
+ private Rgba32[] GetColors(IReadOnlyCollection 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(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();
index++;
}
diff --git a/fxl.codes.kisekae/fxl.codes.kisekae.csproj b/fxl.codes.kisekae/fxl.codes.kisekae.csproj
index 905bde2..42cdc1f 100644
--- a/fxl.codes.kisekae/fxl.codes.kisekae.csproj
+++ b/fxl.codes.kisekae/fxl.codes.kisekae.csproj
@@ -1,14 +1,15 @@
- net8.0
+ net10.0
true
- latestmajor
+ default
+ b2886b11-62f3-4354-b5c5-eaa9ea9678d3
-
-
+
+
@@ -25,6 +26,6 @@
-
+