Initial commit
This commit is contained in:
commit
ef3b7d68fb
30 changed files with 1568 additions and 0 deletions
53
App/Controllers/ImageController.cs
Normal file
53
App/Controllers/ImageController.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System.Text.Json;
|
||||
using StitchATon2.App.Models;
|
||||
using StitchATon2.Domain;
|
||||
|
||||
namespace StitchATon2.App.Controllers;
|
||||
|
||||
public static class ImageController
|
||||
{
|
||||
public static async Task GenerateImage(HttpResponse response, GenerateImageDto dto, TileManager tileManager)
|
||||
{
|
||||
if (dto.GetErrors() is { Count: > 0 } errors)
|
||||
{
|
||||
response.StatusCode = 422;
|
||||
response.ContentType = "text/json";
|
||||
var errorBody = JsonSerializer.Serialize(errors, AppJsonSerializerContext.Default.DictionaryStringListString);
|
||||
response.ContentLength = errorBody.Length;
|
||||
await response.WriteAsync(errorBody);
|
||||
await response.CompleteAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "image/png";
|
||||
|
||||
await tileManager
|
||||
.CreateSection(dto)
|
||||
.WriteToStream(response.Body, dto.OutputScale);
|
||||
|
||||
await response.CompleteAsync();
|
||||
}
|
||||
|
||||
public static async Task GenerateRandomImage(HttpResponse response, TileManager tileManager)
|
||||
{
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "image/png";
|
||||
|
||||
var maxId = tileManager.Configuration.Rows * tileManager.Configuration.Columns;
|
||||
var id0 = Random.Shared.Next(maxId);
|
||||
var id1 = Random.Shared.Next(maxId);
|
||||
|
||||
var tile0 = tileManager.GetTile(id0);
|
||||
var tile1 = tileManager.GetTile(id1);
|
||||
var coordinatePair = $"{tile0.Coordinate}:{tile1.Coordinate}";
|
||||
|
||||
var section = tileManager.CreateSection(coordinatePair, 0, 0, 1, 1);
|
||||
|
||||
var scale = float.Clamp(480f / int.Max(section.Width, section.Height), 0.01f, 1f);
|
||||
Console.WriteLine($"Generate random image for {coordinatePair} scale: {scale}");
|
||||
|
||||
await section.WriteToStream(response.Body, scale);
|
||||
await response.CompleteAsync();
|
||||
}
|
||||
}
|
||||
72
App/Models/GenerateImageDto.cs
Normal file
72
App/Models/GenerateImageDto.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StitchATon2.App.Models;
|
||||
|
||||
public class GenerateImageDto
|
||||
{
|
||||
[JsonPropertyName("canvas_rect")]
|
||||
public string? CanvasRect { get; set; }
|
||||
|
||||
[JsonPropertyName("crop_offset")]
|
||||
public float[]? CropOffset { get; set; }
|
||||
|
||||
[JsonPropertyName("crop_size")]
|
||||
public float[]? CropSize { get; set; }
|
||||
|
||||
[JsonPropertyName("output_scale")]
|
||||
public float? OutputScale { get; set; }
|
||||
|
||||
public Dictionary<string, List<string>> GetErrors()
|
||||
{
|
||||
return ValidateCanvasRect()
|
||||
.Concat(ValidateNumberPair(CropOffset, "crop_offset"))
|
||||
.Concat(ValidateNumberPair(CropSize, "crop_size"))
|
||||
.Concat(ValidateNumber(OutputScale, "output_scale"))
|
||||
.GroupBy(item => item.Item1)
|
||||
.ToDictionary(item => item.Key, item => item.Select(p => p.Item2).ToList());
|
||||
}
|
||||
|
||||
private IEnumerable<(string, string)> ValidateCanvasRect()
|
||||
{
|
||||
if (string.IsNullOrEmpty(CanvasRect))
|
||||
{
|
||||
yield return ("canvas_rect", "canvas_rect is required.");
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<(string, string)> ValidateNumberPair(float[]? numberPair, string fieldName)
|
||||
{
|
||||
if (numberPair is null)
|
||||
{
|
||||
yield return (fieldName, $"{fieldName} is required.");
|
||||
}
|
||||
else if (numberPair.Length != 2)
|
||||
{
|
||||
yield return (fieldName, $"{fieldName} must have exactly 2 elements.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in ValidateNumber(numberPair[0], $"{fieldName}[0]"))
|
||||
yield return item;
|
||||
|
||||
foreach (var item in ValidateNumber(numberPair[1], $"{fieldName}[1]"))
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<(string, string)> ValidateNumber(float? number, string fieldName, double min = 0.0, double max = 1.0)
|
||||
{
|
||||
if (number is null)
|
||||
{
|
||||
yield return (fieldName, $"{fieldName} is required.");
|
||||
}
|
||||
else if (number < min)
|
||||
{
|
||||
yield return (fieldName, $"{fieldName} must be greater than or equal to {min}.");
|
||||
}
|
||||
else if (number > max)
|
||||
{
|
||||
yield return (fieldName, $"{fieldName} must be less than or equal to {max}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
28
App/Program.cs
Normal file
28
App/Program.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using StitchATon2.App.Controllers;
|
||||
using StitchATon2.App.Models;
|
||||
using StitchATon2.Domain;
|
||||
|
||||
var builder = WebApplication.CreateSlimBuilder(args);
|
||||
|
||||
using var tileManager = new TileManager(Configuration.Default);
|
||||
builder.Services.AddSingleton(tileManager);
|
||||
|
||||
builder.Services.ConfigureHttpJsonOptions(options =>
|
||||
{
|
||||
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapPost("/api/image/generate", ImageController.GenerateImage);
|
||||
app.MapGet("/api/image/generate/random", ImageController.GenerateRandomImage);
|
||||
|
||||
app.Run();
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = false)]
|
||||
[JsonSerializable(typeof(GenerateImageDto))]
|
||||
[JsonSerializable(typeof(Dictionary<string,List<string>>))]
|
||||
internal partial class AppJsonSerializerContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
16
App/Properties/launchSettings.json
Normal file
16
App/Properties/launchSettings.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "todos",
|
||||
"applicationUrl": "http://localhost:5088",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASSET_PATH_RO": "C:\\Storage\\tiles1705"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
App/StitchATon2.App.csproj
Normal file
19
App/StitchATon2.App.csproj
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<PublishAot>true</PublishAot>
|
||||
<RootNamespace>StitchATon2.App</RootNamespace>
|
||||
|
||||
<!-- <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>-->
|
||||
<!-- <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Domain\StitchATon2.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
22
App/Utils.cs
Normal file
22
App/Utils.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using StitchATon2.App.Models;
|
||||
using StitchATon2.Domain;
|
||||
using StitchATon2.Domain.ImageCreators;
|
||||
|
||||
namespace StitchATon2.App;
|
||||
|
||||
public static class Utils
|
||||
{
|
||||
public static GridSection CreateSection(this TileManager manager, GenerateImageDto dto)
|
||||
=> manager.CreateSection(
|
||||
dto.CanvasRect!,
|
||||
dto.CropOffset![0],
|
||||
dto.CropOffset![1],
|
||||
dto.CropSize![0],
|
||||
dto.CropSize![1]);
|
||||
|
||||
public static async Task WriteToStream(this GridSection section, Stream stream, float? scale)
|
||||
{
|
||||
var imageCreator = new ImageCreator(section);
|
||||
await imageCreator.WriteToStream(stream, scale!.Value);
|
||||
}
|
||||
}
|
||||
8
App/appsettings.Development.json
Normal file
8
App/appsettings.Development.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
App/appsettings.json
Normal file
9
App/appsettings.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue