2025-07-31 19:39:06 +07:00
|
|
|
using SixLabors.ImageSharp;
|
|
|
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
|
|
|
using SixLabors.ImageSharp.Processing;
|
2025-08-01 20:18:01 +07:00
|
|
|
using StitcherApi.Services.Utilities;
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-08-01 20:18:01 +07:00
|
|
|
namespace StitcherApi.Services.Fast;
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-08-01 20:18:01 +07:00
|
|
|
public class FastProcessor
|
2025-07-31 19:39:06 +07:00
|
|
|
{
|
|
|
|
|
private readonly string _assetPath;
|
2025-08-01 20:18:01 +07:00
|
|
|
private readonly ILogger<FastProcessor> _logger;
|
2025-07-31 19:39:06 +07:00
|
|
|
private const int TILE_SIZE = 720;
|
|
|
|
|
|
2025-08-01 20:18:01 +07:00
|
|
|
public FastProcessor(string assetPath, ILogger<FastProcessor> logger)
|
2025-07-31 19:39:06 +07:00
|
|
|
{
|
|
|
|
|
_assetPath = assetPath;
|
2025-08-01 20:18:01 +07:00
|
|
|
_logger = logger;
|
2025-07-31 19:39:06 +07:00
|
|
|
}
|
|
|
|
|
|
2025-08-01 20:18:01 +07:00
|
|
|
public async Task<byte[]> ProcessAsync(StitchRequest stitchRequest)
|
2025-07-31 19:39:06 +07:00
|
|
|
{
|
2025-07-31 20:41:48 +07:00
|
|
|
using Image<Rgba32> finalImage = new(stitchRequest.CropW, stitchRequest.CropH);
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-07-31 20:41:48 +07:00
|
|
|
for (int r = stitchRequest.StartTileRow; r <= stitchRequest.EndTileRow; r++)
|
2025-07-31 19:39:06 +07:00
|
|
|
{
|
2025-07-31 20:41:48 +07:00
|
|
|
for (int c = stitchRequest.StartTileCol; c <= stitchRequest.EndTileCol; c++)
|
2025-07-31 19:39:06 +07:00
|
|
|
{
|
2025-07-31 20:41:48 +07:00
|
|
|
string tileFileName = TileHelper.GetTileFileName(r, c);
|
|
|
|
|
string tileFilePath = Path.Combine(_assetPath, tileFileName);
|
2025-07-31 19:39:06 +07:00
|
|
|
|
|
|
|
|
if (!File.Exists(tileFilePath))
|
|
|
|
|
{
|
|
|
|
|
throw new FileNotFoundException($"Asset not found: {tileFileName}");
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-01 20:18:01 +07:00
|
|
|
using Image<Rgba32> tileImage = await Image.LoadAsync<Rgba32>(tileFilePath);
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-07-31 20:41:48 +07:00
|
|
|
int tileOriginX = (c - stitchRequest.MinCol) * TILE_SIZE;
|
|
|
|
|
int tileOriginY = (r - stitchRequest.MinRow) * TILE_SIZE;
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-07-31 20:41:48 +07:00
|
|
|
int srcX = Math.Max(0, stitchRequest.CropX - tileOriginX);
|
|
|
|
|
int srcY = Math.Max(0, stitchRequest.CropY - tileOriginY);
|
|
|
|
|
int destX = Math.Max(0, tileOriginX - stitchRequest.CropX);
|
|
|
|
|
int destY = Math.Max(0, tileOriginY - stitchRequest.CropY);
|
2025-07-31 19:39:06 +07:00
|
|
|
|
2025-07-31 20:41:48 +07:00
|
|
|
int overlapW = Math.Max(
|
2025-07-31 19:39:06 +07:00
|
|
|
0,
|
|
|
|
|
Math.Min(stitchRequest.CropX + stitchRequest.CropW, tileOriginX + TILE_SIZE)
|
|
|
|
|
- Math.Max(stitchRequest.CropX, tileOriginX)
|
|
|
|
|
);
|
2025-07-31 20:41:48 +07:00
|
|
|
int overlapH = Math.Max(
|
2025-07-31 19:39:06 +07:00
|
|
|
0,
|
|
|
|
|
Math.Min(stitchRequest.CropY + stitchRequest.CropH, tileOriginY + TILE_SIZE)
|
|
|
|
|
- Math.Max(stitchRequest.CropY, tileOriginY)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (overlapW > 0 && overlapH > 0)
|
|
|
|
|
{
|
2025-07-31 20:41:48 +07:00
|
|
|
Rectangle sourceRect = new Rectangle(srcX, srcY, overlapW, overlapH);
|
2025-07-31 19:39:06 +07:00
|
|
|
finalImage.Mutate(ctx =>
|
|
|
|
|
ctx.DrawImage(
|
|
|
|
|
tileImage,
|
|
|
|
|
new Point(destX, destY),
|
|
|
|
|
sourceRect,
|
|
|
|
|
new GraphicsOptions()
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stitchRequest.OutputScale > 0 && stitchRequest.OutputScale < 1.0)
|
|
|
|
|
{
|
2025-07-31 20:41:48 +07:00
|
|
|
int newWidth = (int)(stitchRequest.CropW * stitchRequest.OutputScale);
|
|
|
|
|
int newHeight = (int)(stitchRequest.CropH * stitchRequest.OutputScale);
|
2025-07-31 19:39:06 +07:00
|
|
|
finalImage.Mutate(x => x.Resize(newWidth, newHeight, KnownResamplers.Bicubic));
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-31 20:41:48 +07:00
|
|
|
using MemoryStream memoryStream = new MemoryStream();
|
2025-07-31 19:39:06 +07:00
|
|
|
await finalImage.SaveAsPngAsync(memoryStream);
|
|
|
|
|
return memoryStream.ToArray();
|
|
|
|
|
}
|
|
|
|
|
}
|