Initial commit

This commit is contained in:
Meizar 2025-07-26 06:56:07 +07:00
commit 8d4b2bc943
17 changed files with 389 additions and 0 deletions

44
WebApp/Coordinate.cs Normal file
View file

@ -0,0 +1,44 @@
namespace WebApp;
internal record Coordinate
{
public string Name { get; }
public int Row { get; }
public int Col { get; }
public string Path => PATH + Name + ".png";
private const string PATH = "D:/tiles1705/";
public Coordinate(string name)
{
Name = name;
int row = 0;
int col = 0;
foreach (var item in name)
{
if (item >= 'A')
{
row = row * 26 + (item - 'A' + 1);
}
else if (item >= '1')
{
col = col * 10 + (item - '1' + 1);
}
}
Row = row;
Col = col;
}
public Coordinate(int row, int col)
{
Row = row;
Col = col;
Name = Helper.ToLetters(row) + col;
}
public override string ToString()
{
return Name;
}
}

17
WebApp/Helper.cs Normal file
View file

@ -0,0 +1,17 @@
namespace WebApp;
public static class Helper
{
public static string ToLetters(int number)
{
var result = "";
while (number > 0)
{
number--; // Adjust for 1-based indexing
char letter = (char)('A' + (number % 26));
result = letter + result;
number /= 26;
}
return result;
}
}

130
WebApp/ImageGenerator.cs Normal file
View file

@ -0,0 +1,130 @@
using System.Collections.Concurrent;
using OpenCvSharp;
namespace WebApp;
public class ImageGenerator
{
private const string PATH = "D:/tiles1705/";
public byte[] GenerateImage(RequestBody requestBody)
{
var start = DateTime.Now;
string[] inputs = requestBody.CanvasRect.Split(":");
Coordinate coord0 = new Coordinate(inputs[0]);
Coordinate coord1 = new Coordinate(inputs[1]);
(var matrix, _, _) = GenerateDict(coord0, coord1);
ConcurrentDictionary<int, Mat> rows = new();
Parallel.ForEach(matrix, pair =>
{
Mat row = new Mat();
List<Mat> mats = new();
foreach (var coord in pair.Value)
{
string fileName = PATH + coord.Name + ".png";
mats.Add(new Mat( fileName ) );
}
Cv2.HConcat(mats, row);
rows[pair.Key] = row;
});
Mat output = new Mat();
Cv2.VConcat(rows.Values, output);
var result = output.ImEncode();
var end = DateTime.Now;
var elapsed = end - start;
Console.WriteLine($"Elapsed: {elapsed.TotalMilliseconds} ms");
return result;
}
public byte[] GenerateImage2(RequestBody requestBody)
{
var start = DateTime.Now;
Coordinate a1 = new Coordinate("A1");
Mat a1Mat = new Mat(a1.Path);
string[] inputs = requestBody.CanvasRect.Split(":");
Coordinate coord0 = new Coordinate(inputs[0]);
Coordinate coord1 = new Coordinate(inputs[1]);
double scale = requestBody.OutputScale;
(var matrix, int rowCount, int colCount) = GenerateMatrix(coord0, coord1);
Mat temp = GenerateTempMat(a1Mat, rowCount, colCount);
Parallel.ForEach(matrix, item =>
{
Mat mat = new Mat(item.Path);
Rect rect = new Rect((item.Col - 1) * a1Mat.Cols, (item.Row - 1) * a1Mat.Rows, a1Mat.Cols, a1Mat.Rows);
mat.CopyTo(temp[rect]);
});
double newWidth = temp.Width * scale;
double newHeight = temp.Height * scale;
temp.Resize(new Size(newWidth, newHeight));
var result = temp.ImEncode();
var end = DateTime.Now;
var elapsed = end - start;
Console.WriteLine($"Elapsed: {elapsed.TotalMilliseconds} ms");
return result;
}
internal (List<Coordinate> Matrix, int RowCount, int ColCount) GenerateMatrix(Coordinate coordinate1, Coordinate coordinate2)
{
int minRow = Math.Min(coordinate1.Row, coordinate2.Row);
int maxRow = Math.Max(coordinate1.Row, coordinate2.Row);
int minCol = Math.Min(coordinate1.Col, coordinate2.Col);
int maxCol = Math.Max(coordinate1.Col, coordinate2.Col);
int rowCount = maxRow - minRow + 1;
int colCount = maxCol - minCol + 1;
// Initialize collections
List<Coordinate> results = new List<Coordinate>(rowCount*colCount);
for (int i = 1; i <= rowCount; i++)
{
for (int j = 1; j <= colCount; j++)
{
results.Add(new Coordinate(i,j));
}
}
return (results, rowCount, colCount);
}
internal (ConcurrentDictionary<int,List<Coordinate>> Matrix, int RowCount, int ColCount) GenerateDict(Coordinate coordinate1, Coordinate coordinate2)
{
ConcurrentDictionary<int,List<Coordinate>> results = new();
int minRow = Math.Min(coordinate1.Row, coordinate2.Row);
int maxRow = Math.Max(coordinate1.Row, coordinate2.Row);
int minCol = Math.Min(coordinate1.Col, coordinate2.Col);
int maxCol = Math.Max(coordinate1.Col, coordinate2.Col);
int rowCount = maxRow - minRow + 1;
int colCount = maxCol - minCol + 1;
for (int i = 0; i < rowCount; i++)
{
List<Coordinate> result = new();
for (int j = 0; j < colCount; j++)
{
int row = minRow + i;
int col = minCol + j;
result.Add(new Coordinate(row, col));
}
results[i] = result;
}
return (results, rowCount, colCount);
}
internal Mat GenerateTempMat(Mat reference, int rowCount, int colCount)
{
return new Mat(reference.Rows * rowCount, reference.Cols * colCount, reference.Type());
}
}

44
WebApp/Program.cs Normal file
View file

@ -0,0 +1,44 @@
using Microsoft.OpenApi.Models;
using WebApp;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Configure the HTTP request pipeline.
if (builder.Environment.IsDevelopment())
{
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Stitch a Ton", Description = "Meizar's stitch a ton solution", Version = "v1" });
});
}
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Stitch a Ton");
});
}
app.UseHttpsRedirection();
app.MapPost("/api/image/generate",
( RequestBody requestBody ) =>
{
ImageGenerator imageGenerator = new ImageGenerator();
var png = imageGenerator.GenerateImage2( requestBody );
return Results.File(png, "image/png", "result.png");
})
.WithName("ImageGenerator")
.Produces(StatusCodes.Status200OK, contentType:"image/png");
app.Run();

View file

@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:47070",
"sslPort": 44330
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5184",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7224;http://localhost:5184",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

9
WebApp/RequestBody.cs Normal file
View file

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace WebApp;
public record struct RequestBody(
[property: JsonPropertyName("canvas_rect")]
string CanvasRect,
[property: JsonPropertyName("output_scale")]
double OutputScale );

16
WebApp/WebApp.csproj Normal file
View file

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>WebApp</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenCvSharp4" Version="4.11.0.20250507" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.11.0.20250507" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,6 @@
@WebApplication_HostAddress = http://localhost:5184
GET {{WebApplication_HostAddress}}/weatherforecast/
Accept: application/json
###

View file

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
WebApp/appsettings.json Normal file
View file

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}